titan-agent 5.6.6 → 5.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,7 +12,7 @@ import { updateIssue, startRun, endRun, addIssueComment, recordSpend } from "./c
12
12
  import { recordTokenUsage, routeModel } from "./costOptimizer.js";
13
13
  import { calculateActualCost } from "./costEstimator.js";
14
14
  import { getSessionGoal } from "./autonomyContext.js";
15
- import { initBudget, checkBudget, recordUsage, markExceeded, cleanupBudget, getDefaultBudget } from "./promptBudget.js";
15
+ import { initBudget, checkBudget, recordUsage, markExceeded, cleanupBudget, getDefaultBudget, resetBudgetUsage } from "./promptBudget.js";
16
16
  import { scanForSecrets } from "../security/secretGuard.js";
17
17
  import { fullExfilScan } from "../security/exfilScan.js";
18
18
  import { runShellHooks } from "../hooks/shellHooks.js";
@@ -644,12 +644,20 @@ Try a COMPLETELY DIFFERENT strategy. Do NOT repeat the same tools or approach.`
644
644
  if (round === 0 && phase === "think" && !ctx.isAutonomous && !ctx.taskEnforcementActive && ctx.activeTools.length > 0 && detectToolUseIntent(ctx.message || "")) {
645
645
  logger.info(COMPONENT, "[ExplicitIntent] User explicitly requested tool use \u2014 forcing tool_choice=required for round 1");
646
646
  }
647
- const budgetMsg = budgetConfig.maxTokens > 0 ? checkBudget(ctx.sessionId, budgetConfig) : null;
648
- if (budgetMsg) {
649
- markExceeded(ctx.sessionId);
650
- result.content = budgetMsg;
651
- phase = "done";
652
- break;
647
+ const budgetCheck = budgetConfig.maxTokens > 0 ? checkBudget(ctx.sessionId, budgetConfig) : null;
648
+ if (budgetCheck) {
649
+ if (budgetCheck.action === "compress") {
650
+ const before = ctx.messages.length;
651
+ const compressed = buildSmartContext(ctx.messages, Math.floor(budgetConfig.maxTokens * 0.6));
652
+ ctx.messages = compressed;
653
+ resetBudgetUsage(ctx.sessionId);
654
+ logger.info(COMPONENT, `[Budget] Compressed context: ${before} \u2192 ${compressed.length} messages, budget reset`);
655
+ } else {
656
+ markExceeded(ctx.sessionId);
657
+ result.content = `\u26A0\uFE0F ${budgetCheck.message}`;
658
+ phase = "done";
659
+ break;
660
+ }
653
661
  }
654
662
  let response;
655
663
  const thinkStart = Date.now();
@@ -1403,12 +1411,20 @@ Examples: use read_file instead of cat/head/tail/grep, and edit_file instead of
1403
1411
  break;
1404
1412
  }
1405
1413
  logger.info(COMPONENT, `Respond phase \u2014 calling LLM without tools to generate final answer`);
1406
- const respondBudgetMsg = budgetConfig.maxTokens > 0 ? checkBudget(ctx.sessionId, budgetConfig) : null;
1407
- if (respondBudgetMsg) {
1408
- markExceeded(ctx.sessionId);
1409
- result.content = respondBudgetMsg;
1410
- phase = "done";
1411
- break;
1414
+ const respondBudgetCheck = budgetConfig.maxTokens > 0 ? checkBudget(ctx.sessionId, budgetConfig) : null;
1415
+ if (respondBudgetCheck) {
1416
+ if (respondBudgetCheck.action === "compress") {
1417
+ const before = ctx.messages.length;
1418
+ const compressed = buildSmartContext(ctx.messages, Math.floor(budgetConfig.maxTokens * 0.6));
1419
+ ctx.messages = compressed;
1420
+ resetBudgetUsage(ctx.sessionId);
1421
+ logger.info(COMPONENT, `[Budget] Respond-phase compressed: ${before} \u2192 ${compressed.length} messages`);
1422
+ } else {
1423
+ markExceeded(ctx.sessionId);
1424
+ result.content = `\u26A0\uFE0F ${respondBudgetCheck.message}`;
1425
+ phase = "done";
1426
+ break;
1427
+ }
1412
1428
  }
1413
1429
  let smartMessages;
1414
1430
  if (ctx.voiceFastPath) {