refactor: thread language locale - #62
Merged
Merged
Conversation
Rework the merged thread-language feature so language handling is centralized
and typed, without changing user-facing behavior:
- Introduce AgentContext (LangChain v1 context_schema) and migrate the tools,
middleware, and runner off config["configurable"] to the context pattern;
thread_id stays in configurable only because the checkpointer keys on it.
- Move response-language steering and {current_date}/{language_directive}
rendering into system_prompt_middleware (dynamic prompt), so nothing is
injected into the user message or checkpoint history and the date reflects
request time rather than server start.
- Normalize language once at the boundary (ThreadPayload before-validator,
typed LanguageCode); downstream helpers trust a valid code instead of each
re-applying the fallback. Rename t() -> translate() with a MessageKey enum
and make the i18n internals private.
- Return the already-fetched thread from _authorize_message (drops the
duplicate query in the export endpoint) and refactor _fetch_usage_guide to
fall back through DEFAULT_LANGUAGE instead of a hardcoded "pt".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… boundary - Adapt existing tests to the required AgentContext.language, the context-based tool runtime (ToolRuntime), and the now-private i18n internals (use the public API). - Add coverage for behavior that was previously untested: localized_field pt-fallback, non-pt metadata localization in the tools, the usage-guide language fallback/dedupe, per-(table_id, language) name-cache keying, the ThreadPayload normalization boundary, run_agent forwarding context to the agent, and language-localized export failure details. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The config->context refactor moved user_id off config["configurable"], which LangChain copies into LangSmith trace attributes — so user_id stopped showing in the Attributes tab. Declare thread_id/user_id/language explicitly under config["metadata"] (the intended field for trace attributes) so they're surfaced independently of that incidental copy: restores user_id and adds language as a new filterable attribute. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refactor of the already-merged thread-language feature (pt/en/es).
Main changes
Language steering moved to a middleware. A
dynamic_promptmiddleware renders the system prompt per run, filling{current_date}and a new{language_directive}placeholder. This removes the old approach of prepending the directive to the user message — so it no longer leaks into the persistedMessageor the checkpoint history, and the date now reflects request time rather than server-start time.config["configurable"]→ LangChain v1context. IntroducedAgentContext(ascontext_schema); tools and the middleware now readruntime.contextinstead ofconfig["configurable"].thread_idstays inconfigurableonly because the langgraph checkpointer keys on it.Language normalized once, at the boundary.
ThreadPayload.language(abeforevalidator) is the single normalization point, typedLanguageCode; downstream helpers trust a valid code instead of each re-applying a fallback. Renamedt()→translate()with aMessageKeyenum, and made theapp.i18ninternals private.Trace attributes via
config["metadata"].thread_id/user_id/languageare declared explicitly as metadata so LangSmith surfaces them as Attributes (the context move had droppeduser_idfrom traces;languageis newly filterable).Small fixes.
_authorize_messagereturns the thread it already fetched (drops a duplicate query in the export endpoint);_fetch_usage_guidefalls back throughDEFAULT_LANGUAGEinstead of a hardcoded"pt".Tests
Expanded coverage for behavior that was previously untested:
localized_fieldpt-fallback, non-pt metadata localization in the tools, the usage-guide language fallback, per-(table_id, language)name-cache keying, theThreadPayloadnormalization boundary,run_agentforwarding context to the agent, and the trace metadata. Full suite green.Notes
GraphQL queries and the DB migration are unchanged from staging (comment-only diffs), so no new backend/schema dependency beyond what's already live.