Skip to content

fix(workflow): Skip task dispatch on progressive-SSE partial chunks - #6638

Open
a2105z wants to merge 1 commit into
google:mainfrom
a2105z:fix/progressive-sse-task-fc-partial-gate-v2
Open

fix(workflow): Skip task dispatch on progressive-SSE partial chunks#6638
a2105z wants to merge 1 commit into
google:mainfrom
a2105z:fix/progressive-sse-task-fc-partial-gate-v2

Conversation

@a2105z

@a2105z a2105z commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

Problem:
Under RunConfig(streaming_mode=StreamingMode.SSE) with progressive SSE (default-on), intermediate model chunks are marked partial=True, including chunks that already name a task-delegation function call. The chat wrapper's _extract_task_delegation_fcs had no partial gate, so it dispatched the child task and breaks out of run_async before the Runner-persisted non-partial aggregate was yielded.

Effects:

  1. The matching task FC never lands in session history, while the synthesized task FR does → orphaned FR (hard raise on older ADK; prune/warn on current main).
  2. Dispatch can fire from a truncated/empty partial args chunk instead of the complete aggregate.

Solution:
Ignore task-delegation FCs when event.partial is true in _extract_task_delegation_fcs, matching the existing partial gate in process_llm_agent_output in the same module. Dispatch + break then wait for the non-partial aggregate the Runner actually persists (with complete streamed args).

This matches the approach discussed and verified on #6583.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.

  • All unit tests pass locally.

  • test_extract_task_delegation_fcs_skips_partial_events — unit gate

  • test_chat_root_dispatches_task_fc_only_from_non_partial_sse_chunk — e2e under StreamingMode.SSE (complete args, single dispatch, matched FC/FR ids, usable next turn)

  • Confirmed both tests fail without the gate (orphaned FR / prune path)

  • pytest tests/unittests/workflow/test_llm_agent_as_node.py tests/unittests/workflow/test_task_api_e2e.py60 passed, 8 skipped, 1 xfailed

Manual End-to-End (E2E) Tests:

Covered by the progressive-SSE e2e regression above (custom LLM emits partial incomplete FC then non-partial aggregate with full args).

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.

Additional context

@llalitkumarrr asked for this PR on #6583 after verifying the partial-gate approach against the reproduction.

@google-cla

google-cla Bot commented Aug 7, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@adk-bot adk-bot added the live [Component] This issue is related to live, voice and video chat label Aug 7, 2026
Under PROGRESSIVE_SSE_STREAMING the chat wrapper was extracting task-
delegation FCs from partial=True chunks, breaking before the Runner-
persisted aggregate was yielded. That left an orphaned task FR and could
dispatch with truncated streamed args. Gate extraction like
process_llm_agent_output already does for partial model events.

Fixes google#6583
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

live [Component] This issue is related to live, voice and video chat

Projects

None yet

3 participants