{"version":3,"file":"tool-budget.d.ts","sourceRoot":"","sources":["../../../../src/runs/shared/tool-budget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEnG,eAAO,MAAM,yBAAyB,yCAA0C,CAAC;AACjF,eAAO,MAAM,eAAe,4BAA4B,CAAC;AACzD,eAAO,MAAM,yBAAyB,sCAAsC,CAAC;AAE7E,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,GAAG,SAAS,GAAG,GAAG,GAAG,MAAM,EAAE,CAIrG;AAED,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,OAAO,EACZ,KAAK,SAAe,EACpB,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;CAAO,GACnC;IAAE,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAiCjD;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,kBAAkB,GAAG,eAAe,CAElF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,eAAe,CAUpH;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAGrH;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzF;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEhH;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAE9F;AAED,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAO,GACnC,kBAAkB,GAAG,SAAS,CAUhC","sourcesContent":["import type { ResolvedToolBudget, ToolBudgetConfig, ToolBudgetState } from \"../../shared/types.ts\";\n\nexport const DEFAULT_TOOL_BUDGET_BLOCK = [\"read\", \"grep\", \"find\", \"ls\"] as const;\nexport const TOOL_BUDGET_ENV = \"PI_SUBAGENT_TOOL_BUDGET\";\nexport const TOOL_BUDGET_ZERO_AUTH_ENV = \"PI_SUBAGENT_TOOL_BUDGET_ZERO_AUTH\";\n\nexport function normalizeToolBudgetBlock(block: ToolBudgetConfig[\"block\"] | undefined): \"*\" | string[] {\n\tif (block === \"*\") return \"*\";\n\tif (block === undefined) return [...DEFAULT_TOOL_BUDGET_BLOCK];\n\treturn [...new Set(block.map((tool) => tool.trim()).filter(Boolean))];\n}\n\nexport function validateToolBudgetConfig(\n\traw: unknown,\n\tlabel = \"toolBudget\",\n\toptions: { minimumHard?: 0 | 1 } = {},\n): { budget?: ResolvedToolBudget; 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 hard and optional soft/block.` };\n\tconst value = raw as ToolBudgetConfig;\n\tconst minimumHard = options.minimumHard ?? 1;\n\tif (typeof value.hard !== \"number\" || !Number.isInteger(value.hard) || value.hard < minimumHard) {\n\t\treturn { error: `${label}.hard must be an integer >= ${minimumHard}.` };\n\t}\n\tif (\n\t\tvalue.soft !== undefined &&\n\t\t(typeof value.soft !== \"number\" || !Number.isInteger(value.soft) || value.soft < 1)\n\t) {\n\t\treturn { error: `${label}.soft must be an integer >= 1 when provided.` };\n\t}\n\tif (value.soft !== undefined && value.soft > value.hard) {\n\t\treturn { error: `${label}.soft must be <= ${label}.hard.` };\n\t}\n\tif (value.block !== undefined && value.block !== \"*\") {\n\t\tif (!Array.isArray(value.block)) return { error: `${label}.block must be \"*\" or an array of tool names.` };\n\t\tif (value.block.length === 0) return { error: `${label}.block must contain at least one tool name.` };\n\t\tfor (const item of value.block) {\n\t\t\tif (typeof item !== \"string\" || !item.trim())\n\t\t\t\treturn { error: `${label}.block must contain non-empty tool names.` };\n\t\t}\n\t}\n\treturn {\n\t\tbudget: {\n\t\t\thard: value.hard,\n\t\t\t...(value.soft !== undefined ? { soft: value.soft } : {}),\n\t\t\tblock: normalizeToolBudgetBlock(value.block),\n\t\t},\n\t};\n}\n\nexport function initialToolBudgetState(budget: ResolvedToolBudget): ToolBudgetState {\n\treturn { ...budget, toolCount: 0, outcome: \"within-budget\" };\n}\n\nexport function toolBudgetState(budget: ResolvedToolBudget, toolCount: number, blockedTool?: string): ToolBudgetState {\n\tconst overHard = toolCount > budget.hard;\n\tconst overSoft = budget.soft !== undefined && toolCount >= budget.soft;\n\treturn {\n\t\t...budget,\n\t\ttoolCount,\n\t\toutcome: overHard ? \"hard-blocked\" : overSoft ? \"soft-reached\" : \"within-budget\",\n\t\t...(overSoft ? { softReachedAt: budget.soft } : {}),\n\t\t...(overHard ? { hardReachedAt: budget.hard, blockedTool } : {}),\n\t};\n}\n\nexport function shouldBlockToolForBudget(budget: ResolvedToolBudget, toolName: string, nextToolCount: number): boolean {\n\tif (nextToolCount <= budget.hard) return false;\n\treturn budget.block === \"*\" || budget.block.includes(toolName);\n}\n\nexport function toolBudgetSoftNudge(budget: ResolvedToolBudget, toolCount: number): string {\n\treturn `Tool budget soft limit reached after ${toolCount} tool call${toolCount === 1 ? \"\" : \"s\"} (soft ${budget.soft}, hard ${budget.hard}). Stop starting new browsing/search work and finalize from the context you already have.`;\n}\n\nexport function toolBudgetBlockedMessage(budget: ResolvedToolBudget, toolName: string, toolCount: number): string {\n\treturn `Tool budget hard limit reached after ${toolCount} tool call${toolCount === 1 ? \"\" : \"s\"} (hard ${budget.hard}). The '${toolName}' tool is blocked so you can finalize from the context you already have.`;\n}\n\nexport function encodeToolBudgetEnv(budget: ResolvedToolBudget | undefined): string | undefined {\n\treturn budget ? JSON.stringify(budget) : undefined;\n}\n\nexport function decodeToolBudgetEnv(\n\tvalue: string | undefined,\n\toptions: { allowZero?: boolean } = {},\n): ResolvedToolBudget | undefined {\n\tif (!value?.trim()) return undefined;\n\tconst parsed = JSON.parse(value) as unknown;\n\tconst normalized = validateToolBudgetConfig(\n\t\tparsed,\n\t\tTOOL_BUDGET_ENV,\n\t\toptions.allowZero ? { minimumHard: 0 } : undefined,\n\t);\n\tif (normalized.error) throw new Error(normalized.error);\n\treturn normalized.budget;\n}\n"]}