Repository navigation
fix(integrations): recall with the end of a long prompt in Hermes, LangChain, LangGraph, and Pydantic AI - #2647
Open
Fengzdadi wants to merge 1 commit into
Conversation
…ngChain, LangGraph, and Pydantic AI The four in-process Python adapters cut an automatic recall query to its first 8,192 characters, so a long prompt lost its end, which is usually the question in hand. They now send the same query as the hook hosts and Bub: a prompt within the bounds trimmed, a longer one cut to its most recent text within 8,192 characters and 8,192 UTF-8 bytes without splitting a character. The rule comes from powercontext_integration_lifecycle.prepared_context. Hermes ships a generated copy beside its other plugin helpers. The SDK adapters install with the core but also support released cores that predate that package (the LangChain job pins core 1.5.0), so importing it would raise their floor; each ships a private generated copy instead, and make check rejects drift. Pydantic AI no longer cuts the latest user text before using it, so the user_prompt capture fallback keeps the whole prompt; capture still applies its own byte limit. tests/test_recall_query_bound.py now drives one real turn through each adapter's public entry point against a recording Server and checks the query for every fixture case. The LangGraph over-limit regression places its question at the end of the prompt, where users put it. Explicit search commands and tools (Hermes commands.py, LangGraph tools.py) are unchanged.
Fengzdadi
requested review from
Alanxtl,
AlexStocks,
PsiACE,
frostming,
thunguo and
zhanghuidinah
as code owners
November 14, 2026 02:35
13 of 17 tasks
This branch has not been deployed
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.
Which issue or RFC does this PR close?
Part of #2250 ("② fix divergences": automatic recall query bound for the in-process Python adapters).
Rationale for this change
POST /v1/context/prepareaccepts a query of at most 8,192 characters. Claude Code, Codex, WorkBuddy, Kimi Code, ZCode, Pi, OpenCode, DSH, and Bub send a long prompt's end (#2252,tests/fixtures/recall_query_bound.json). Hermes, LangChain, LangGraph, and Pydantic AI still sentquery[:8192], the start. A prompt longer than 8,192 characters lost its end, which is usually the question in hand, so recall ran on preamble or pasted context instead of the request.What changes are included in this PR?
Behavior
prefetch,queue_prefetch(and the evaluation-trace query)PowerContextMiddlewaremodel-call recall (and the optional Langfuse recall observation)PowerContextRecallPowerContextcapability recallThe shared rule is
bounded_recall_queryinsrc/powercontext_integration_lifecycle/prepared_context.py: trim; keep text within 8,192 characters and 8,192 UTF-8 bytes as is; otherwise keep the last 8,192 characters, then the last 8,192 bytes, without splitting a character.Pydantic AI also stops cutting the latest user text at 8,192 characters before using it. The
user_promptcapture event falls back to that text whenctx.prompthas none, so the fallback now keeps the whole prompt; the event keeps its ownCAPTURE_MAX_BYTESlimit.How the adapters get the rule
integrations/hermes/plugins/powercontext/prepared_context.py, besidepowercontext_client_config.py, because its plugin directory installs without the PowerContext package.powercontext[client], but they support released cores that predatepowercontext_integration_lifecycle(first shipped in 1.5.1). TheVerify standalone LangChain adapter with released corejob pins core 1.5.0, and the text-assembly guide documents legacy recall with core 0.2.0. Importing the package would raise that floor, so each adapter ships a private generated copy (_prepared_context.py) instead. The wheels contain it and import nothing new.scripts/generate_integration_lifecycle.pywrites all four copies;make check(integration-lifecycle-check) rejects drift.pyproject.tomllints the copies as Python 3.9 like their source.Tests
tests/inprocess_adapter_turns.pyruns one turn through each adapter's public entry point (HermesPowerContextMemoryProvider, LangChaincreate_agentwith the middleware, LangGraphcreate_react_agentwithPowerContextRecall, Pydantic AIAgentwithPowerContext) and its real HTTP client, against a recording Server on an ephemeral loopback port.tests/test_recall_query_bound.pychecks the query each adapter sends for every case inrecall_query_bound.json. Against the previous adapters, 25 of the 32 cases fail: every over-the-bound case for all four adapters, and Hermes's untrimmed within-the-bounds case.tests/langgraph_adapter/test_recall.py::test_recall_completes_graph_for_over_limit_promptasserted that recall fires on a long prompt whose question came first. Its prompt now ends with the question; the assertions are unchanged.Docs
docs/{en,zh}/docs/integrations/{hermes,langchain,langgraph,pydantic-ai}.mddescribe the query the adapter sends.Not included
commands.pyand LangGraphtools.py(powercontext_search,powercontext_context). The model or user writes those queries directly.Overlap with #2550
scripts/generate_integration_lifecycle.pywith whole-package copies. This PR adds single-file copies for Hermes and the SDK adapters. Whichever merges second keeps the Hermes, WorkBuddy, and SDK adapter entries inCOPIES, drops the Claude Code and Codex ones, and rerunsmake integration-lifecycle.Are there any user-facing changes?
Yes. A prompt longer than 8,192 characters, or 8,192 UTF-8 bytes, now recalls with its end instead of its start in these four adapters. Hermes also trims surrounding whitespace from the query. No API or persisted format changes; capture is unchanged.
How was this change tested?
uv run pytest tests/test_recall_query_bound.py(41 passed); with the adapter sources reverted, 25 fail as described above.uv run pytest tests/langchain_middleware tests/langgraph_adapter tests/pydantic_ai_adapter tests/integrations/test_hermes_provider.py tests/test_hermes_cli.py tests/integration_conformance tests/test_recall_query_bound.py tests/test_automatic_prompt_privacy.py tests/test_integration_lifecycle.py: 395 passed, 2 skipped.make checkpasses.make test: 10,628 passed, 16 failed. Three failures were load-related (twotest_artifact_processingcases and an asyncio timeout intests/e2e/test_langgraph_chain.py) and passed when rerun serially. The other 13 (test_ci_installation_roles,test_jev_rerank_comparison, and onetest_gateway_authenticationcase) fail the same way on unmodifiedupstream/master195be9b._prepared_context.py; imported the three adapters withpowercontext_integration_lifecycleblocked from import. The CI job against released core 1.5.0 was not run locally.Self-review against
REVIEW.md, plus an independent Opus review. Neither found a blocking issue. The independent review checked that a credential near the cut cannot survive as a fragment once the follow-up scrubs first. It also confirmed that the LangGraph regression now fails under head truncation. Remaining non-blocking notes:scripts/generate_integration_lifecycle.pycovers onlyintegrations/*/plugins/*. A stray hand-kept copy inside an SDK adapter'ssrc/would not be flagged. The listed copies are drift-checked.invokepath and Hermesqueue_prefetchshare the tested code path, but the new tests do not drive them. The reviewer checked LangChaininvokewith a scratch script.AI usage statement
Claude Code (Claude Opus 5.5) wrote the change, the tests, and this description, and ran the checks above.