@linxiraos/pi-ai 1.0.0 → 1.0.2

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.
Files changed (355) hide show
  1. package/CHANGELOG.md +123 -30
  2. package/package.json +135 -136
  3. package/src/auth/sqlite-credential-store.ts +0 -56
  4. package/src/auth-retry.ts +5 -4
  5. package/src/auth-storage.ts +122 -112
  6. package/src/dialect/owned-stream.ts +3 -0
  7. package/src/error/auth-classify.ts +7 -6
  8. package/src/error/aws.ts +5 -1
  9. package/src/error/flags.ts +25 -1
  10. package/src/error/provider.ts +6 -5
  11. package/src/error/rate-limit.ts +71 -1
  12. package/src/providers/amazon-bedrock.ts +38 -0
  13. package/src/providers/anthropic-client.ts +6 -10
  14. package/src/providers/anthropic.ts +107 -259
  15. package/src/providers/aws-credentials.ts +222 -29
  16. package/src/providers/azure-openai-responses.ts +1 -0
  17. package/src/providers/cursor/exec-modern.ts +1 -0
  18. package/src/providers/cursor-pi-args.ts +22 -0
  19. package/src/providers/cursor.ts +81 -1
  20. package/src/providers/devin.ts +3 -3
  21. package/src/providers/google-antigravity-forced-tool.md +1 -0
  22. package/src/providers/google-gemini-cli.ts +83 -40
  23. package/src/providers/google-shared.ts +22 -8
  24. package/src/providers/ollama.ts +15 -3
  25. package/src/providers/openai-codex/request-transformer.ts +47 -21
  26. package/src/providers/openai-codex-responses.ts +3 -3
  27. package/src/providers/openai-reasoning-fallback.ts +21 -8
  28. package/src/providers/openai-responses.ts +77 -12
  29. package/src/providers/openai-shared.ts +114 -15
  30. package/src/providers/pi-native-server.ts +1 -0
  31. package/src/providers/register-builtins.ts +18 -14
  32. package/src/providers/vision-guard.ts +15 -3
  33. package/src/registry/amazon-bedrock.ts +9 -14
  34. package/src/registry/api-key-login.ts +26 -12
  35. package/src/registry/aws.ts +16 -8
  36. package/src/registry/cloudflare-ai-gateway.ts +10 -29
  37. package/src/registry/kagi.ts +11 -29
  38. package/src/registry/litellm.ts +11 -29
  39. package/src/registry/llama-cpp.ts +11 -21
  40. package/src/registry/lm-studio.ts +9 -20
  41. package/src/registry/oauth/callback-server.ts +93 -5
  42. package/src/registry/oauth/google-antigravity.ts +99 -44
  43. package/src/registry/oauth/perplexity.ts +32 -4
  44. package/src/registry/parallel.ts +10 -28
  45. package/src/registry/tavily.ts +9 -27
  46. package/src/registry/together.ts +7 -3
  47. package/src/registry/vercel-ai-gateway.ts +10 -28
  48. package/src/registry/vllm.ts +11 -21
  49. package/src/stream.ts +459 -53
  50. package/src/types.ts +23 -0
  51. package/src/usage/alibaba-token-plan.ts +8 -15
  52. package/src/usage/claude.ts +12 -19
  53. package/src/usage/cursor.ts +179 -59
  54. package/src/usage/gemini.ts +4 -3
  55. package/src/usage/github-copilot.ts +3 -2
  56. package/src/usage/google-antigravity.ts +10 -17
  57. package/src/usage/kimi.ts +35 -17
  58. package/src/usage/minimax-code.ts +7 -27
  59. package/src/usage/openai-codex-reset.ts +3 -2
  60. package/src/usage/openai-codex.ts +5 -5
  61. package/src/usage/opencode-go.ts +170 -60
  62. package/src/usage/shared.ts +33 -10
  63. package/src/usage/synthetic.ts +4 -11
  64. package/src/usage/umans.ts +2 -2
  65. package/src/usage/xai-oauth.ts +62 -34
  66. package/src/usage/zai.ts +4 -6
  67. package/src/usage.ts +0 -20
  68. package/src/utils/aws-profile.ts +39 -1
  69. package/src/utils/block-symbols.ts +18 -0
  70. package/src/utils/empty-completion-retry.ts +4 -1
  71. package/src/utils/leaked-thinking-stream.ts +3 -0
  72. package/src/utils/openrouter-headers.ts +4 -4
  73. package/src/utils/thinking-loop.ts +17 -38
  74. package/dist/types/api-registry.d.ts +0 -30
  75. package/dist/types/auth/sqlite-credential-store.d.ts +0 -117
  76. package/dist/types/auth-broker/client.d.ts +0 -93
  77. package/dist/types/auth-broker/discover.d.ts +0 -39
  78. package/dist/types/auth-broker/index.d.ts +0 -7
  79. package/dist/types/auth-broker/refresher.d.ts +0 -25
  80. package/dist/types/auth-broker/remote-store.d.ts +0 -136
  81. package/dist/types/auth-broker/server.d.ts +0 -48
  82. package/dist/types/auth-broker/snapshot-cache.d.ts +0 -17
  83. package/dist/types/auth-broker/types.d.ts +0 -152
  84. package/dist/types/auth-broker/wire-schema-resource.d.ts +0 -53
  85. package/dist/types/auth-broker/wire-schemas.d.ts +0 -5
  86. package/dist/types/auth-gateway/http.d.ts +0 -56
  87. package/dist/types/auth-gateway/index.d.ts +0 -3
  88. package/dist/types/auth-gateway/server.d.ts +0 -36
  89. package/dist/types/auth-gateway/types.d.ts +0 -127
  90. package/dist/types/auth-retry.d.ts +0 -150
  91. package/dist/types/auth-storage.d.ts +0 -1258
  92. package/dist/types/dialect/anthropic.d.ts +0 -15
  93. package/dist/types/dialect/catalog.d.ts +0 -3
  94. package/dist/types/dialect/coercion.d.ts +0 -23
  95. package/dist/types/dialect/deepseek.d.ts +0 -14
  96. package/dist/types/dialect/demotion.d.ts +0 -30
  97. package/dist/types/dialect/examples.d.ts +0 -18
  98. package/dist/types/dialect/factory.d.ts +0 -3
  99. package/dist/types/dialect/fenced-thinking.d.ts +0 -53
  100. package/dist/types/dialect/gemini.d.ts +0 -17
  101. package/dist/types/dialect/gemma.d.ts +0 -15
  102. package/dist/types/dialect/glm.d.ts +0 -9
  103. package/dist/types/dialect/harmony.d.ts +0 -8
  104. package/dist/types/dialect/hermes.d.ts +0 -9
  105. package/dist/types/dialect/history.d.ts +0 -3
  106. package/dist/types/dialect/index.d.ts +0 -11
  107. package/dist/types/dialect/inventory.d.ts +0 -9
  108. package/dist/types/dialect/kimi.d.ts +0 -14
  109. package/dist/types/dialect/minimax.d.ts +0 -3
  110. package/dist/types/dialect/owned-stream.d.ts +0 -4
  111. package/dist/types/dialect/qwen3.d.ts +0 -9
  112. package/dist/types/dialect/rendering.d.ts +0 -54
  113. package/dist/types/dialect/thinking.d.ts +0 -6
  114. package/dist/types/dialect/types.d.ts +0 -68
  115. package/dist/types/dialect/xml.d.ts +0 -9
  116. package/dist/types/error/abort.d.ts +0 -14
  117. package/dist/types/error/auth-classify.d.ts +0 -20
  118. package/dist/types/error/auth.d.ts +0 -27
  119. package/dist/types/error/aws.d.ts +0 -27
  120. package/dist/types/error/classes.d.ts +0 -106
  121. package/dist/types/error/finalize.d.ts +0 -39
  122. package/dist/types/error/flags.d.ts +0 -94
  123. package/dist/types/error/format.d.ts +0 -20
  124. package/dist/types/error/gateway.d.ts +0 -20
  125. package/dist/types/error/index.d.ts +0 -14
  126. package/dist/types/error/oauth.d.ts +0 -43
  127. package/dist/types/error/provider.d.ts +0 -42
  128. package/dist/types/error/rate-limit.d.ts +0 -80
  129. package/dist/types/error/retryable.d.ts +0 -27
  130. package/dist/types/error/validation.d.ts +0 -32
  131. package/dist/types/index.d.ts +0 -51
  132. package/dist/types/provider-details.d.ts +0 -24
  133. package/dist/types/providers/amazon-bedrock.d.ts +0 -39
  134. package/dist/types/providers/anthropic-client.d.ts +0 -106
  135. package/dist/types/providers/anthropic-messages-server-schema.d.ts +0 -937
  136. package/dist/types/providers/anthropic-messages-server.d.ts +0 -17
  137. package/dist/types/providers/anthropic-wire.d.ts +0 -345
  138. package/dist/types/providers/anthropic.d.ts +0 -261
  139. package/dist/types/providers/aws-credentials.d.ts +0 -48
  140. package/dist/types/providers/aws-eventstream.d.ts +0 -39
  141. package/dist/types/providers/aws-sigv4.d.ts +0 -55
  142. package/dist/types/providers/azure-openai-responses.d.ts +0 -16
  143. package/dist/types/providers/bedrock-mantle.d.ts +0 -13
  144. package/dist/types/providers/claude-code-fingerprint.d.ts +0 -19
  145. package/dist/types/providers/cowork-fetch.d.ts +0 -3
  146. package/dist/types/providers/cursor/exec-modern.d.ts +0 -98
  147. package/dist/types/providers/cursor-pi-args.d.ts +0 -105
  148. package/dist/types/providers/cursor.d.ts +0 -221
  149. package/dist/types/providers/devin.d.ts +0 -12
  150. package/dist/types/providers/error-message.d.ts +0 -25
  151. package/dist/types/providers/github-copilot-headers.d.ts +0 -40
  152. package/dist/types/providers/gitlab-duo-workflow.d.ts +0 -254
  153. package/dist/types/providers/gitlab-duo.d.ts +0 -27
  154. package/dist/types/providers/google-auth.d.ts +0 -24
  155. package/dist/types/providers/google-gemini-cli.d.ts +0 -120
  156. package/dist/types/providers/google-shared.d.ts +0 -203
  157. package/dist/types/providers/google-types.d.ts +0 -155
  158. package/dist/types/providers/google-vertex.d.ts +0 -7
  159. package/dist/types/providers/google.d.ts +0 -4
  160. package/dist/types/providers/grammar.d.ts +0 -1
  161. package/dist/types/providers/kimi.d.ts +0 -27
  162. package/dist/types/providers/mock.d.ts +0 -179
  163. package/dist/types/providers/ollama.d.ts +0 -8
  164. package/dist/types/providers/openai-anthropic-shim.d.ts +0 -35
  165. package/dist/types/providers/openai-chat-server-schema.d.ts +0 -1311
  166. package/dist/types/providers/openai-chat-server.d.ts +0 -16
  167. package/dist/types/providers/openai-chat-wire.d.ts +0 -669
  168. package/dist/types/providers/openai-codex/request-transformer.d.ts +0 -109
  169. package/dist/types/providers/openai-codex/response-handler.d.ts +0 -26
  170. package/dist/types/providers/openai-codex-responses.d.ts +0 -238
  171. package/dist/types/providers/openai-completions.d.ts +0 -48
  172. package/dist/types/providers/openai-reasoning-fallback.d.ts +0 -25
  173. package/dist/types/providers/openai-responses-server-schema.d.ts +0 -1314
  174. package/dist/types/providers/openai-responses-server.d.ts +0 -17
  175. package/dist/types/providers/openai-responses-wire.d.ts +0 -6099
  176. package/dist/types/providers/openai-responses.d.ts +0 -131
  177. package/dist/types/providers/openai-shared.d.ts +0 -624
  178. package/dist/types/providers/pi-native-client.d.ts +0 -13
  179. package/dist/types/providers/pi-native-server.d.ts +0 -69
  180. package/dist/types/providers/register-builtins.d.ts +0 -37
  181. package/dist/types/providers/synthetic.d.ts +0 -26
  182. package/dist/types/providers/transform-messages.d.ts +0 -32
  183. package/dist/types/providers/vision-guard.d.ts +0 -20
  184. package/dist/types/registry/aiand.d.ts +0 -7
  185. package/dist/types/registry/aimlapi.d.ts +0 -4
  186. package/dist/types/registry/alibaba-coding-plan.d.ts +0 -8
  187. package/dist/types/registry/alibaba-token-plan.d.ts +0 -18
  188. package/dist/types/registry/amazon-bedrock.d.ts +0 -5
  189. package/dist/types/registry/anthropic.d.ts +0 -10
  190. package/dist/types/registry/api-key-login.d.ts +0 -42
  191. package/dist/types/registry/api-key-validation.d.ts +0 -43
  192. package/dist/types/registry/aws.d.ts +0 -13
  193. package/dist/types/registry/azure.d.ts +0 -4
  194. package/dist/types/registry/baseten.d.ts +0 -7
  195. package/dist/types/registry/bedrock-mantle.d.ts +0 -22
  196. package/dist/types/registry/cerebras.d.ts +0 -7
  197. package/dist/types/registry/cloudflare-ai-gateway.d.ts +0 -13
  198. package/dist/types/registry/coreweave.d.ts +0 -7
  199. package/dist/types/registry/cursor.d.ts +0 -7
  200. package/dist/types/registry/deepseek.d.ts +0 -8
  201. package/dist/types/registry/derived.d.ts +0 -5
  202. package/dist/types/registry/devin.d.ts +0 -8
  203. package/dist/types/registry/exa.d.ts +0 -8
  204. package/dist/types/registry/firepass.d.ts +0 -16
  205. package/dist/types/registry/fireworks.d.ts +0 -7
  206. package/dist/types/registry/github-copilot.d.ts +0 -7
  207. package/dist/types/registry/gitlab-duo-workflow.d.ts +0 -10
  208. package/dist/types/registry/gitlab-duo.d.ts +0 -9
  209. package/dist/types/registry/gmi-cloud.d.ts +0 -7
  210. package/dist/types/registry/google-antigravity.d.ts +0 -9
  211. package/dist/types/registry/google-gemini-cli.d.ts +0 -9
  212. package/dist/types/registry/google-vertex.d.ts +0 -5
  213. package/dist/types/registry/google.d.ts +0 -4
  214. package/dist/types/registry/groq.d.ts +0 -4
  215. package/dist/types/registry/huggingface.d.ts +0 -7
  216. package/dist/types/registry/index.d.ts +0 -4
  217. package/dist/types/registry/kagi.d.ts +0 -14
  218. package/dist/types/registry/kilo.d.ts +0 -7
  219. package/dist/types/registry/kimi-code.d.ts +0 -7
  220. package/dist/types/registry/litellm.d.ts +0 -13
  221. package/dist/types/registry/llama-cpp.d.ts +0 -8
  222. package/dist/types/registry/lm-studio.d.ts +0 -8
  223. package/dist/types/registry/meta.d.ts +0 -7
  224. package/dist/types/registry/minimax-code-cn.d.ts +0 -6
  225. package/dist/types/registry/minimax-code.d.ts +0 -6
  226. package/dist/types/registry/minimax.d.ts +0 -4
  227. package/dist/types/registry/mistral.d.ts +0 -4
  228. package/dist/types/registry/moonshot.d.ts +0 -7
  229. package/dist/types/registry/nanogpt.d.ts +0 -7
  230. package/dist/types/registry/novita.d.ts +0 -6
  231. package/dist/types/registry/nvidia.d.ts +0 -7
  232. package/dist/types/registry/oauth/anthropic-constants.d.ts +0 -12
  233. package/dist/types/registry/oauth/anthropic.d.ts +0 -24
  234. package/dist/types/registry/oauth/callback-server.d.ts +0 -74
  235. package/dist/types/registry/oauth/cursor.d.ts +0 -16
  236. package/dist/types/registry/oauth/device-code.d.ts +0 -25
  237. package/dist/types/registry/oauth/devin.d.ts +0 -5
  238. package/dist/types/registry/oauth/github-copilot.d.ts +0 -30
  239. package/dist/types/registry/oauth/gitlab-duo-workflow.d.ts +0 -6
  240. package/dist/types/registry/oauth/gitlab-duo.d.ts +0 -3
  241. package/dist/types/registry/oauth/google-antigravity.d.ts +0 -11
  242. package/dist/types/registry/oauth/google-gemini-cli.d.ts +0 -22
  243. package/dist/types/registry/oauth/google-oauth-shared.d.ts +0 -56
  244. package/dist/types/registry/oauth/index.d.ts +0 -45
  245. package/dist/types/registry/oauth/kimi.d.ts +0 -21
  246. package/dist/types/registry/oauth/minimax-code.d.ts +0 -27
  247. package/dist/types/registry/oauth/openai-codex.d.ts +0 -33
  248. package/dist/types/registry/oauth/opencode.d.ts +0 -18
  249. package/dist/types/registry/oauth/perplexity.d.ts +0 -9
  250. package/dist/types/registry/oauth/pkce.d.ts +0 -8
  251. package/dist/types/registry/oauth/types.d.ts +0 -87
  252. package/dist/types/registry/oauth/wafer.d.ts +0 -1
  253. package/dist/types/registry/oauth/xai-oauth.d.ts +0 -46
  254. package/dist/types/registry/oauth/xiaomi.d.ts +0 -25
  255. package/dist/types/registry/oauth/zai.d.ts +0 -25
  256. package/dist/types/registry/ollama-cloud.d.ts +0 -7
  257. package/dist/types/registry/ollama.d.ts +0 -12
  258. package/dist/types/registry/openai-codex-device.d.ts +0 -8
  259. package/dist/types/registry/openai-codex.d.ts +0 -9
  260. package/dist/types/registry/openai.d.ts +0 -4
  261. package/dist/types/registry/opencode-go.d.ts +0 -6
  262. package/dist/types/registry/opencode-zen.d.ts +0 -6
  263. package/dist/types/registry/openrouter.d.ts +0 -13
  264. package/dist/types/registry/parallel.d.ts +0 -14
  265. package/dist/types/registry/perplexity.d.ts +0 -7
  266. package/dist/types/registry/qianfan.d.ts +0 -7
  267. package/dist/types/registry/qwen-portal.d.ts +0 -7
  268. package/dist/types/registry/registry.d.ts +0 -367
  269. package/dist/types/registry/sakana.d.ts +0 -7
  270. package/dist/types/registry/siliconflow-cn.d.ts +0 -7
  271. package/dist/types/registry/siliconflow.d.ts +0 -7
  272. package/dist/types/registry/synthetic.d.ts +0 -6
  273. package/dist/types/registry/tavily.d.ts +0 -14
  274. package/dist/types/registry/together.d.ts +0 -6
  275. package/dist/types/registry/types.d.ts +0 -75
  276. package/dist/types/registry/umans.d.ts +0 -7
  277. package/dist/types/registry/venice.d.ts +0 -13
  278. package/dist/types/registry/vercel-ai-gateway.d.ts +0 -7
  279. package/dist/types/registry/vllm.d.ts +0 -7
  280. package/dist/types/registry/wafer-serverless.d.ts +0 -6
  281. package/dist/types/registry/xai-oauth.d.ts +0 -7
  282. package/dist/types/registry/xai.d.ts +0 -7
  283. package/dist/types/registry/xiaomi-token-plan-ams.d.ts +0 -6
  284. package/dist/types/registry/xiaomi-token-plan-cn.d.ts +0 -6
  285. package/dist/types/registry/xiaomi-token-plan-sgp.d.ts +0 -6
  286. package/dist/types/registry/xiaomi.d.ts +0 -6
  287. package/dist/types/registry/zai.d.ts +0 -15
  288. package/dist/types/registry/zenmux.d.ts +0 -7
  289. package/dist/types/registry/zhipu-coding-plan.d.ts +0 -7
  290. package/dist/types/stream.d.ts +0 -46
  291. package/dist/types/types.d.ts +0 -1064
  292. package/dist/types/usage/alibaba-token-plan.d.ts +0 -3
  293. package/dist/types/usage/claude.d.ts +0 -4
  294. package/dist/types/usage/cursor.d.ts +0 -4
  295. package/dist/types/usage/gemini.d.ts +0 -2
  296. package/dist/types/usage/github-copilot.d.ts +0 -7
  297. package/dist/types/usage/google-antigravity.d.ts +0 -15
  298. package/dist/types/usage/kimi.d.ts +0 -2
  299. package/dist/types/usage/minimax-code.d.ts +0 -3
  300. package/dist/types/usage/ollama.d.ts +0 -5
  301. package/dist/types/usage/openai-codex-base-url.d.ts +0 -18
  302. package/dist/types/usage/openai-codex-reset.d.ts +0 -88
  303. package/dist/types/usage/openai-codex.d.ts +0 -10
  304. package/dist/types/usage/opencode-go.d.ts +0 -2
  305. package/dist/types/usage/shared.d.ts +0 -1
  306. package/dist/types/usage/synthetic.d.ts +0 -2
  307. package/dist/types/usage/umans.d.ts +0 -2
  308. package/dist/types/usage/xai-oauth.d.ts +0 -12
  309. package/dist/types/usage/zai.d.ts +0 -3
  310. package/dist/types/usage.d.ts +0 -527
  311. package/dist/types/utils/abort.d.ts +0 -25
  312. package/dist/types/utils/anthropic-auth.d.ts +0 -35
  313. package/dist/types/utils/aws-profile.d.ts +0 -17
  314. package/dist/types/utils/block-symbols.d.ts +0 -62
  315. package/dist/types/utils/deterministic-id.d.ts +0 -16
  316. package/dist/types/utils/empty-completion-retry.d.ts +0 -21
  317. package/dist/types/utils/event-stream.d.ts +0 -39
  318. package/dist/types/utils/foundry.d.ts +0 -1
  319. package/dist/types/utils/google-validation.d.ts +0 -2
  320. package/dist/types/utils/harmony-leak.d.ts +0 -135
  321. package/dist/types/utils/http-inspector.d.ts +0 -49
  322. package/dist/types/utils/idle-iterator.d.ts +0 -149
  323. package/dist/types/utils/leaked-thinking-stream.d.ts +0 -33
  324. package/dist/types/utils/openai-http.d.ts +0 -48
  325. package/dist/types/utils/openrouter-headers.d.ts +0 -1
  326. package/dist/types/utils/parse-bind.d.ts +0 -23
  327. package/dist/types/utils/provider-response.d.ts +0 -3
  328. package/dist/types/utils/proxy.d.ts +0 -39
  329. package/dist/types/utils/request-debug.d.ts +0 -29
  330. package/dist/types/utils/retry-after.d.ts +0 -4
  331. package/dist/types/utils/retry.d.ts +0 -14
  332. package/dist/types/utils/schema/adapt.d.ts +0 -24
  333. package/dist/types/utils/schema/compatibility.d.ts +0 -30
  334. package/dist/types/utils/schema/dereference.d.ts +0 -11
  335. package/dist/types/utils/schema/draft.d.ts +0 -10
  336. package/dist/types/utils/schema/equality.d.ts +0 -4
  337. package/dist/types/utils/schema/fields.d.ts +0 -54
  338. package/dist/types/utils/schema/index.d.ts +0 -14
  339. package/dist/types/utils/schema/json-schema-validator.d.ts +0 -20
  340. package/dist/types/utils/schema/meta-validator.d.ts +0 -2
  341. package/dist/types/utils/schema/normalize.d.ts +0 -153
  342. package/dist/types/utils/schema/spill.d.ts +0 -8
  343. package/dist/types/utils/schema/stamps.d.ts +0 -17
  344. package/dist/types/utils/schema/strict-tool-validation.d.ts +0 -16
  345. package/dist/types/utils/schema/types.d.ts +0 -4
  346. package/dist/types/utils/schema/typescript.d.ts +0 -24
  347. package/dist/types/utils/schema/wire.d.ts +0 -52
  348. package/dist/types/utils/sdk-stream-timeout.d.ts +0 -33
  349. package/dist/types/utils/sse-debug.d.ts +0 -5
  350. package/dist/types/utils/stream-markup-healing.d.ts +0 -87
  351. package/dist/types/utils/thinking-loop.d.ts +0 -102
  352. package/dist/types/utils/tool-call-loop-guard.d.ts +0 -26
  353. package/dist/types/utils/tool-choice.d.ts +0 -52
  354. package/dist/types/utils/validation.d.ts +0 -28
  355. package/dist/types/utils.d.ts +0 -57
