fix: truncateToolOutput may exceed maxChars when limit < marker overhead

- Fall back to hard slice when maxChars is too small to fit the marker
- Fix misplaced JSDoc for outputSchema in AgentConfig
- Tighten test assertion to verify length <= maxChars
This commit is contained in:
JackChen 2026-04-16 17:36:51 +08:00
parent 4da2ea9b16
commit a97e80ca37
3 changed files with 14 additions and 8 deletions

View File

@ -220,7 +220,13 @@ export function truncateToolOutput(data: string, maxChars: number): string {
const markerTemplate = '\n\n[...truncated characters...]\n\n' const markerTemplate = '\n\n[...truncated characters...]\n\n'
const markerOverhead = markerTemplate.length + String(data.length).length const markerOverhead = markerTemplate.length + String(data.length).length
const available = Math.max(0, maxChars - markerOverhead) // When maxChars is too small to fit any content alongside the marker,
// fall back to a hard slice so the result never exceeds maxChars.
if (maxChars <= markerOverhead) {
return data.slice(0, maxChars)
}
const available = maxChars - markerOverhead
const headChars = Math.floor(available * 0.7) const headChars = Math.floor(available * 0.7)
const tailChars = available - headChars const tailChars = available - headChars
const truncatedCount = data.length - headChars - tailChars const truncatedCount = data.length - headChars - tailChars

View File

@ -253,11 +253,6 @@ export interface AgentConfig {
* calls and text outputs to detect stuck loops before `maxTurns` is reached. * calls and text outputs to detect stuck loops before `maxTurns` is reached.
*/ */
readonly loopDetection?: LoopDetectionConfig readonly loopDetection?: LoopDetectionConfig
/**
* Optional Zod schema for structured output. When set, the agent's final
* output is parsed as JSON and validated against this schema. A single
* retry with error feedback is attempted on validation failure.
*/
/** /**
* Maximum tool output length in characters for all tools used by this agent. * Maximum tool output length in characters for all tools used by this agent.
* When set, tool outputs exceeding this limit are truncated (head + tail * When set, tool outputs exceeding this limit are truncated (head + tail
@ -265,6 +260,11 @@ export interface AgentConfig {
* takes priority over this value. * takes priority over this value.
*/ */
readonly maxToolOutputChars?: number readonly maxToolOutputChars?: number
/**
* Optional Zod schema for structured output. When set, the agent's final
* output is parsed as JSON and validated against this schema. A single
* retry with error feedback is attempted on validation failure.
*/
readonly outputSchema?: ZodSchema readonly outputSchema?: ZodSchema
/** /**
* Called before each agent run. Receives the prompt and agent config. * Called before each agent run. Receives the prompt and agent config.

View File

@ -231,9 +231,9 @@ describe('truncateToolOutput', () => {
it('handles very small maxChars gracefully', () => { it('handles very small maxChars gracefully', () => {
const data = 'x'.repeat(100) const data = 'x'.repeat(100)
// With maxChars=1, the marker alone exceeds the budget, but it should not crash // With maxChars=1, the marker alone exceeds the budget — falls back to hard slice
const result = truncateToolOutput(data, 1) const result = truncateToolOutput(data, 1)
expect(result).toContain('[...truncated') expect(result.length).toBeLessThanOrEqual(1)
}) })
}) })