fix: apply context compression to prevent token overflow (Issue #721) (#722)

* fix: apply context compression to prevent token overflow (Issue #721)

- Add token_limit configuration to conf.yaml.example for BASIC_MODEL and REASONING_MODEL
- Implement context compression in _execute_agent_step() before agent invocation
- Preserve first 3 messages (system prompt + context) during compression
- Enhance ContextManager logging with better token count reporting
- Prevent 400 Input tokens exceeded errors by automatically compressing message history

* feat: add model-based token limit inference for Issue #721

- Add smart default token limits based on common LLM models
- Support model name inference when token_limit not explicitly configured
- Models include: OpenAI (GPT-4o, GPT-4, etc.), Claude, Gemini, Doubao, DeepSeek, etc.
- Conservative defaults prevent token overflow even without explicit configuration
- Priority: explicit config > model inference > safe default (100,000 tokens)
- Ensures Issue #721 protection for all users, not just those with token_limit set
This commit is contained in:
Willem Jiang
2025-11-28 18:52:42 +08:00
committed by GitHub
parent 223ec57fe4
commit b24f4d3f38
4 changed files with 110 additions and 8 deletions

View File

@@ -974,6 +974,24 @@ async def _execute_agent_step(
except Exception as validation_error:
logger.error(f"Error validating agent input messages: {validation_error}")
# Apply context compression to prevent token overflow (Issue #721)
llm_token_limit = get_llm_token_limit_by_type(AGENT_LLM_MAP[agent_name])
if llm_token_limit:
token_count_before = sum(
len(str(msg.content).split()) for msg in agent_input.get("messages", []) if hasattr(msg, "content")
)
compressed_state = ContextManager(llm_token_limit, preserve_prefix_message_count=3).compress_messages(
{"messages": agent_input["messages"]}
)
agent_input["messages"] = compressed_state.get("messages", [])
token_count_after = sum(
len(str(msg.content).split()) for msg in agent_input.get("messages", []) if hasattr(msg, "content")
)
logger.info(
f"Context compression for {agent_name}: {len(compressed_state.get('messages', []))} messages, "
f"estimated tokens before: ~{token_count_before}, after: ~{token_count_after}"
)
try:
result = await agent.ainvoke(
input=agent_input, config={"recursion_limit": recursion_limit}