feat(mcp): add context length guard to prevent oversized requests

* feat: add X-Client-ID header for claw402 monitoring

* feat(mcp): add context length guard to prevent oversized requests

- Add MaxContext field to Config (default 0 = no limit)
- Add WithMaxContext() option for setting model context limits
- Add context_guard.go: token estimation + message truncation
- Integrate guard into both BuildMCPRequestBody and BuildRequestBodyFromRequest
- Support both map[string]string and map[string]any message formats
- Truncates oldest non-system messages when estimated tokens exceed limit
- Always preserves system messages and keeps at least 1 non-system message
- Logs warning when truncation occurs for debugging

Usage: mcp.NewDeepSeekClient(mcp.WithMaxContext(131072))
This commit is contained in:
shinchan-zhai
2026-03-18 11:10:22 +08:00
committed by GitHub
parent d5fbe445e1
commit 16ebe0a64c
5 changed files with 310 additions and 0 deletions

View File

@@ -227,6 +227,16 @@ func (client *Client) BuildMCPRequestBody(systemPrompt, userPrompt string) map[s
"content": userPrompt,
})
// Guard: truncate messages if they would exceed the model's context window
if client.Cfg.MaxContext > 0 {
truncated, removed := truncateMessages(messages, client.Cfg.MaxContext, client.MaxTokens)
if removed > 0 {
client.Log.Warnf("⚠️ [%s] Context guard: truncated %d oldest messages to fit within %d token limit",
client.String(), removed, client.Cfg.MaxContext)
messages = truncated
}
}
// Build request body
requestBody := map[string]interface{}{
"model": client.Model,
@@ -575,6 +585,20 @@ func (client *Client) BuildRequestBodyFromRequest(req *Request) map[string]any {
messages = append(messages, m)
}
// Guard: truncate messages if they would exceed the model's context window
maxOut := client.MaxTokens
if req.MaxTokens != nil {
maxOut = *req.MaxTokens
}
if client.Cfg.MaxContext > 0 {
truncated, removed := truncateMessagesAny(messages, client.Cfg.MaxContext, maxOut)
if removed > 0 {
client.Log.Warnf("⚠️ [%s] Context guard: truncated %d oldest messages to fit within %d token limit",
client.String(), removed, client.Cfg.MaxContext)
messages = truncated
}
}
// Build basic request body
requestBody := map[string]interface{}{
"model": req.Model,