mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
3446eb8d5d
* updates to final deprecated pieces and versions * fix mypy * fix readme links
242 lines
9.1 KiB
Python
242 lines
9.1 KiB
Python
# Copyright (c) Microsoft. All rights reserved.
|
|
|
|
import asyncio
|
|
from typing import Any
|
|
|
|
from agent_framework import (
|
|
CharacterEstimatorTokenizer,
|
|
ChatResponse,
|
|
Content,
|
|
Message,
|
|
SelectiveToolCallCompactionStrategy,
|
|
SlidingWindowStrategy,
|
|
SummarizationStrategy,
|
|
TokenBudgetComposedStrategy,
|
|
ToolResultCompactionStrategy,
|
|
TruncationStrategy,
|
|
apply_compaction,
|
|
)
|
|
|
|
"""This sample demonstrates selecting one compaction strategy at a time.
|
|
|
|
How to use this sample:
|
|
- Keep one ``selected_strategy`` block active in ``main``.
|
|
- Comment the active block and uncomment one of the alternatives to switch strategies.
|
|
- Run again to compare behavior against the same "before" message list shown once.
|
|
"""
|
|
|
|
SUMMARY_OF_MESSAGE_IDS_KEY = "_summary_of_message_ids"
|
|
SUMMARIZED_BY_SUMMARY_ID_KEY = "_summarized_by_summary_id"
|
|
|
|
# Keep optional strategy classes imported for quick uncomment/switch in main().
|
|
AVAILABLE_STRATEGY_TYPES = (
|
|
TruncationStrategy,
|
|
CharacterEstimatorTokenizer,
|
|
SlidingWindowStrategy,
|
|
SelectiveToolCallCompactionStrategy,
|
|
ToolResultCompactionStrategy,
|
|
SummarizationStrategy,
|
|
TokenBudgetComposedStrategy,
|
|
)
|
|
|
|
|
|
class LocalSummaryClient:
|
|
"""Simple local summarizer compatible with SupportsChatGetResponse."""
|
|
|
|
async def get_response(
|
|
self,
|
|
messages: list[Message],
|
|
*,
|
|
stream: bool = False,
|
|
options: dict[str, Any] | None = None,
|
|
**kwargs: Any,
|
|
) -> ChatResponse:
|
|
return ChatResponse(messages=[Message(role="assistant", contents=[f"Summary for {len(messages)} messages."])])
|
|
|
|
|
|
async def main() -> None:
|
|
# 1. Build one baseline history and print it once.
|
|
messages = [
|
|
Message(role="system", contents=["You are a helpful assistant."]),
|
|
Message(role="user", contents=["Plan a data migration."]),
|
|
Message(role="assistant", contents=["I will gather requirements."]),
|
|
Message(
|
|
role="assistant",
|
|
contents=[
|
|
Content.from_function_call(
|
|
call_id="call_1",
|
|
name="list_tables",
|
|
arguments='{"db":"legacy"}',
|
|
)
|
|
],
|
|
),
|
|
Message(
|
|
role="tool",
|
|
contents=[
|
|
Content.from_function_result(
|
|
call_id="call_1",
|
|
result="users, orders, events",
|
|
)
|
|
],
|
|
),
|
|
Message(role="assistant", contents=["I found three core tables."]),
|
|
Message(role="user", contents=["Estimate effort and risks."]),
|
|
Message(role="assistant", contents=["Primary risk is schema drift."]),
|
|
]
|
|
print("\n--- Before compaction ---")
|
|
print(f"Message count: {len(messages)}")
|
|
for index, message in enumerate(messages, start=1):
|
|
message_text = message.text or ", ".join(content.type for content in message.contents)
|
|
print(f"{index:02d}. [{message.role}] {message_text}")
|
|
|
|
# 2. Select exactly one strategy (default shown below).
|
|
# Truncate when included history exceeds 5 messages, then keep 4.
|
|
# System remains anchored, so the oldest non-system messages are removed first.
|
|
# selected_strategy_name = "TruncationStrategy"
|
|
# selected_strategy = TruncationStrategy(max_n=5, compact_to=4, preserve_system=True)
|
|
|
|
# Keep the most recent 4 non-system groups and preserve the system anchor.
|
|
# A group represents a user turn (and related assistant/tool follow-up).
|
|
# selected_strategy_name = "SlidingWindowStrategy"
|
|
# selected_strategy = SlidingWindowStrategy(keep_last_groups=4, preserve_system=True)
|
|
|
|
# This means all tool-call groups are removed (assistant function_call message
|
|
# plus matching tool result messages). In this example, setting to 0 removes
|
|
# the single assistant+tool pair.
|
|
selected_strategy_name = "SelectiveToolCallCompactionStrategy"
|
|
selected_strategy = SelectiveToolCallCompactionStrategy(keep_last_tool_call_groups=0)
|
|
|
|
# Collapse older tool-call groups into short "[Tool results: tool_name]" summaries
|
|
# while keeping the most recent group verbatim. Unlike SelectiveToolCallCompactionStrategy
|
|
# which fully excludes groups, this preserves a readable trace of tool usage.
|
|
# selected_strategy_name = "ToolResultCompactionStrategy"
|
|
# selected_strategy = ToolResultCompactionStrategy(keep_last_tool_call_groups=0)
|
|
|
|
# Summarize older messages so only recent context remains, and attach summary
|
|
# trace metadata linking summary -> originals and originals -> summary.
|
|
# summary_client = LocalSummaryClient()
|
|
# selected_strategy_name = "SummarizationStrategy"
|
|
# selected_strategy = SummarizationStrategy(
|
|
# client=summary_client, target_count=3, threshold=2
|
|
# )
|
|
|
|
# tokenizer = CharacterEstimatorTokenizer()
|
|
# selected_strategy_name = "TokenBudgetComposedStrategy"
|
|
# selected_strategy = TokenBudgetComposedStrategy(
|
|
# token_budget=150,
|
|
# tokenizer=tokenizer,
|
|
# strategies=[
|
|
# SelectiveToolCallCompactionStrategy(keep_last_tool_call_groups=0),
|
|
# SlidingWindowStrategy(keep_last_groups=2),
|
|
# ],
|
|
# )
|
|
|
|
# 3. Apply the selected strategy and print projected output.
|
|
projected = await apply_compaction(messages, strategy=selected_strategy)
|
|
print(f"\n--- After compaction ({selected_strategy_name}) ---")
|
|
print(f"Message count: {len(projected)}")
|
|
for index, message in enumerate(projected, start=1):
|
|
message_text = message.text or ", ".join(content.type for content in message.contents)
|
|
print(f"{index:02d}. [{message.role}] {message_text}")
|
|
|
|
summaries = []
|
|
summarized = []
|
|
for message in messages:
|
|
group_annotation = message.additional_properties.get("_group")
|
|
if not isinstance(group_annotation, dict):
|
|
continue
|
|
if group_annotation.get(SUMMARY_OF_MESSAGE_IDS_KEY):
|
|
summaries.append(message)
|
|
if group_annotation.get(SUMMARIZED_BY_SUMMARY_ID_KEY):
|
|
summarized.append(message)
|
|
if summaries or summarized:
|
|
print("Summary trace metadata present:")
|
|
for message in summaries:
|
|
group_annotation = message.additional_properties.get("_group")
|
|
summarized_ids = (
|
|
group_annotation.get(SUMMARY_OF_MESSAGE_IDS_KEY) if isinstance(group_annotation, dict) else None
|
|
)
|
|
print(f" summary_id={message.message_id} summarizes={summarized_ids}")
|
|
for message in summarized:
|
|
group_annotation = message.additional_properties.get("_group")
|
|
summarized_by = (
|
|
group_annotation.get(SUMMARIZED_BY_SUMMARY_ID_KEY) if isinstance(group_annotation, dict) else None
|
|
)
|
|
print(f" original_id={message.message_id} summarized_by={summarized_by}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|
|
|
|
"""
|
|
Sample output (always present):
|
|
--- Before compaction ---
|
|
Message count: 8
|
|
01. [system] You are a helpful assistant.
|
|
02. [user] Plan a data migration.
|
|
03. [assistant] I will gather requirements.
|
|
04. [assistant] function_call
|
|
05. [tool] function_result
|
|
06. [assistant] I found three core tables.
|
|
07. [user] Estimate effort and risks.
|
|
08. [assistant] Primary risk is schema drift.
|
|
"""
|
|
|
|
"""
|
|
Sample output (varies based on selected strategy):
|
|
--- After compaction (TruncationStrategy) ---
|
|
Message count: 4
|
|
01. [system] You are a helpful assistant.
|
|
02. [assistant] I found three core tables.
|
|
03. [user] Estimate effort and risks.
|
|
04. [assistant] Primary risk is schema drift.
|
|
|
|
--- After compaction (SlidingWindowStrategy) ---
|
|
Message count: 6
|
|
01. [system] You are a helpful assistant.
|
|
02. [assistant] function_call
|
|
03. [tool] function_result
|
|
04. [assistant] I found three core tables.
|
|
05. [user] Estimate effort and risks.
|
|
06. [assistant] Primary risk is schema drift.
|
|
|
|
--- After compaction (SelectiveToolCallCompactionStrategy) ---
|
|
Message count: 6
|
|
01. [system] You are a helpful assistant.
|
|
02. [user] Plan a data migration.
|
|
03. [assistant] I will gather requirements.
|
|
04. [assistant] I found three core tables.
|
|
05. [user] Estimate effort and risks.
|
|
06. [assistant] Primary risk is schema drift.
|
|
|
|
--- After compaction (ToolResultCompactionStrategy) ---
|
|
Message count: 7
|
|
01. [system] You are a helpful assistant.
|
|
02. [assistant] [Tool results: list_tables]
|
|
03. [user] Plan a data migration.
|
|
04. [assistant] I will gather requirements.
|
|
05. [assistant] I found three core tables.
|
|
06. [user] Estimate effort and risks.
|
|
07. [assistant] Primary risk is schema drift.
|
|
|
|
--- After compaction (SummarizationStrategy) ---
|
|
Message count: 5
|
|
01. [system] You are a helpful assistant.
|
|
02. [assistant] Summary for 2 messages.
|
|
03. [assistant] I found three core tables.
|
|
04. [user] Estimate effort and risks.
|
|
05. [assistant] Primary risk is schema drift.
|
|
Summary trace metadata present:
|
|
summary_id=summary_8 summarizes=['msg_1', 'msg_2', 'msg_3', 'msg_4']
|
|
original_id=msg_1 summarized_by=summary_8
|
|
original_id=msg_2 summarized_by=summary_8
|
|
original_id=msg_3 summarized_by=summary_8
|
|
original_id=msg_4 summarized_by=summary_8
|
|
|
|
--- After compaction (TokenBudgetComposedStrategy) ---
|
|
Message count: 3
|
|
01. [system] You are a helpful assistant.
|
|
02. [user] Estimate effort and risks.
|
|
03. [assistant] Primary risk is schema drift.
|
|
"""
|