agentscope-ai / agentscope-ai/QwenPaw
[Bug] Context compaction can still exceed the complete provider request budget and fail active turns
- Langage dominant
- Python
- Étoiles
- 34.9k
- Forks
- 3.1k
- Merge moyen
- 1 j 15 h
- PR mergées (30 j)
- 225
Description
## Summary
Improve context compaction so that its trigger and final budget are based on the complete request that will be sent to the provider, not only the currently visible/live conversation context.
## Environment
- QwenPaw: `2.2.0b7`
- AgentScope: `2.0.7.post1`
- ReMe: `0.4.1.10`
- Provider/model: OpenAI-compatible providers and models with different context limits
- Workload: long-running sessions with many tool calls, large tool results, and concurrent agent activity
## Observed behavior
In a long tool-intensive session, the logs can report that compaction is at or below the configured trigger:
```text
scroll: compact timing outcome=at_or_below_trigger
```
However, a subsequent request can still fail because the final request is larger than the model's hard input limit:
```text
CONTEXT_UNFIT: context compaction could not fit the active request
```
One observed example was effectively:
```text
final context: 313235 tokens
model hard limit: 267904 tokens
```
The current compaction path can also report that the context remains above the compression trigger after compaction, while the active request is still allowed to proceed until the provider rejects it.
## Why this is a problem
The compaction decision and the provider request do not appear to use the same budget. The final request may include additional content that is not fully represented by the live-context count, including:
- system instructions;
- tool schemas and tool descriptions;
- current user input;
- active-turn tool calls and results;
- agent state and continuation metadata;
- media/message wrappers;
- provider-specific request formatting.
As a result, a session can be considered below the compaction trigger but still exceed the actual provider/model input limit.
## Active-turn edge case
The current policy intentionally protects the active turn and recent tool results. This is useful for correctness, but a single long-running tool turn can itself exceed the model input limit before it becomes safe to compact.
The effective behavior is:
```text
long active turn produces tool results
→ historical context may be compacted
→ active/pending/recent results remain verbatim
→ final request remains over the hard limit
→ CONTEXT_UNFIT
```
This is especially likely with:
- multi-step tool workflows;
- agent-to-agent calls;
- large MCP results;
- concurrent background agents;
- repeated reads of saved artifacts into the active turn.
## Requested improvements
### 1. Reserve budget for the complete request
Calculate compaction against a request budget such as:
```text
model_hard_limit
- system_prompt_tokens
- tool_schema_tokens
- current_request_tokens
- media/wrapper allowance
- safety margin
```
The trigger should be based on the estimated final provider request, not only the live message context.
### 2. Expose detailed budget accounting
Add structured diagnostic fields/logs for:
- pre-compaction live-context tokens;
- post-compaction live-context tokens;
- final estimated request tokens;
- system prompt tokens;
- tool schema tokens;
- current-turn tokens;
- protected/pending tool-result tokens;
- reserve and hard-limit values;
- provider/model context limit used for the decision.
This would make `at_or_below_trigger` and `CONTEXT_UNFIT` explainable instead of contradictory.
### 3. Add an active-turn budget
Set a maximum token/byte budget for one active turn. When it is reached:
- fold older completed tool results into bounded previews;
- offload full results to artifacts;
- preserve recovery pointers;
- avoid repeatedly re-inserting full artifact contents into the prompt.
The current “protect the active turn” policy should have an emergency path when the active turn alone cannot fit.
### 4. Improve failure handling
If compaction still cannot produce a request below the hard limit:
- stop retrying the same oversized request;
- return a clear user-facing message recommending a new continuation session;
- automatically save a bounded summary/checkpoint;
- optionally offer “Continue in new session”;
- keep the original session recoverable.
### 5. Add total tool-result budgets
Per-result limits are not sufficient when many individually acceptable results accumulate. Add configurable limits for:
- total tool-result tokens per turn;
- total tool-result bytes per turn;
- number of protected recent results;
- total active-turn event/result count.
### 6. Add regression tests
Please add tests covering:
1. A context below the live trigger but above the final provider request limit after tool schemas and system instructions are added.
2. A single active tool turn whose results exceed the hard input limit.
3. Multiple individually bounded tool results whose combined size exceeds the request budget.
4. A large artifact that is accidentally read back in full during the same turn.
5. Failed compaction followed by a safe continuation-session fallback.
6. Different provider-reported context limits and missing/unknown limits.
## Expected result
A long-running session should either:
- compact early enough that the complete provider request fits; or
- stop safely with a clear continuation/new-session action.
It should not report that compaction is unnecessary and then produce an oversized request that fails with `CONTEXT_UNFIT`.
## Privacy note
The examples above are intentionally sanitized. No local paths, account identifiers, session IDs, provider endpoints, API keys, or business file names are included.
Guide de contribution
Ouvrir le guide de contribution
Évaluation
Cette issue n'a pas encore été évaluée.