{"version":3,"file":"turn-budget.d.ts","sourceRoot":"","sources":["../../../../src/runs/shared/turn-budget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEjF,eAAO,MAAM,+BAA+B,IAAI,CAAC;AAEjD,wBAAgB,uBAAuB,CACtC,GAAG,EAAE,OAAO,EACZ,KAAK,SAAe,GAClB;IAAE,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAgBrD;AAED,wBAAgB,4BAA4B,CAC3C,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAC3D,MAAM,CAaR;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAExF;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE/F;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE5F;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,CAOzG;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,eAAe,CAQjH;AAED,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,kBAAkB,EAC1B,SAAS,EAAE,MAAM,EACjB,yBAAyB,SAAY,GACnC,eAAe,CAQjB;AAED,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,kBAAkB,EAC1B,SAAS,EAAE,MAAM,EACjB,qBAAqB,EAAE,OAAO,EAC9B,wBAAwB,EAAE,OAAO,EACjC,gBAAgB,UAAQ,GACtB,UAAU,GAAG,OAAO,GAAG,OAAO,CAKhC","sourcesContent":["import type { ResolvedTurnBudget, TurnBudgetState } from \"../../shared/types.ts\";\n\nexport const DEFAULT_TURN_BUDGET_GRACE_TURNS = 1;\n\nexport function resolveTurnBudgetConfig(\n\traw: unknown,\n\tlabel = \"turnBudget\",\n): { turnBudget?: ResolvedTurnBudget; error?: string } {\n\tif (raw === undefined) return {};\n\tif (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n\t\treturn { error: `${label} must be an object with maxTurns and optional graceTurns.` };\n\t}\n\tconst unknownField = Object.keys(raw).find((key) => key !== \"maxTurns\" && key !== \"graceTurns\");\n\tif (unknownField) return { error: `${label}.${unknownField} is not supported.` };\n\tconst budget = raw as { maxTurns?: unknown; graceTurns?: unknown };\n\tif (typeof budget.maxTurns !== \"number\" || !Number.isInteger(budget.maxTurns) || budget.maxTurns < 1) {\n\t\treturn { error: `${label}.maxTurns must be an integer >= 1.` };\n\t}\n\tconst graceTurns = budget.graceTurns ?? DEFAULT_TURN_BUDGET_GRACE_TURNS;\n\tif (typeof graceTurns !== \"number\" || !Number.isInteger(graceTurns) || graceTurns < 0) {\n\t\treturn { error: `${label}.graceTurns must be an integer >= 0.` };\n\t}\n\treturn { turnBudget: { maxTurns: budget.maxTurns, graceTurns } };\n}\n\nexport function appendTurnBudgetSystemPrompt(\n\tsystemPrompt: string,\n\tbudget: { maxTurns: number; graceTurns?: number } | undefined,\n): string {\n\tif (!budget) return systemPrompt;\n\tconst graceTurns = budget.graceTurns ?? DEFAULT_TURN_BUDGET_GRACE_TURNS;\n\tconst grace = graceTurns === 1 ? \"1 additional assistant turn\" : `${graceTurns} additional assistant turns`;\n\tconst block = [\n\t\t\"## Turn budget\",\n\t\t`This child run has a soft budget of ${budget.maxTurns} assistant turn${budget.maxTurns === 1 ? \"\" : \"s\"}.`,\n\t\t`After that, ${grace} may be allowed only for a final wrap-up.`,\n\t\t\"When you approach or reach the soft budget, stop starting new tool work and return the final answer immediately.\",\n\t\t\"This runner uses process-mode execution, so live steering after launch may be unavailable; treat this instruction as the wrap-up request.\",\n\t\t\"If you continue past the soft budget plus grace turns, the supervisor may abort the process and return only partial output.\",\n\t].join(\"\\n\");\n\treturn systemPrompt.trim() ? `${systemPrompt.trim()}\\n\\n${block}` : block;\n}\n\nexport function turnBudgetSoftNote(budget: ResolvedTurnBudget, turnCount: number): string {\n\treturn `Turn budget wrap-up was requested after ${turnCount} assistant turn${turnCount === 1 ? \"\" : \"s\"} (soft limit ${budget.maxTurns}, grace ${budget.graceTurns}). Process-mode live steering is unavailable, so the child was warned at launch to wrap up by this budget. Output may be partial.`;\n}\n\nexport function turnBudgetExceededMessage(budget: ResolvedTurnBudget, turnCount: number): string {\n\treturn `Subagent exceeded turn budget after ${turnCount} assistant turn${turnCount === 1 ? \"\" : \"s\"} (soft limit ${budget.maxTurns} + grace ${budget.graceTurns}).`;\n}\n\nexport function turnBudgetDeferredNote(budget: ResolvedTurnBudget, turnCount: number): string {\n\treturn `Turn-budget termination was deferred at ${turnCount} assistant turn${turnCount === 1 ? \"\" : \"s\"} (soft limit ${budget.maxTurns} + grace ${budget.graceTurns}) because the assistant started tool work. The run ended before another safe assistant boundary; output may be partial.`;\n}\n\nexport function formatTurnBudgetOutput(message: string, output: string): string {\n\treturn output.trim() ? `${message}\\n\\nPartial output before turn-budget abort:\\n${output}` : message;\n}\n\nexport function initialTurnBudgetState(budget: { maxTurns: number; graceTurns?: number }): TurnBudgetState {\n\treturn {\n\t\tmaxTurns: budget.maxTurns,\n\t\tgraceTurns: budget.graceTurns ?? DEFAULT_TURN_BUDGET_GRACE_TURNS,\n\t\toutcome: \"within-budget\",\n\t\tturnCount: 0,\n\t};\n}\n\nexport function turnBudgetState(budget: ResolvedTurnBudget, turnCount: number, exceeded: boolean): TurnBudgetState {\n\treturn {\n\t\t...budget,\n\t\tturnCount,\n\t\toutcome: exceeded ? \"exceeded\" : \"wrap-up-requested\",\n\t\twrapUpRequestedAtTurn: budget.maxTurns,\n\t\t...(exceeded ? { exceededAtTurn: turnCount } : {}),\n\t};\n}\n\nexport function turnBudgetDeferredState(\n\tbudget: ResolvedTurnBudget,\n\tturnCount: number,\n\tterminationDeferredAtTurn = turnCount,\n): TurnBudgetState {\n\treturn {\n\t\t...budget,\n\t\tturnCount,\n\t\toutcome: \"termination-deferred\",\n\t\twrapUpRequestedAtTurn: budget.maxTurns,\n\t\tterminationDeferredAtTurn,\n\t};\n}\n\nexport function turnBudgetDecision(\n\tbudget: ResolvedTurnBudget,\n\tturnCount: number,\n\tterminalAssistantStop: boolean,\n\ttoolWorkActiveOrStarting: boolean,\n\tenforceHardLimit = false,\n): \"continue\" | \"defer\" | \"abort\" {\n\tconst hardLimit = budget.maxTurns + budget.graceTurns;\n\tif (terminalAssistantStop || turnCount < hardLimit) return \"continue\";\n\tif (toolWorkActiveOrStarting && !enforceHardLimit) return \"defer\";\n\treturn \"abort\";\n}\n"]}