Skip to content

fix(agentlang): isolate stream fallback correlations by context - #85

Open
Linxiushen wants to merge 1 commit into
dtyq:masterfrom
Linxiushen:fix/scoped-stream-fallback-correlation
Open

fix(agentlang): isolate stream fallback correlations by context#85
Linxiushen wants to merge 1 commit into
dtyq:masterfrom
Linxiushen:fix/scoped-stream-fallback-correlation

Conversation

@Linxiushen

Copy link
Copy Markdown

Summary

  • isolate V2 stream-fallback correlation IDs by AgentContext.context_id
  • preserve the existing global scope for callers without an Agent context
  • clear unconsumed fallback state on stream success, Agent run completion, and Agent close
  • add deterministic concurrent-context fallback regression coverage

Problem

The correlation manager already scopes paired Agent events by context, but streaming fallback still uses one process-wide mutable slot.

With concurrent Agent contexts, including independent sessions and parent/child Agents, the following interleaving is possible:

parent stream starts -> fallback slot = parent request ID
child stream starts  -> fallback slot = child request ID
parent falls back    -> consumes the child's request ID
child falls back     -> has no matching request ID

V2 streaming uses the request ID as its correlation ID. Reusing the wrong value can associate a final regular response with another Agent run, while a missing value makes partial chunks and the final response appear as separate replies.

Approach

Fallback correlations are now stored by the same AgentContext.context_id scope already used for paired events. ProcessorManager sets and clears the marker in the current context, and RegularCallProcessor only consumes that context's marker.

The current Agent loop has one in-flight LLM call per context, while parallel sub-agents receive isolated contexts. This keeps the change aligned with the runtime's existing ownership boundary and avoids introducing another request-chain identifier.

Unconsumed markers are cleared at the end of a run and when an Agent closes. This covers cancellation, deterministic errors that skip fallback, and early termination. Callers that omit a context keep the previous single global-scope behavior.

Tests

  • two stream calls are held at an asyncio barrier, fail concurrently, and then pass through the public regular-response processor path with their original correlations
  • a successful stream clears only its own scope while another failed stream remains available for fallback
  • direct scoped set/pop/clear behavior and global-scope compatibility
  • Agent close is idempotent and clears only its own scope
  • run_main_agent() cancellation propagates while request-finally clears only the current scope
pytest -q tests/agentlang --ignore=tests/agentlang/test_config_local_models.py
48 passed

pytest tests/core/test_agent_correlation_cleanup.py
2 passed

ruff check tests/agentlang/test_correlation_id_manager_scope.py tests/core/test_agent_correlation_cleanup.py
All checks passed

git diff --check
passed

Fixes #84

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.

fix(agentlang): isolate stream fallback correlations across agent contexts

1 participant