Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 3 additions & 19 deletions src/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import { WorkerAgent } from './worker.js';
import { getLogger } from './utils/logger.js';
import { getMissingCredential, saveCredential, saveProviderToYaml, saveOrchestratorToYaml, saveClaudeCodeModelToYaml, saveClaudeCodeAuth } from './utils/config.js';
import { resetClaudeCodeSpawner, getSpawner } from './tools/coding.js';

const MAX_RESULT_LENGTH = 3000;
const LARGE_FIELDS = ['stdout', 'stderr', 'content', 'diff', 'output', 'body', 'html', 'text', 'log', 'logs'];
import { truncateToolResult } from './utils/truncate.js';

export class OrchestratorAgent {
constructor({ config, conversationManager, personaManager, selfManager, jobManager, automationManager, memoryManager, shareQueue }) {
Expand Down Expand Up @@ -282,23 +280,9 @@ export class OrchestratorAgent {
}
}

/** Truncate a tool result. */
/** Truncate a tool result. Delegates to shared utility. */
_truncateResult(name, result) {
let str = JSON.stringify(result);
if (str.length <= MAX_RESULT_LENGTH) return str;

if (result && typeof result === 'object') {
const truncated = { ...result };
for (const field of LARGE_FIELDS) {
if (typeof truncated[field] === 'string' && truncated[field].length > 500) {
truncated[field] = truncated[field].slice(0, 500) + `\n... [truncated ${truncated[field].length - 500} chars]`;
}
}
str = JSON.stringify(truncated);
if (str.length <= MAX_RESULT_LENGTH) return str;
}

return str.slice(0, MAX_RESULT_LENGTH) + `\n... [truncated, total ${str.length} chars]`;
return truncateToolResult(name, result);
}

async processMessage(chatId, userMessage, user, onUpdate, sendPhoto, opts = {}) {
Expand Down
42 changes: 42 additions & 0 deletions src/utils/truncate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Shared tool-result truncation logic.
* Used by both OrchestratorAgent and WorkerAgent to cap tool outputs
* before feeding them back into the LLM context window.
*/

const MAX_RESULT_LENGTH = 3000;

const LARGE_FIELDS = [
'stdout', 'stderr', 'content', 'diff', 'output',
'body', 'html', 'text', 'log', 'logs',
];

/**
* Truncate a serialized tool result to fit within the context budget.
*
* Strategy:
* 1. If JSON.stringify(result) fits, return it as-is.
* 2. Otherwise, trim known large string fields to 500 chars each and retry.
* 3. If still too large, hard-slice the serialized string.
*
* @param {string} _name - Tool name (reserved for future per-tool limits)
* @param {any} result - Raw tool result object
* @returns {string} JSON string, guaranteed ≤ MAX_RESULT_LENGTH (+tail note)
*/
export function truncateToolResult(_name, result) {
let str = JSON.stringify(result);
if (str.length <= MAX_RESULT_LENGTH) return str;

if (result && typeof result === 'object') {
const truncated = { ...result };
for (const field of LARGE_FIELDS) {
if (typeof truncated[field] === 'string' && truncated[field].length > 500) {
truncated[field] = truncated[field].slice(0, 500) + `\n... [truncated ${truncated[field].length - 500} chars]`;
}
}
str = JSON.stringify(truncated);
if (str.length <= MAX_RESULT_LENGTH) return str;
}

return str.slice(0, MAX_RESULT_LENGTH) + `\n... [truncated, total ${str.length} chars]`;
}
20 changes: 2 additions & 18 deletions src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import { getMissingCredential } from './utils/config.js';
import { getWorkerPrompt } from './prompts/workers.js';
import { getUnifiedSkillById } from './skills/custom.js';
import { getLogger } from './utils/logger.js';

const MAX_RESULT_LENGTH = 3000;
const LARGE_FIELDS = ['stdout', 'stderr', 'content', 'diff', 'output', 'body', 'html', 'text', 'log', 'logs'];
import { truncateToolResult } from './utils/truncate.js';

/**
* WorkerAgent — runs a scoped agent loop in the background.
Expand Down Expand Up @@ -371,21 +369,7 @@ export class WorkerAgent {
}

_truncateResult(name, result) {
let str = JSON.stringify(result);
if (str.length <= MAX_RESULT_LENGTH) return str;

if (result && typeof result === 'object') {
const truncated = { ...result };
for (const field of LARGE_FIELDS) {
if (typeof truncated[field] === 'string' && truncated[field].length > 500) {
truncated[field] = truncated[field].slice(0, 500) + `\n... [truncated ${truncated[field].length - 500} chars]`;
}
}
str = JSON.stringify(truncated);
if (str.length <= MAX_RESULT_LENGTH) return str;
}

return str.slice(0, MAX_RESULT_LENGTH) + `\n... [truncated, total ${str.length} chars]`;
return truncateToolResult(name, result);
}

_formatToolSummary(name, input) {
Expand Down