@@ -36,8 +36,6 @@ import type {
36
36
  CredentialRankingContext,
37
37
  CredentialRankingStrategy,
38
38
  ObservedUsageEntry,
39
- UsageCostHistoryEntry,
40
- UsageCostHistoryQuery,
41
39
  UsageCredential,
42
40
  UsageFetchContext,
43
41
  UsageFetchParams,
@@ -66,7 +64,7 @@ import {
66
64
  listCodexResetCredits,
67
65
  pickSoonestExpiringCredit,
68
66
  } from "./usage/openai-codex-reset";
69
- import { opencodeGoUsageProvider } from "./usage/opencode-go";
67
+ import { opencodeGoRankingStrategy, opencodeGoUsageProvider } from "./usage/opencode-go";
70
68
  import { syntheticUsageProvider } from "./usage/synthetic";
71
69
  import { umansUsageProvider } from "./usage/umans";
72
70
  import { xaiOauthUsageProvider } from "./usage/xai-oauth";
@@ -454,10 +452,6 @@ export interface AuthCredentialStore {
454
452
  * skipped — the broker host records into its own database instead.
455
453
  */
456
454
  recordUsageSnapshots?(entries: UsageHistoryEntry[]): void;
457
- /** Append observed request costs for providers without upstream usage APIs. */
458
- recordUsageCosts?(entries: UsageCostHistoryEntry[]): void;
459
- /** Read observed request costs, oldest first. */
460
- listUsageCosts?(query?: UsageCostHistoryQuery): UsageCostHistoryEntry[];
461
455
  /** Read recorded usage-limit snapshots, oldest first. */
462
456
  listUsageHistory?(query?: UsageHistoryQuery): UsageHistoryEntry[];
463
457
  /**
@@ -625,7 +619,7 @@ export type AuthStorageOptions = {
625
619
  * so the TUI can show where a token came from (broker URL or local SQLite path).
626
620
  *
627
621
  * Examples:
628
- * - `"local ~/.omp/agent/agent.db"`
622
+ * - `"local ~/.zeta/agent/agent.db"`
629
623
  * - `"broker http://omp.internal:8765"`
630
624
  */
631
625
  sourceLabel?: string;
@@ -698,6 +692,10 @@ const DEFAULT_USAGE_REQUEST_TIMEOUT_MS = 10_000;
698
692
  const USAGE_REPORT_CACHE_KEY_VERSION_OVERRIDES: Partial<Record<Provider, number>> = {
699
693
  "google-antigravity": 2,
700
694
  zai: 2,
695
+ // v2: retires cached reports from the OMP-observed spend estimator (dollar
696
+ // units) now that limits come from the upstream percent-based `/usage`
697
+ // endpoint; the 24h last-good retention would otherwise keep serving them.
698
+ "opencode-go": 2,
701
699
  // v2: cache identity gained an `org:` component so two subscriptions on one
702
700
  // account email stop sharing a slot. v3 retires parsed reports created before
703
701
  // Anthropic extra-usage rows existed; header ingestion can otherwise keep
@@ -1072,6 +1070,7 @@ const DEFAULT_RANKING_STRATEGIES = new Map<Provider, CredentialRankingStrategy>(
1072
1070
  ["anthropic", claudeRankingStrategy],
1073
1071
  ["google-antigravity", antigravityRankingStrategy],
1074
1072
  ["zai", zaiRankingStrategy],
1073
+ ["opencode-go", opencodeGoRankingStrategy],
1075
1074
  ]);
1076
1075
 
1077
1076
  function resolveDefaultRankingStrategy(provider: Provider): CredentialRankingStrategy | undefined {
@@ -1211,6 +1210,14 @@ type OAuthCandidate = UsageCandidate<OAuthCredential>;
1211
1210
  type ApiKeyCandidate = UsageCandidate<ApiKeyCredential>;
1212
1211
  type UsageRankingResult<T extends AuthCredential> = UsageCandidate<T> & { blockedUntil: number | undefined };
1213
1212
 
1213
+ type CredentialBlockRouting = {
1214
+ providerKey: string;
1215
+ strategy: CredentialRankingStrategy | undefined;
1216
+ rankingContext: CredentialRankingContext;
1217
+ blockScope: string | undefined;
1218
+ siblingBlockScopes: readonly string[];
1219
+ };
1220
+
1214
1221
  type UsageRankedCandidate<T extends AuthCredential> = UsageCandidate<T> & {
1215
1222
  blocked: boolean;
1216
1223
  blockedUntil?: number;
@@ -3167,7 +3174,6 @@ export class AuthStorage {
3167
3174
  const report = await providerImpl.fetchUsage(params, {
3168
3175
  fetch: this.#usageFetch,
3169
3176
  logger: this.#usageLogger,
3170
- listUsageCosts: query => this.#store.listUsageCosts?.(query) ?? [],
3171
3177
  });
3172
3178
  // Attribute the report to the credential's organization. The orgId and
3173
3179
  // orgName fallbacks apply independently: Claude's usage endpoint stamps
@@ -3189,6 +3195,13 @@ export class AuthStorage {
3189
3195
  }
3190
3196
  return report;
3191
3197
  } catch (error) {
3198
+ if (error instanceof AIError.ProviderHttpError && (error.status === 401 || error.status === 403)) {
3199
+ // Definitive auth failure (revoked key, lapsed subscription): purge
3200
+ // the last-good report so #fetchUsageCached's failure branch can't
3201
+ // keep rendering and ranking from stale quota the way it does for
3202
+ // transient failures. Mirrors the definitive-OAuth-refresh path.
3203
+ this.#usageCache.set(this.#buildUsageReportCacheKey(request), { value: null, expiresAt: 0 });
3204
+ }
3192
3205
  logger.debug("AuthStorage usage fetch failed", {
3193
3206
  provider: request.provider,
3194
3207
  error: String(error),
@@ -3289,42 +3302,6 @@ export class AuthStorage {
3289
3302
  return this.#store.listUsageHistory?.(query) ?? [];
3290
3303
  }
3291
3304
 
3292
- /** Record one observed provider request cost for later local usage aggregation. */
3293
- recordUsageCost(
3294
- provider: Provider,
3295
- costUsd: number,
3296
- options?: { sessionId?: string; recordedAt?: number; baseUrl?: string },
3297
- ): boolean {
3298
- if (!Number.isFinite(costUsd) || costUsd <= 0) return false;
3299
- const record = this.#store.recordUsageCosts;
3300
- if (!record) return false;
3301
- const credential = this.#resolveObservedUsageCredential(provider, options?.sessionId);
3302
- if (!credential) return false;
3303
- const entry: UsageCostHistoryEntry = {
3304
- recordedAt: options?.recordedAt ?? Date.now(),
3305
- provider,
3306
- accountKey: this.#buildUsageCacheIdentity(credential),
3307
- costUsd,
3308
- };
3309
- try {
3310
- record.call(this.#store, [entry]);
3311
- const cacheKey = this.#buildUsageReportCacheKey({
3312
- provider,
3313
- credential,
3314
- baseUrl: options?.baseUrl,
3315
- });
3316
- const existing = this.#usageCache.getStale<UsageReport | null>(cacheKey);
3317
- this.#usageCache.set(cacheKey, { value: existing?.value ?? null, expiresAt: Date.now() - 1 });
3318
- return true;
3319
- } catch (error) {
3320
- this.#usageLogger?.debug("usage cost record failed", {
3321
- provider,
3322
- error: String(error),
3323
- });
3324
- return false;
3325
- }
3326
- }
3327
-
3328
3305
  /**
3329
3306
  * Forward one completed request's usage to the store's observer hook.
3330
3307
  * Broker-backed stores batch these into per-install reports so the broker
@@ -3375,28 +3352,6 @@ export class AuthStorage {
3375
3352
  return this.#store.getClientUsageSummary?.(sinceMs) ?? { clients: [] };
3376
3353
  }
3377
3354
 
3378
- #resolveObservedUsageCredential(provider: Provider, sessionId?: string): UsageCredential | undefined {
3379
- const entries = this.#getStoredCredentials(provider);
3380
- const sessionCredential = this.#getSessionCredential(provider, sessionId);
3381
- if (sessionCredential) {
3382
- const credential = entries[sessionCredential.index]?.credential;
3383
- if (credential) {
3384
- return credential.type === "api_key"
3385
- ? { type: "api_key", apiKey: credential.key }
3386
- : this.#buildUsageCredential(credential);
3387
- }
3388
- }
3389
- if (entries.length === 1) {
3390
- const credential = entries[0]!.credential;
3391
- return credential.type === "api_key"
3392
- ? { type: "api_key", apiKey: credential.key }
3393
- : this.#buildUsageCredential(credential);
3394
- }
3395
- const envKey = getEnvApiKey(provider);
3396
- if (envKey) return { type: "api_key", apiKey: envKey };
3397
- return undefined;
3398
- }
3399
-
3400
3355
  ingestUsageHeaders(
3401
3356
  provider: Provider,
3402
3357
  headers: Record<string, string>,
@@ -3480,9 +3435,9 @@ export class AuthStorage {
3480
3435
  return true;
3481
3436
  }
3482
3437
 
3483
- #collectUsageRequests(options?: {
3438
+ async #collectUsageRequests(options?: {
3484
3439
  baseUrlResolver?: (provider: Provider) => string | undefined;
3485
- }): UsageRequestDescriptor[] {
3440
+ }): Promise<UsageRequestDescriptor[]> {
3486
3441
  const resolver = this.#usageProviderResolver;
3487
3442
  if (!resolver) return [];
3488
3443
 
@@ -3542,10 +3497,19 @@ export class AuthStorage {
3542
3497
 
3543
3498
  for (const entry of entries) {
3544
3499
  const credential = entry.credential;
3545
- const request =
3546
- credential.type === "api_key"
3547
- ? this.#buildUsageRequest(provider, { type: "api_key", apiKey: credential.key }, baseUrl)
3548
- : this.#buildUsageRequestForOauth(provider, credential, baseUrl);
3500
+ let request: UsageRequestDescriptor;
3501
+ if (credential.type === "api_key") {
3502
+ // Stored keys may be references (env var name, "!command") —
3503
+ // resolve to the actual secret before it reaches a provider
3504
+ // fetcher's Authorization header. Unresolvable references are
3505
+ // skipped: probing with the literal reference string would
3506
+ // 401 and flag a working credential as bad.
3507
+ const apiKey = await this.#configValueResolver(credential.key);
3508
+ if (!apiKey) continue;
3509
+ request = this.#buildUsageRequest(provider, { type: "api_key", apiKey }, baseUrl);
3510
+ } else {
3511
+ request = this.#buildUsageRequestForOauth(provider, credential, baseUrl);
3512
+ }
3549
3513
  if (providerImpl.supports && !providerImpl.supports(request)) continue;
3550
3514
  requests.push(request);
3551
3515
  }
@@ -3997,7 +3961,7 @@ export class AuthStorage {
3997
3961
  }
3998
3962
  if (!this.#usageProviderResolver) return null;
3999
3963
 
4000
- const requests = this.#collectUsageRequests(options);
3964
+ const requests = await this.#collectUsageRequests(options);
4001
3965
  if (requests.length === 0) return [];
4002
3966
 
4003
3967
  this.#usageLogger?.debug("Usage fetch requested", {
@@ -4093,7 +4057,6 @@ export class AuthStorage {
4093
4057
  const ctx: UsageFetchContext = {
4094
4058
  fetch: this.#usageFetch,
4095
4059
  logger: this.#usageLogger,
4096
- listUsageCosts: query => this.#store.listUsageCosts?.(query) ?? [],
4097
4060
  };
4098
4061
 
4099
4062
  const results: CredentialHealthResult[] = [];
@@ -4115,10 +4078,21 @@ export class AuthStorage {
4115
4078
 
4116
4079
  const baseUrl = options?.baseUrlResolver?.(row.provider as Provider);
4117
4080
  const cred = row.credential;
4118
- const initialRequest: UsageRequestDescriptor =
4119
- cred.type === "api_key"
4120
- ? this.#buildUsageRequest(row.provider as Provider, { type: "api_key", apiKey: cred.key }, baseUrl)
4121
- : this.#buildUsageRequestForOauth(row.provider as Provider, cred, baseUrl);
4081
+ let initialRequest: UsageRequestDescriptor;
4082
+ if (cred.type === "api_key") {
4083
+ // Stored keys may be references (env var name, "!command") — probe
4084
+ // with the resolved secret, not the reference string, so both the
4085
+ // usage probe and the completion probe exercise the real bytes.
4086
+ const apiKey = await this.#configValueResolver(cred.key);
4087
+ if (!apiKey) {
4088
+ base.reason = "api key reference could not be resolved";
4089
+ results.push(base);
4090
+ continue;
4091
+ }
4092
+ initialRequest = this.#buildUsageRequest(row.provider as Provider, { type: "api_key", apiKey }, baseUrl);
4093
+ } else {
4094
+ initialRequest = this.#buildUsageRequestForOauth(row.provider as Provider, cred, baseUrl);
4095
+ }
4122
4096
 
4123
4097
  const timeoutSignal = AbortSignal.timeout(timeoutMs);
4124
4098
  const probeSignal = options?.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
@@ -4271,6 +4245,58 @@ export class AuthStorage {
4271
4245
  return sessionCredential ? { ...sessionCredential, explicit: false } : undefined;
4272
4246
  }
4273
4247
 
4248
+ #credentialBlockRouting(
4249
+ provider: string,
4250
+ credentialType: AuthCredential["type"],
4251
+ modelId: string | undefined,
4252
+ ): CredentialBlockRouting {
4253
+ const providerKey = this.#getProviderTypeKey(provider, credentialType);
4254
+ const strategy = this.#rankingStrategyResolver?.(provider);
4255
+ const rankingContext: CredentialRankingContext = { modelId };
4256
+ const blockScope = strategy?.blockScope?.(rankingContext);
4257
+ return {
4258
+ providerKey,
4259
+ strategy,
4260
+ rankingContext,
4261
+ blockScope,
4262
+ siblingBlockScopes: strategy?.blockScopes?.(rankingContext) ?? (blockScope ? [blockScope] : []),
4263
+ };
4264
+ }
4265
+
4266
+ #blockCredentialForRotation(
4267
+ provider: string,
4268
+ credentialType: AuthCredential["type"],
4269
+ targetIndex: number,
4270
+ blockedUntil: number,
4271
+ routing: CredentialBlockRouting,
4272
+ ): UsageLimitMarkResult {
4273
+ if (targetIndex >= 0) {
4274
+ this.#markCredentialBlocked(provider, routing.providerKey, targetIndex, blockedUntil, routing.blockScope);
4275
+ }
4276
+
4277
+ const remainingCredentials = this.#getCredentialsForProvider(provider)
4278
+ .map((credential, index) => ({ credential, index }))
4279
+ .filter(
4280
+ (entry): entry is { credential: AuthCredential; index: number } =>
4281
+ entry.credential.type === credentialType && entry.index !== targetIndex,
4282
+ );
4283
+
4284
+ let retryAtMs: number | undefined;
4285
+ for (const candidate of remainingCredentials) {
4286
+ // Sibling availability must use the same scope set selection reads, or
4287
+ // this reports a sibling as free that selection will then refuse.
4288
+ const candidateBlockedUntil = this.#getCredentialBlockedUntil(
4289
+ provider,
4290
+ routing.providerKey,
4291
+ candidate.index,
4292
+ routing.siblingBlockScopes,
4293
+ );
4294
+ if (candidateBlockedUntil === undefined) return { switched: true };
4295
+ if (retryAtMs === undefined || candidateBlockedUntil < retryAtMs) retryAtMs = candidateBlockedUntil;
4296
+ }
4297
+ return { switched: false, retryAtMs };
4298
+ }
4299
+
4274
4300
  /**
4275
4301
  * Marks the current session's credential as temporarily blocked due to usage limits.
4276
4302
  * Uses usage reports to determine accurate reset time when available.
@@ -4313,21 +4339,17 @@ export class AuthStorage {
4313
4339
  const credentialType = sessionCredential.type;
4314
4340
  const targetCredentialId = target.id;
4315
4341
 
4316
- const providerKey = this.#getProviderTypeKey(provider, credentialType);
4317
- const strategy = this.#rankingStrategyResolver?.(provider);
4318
- const rankingContext: CredentialRankingContext = { modelId: options?.modelId };
4319
- const blockScope = strategy?.blockScope?.(rankingContext);
4320
- const siblingBlockScopes = strategy?.blockScopes?.(rankingContext) ?? (blockScope ? [blockScope] : []);
4342
+ const routing = this.#credentialBlockRouting(provider, credentialType, options?.modelId);
4321
4343
  const now = Date.now();
4322
4344
  let blockedUntil = now + (options?.retryAfterMs ?? AuthStorage.#defaultBackoffMs);
4323
4345
 
4324
- if (credentialType === "oauth" && target.credential.type === "oauth" && strategy) {
4346
+ if (credentialType === "oauth" && target.credential.type === "oauth" && routing.strategy) {
4325
4347
  const report = await raceUsageWithSignal(
4326
4348
  this.#getUsageReport(provider, target.credential, options),
4327
4349
  options?.signal,
4328
4350
  );
4329
4351
  if (report) {
4330
- const scopedLimits = this.#getScopedUsageLimits(strategy, report, rankingContext);
4352
+ const scopedLimits = this.#getScopedUsageLimits(routing.strategy, report, routing.rankingContext);
4331
4353
  if (this.#isUsageLimitReached(scopedLimits)) {
4332
4354
  const resetAtMs = this.#getUsageResetAtMs(scopedLimits, Date.now());
4333
4355
  if (resetAtMs && resetAtMs > blockedUntil) {
@@ -4343,32 +4365,7 @@ export class AuthStorage {
4343
4365
  const targetIndex = this.#getStoredCredentials(provider).findIndex(
4344
4366
  entry => entry.id === targetCredentialId && entry.credential.type === credentialType,
4345
4367
  );
4346
- if (targetIndex >= 0) {
4347
- this.#markCredentialBlocked(provider, providerKey, targetIndex, blockedUntil, blockScope);
4348
- }
4349
-
4350
- const remainingCredentials = this.#getCredentialsForProvider(provider)
4351
- .map((credential, index) => ({ credential, index }))
4352
- .filter(
4353
- (entry): entry is { credential: AuthCredential; index: number } =>
4354
- entry.credential.type === credentialType && entry.index !== targetIndex,
4355
- );
4356
-
4357
- let retryAtMs: number | undefined;
4358
- for (const candidate of remainingCredentials) {
4359
- // Sibling availability must use the same scope set selection reads, or
4360
- // this reports a sibling as free that selection will then refuse, most
4361
- // visibly when the sibling still carries a legacy shared block.
4362
- const candidateBlockedUntil = this.#getCredentialBlockedUntil(
4363
- provider,
4364
- providerKey,
4365
- candidate.index,
4366
- siblingBlockScopes,
4367
- );
4368
- if (candidateBlockedUntil === undefined) return { switched: true };
4369
- if (retryAtMs === undefined || candidateBlockedUntil < retryAtMs) retryAtMs = candidateBlockedUntil;
4370
- }
4371
- return { switched: false, retryAtMs };
4368
+ return this.#blockCredentialForRotation(provider, credentialType, targetIndex, blockedUntil, routing);
4372
4369
  }
4373
4370
 
4374
4371
  #resolveWindowResetAt(window: UsageLimit["window"]): number | undefined {
@@ -6078,6 +6075,8 @@ export class AuthStorage {
6078
6075
  * - usage-limit / account-rate-limit error → {@link AuthStorage.markUsageLimitReached}
6079
6076
  * (temporary block via its own backoff — default plus server usage-report
6080
6077
  * reset; sticky left intact so the next resolve re-ranks around the block).
6078
+ * - account-scoped policy denial → temporarily block that account without
6079
+ * marking its credential suspect, then rotate through eligible siblings.
6081
6080
  * - otherwise (hard 401 / auth failure) → mark the credential suspect (or
6082
6081
  * reload when no broker hook is wired) and block it, then drop matching
6083
6082
  * sticky state.
@@ -6114,6 +6113,17 @@ export class AuthStorage {
6114
6113
  });
6115
6114
  if (!sessionCredential) return false;
6116
6115
 
6116
+ if (AIError.isAccountPolicyError(error)) {
6117
+ const routing = this.#credentialBlockRouting(provider, sessionCredential.type, options?.modelId);
6118
+ return this.#blockCredentialForRotation(
6119
+ provider,
6120
+ sessionCredential.type,
6121
+ sessionCredential.index,
6122
+ Date.now() + AuthStorage.#defaultBackoffMs,
6123
+ routing,
6124
+ ).switched;
6125
+ }
6126
+
6117
6127
  const providerKey = this.#getProviderTypeKey(provider, sessionCredential.type);
6118
6128
  // Snapshot sibling availability before mutating so a soft-deleting
6119
6129
  // suspect hook can't reindex the answer out from under us.
@@ -7,6 +7,7 @@ import type {
7
7
  } from "../types";
8
8
  import {
9
9
  clearStreamingPartialJson,
10
+ copyCursorExecResolved,
10
11
  getStreamingPartialJson,
11
12
  type StreamingPartialJsonCarrier,
12
13
  setStreamingPartialJson,
@@ -54,6 +55,7 @@ function cloneToolCall(source: StreamingToolCall): StreamingToolCall {
54
55
  };
55
56
  const partialJson = getStreamingPartialJson(source);
56
57
  if (partialJson !== undefined) setStreamingPartialJson(block, partialJson);
58
+ copyCursorExecResolved(block, source);
57
59
  return block;
58
60
  }
59
61
 
@@ -65,6 +67,7 @@ function syncToolCall(target: StreamingToolCall, source: StreamingToolCall): voi
65
67
  const partialJson = getStreamingPartialJson(source);
66
68
  if (partialJson === undefined) clearStreamingPartialJson(target);
67
69
  else setStreamingPartialJson(target, partialJson);
70
+ copyCursorExecResolved(target, source);
68
71
  }
69
72
 
70
73
  function hasNamedNativeToolCall(source: StreamingToolCall | undefined): source is StreamingToolCall {
@@ -1,5 +1,5 @@
1
1
  import { extractHttpStatusFromError } from "@linxiraos/pi-utils";
2
- import { isOAuthExpiry, isUsageLimit } from "./flags";
2
+ import { isAccountPolicyError, isOAuthExpiry, isUsageLimit } from "./flags";
3
3
  import { isConcurrencyCapExclusion, isUsageLimitOutcome } from "./rate-limit";
4
4
 
5
5
  /**
@@ -27,15 +27,16 @@ export function isInvalidatedOAuthTokenError(error: unknown): boolean {
27
27
  /**
28
28
  * Whether an upstream failure should rotate to a sibling credential: a hard
29
29
  * `401`, a `403` (token valid but access denied — plan, model policy, or org
30
- * restriction a sibling account may not share), a body-classified usage limit
31
- * (Codex `usage_limit_reached`, Anthropic account rate-limit, Google
30
+ * restriction a sibling account may not share), an account-scoped policy
31
+ * denial such as Codex `cyber_policy`, a body-classified usage limit (Codex
32
+ * `usage_limit_reached`, Anthropic account rate-limit, Google
32
33
  * `resource_exhausted`, OpenAI `insufficient_quota`, …), or a bare `429`
33
- * whose payload did not preserve a richer quota code.
34
- * Transient 429s (`Too many requests`, per-minute caps) stay in the
35
- * upstream-backoff lane.
34
+ * whose payload did not preserve a richer quota code. Transient 429s
35
+ * (`Too many requests`, per-minute caps) stay in the upstream-backoff lane.
36
36
  */
37
37
  export function isAuthRetryableError(error: unknown): boolean {
38
38
  if (isUsageLimit(error)) return true;
39
+ if (isAccountPolicyError(error)) return true;
39
40
  if (isInvalidatedOAuthTokenError(error)) return true;
40
41
  const httpStatus = extractHttpStatusFromError(error);
41
42
  const message = error instanceof Error ? error.message : typeof error === "string" ? error : undefined;
package/src/error/aws.ts CHANGED
@@ -13,7 +13,11 @@ export type AwsCredentialsErrorKind =
13
13
  /** STS web-identity exchange failed or returned malformed credentials. */
14
14
  | "web-identity"
15
15
  /** ECS/container credential endpoint failed or returned malformed credentials. */
16
- | "container";
16
+ | "container"
17
+ /** Shared-config role chain is misconfigured (cycle, missing source_profile, unsupported credential_source). */
18
+ | "profile"
19
+ /** STS `AssumeRole` call failed or returned malformed credentials. */
20
+ | "assume-role";
17
21
 
18
22
  /** A failure resolving AWS credentials for the Bedrock provider. */
19
23
  export class AwsCredentialsError extends Error {
@@ -24,7 +24,10 @@ export const Flag = {
24
24
  StaleResponsesItem: 0x0010_0000,
25
25
  MalformedFunctionCall: 0x0020_0000,
26
26
  ProviderFinishError: 0x0040_0000,
27
+ EmptyResponse: 0x0000_2000,
27
28
  ContentBlocked: 0x0000_8000,
29
+ /** Account-scoped provider policy denial that may succeed with another credential. */
30
+ AccountPolicy: 0x0000_4000,
28
31
  ContextOverflow: 0x0080_0000,
29
32
  AuthFailed: 0x0100_0000,
30
33
  SilentAbort: 0x0200_0000,
@@ -48,7 +51,9 @@ const KIND_MASK =
48
51
  Flag.StaleResponsesItem |
49
52
  Flag.MalformedFunctionCall |
50
53
  Flag.ProviderFinishError |
54
+ Flag.EmptyResponse |
51
55
  Flag.ContentBlocked |
56
+ Flag.AccountPolicy |
52
57
  Flag.ContextOverflow |
53
58
  Flag.AuthFailed |
54
59
  Flag.SilentAbort |
@@ -59,7 +64,12 @@ const KIND_MASK =
59
64
  Flag.OAuthExpiry;
60
65
 
61
66
  const RETRIABLE_KINDS =
62
- Flag.Transient | Flag.UsageLimit | Flag.ThinkingLoop | Flag.StaleResponsesItem | Flag.ProviderFinishError;
67
+ Flag.Transient |
68
+ Flag.UsageLimit |
69
+ Flag.ThinkingLoop |
70
+ Flag.StaleResponsesItem |
71
+ Flag.ProviderFinishError |
72
+ Flag.EmptyResponse;
63
73
 
64
74
  const OVERFLOW_PATTERNS = [
65
75
  /prompt is too long/i, // Anthropic
@@ -101,7 +111,9 @@ const AUTH_FAILURE_PATTERN =
101
111
  /\b(?:401|403|unauthorized|forbidden|authentication|auth[_ ]?unavailable|no auth available|(?:invalid|no)[_ ]?api[_ ]?key)\b/i;
102
112
  const MALFORMED_FUNCTION_CALL_PATTERN = /\bmalformed.?function.?call\b/i;
103
113
  const PROVIDER_FINISH_ERROR_PATTERN = /\bProvider (?:returned error finish_reason|finish_reason:\s*error)\b/i;
114
+ const EMPTY_RESPONSE_PATTERN = /\bthought-only response without final output\b/i;
104
115
  const CONTENT_FILTER_PATTERN = /\b(?:incomplete:\s*)?content_filter\b/i;
116
+ const ACCOUNT_POLICY_PATTERN = /\bcyber_policy\b|trusted access for cyber/i;
105
117
  const STALE_RESPONSE_ITEM_PATTERNS = [/\bItem with id ['"][^'"]+['"] not found\.?/i, /previous[ _]?response/i] as const;
106
118
  const STALE_RESPONSE_ITEM_DETAIL_PATTERN = /not[ _]?found|invalid|expired|stale|zero[ _-]?data[ _-]?retention/i;
107
119
  /**
@@ -193,7 +205,9 @@ const ERROR_KIND_LABELS: readonly [Flag, string][] = [
193
205
  [Flag.StaleResponsesItem, "stale-responses-item"],
194
206
  [Flag.MalformedFunctionCall, "malformed-function-call"],
195
207
  [Flag.ProviderFinishError, "provider-finish-error"],
208
+ [Flag.EmptyResponse, "empty-response"],
196
209
  [Flag.ContentBlocked, "content-blocked"],
210
+ [Flag.AccountPolicy, "account-policy"],
197
211
  [Flag.ContextOverflow, "context-overflow"],
198
212
  [Flag.AuthFailed, "auth-failed"],
199
213
  [Flag.SilentAbort, "silent-abort"],
@@ -335,7 +349,9 @@ function classifyText(errorMessage: string | undefined, errorStatus: number | un
335
349
  if (matchesOverflowText(errorMessage)) kinds |= Flag.ContextOverflow;
336
350
  if (isMalformedFunctionCallText(errorMessage)) kinds |= Flag.MalformedFunctionCall;
337
351
  if (isProviderFinishErrorText(errorMessage)) kinds |= Flag.ProviderFinishError;
352
+ if (EMPTY_RESPONSE_PATTERN.test(errorMessage)) kinds |= Flag.EmptyResponse | Flag.Transient;
338
353
  if (isContentBlockedText(errorMessage)) kinds |= Flag.ContentBlocked;
354
+ if (ACCOUNT_POLICY_PATTERN.test(errorMessage)) kinds |= Flag.AccountPolicy | Flag.ContentBlocked;
339
355
  if (isAuthFailureText(errorMessage)) kinds |= Flag.AuthFailed;
340
356
 
341
357
  const statusClean = errorStatus ? errorStatus : (status({ message: errorMessage }) ?? undefined);
@@ -398,6 +414,9 @@ export function classify(error: unknown, api?: Api): number {
398
414
  if ("errorId" in link && typeof (link as { errorId: unknown }).errorId === "number") {
399
415
  kinds |= (link as { errorId: number }).errorId & KIND_MASK;
400
416
  }
417
+ if ("code" in link && typeof link.code === "string" && ACCOUNT_POLICY_PATTERN.test(link.code)) {
418
+ kinds |= Flag.AccountPolicy | Flag.ContentBlocked;
419
+ }
401
420
  }
402
421
 
403
422
  if (link instanceof AwsCredentialsError) {
@@ -475,6 +494,11 @@ export function isUsageLimit(error: unknown, api?: Api): boolean {
475
494
  return is(classify(error, api), Flag.UsageLimit);
476
495
  }
477
496
 
497
+ /** Whether an upstream rejection is an account-scoped policy denial worth retrying with a sibling credential. */
498
+ export function isAccountPolicyError(error: unknown, api?: Api): boolean {
499
+ return is(classify(error, api), Flag.AccountPolicy);
500
+ }
501
+
478
502
  /**
479
503
  * Strict-tool rejection: grammar too large, schema too complex, or structured
480
504
  * outputs unsupported by the model/endpoint.
@@ -9,6 +9,8 @@ export type ProviderResponseErrorKind =
9
9
  | "output"
10
10
  /** Response body was empty/missing when content was required. */
11
11
  | "empty-body"
12
+ /** Response completed without actionable output (for example, thoughts only). */
13
+ | "empty-output"
12
14
  /** Malformed wire envelope (unexpected message ordering / shape). */
13
15
  | "envelope"
14
16
  /** Content was blocked by a provider safety filter. */
@@ -38,11 +40,10 @@ export class ProviderResponseError extends Error {
38
40
  this.kind = options.kind ?? "output";
39
41
  // A safety filter block is terminal and intentionally non-retryable.
40
42
  if (this.kind === "content-blocked") attach(this, create(Flag.ContentBlocked));
41
- // An incomplete stream (connection dropped / truncated before any terminal
42
- // event) or an empty body never produced any content — the request didn't
43
- // complete, so it is safe to retry and eligible for model fallback. The
44
- // retry layer's replay-unsafe guard still blocks a retry when partial tool
45
- // output was already emitted.
43
+ // A logically empty completed output needs a session-level reminder that
44
+ // asks for the missing final answer. Empty bodies and incomplete streams
45
+ // stay on the generic transient retry/model-fallback path.
46
+ else if (this.kind === "empty-output") attach(this, create(Flag.Transient, Flag.EmptyResponse));
46
47
  else if (this.kind === "incomplete-stream" || this.kind === "empty-body") attach(this, create(Flag.Transient));
47
48
  }
48
49
  }