Prevent chat from exceeding Claude context limit

- Cap conversation history to last 20 messages
- Truncate tool results over 8KB before sending back to Claude
- Trim long assistant messages in client-side history to 2KB

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
DJP 2026-04-08 12:17:27 -04:00
parent 2f1afed855
commit 3209a5dbee
2 changed files with 22 additions and 6 deletions

View file

@ -260,15 +260,22 @@ export async function POST(req: NextRequest) {
);
}
const { messages, context } = await req.json();
const { messages: rawMessages, context } = await req.json();
if (!messages || !Array.isArray(messages) || messages.length === 0) {
if (!rawMessages || !Array.isArray(rawMessages) || rawMessages.length === 0) {
return NextResponse.json(
{ error: "messages array is required" },
{ status: 400 }
);
}
// Limit conversation history to prevent exceeding Claude's context window.
// Keep the last 20 messages (10 user + 10 assistant turns).
const MAX_HISTORY = 20;
const messages = rawMessages.length > MAX_HISTORY
? rawMessages.slice(-MAX_HISTORY)
: rawMessages;
const userId = session.user.id;
const organizationId = session.user.organizationId;
const userRole = session.user.role;
@ -389,11 +396,17 @@ export async function POST(req: NextRequest) {
error: result.error,
});
// Truncate large tool results to avoid exceeding context limits
let resultJson = JSON.stringify(
result.success ? result.data : { error: result.error }
);
if (resultJson.length > 8000) {
resultJson = resultJson.slice(0, 8000) + '... [truncated]"}';
}
toolResults.push({
tool_use_id: toolCall.id,
content: JSON.stringify(
result.success ? result.data : { error: result.error }
),
content: resultJson,
});
}

View file

@ -145,9 +145,12 @@ export function useChat(context?: ChatContext) {
// Build message history for the API — send plain text only.
// Tool interactions are resolved server-side within a single request,
// so we never send tool_use/tool_result blocks back in history.
// Trim long assistant responses to keep token count manageable.
const apiMessages = [...messages, userMsg].map((m) => ({
role: m.role,
content: m.content,
content: typeof m.content === "string" && m.content.length > 2000
? m.content.slice(0, 2000) + "..."
: m.content,
}));
abortRef.current = new AbortController();