Skip to content

fix(core): remove orphaned FunctionExecutionResultMessage after mid-list token truncation - #8035

Open
zerafachris (zerafachris) wants to merge 2 commits into
microsoft:mainfrom
zerafachris:fix/token-limited-context-orphaned-result-7955
Open

fix(core): remove orphaned FunctionExecutionResultMessage after mid-list token truncation#8035
zerafachris (zerafachris) wants to merge 2 commits into
microsoft:mainfrom
zerafachris:fix/token-limited-context-orphaned-result-7955

Conversation

@zerafachris

Copy link
Copy Markdown

Summary

TokenLimitedChatCompletionContext.get_messages() drops messages from the middle of the list to stay within the token budget. When a middle-list AssistantMessage that carries FunctionCall items is removed, its paired FunctionExecutionResultMessage becomes orphaned and will cause an API error.

Root cause

The previous clean-up guard was:

if messages and isinstance(messages[0], FunctionExecutionResultMessage):
    messages = messages[1:]

This only catches the degenerate case where an orphaned result ends up at position 0. Any orphaned result elsewhere in the list passed through silently.

Fix

After the truncation loop, collect the call_ids of every FunctionCall that still exists in a surviving AssistantMessage, then filter out any FunctionExecutionResultMessage whose results reference a call_id that is no longer present (or that has no results at all).

active_call_ids: set[str] = set()
for msg in messages:
    if isinstance(msg, AssistantMessage) and isinstance(msg.content, list):
        for item in msg.content:
            if isinstance(item, FunctionCall):
                active_call_ids.add(item.id)
messages = [
    m
    for m in messages
    if not isinstance(m, FunctionExecutionResultMessage)
    or (m.content and all(r.call_id in active_call_ids for r in m.content))
]

Tests

Added a regression test (test_token_limited_mid_list_orphaned_function_result_is_removed) that:

  • Builds a 7-message list with an AssistantMessage(content=[FunctionCall(id="call_1", ...)]) at index 3 and a paired FunctionExecutionResultMessage at index 4.
  • Sets token_limit=6 so the truncation loop removes the AssistantMessage, orphaning the result.
  • Asserts no FunctionExecutionResultMessage survives in the returned list.

All 10 existing tests in test_model_context.py continue to pass.

Closes #7955.


Prepared with AI assistance (Claude Code, Anthropic), reviewed for correctness before submission.

…pply_filter

The previous implementation iterated per_source filters and appended matching
messages in filter-config order.  When multiple sources were configured,
messages from a later-listed source that chronologically preceded messages from
an earlier-listed source were emitted out of order, breaking the LLM's
conversation timeline.

Fix: track the original message index for each selected message and emit in
original conversation order.  The per-source count/position filtering logic is
unchanged; only the final order of the merged result is fixed.

Fixes microsoft#7971

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ist truncation

TokenLimitedChatCompletionContext.get_messages() removes messages from the
middle of the list to stay within the token budget.  When an AssistantMessage
that carries FunctionCall items is removed, its paired
FunctionExecutionResultMessage becomes orphaned and will cause an API error.

The previous clean-up only caught the degenerate case where a
FunctionExecutionResultMessage appeared at position 0 after truncation.  Any
orphaned result that landed elsewhere in the list was silently passed through.

After the truncation loop, collect the call_ids of every FunctionCall that
still exists in a surviving AssistantMessage, then filter out any
FunctionExecutionResultMessage whose results reference a call_id that is no
longer present (or that has no results at all).

Fixes microsoft#7955.

Prepared with AI assistance (Claude Code, Anthropic), reviewed for correctness before submission.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@zerafachris

Copy link
Copy Markdown
Author

I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.

@zerafachris

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

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.

TokenLimitedChatCompletionContext can orphan a FunctionExecutionResultMessage mid-list when truncating

1 participant