Skip to content

fix(hyperagent): sticky thread for agentic tool loops (Claude Code) - #8470

Merged
diegosouzapw merged 5 commits into
diegosouzapw:release/v3.8.49from
artickc:fix/hyperagent-tool-loop-thread-sticky
Jul 28, 2026
Merged

diegosouzapw merged 5 commits into
diegosouzapw:release/v3.8.49from
artickc:fix/hyperagent-tool-loop-thread-sticky

Conversation

@artickc

@artickc artickc commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #7994.

When a reverse-conversion proxy (e.g. tools→text Intent+JSON for web models, then text→native tool_calls for Claude Code) rewrites the assistant message between turns, conversationFingerprint(prefix) no longer matches the key stored after turn 1. HyperAgent then created a new thread, so multi-turn tool results looked like a cold start (model re-states protocol instead of continuing).

Changes

  • Sticky key by root user task (rootUserFingerprint) after normalizing common agentic user-pin wrappers (My current task:, etc.)
  • Flatten Anthropic tool_use / tool_result content blocks in extractMessageText so Claude Code histories contribute to fingerprints + lastUserText
  • Store root key on every successful turn; resolve via prefix → root → last-assistant (legacy)
  • Regression tests: mutated-assistant tool loop, Anthropic tool_result flatten, root key skips pure observations

Tests

node --import tsx --test tests/unit/executor-hyperagent.test.ts

19/19 PASS

Risk

Low — only HyperAgent thread cache keying; chat body / SSE protocol unchanged. Cookie isolation preserved (projectKey still gates lookups).

Follow-up to diegosouzapw#7994. When a reverse-conversion proxy rewrites assistant
text between turns (Intent+JSON -> native tool_calls -> re-serialized tool
text), conversationFingerprint(prefix) no longer matches the key stored
after turn 1, so HyperAgent created a new thread and multi-turn tool
results appeared as a cold start.

- Key sticky sessions by root user task (normalize pin wrappers)
- Flatten Anthropic tool_use / tool_result for lastUserText + fingerprints
- Regression tests for mutated-assistant tool loops

Tests: tests/unit/executor-hyperagent.test.ts (19/19)
@artickc
artickc requested a review from diegosouzapw as a code owner July 24, 2026 21:00
@diegosouzapw

Copy link
Copy Markdown
Owner

Thanks for the detailed follow-up to #7994 — this is a well-documented fix and the reproduction of the reverse-conversion tool-loop cold-start problem makes sense. We ran your test suite as-is (node --import tsx/esm --test tests/unit/executor-hyperagent.test.ts) and confirmed 19/19 green, and lint is clean on both touched files.

One thing we want to work through before merging: the new rootUserFingerprint fallback key is derived only from the first real user message text, scoped by the HyperAgent cookie (connection), not by conversation. Since a HyperAgent connection is commonly shared across multiple end-users/API keys in an OmniRoute deployment, we found that two unrelated conversations under the same connection that happen to open with the same (normalized) first message — plausible with short/generic agentic templates — get silently routed onto the same cached thread once one of them registers that root key. We reproduced this directly against your branch with a small standalone script exercising storeHyperAgentThreadAfterTurn/resolveHyperAgentThreadBinding.

We'd like to land your fix, but with the root-key fallback made a bit more specific (e.g. requiring some corroborating signal beyond just the first user line, or moving it strictly after the existing last-assistant fallback rather than before it) plus a regression test for the "two different conversations, same opening line" case. Happy to help pair on the exact shape if useful — otherwise feel free to push the update to this branch and we'll re-run the suite.

ikelvingo and others added 4 commits July 25, 2026 11:55
…agent sticky thread)

open-sse/executors/hyperagent.ts grows 937->1026 lines and gains one new
cognitive/cyclomatic-complexity violation (extractMessageText, from the
new Anthropic tool_use/tool_result flattening branches) on top of
inherited base-tip drift already present on origin/release/v3.8.49
(file-size was already at cap; cognitive-complexity 951->956 and
cyclomatic-complexity 2130->2169 drift predates this PR). Rebaselined
file-size to 1026, cognitiveComplexity to 957, complexity count to 2170,
matching measured values on the merged tree.

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
# Conflicts:
#	config/quality/file-size-baseline.json
@diegosouzapw
diegosouzapw merged commit 530221a into diegosouzapw:release/v3.8.49 Jul 28, 2026
5 checks passed
@diegosouzapw diegosouzapw mentioned this pull request Jul 28, 2026
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…iegosouzapw#8470)

* fix(hyperagent): sticky thread for agentic tool loops (Claude Code)

Follow-up to diegosouzapw#7994. When a reverse-conversion proxy rewrites assistant
text between turns (Intent+JSON -> native tool_calls -> re-serialized tool
text), conversationFingerprint(prefix) no longer matches the key stored
after turn 1, so HyperAgent created a new thread and multi-turn tool
results appeared as a cold start.

- Key sticky sessions by root user task (normalize pin wrappers)
- Flatten Anthropic tool_use / tool_result for lastUserText + fingerprints
- Regression tests for mutated-assistant tool loops

Tests: tests/unit/executor-hyperagent.test.ts (19/19)

* chore(quality): rebaseline for PR diegosouzapw#8470 own-growth (hyperagent sticky thread)

open-sse/executors/hyperagent.ts grows 937->1026 lines and gains one new
cognitive/cyclomatic-complexity violation (extractMessageText, from the
new Anthropic tool_use/tool_result flattening branches) on top of
inherited base-tip drift already present on origin/release/v3.8.49
(file-size was already at cap; cognitive-complexity 951->956 and
cyclomatic-complexity 2130->2169 drift predates this PR). Rebaselined
file-size to 1026, cognitiveComplexity to 957, complexity count to 2170,
matching measured values on the merged tree.

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

---------

Co-authored-by: ikelvingo <im.kelvinwong@gmail.com>
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…iegosouzapw#8470)

* fix(hyperagent): sticky thread for agentic tool loops (Claude Code)

Follow-up to diegosouzapw#7994. When a reverse-conversion proxy rewrites assistant
text between turns (Intent+JSON -> native tool_calls -> re-serialized tool
text), conversationFingerprint(prefix) no longer matches the key stored
after turn 1, so HyperAgent created a new thread and multi-turn tool
results appeared as a cold start.

- Key sticky sessions by root user task (normalize pin wrappers)
- Flatten Anthropic tool_use / tool_result for lastUserText + fingerprints
- Regression tests for mutated-assistant tool loops

Tests: tests/unit/executor-hyperagent.test.ts (19/19)

* chore(quality): rebaseline for PR diegosouzapw#8470 own-growth (hyperagent sticky thread)

open-sse/executors/hyperagent.ts grows 937->1026 lines and gains one new
cognitive/cyclomatic-complexity violation (extractMessageText, from the
new Anthropic tool_use/tool_result flattening branches) on top of
inherited base-tip drift already present on origin/release/v3.8.49
(file-size was already at cap; cognitive-complexity 951->956 and
cyclomatic-complexity 2130->2169 drift predates this PR). Rebaselined
file-size to 1026, cognitiveComplexity to 957, complexity count to 2170,
matching measured values on the merged tree.

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

---------

Co-authored-by: ikelvingo <im.kelvinwong@gmail.com>
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants