{"version":3,"file":"provider-health.d.ts","sourceRoot":"","sources":["../../src/core/provider-health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;CAChB;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAKzE;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAO7E;AAED,qFAAqF;AACrF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAmC,GACxC,kBAAkB,GAAG,SAAS,CAQhC;AAED,0DAA0D;AAC1D,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD","sourcesContent":["/**\n * Process-wide provider health signal.\n *\n * When the main session's turn fails with a usage/quota/rate-limit error that\n * does not recover (retries exhausted or disabled), the session records the\n * provider as \"exhausted\" for a short window. The subagent Task tool reads this\n * to skip pointless spawns: subagents inherit the parent's provider, so they\n * would hit the same wall. The signal is cleared on the next successful response\n * and self-expires after a TTL so it never sticks longer than necessary.\n */\n\n/** How long an exhaustion signal stays active before it self-expires. */\nconst PROVIDER_EXHAUSTION_TTL_MS = 45_000;\n\nexport interface ProviderExhaustion {\n\tprovider: string;\n\t/** Epoch ms when the exhaustion was recorded. */\n\tat: number;\n\t/** The provider error message that triggered it (truncated for display). */\n\tmessage: string;\n}\n\nconst records = new Map<string, ProviderExhaustion>();\n\n/**\n * Heuristic: does this provider error indicate quota/credit/rate-limit\n * exhaustion (as opposed to a transient network/overload blip)?\n */\nexport function isProviderQuotaError(message: string | undefined): boolean {\n\tif (!message) return false;\n\treturn /usage limit|quota|rate.?limit|too many requests|429|insufficient|out of credit|credit balance|billing|payment required|402|exceeded/i.test(\n\t\tmessage,\n\t);\n}\n\n/** Record that a provider is currently exhausted/rate-limited. */\nexport function markProviderExhausted(provider: string, message: string): void {\n\tconst trimmed = message.trim();\n\trecords.set(provider, {\n\t\tprovider,\n\t\tat: Date.now(),\n\t\tmessage: trimmed.length > 200 ? `${trimmed.slice(0, 199)}\\u2026` : trimmed,\n\t});\n}\n\n/** Clear any exhaustion signal for a provider (e.g. after a successful response). */\nexport function clearProviderExhaustion(provider: string): void {\n\trecords.delete(provider);\n}\n\n/**\n * Return the active exhaustion record for a provider, or undefined when none is\n * active or it has expired. Expired records are pruned on read.\n */\nexport function getProviderExhaustion(\n\tprovider: string,\n\tttlMs: number = PROVIDER_EXHAUSTION_TTL_MS,\n): ProviderExhaustion | undefined {\n\tconst record = records.get(provider);\n\tif (!record) return undefined;\n\tif (Date.now() - record.at >= ttlMs) {\n\t\trecords.delete(provider);\n\t\treturn undefined;\n\t}\n\treturn record;\n}\n\n/** Test helper: clear all recorded exhaustion signals. */\nexport function resetProviderHealthForTesting(): void {\n\trecords.clear();\n}\n"]}