Repository navigation
[Question] Can event compaction orphan a long-running tool call after its intermediate response? #6179
Description
Question / clarification
Is it intended that event compaction can orphan a LongRunningFunctionTool's function call when an intermediate response has already been emitted but the final response arrives after compaction?
I'm trying to understand whether the following flow is expected behavior or a gap, before assuming either.
My understanding of the relevant flow
The orphan-safety check _longest_self_contained_prefix (src/google/adk/apps/compaction.py) tracks "open obligations" by function-call id: a function_call (or tool-confirmation / auth request) opens one, and a function_response with the same id closes it. A prefix is only compacted up to a point where no obligation is open. This appears to protect:
- pending calls with no response yet (
test_sliding_window_excludes_pending_function_call_events), and - the real HITL shape, where a separate
adk_request_confirmationcall stays open (test_sliding_window_real_hitl_shape_blocks_compaction).
The case I'm unsure about
A LongRunningFunctionTool whose function returns a non-empty intermediate result (e.g. the export_data sample under contributing/samples/tools/long_running_functions/ returns {"status": "in-progress"}). In src/google/adk/flows/llm_flows/functions.py, the (tool.is_long_running or tool._defers_response) and not function_response branch only skips building the response event when the return is empty — so a non-empty intermediate return does emit a function_response event with the same id as the call. The model is instructed not to call again, and the final result is delivered later as another function_response reusing the same function_call_id.
If that's correct, then at compaction time the window is [function_call(id=X), intermediate_response(id=X)]. The intermediate response closes the obligation, and _longest_self_contained_prefix does not appear to consult long_running_tool_ids, so both events look safe to compact. Sliding-window compaction has no event_retention_size, and token-threshold with event_retention_size=0 would not retain them either.
My concern is what happens once that range is summarized away and the final response (same id) later arrives as the latest event:
contents._process_compaction_eventswould drop the now-compactedfunction_call, while the finalfunction_response(outside the compacted timestamp range) is kept, and_rearrange_events_for_latest_function_response(src/google/adk/flows/llm_flows/contents.py) raisesValueError("No function call event found ...")when it can't locate the matching call.
I have not confirmed this end-to-end through runner.run_async; I'm reasoning from the code paths above and would like to know whether I'm missing a safeguard.
Questions
- Is this an accepted limitation (i.e. long-running tools that emit an intermediate response are expected to keep their call un-compacted some other way), or a genuine gap?
- Is there an existing mechanism that prevents the intermediate-response case from reaching
_rearrange_events_for_latest_function_responsewith an orphaned response that I've overlooked?
Environment
- google-adk: 2.2.0 (relevant code also present on
main@b9e7fcad)
Activity
sanketpatil06 commentedon Jun 24, 2026
Hi @arisa-galbo , thanks for the detailed report.
The compaction logic removes the original
function_callevent too early when it sees the intermediate response. Because the original call is gone, the final response is left without a match, causing theValueError.A fix for this is already in review under PR #5832 (addressing issue #5602).
arisa-galbo commentedon Jun 24, 2026
@sanketpatil06
Thank you for your prompt reply and for keeping me updated on the situation.
I apologize for missing this issue in the tracking system.
I will check both the original issue and the corresponding pull request to learn from them.
I appreciate your daily support.
GWeale commentedon Aug 6, 2026
fixed in v2.5.0, prompt assembly now re-injects a function call that compaction folded away, so the long-running resume no longer orphans the response.