mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Implement annotation-based context compaction (#4469)
* Implement annotation-based context compaction Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Handle missing compaction attributes in BaseChatClient Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix CI typing and bandit issues Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Optimize incremental compaction annotation pass Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refinement * Python: add ToolResultCompactionStrategy and CompactionProvider Add ToolResultCompactionStrategy that collapses older tool-call groups into short summary messages (e.g. [Tool calls: get_weather]) while keeping the most recent groups verbatim. This mirrors the .NET ToolResultCompactionStrategy from PR #4533. Add CompactionProvider as a context-provider that auto-applies compaction before each agent turn and stores compacted history in session state after each turn. Includes tests and samples for both features. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refinement and alignment with dotnet PR * updated tool result compaction * updated tool result compaction * Python: add ToolResultCompactionStrategy, CompactionProvider, and skip_excluded - ToolResultCompactionStrategy collapses older tool-call groups into [Tool results: func_name: result] summaries with bidirectional tracing (same pattern as SummarizationStrategy). - CompactionProvider as BaseContextProvider with separate before_strategy and after_strategy parameters. before_strategy compacts loaded context; after_strategy compacts stored history via history_source_id. - InMemoryHistoryProvider gains skip_excluded flag to filter out messages marked as excluded by compaction strategies. - Tests, samples, and exports updated. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fixed checks * fix mypy * Fix: ensure summary messages from both strategies get full compaction annotations SummarizationStrategy was not calling annotate_message_groups after inserting its summary message, so the summary lacked core group annotations (id, kind, index, has_reasoning, _excluded). Added the missing call. ToolResultCompactionStrategy already had it. Added tests verifying both strategies produce fully annotated summaries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * updated propagation * fix mypy --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
565c0b1623
commit
3e03a305f6
@@ -524,6 +524,58 @@ def test_response_content_creation_with_reasoning() -> None:
|
||||
assert response.messages[0].contents[0].text == "Reasoning step"
|
||||
|
||||
|
||||
def test_response_content_keeps_reasoning_and_function_calls_in_one_message() -> None:
|
||||
"""Reasoning + function calls should parse into one assistant message."""
|
||||
client = OpenAIResponsesClient(model_id="test-model", api_key="test-key")
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.output_parsed = None
|
||||
mock_response.metadata = {}
|
||||
mock_response.usage = None
|
||||
mock_response.id = "test-id"
|
||||
mock_response.model = "test-model"
|
||||
mock_response.created_at = 1000000000
|
||||
|
||||
mock_reasoning_content = MagicMock()
|
||||
mock_reasoning_content.text = "Reasoning step"
|
||||
|
||||
mock_reasoning_item = MagicMock()
|
||||
mock_reasoning_item.type = "reasoning"
|
||||
mock_reasoning_item.id = "rs_123"
|
||||
mock_reasoning_item.content = [mock_reasoning_content]
|
||||
mock_reasoning_item.summary = []
|
||||
|
||||
mock_function_call_item_1 = MagicMock()
|
||||
mock_function_call_item_1.type = "function_call"
|
||||
mock_function_call_item_1.id = "fc_1"
|
||||
mock_function_call_item_1.call_id = "call_1"
|
||||
mock_function_call_item_1.name = "tool_1"
|
||||
mock_function_call_item_1.arguments = '{"x": 1}'
|
||||
|
||||
mock_function_call_item_2 = MagicMock()
|
||||
mock_function_call_item_2.type = "function_call"
|
||||
mock_function_call_item_2.id = "fc_2"
|
||||
mock_function_call_item_2.call_id = "call_2"
|
||||
mock_function_call_item_2.name = "tool_2"
|
||||
mock_function_call_item_2.arguments = '{"y": 2}'
|
||||
|
||||
mock_response.output = [
|
||||
mock_reasoning_item,
|
||||
mock_function_call_item_1,
|
||||
mock_function_call_item_2,
|
||||
]
|
||||
|
||||
response = client._parse_response_from_openai(mock_response, options={}) # type: ignore
|
||||
|
||||
assert len(response.messages) == 1
|
||||
assert response.messages[0].role == "assistant"
|
||||
assert [content.type for content in response.messages[0].contents] == [
|
||||
"text_reasoning",
|
||||
"function_call",
|
||||
"function_call",
|
||||
]
|
||||
|
||||
|
||||
def test_response_content_creation_with_code_interpreter() -> None:
|
||||
"""Test _parse_response_from_openai with code interpreter outputs."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user