mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
3e03a305f6
* 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>
116 lines
3.8 KiB
Python
116 lines
3.8 KiB
Python
# Copyright (c) Microsoft. All rights reserved.
|
|
|
|
import asyncio
|
|
from typing import Any
|
|
|
|
from agent_framework import (
|
|
CharacterEstimatorTokenizer,
|
|
ChatResponse,
|
|
Message,
|
|
SelectiveToolCallCompactionStrategy,
|
|
SlidingWindowStrategy,
|
|
SummarizationStrategy,
|
|
TokenBudgetComposedStrategy,
|
|
annotate_message_groups,
|
|
apply_compaction,
|
|
included_token_count,
|
|
)
|
|
|
|
"""This sample demonstrates composed in-run compaction with a token budget.
|
|
|
|
Key components:
|
|
- TokenBudgetComposedStrategy
|
|
- Sequential strategy composition
|
|
- Summarization with a SupportsChatGetResponse-compatible summarizer client
|
|
"""
|
|
|
|
|
|
class BudgetSummaryClient:
|
|
async def get_response(
|
|
self,
|
|
messages: list[Message],
|
|
*,
|
|
stream: bool = False,
|
|
options: dict[str, Any] | None = None,
|
|
**kwargs: Any,
|
|
) -> ChatResponse:
|
|
summary_text = f"Budget summary generated from {len(messages)} prompt messages."
|
|
return ChatResponse(messages=[Message(role="assistant", text=summary_text)])
|
|
|
|
|
|
def _build_long_history() -> list[Message]:
|
|
history = [Message(role="system", text="You are a migration copilot.")]
|
|
for i in range(1, 8):
|
|
history.append(
|
|
Message(
|
|
role="user",
|
|
text=f"Iteration {i}: capture migration requirements and edge cases.",
|
|
)
|
|
)
|
|
history.append(
|
|
Message(
|
|
role="assistant",
|
|
text=(
|
|
f"Iteration {i}: detailed plan with dependencies, rollback guidance, and testing details. "
|
|
"This sentence is intentionally long to create token pressure."
|
|
),
|
|
)
|
|
)
|
|
return history
|
|
|
|
|
|
async def main() -> None:
|
|
# 1. Build synthetic history representing long-running in-run growth.
|
|
messages = _build_long_history()
|
|
|
|
# 2. Configure tokenizer and measure token count before compaction.
|
|
tokenizer = CharacterEstimatorTokenizer()
|
|
annotate_message_groups(messages, tokenizer=tokenizer)
|
|
budget_before = included_token_count(messages)
|
|
|
|
# 3. Configure composed strategy stack.
|
|
composed = TokenBudgetComposedStrategy(
|
|
token_budget=200,
|
|
tokenizer=tokenizer,
|
|
strategies=[
|
|
SelectiveToolCallCompactionStrategy(keep_last_tool_call_groups=0),
|
|
SummarizationStrategy(
|
|
client=BudgetSummaryClient(),
|
|
target_count=3,
|
|
threshold=3,
|
|
),
|
|
SlidingWindowStrategy(keep_last_groups=4),
|
|
],
|
|
)
|
|
|
|
# 4. Apply compaction and inspect the budget result.
|
|
projected = await apply_compaction(messages, strategy=composed, tokenizer=tokenizer)
|
|
budget_after = included_token_count(messages)
|
|
|
|
print(f"Projected messages after compaction: {len(projected)}")
|
|
print(f"Included token count before compaction: {budget_before}")
|
|
print(f"Included token count after compaction: {budget_after}")
|
|
print("Projected roles:", [m.role for m in projected])
|
|
print("Projected messages with token counts:")
|
|
for msg in projected:
|
|
group = msg.additional_properties.get("_group")
|
|
token_count = group.get("token_count") if isinstance(group, dict) else None
|
|
text_preview = msg.text[:80] if msg.text else "<non-text>"
|
|
print(f"- [{msg.role}] {text_preview} ({token_count} tokens)")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|
|
|
|
"""
|
|
Sample output:
|
|
Projected messages after compaction: 3
|
|
Included token count before compaction: 793
|
|
Included token count after compaction: 144
|
|
Projected roles: ['system', 'user', 'assistant']
|
|
Projected messages with token counts:
|
|
- [system] You are a migration copilot. (35 tokens)
|
|
- [user] Iteration 7: capture migration requirements and edge cases. (43 tokens)
|
|
- [assistant] Iteration 7: detailed plan with dependencies, rollback guidance, and testing det (66 tokens)
|
|
"""
|