@ouro.bot/cli 0.1.0-alpha.33 → 0.1.0-alpha.330

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 (315) hide show
  1. package/README.md +188 -187
  2. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +1 -1
  4. package/changelog.json +1976 -0
  5. package/dist/arc/attention-types.js +8 -0
  6. package/dist/arc/cares.js +140 -0
  7. package/dist/arc/episodes.js +117 -0
  8. package/dist/arc/intentions.js +133 -0
  9. package/dist/arc/json-store.js +117 -0
  10. package/dist/arc/obligations.js +237 -0
  11. package/dist/arc/packets.js +193 -0
  12. package/dist/arc/presence.js +185 -0
  13. package/dist/arc/task-lifecycle.js +65 -0
  14. package/dist/heart/active-work.js +832 -0
  15. package/dist/heart/agent-entry.js +37 -2
  16. package/dist/heart/attachments/image-normalize.js +194 -0
  17. package/dist/heart/attachments/materialize.js +97 -0
  18. package/dist/heart/attachments/originals.js +88 -0
  19. package/dist/heart/attachments/render.js +29 -0
  20. package/dist/heart/attachments/sources/adapter.js +2 -0
  21. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  22. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  23. package/dist/heart/attachments/sources/index.js +16 -0
  24. package/dist/heart/attachments/store.js +103 -0
  25. package/dist/heart/attachments/types.js +93 -0
  26. package/dist/heart/auth/auth-flow.js +463 -0
  27. package/dist/heart/bridges/manager.js +358 -0
  28. package/dist/heart/bridges/state-machine.js +135 -0
  29. package/dist/heart/bridges/store.js +123 -0
  30. package/dist/heart/bundle-state.js +168 -0
  31. package/dist/heart/commitments.js +111 -0
  32. package/dist/heart/config-registry.js +304 -0
  33. package/dist/heart/config.js +53 -21
  34. package/dist/heart/core.js +695 -195
  35. package/dist/heart/cross-chat-delivery.js +131 -0
  36. package/dist/heart/daemon/agent-config-check.js +149 -0
  37. package/dist/heart/daemon/agent-discovery.js +79 -3
  38. package/dist/heart/daemon/agent-service.js +360 -0
  39. package/dist/heart/daemon/agentic-repair.js +170 -0
  40. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  41. package/dist/heart/daemon/cadence.js +70 -0
  42. package/dist/heart/daemon/cli-defaults.js +591 -0
  43. package/dist/heart/daemon/cli-exec.js +2277 -0
  44. package/dist/heart/daemon/cli-help.js +306 -0
  45. package/dist/heart/daemon/cli-parse.js +824 -0
  46. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  47. package/dist/heart/daemon/cli-render.js +512 -0
  48. package/dist/heart/daemon/cli-types.js +8 -0
  49. package/dist/heart/daemon/daemon-cli.js +29 -1171
  50. package/dist/heart/daemon/daemon-entry.js +358 -3
  51. package/dist/heart/daemon/daemon-health.js +141 -0
  52. package/dist/heart/daemon/daemon-runtime-sync.js +157 -12
  53. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  54. package/dist/heart/daemon/daemon.js +751 -58
  55. package/dist/heart/daemon/doctor-types.js +8 -0
  56. package/dist/heart/daemon/doctor.js +401 -0
  57. package/dist/heart/daemon/health-monitor.js +79 -1
  58. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  59. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  60. package/dist/heart/daemon/http-health-probe.js +80 -0
  61. package/dist/heart/daemon/inner-status.js +89 -0
  62. package/dist/heart/daemon/interactive-repair.js +69 -0
  63. package/dist/heart/daemon/launchd.js +46 -9
  64. package/dist/heart/daemon/log-tailer.js +82 -12
  65. package/dist/heart/daemon/logs-prune.js +105 -0
  66. package/dist/heart/daemon/message-router.js +17 -8
  67. package/dist/heart/daemon/os-cron-deps.js +134 -0
  68. package/dist/heart/daemon/ouro-bot-entry.js +1 -1
  69. package/dist/heart/daemon/process-manager.js +201 -0
  70. package/dist/heart/daemon/provider-discovery.js +105 -0
  71. package/dist/heart/daemon/pulse.js +463 -0
  72. package/dist/heart/daemon/run-hooks.js +2 -0
  73. package/dist/heart/daemon/runtime-logging.js +67 -16
  74. package/dist/heart/daemon/runtime-metadata.js +101 -0
  75. package/dist/heart/daemon/runtime-mode.js +67 -0
  76. package/dist/heart/daemon/safe-mode.js +161 -0
  77. package/dist/heart/daemon/sense-manager.js +72 -3
  78. package/dist/heart/daemon/session-id-resolver.js +131 -0
  79. package/dist/heart/daemon/skill-management-installer.js +94 -0
  80. package/dist/heart/daemon/socket-client.js +307 -0
  81. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  82. package/dist/heart/daemon/startup-tui.js +237 -0
  83. package/dist/heart/daemon/task-scheduler.js +3 -25
  84. package/dist/heart/daemon/thoughts.js +510 -0
  85. package/dist/heart/daemon/up-progress.js +135 -0
  86. package/dist/heart/delegation.js +62 -0
  87. package/dist/heart/habits/habit-migration.js +181 -0
  88. package/dist/heart/habits/habit-parser.js +140 -0
  89. package/dist/heart/habits/habit-scheduler.js +371 -0
  90. package/dist/heart/{daemon → hatch}/hatch-flow.js +32 -120
  91. package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
  92. package/dist/heart/{daemon → hatch}/specialist-prompt.js +10 -7
  93. package/dist/heart/{daemon → hatch}/specialist-tools.js +49 -3
  94. package/dist/heart/identity.js +154 -59
  95. package/dist/heart/kicks.js +2 -20
  96. package/dist/heart/mcp/mcp-server.js +653 -0
  97. package/dist/heart/migrate-config.js +127 -0
  98. package/dist/heart/model-capabilities.js +59 -0
  99. package/dist/heart/outlook/outlook-http-hooks.js +64 -0
  100. package/dist/heart/outlook/outlook-http-response.js +7 -0
  101. package/dist/heart/outlook/outlook-http-routes.js +232 -0
  102. package/dist/heart/outlook/outlook-http-static.js +99 -0
  103. package/dist/heart/outlook/outlook-http-transport.js +116 -0
  104. package/dist/heart/outlook/outlook-http.js +99 -0
  105. package/dist/heart/outlook/outlook-read.js +28 -0
  106. package/dist/heart/outlook/outlook-render.js +1032 -0
  107. package/dist/heart/outlook/outlook-types.js +27 -0
  108. package/dist/heart/outlook/outlook-view.js +194 -0
  109. package/dist/heart/outlook/readers/agent-machine.js +355 -0
  110. package/dist/heart/outlook/readers/continuity-readers.js +332 -0
  111. package/dist/heart/outlook/readers/runtime-readers.js +660 -0
  112. package/dist/heart/outlook/readers/sessions.js +231 -0
  113. package/dist/heart/outlook/readers/shared.js +111 -0
  114. package/dist/heart/progress-story.js +42 -0
  115. package/dist/heart/provider-failover.js +135 -0
  116. package/dist/heart/provider-models.js +81 -0
  117. package/dist/heart/provider-ping.js +162 -0
  118. package/dist/heart/providers/anthropic-token.js +163 -0
  119. package/dist/heart/providers/anthropic.js +169 -46
  120. package/dist/heart/providers/azure.js +98 -11
  121. package/dist/heart/providers/error-classification.js +63 -0
  122. package/dist/heart/providers/github-copilot.js +136 -0
  123. package/dist/heart/providers/minimax-vlm.js +189 -0
  124. package/dist/heart/providers/minimax.js +23 -5
  125. package/dist/heart/providers/openai-codex.js +33 -22
  126. package/dist/heart/session-activity.js +190 -0
  127. package/dist/heart/session-events.js +726 -0
  128. package/dist/heart/session-recall.js +162 -0
  129. package/dist/heart/start-of-turn-packet.js +341 -0
  130. package/dist/heart/streaming.js +36 -27
  131. package/dist/heart/sync.js +332 -0
  132. package/dist/heart/target-resolution.js +127 -0
  133. package/dist/heart/tempo.js +93 -0
  134. package/dist/heart/temporal-view.js +41 -0
  135. package/dist/heart/tool-activity-callbacks.js +36 -0
  136. package/dist/heart/tool-description.js +135 -0
  137. package/dist/heart/tool-friction.js +55 -0
  138. package/dist/heart/tool-loop.js +200 -0
  139. package/dist/heart/turn-context.js +358 -0
  140. package/dist/heart/turn-coordinator.js +28 -0
  141. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
  142. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  143. package/dist/heart/{daemon → versioning}/ouro-path-installer.js +78 -35
  144. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  145. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  146. package/dist/heart/{daemon → versioning}/update-checker.js +12 -2
  147. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  148. package/dist/mind/associative-recall.js +137 -66
  149. package/dist/mind/bundle-manifest.js +7 -1
  150. package/dist/mind/context.js +89 -93
  151. package/dist/mind/diary-integrity.js +60 -0
  152. package/dist/mind/{memory.js → diary.js} +84 -96
  153. package/dist/mind/embedding-provider.js +60 -0
  154. package/dist/mind/file-state.js +179 -0
  155. package/dist/mind/first-impressions.js +14 -1
  156. package/dist/mind/friends/channel.js +56 -0
  157. package/dist/mind/friends/group-context.js +144 -0
  158. package/dist/mind/friends/resolver.js +37 -0
  159. package/dist/mind/friends/store-file.js +58 -3
  160. package/dist/mind/friends/trust-explanation.js +74 -0
  161. package/dist/mind/friends/types.js +8 -0
  162. package/dist/mind/journal-index.js +161 -0
  163. package/dist/mind/obligation-steering.js +221 -0
  164. package/dist/mind/pending.js +74 -7
  165. package/dist/mind/prompt.js +949 -111
  166. package/dist/mind/provenance-trust.js +26 -0
  167. package/dist/mind/scrutiny.js +173 -0
  168. package/dist/mind/token-estimate.js +8 -12
  169. package/dist/nerves/cli-logging.js +7 -1
  170. package/dist/nerves/coverage/audit.js +1 -1
  171. package/dist/nerves/coverage/file-completeness.js +83 -5
  172. package/dist/nerves/coverage/run-artifacts.js +1 -1
  173. package/dist/nerves/event-buffer.js +111 -0
  174. package/dist/nerves/index.js +224 -4
  175. package/dist/nerves/observation.js +20 -0
  176. package/dist/nerves/redact.js +79 -0
  177. package/dist/nerves/runtime.js +5 -1
  178. package/dist/outlook-ui/assets/index-IuR4F6y6.js +61 -0
  179. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  180. package/dist/outlook-ui/index.html +15 -0
  181. package/dist/repertoire/ado-client.js +15 -56
  182. package/dist/repertoire/ado-semantic.js +11 -10
  183. package/dist/repertoire/api-client.js +97 -0
  184. package/dist/repertoire/bitwarden-store.js +319 -0
  185. package/dist/repertoire/bundle-templates.js +72 -0
  186. package/dist/repertoire/bw-installer.js +79 -0
  187. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  188. package/dist/repertoire/coding/context-pack.js +330 -0
  189. package/dist/repertoire/coding/feedback.js +197 -30
  190. package/dist/repertoire/coding/manager.js +158 -9
  191. package/dist/repertoire/coding/spawner.js +55 -9
  192. package/dist/repertoire/coding/tools.js +170 -7
  193. package/dist/repertoire/commerce-errors.js +109 -0
  194. package/dist/repertoire/commerce-self-test.js +156 -0
  195. package/dist/repertoire/credential-access.js +527 -0
  196. package/dist/repertoire/duffel-client.js +185 -0
  197. package/dist/repertoire/github-client.js +14 -55
  198. package/dist/repertoire/graph-client.js +11 -52
  199. package/dist/repertoire/guardrails.js +375 -0
  200. package/dist/repertoire/mcp-client.js +255 -0
  201. package/dist/repertoire/mcp-manager.js +305 -0
  202. package/dist/repertoire/mcp-tools.js +63 -0
  203. package/dist/repertoire/shell-sessions.js +133 -0
  204. package/dist/repertoire/skills.js +14 -23
  205. package/dist/repertoire/stripe-client.js +131 -0
  206. package/dist/repertoire/tasks/board.js +43 -5
  207. package/dist/repertoire/tasks/fix.js +182 -0
  208. package/dist/repertoire/tasks/index.js +28 -10
  209. package/dist/repertoire/tasks/lifecycle.js +2 -2
  210. package/dist/repertoire/tasks/parser.js +3 -2
  211. package/dist/repertoire/tasks/scanner.js +194 -37
  212. package/dist/repertoire/tasks/transitions.js +16 -79
  213. package/dist/repertoire/tool-results.js +29 -0
  214. package/dist/repertoire/tools-attachments.js +316 -0
  215. package/dist/repertoire/tools-base.js +45 -771
  216. package/dist/repertoire/tools-bluebubbles.js +1 -0
  217. package/dist/repertoire/tools-bridge.js +141 -0
  218. package/dist/repertoire/tools-bundle.js +984 -0
  219. package/dist/repertoire/tools-config.js +185 -0
  220. package/dist/repertoire/tools-continuity.js +248 -0
  221. package/dist/repertoire/tools-credential.js +182 -0
  222. package/dist/repertoire/tools-files.js +342 -0
  223. package/dist/repertoire/tools-flight.js +224 -0
  224. package/dist/repertoire/tools-flow.js +105 -0
  225. package/dist/repertoire/tools-github.js +1 -7
  226. package/dist/repertoire/tools-memory.js +376 -0
  227. package/dist/repertoire/tools-session.js +739 -0
  228. package/dist/repertoire/tools-shell.js +120 -0
  229. package/dist/repertoire/tools-stripe.js +180 -0
  230. package/dist/repertoire/tools-surface.js +243 -0
  231. package/dist/repertoire/tools-teams.js +12 -62
  232. package/dist/repertoire/tools-travel.js +125 -0
  233. package/dist/repertoire/tools-user-profile.js +144 -0
  234. package/dist/repertoire/tools-vault.js +110 -0
  235. package/dist/repertoire/tools.js +144 -138
  236. package/dist/repertoire/travel-api-client.js +360 -0
  237. package/dist/repertoire/user-profile.js +118 -0
  238. package/dist/repertoire/vault-setup.js +241 -0
  239. package/dist/scripts/claude-code-hook.js +41 -0
  240. package/dist/scripts/claude-code-stop-hook.js +47 -0
  241. package/dist/senses/attention-queue.js +116 -0
  242. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  243. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  244. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +225 -9
  245. package/dist/senses/bluebubbles/entry.js +13 -0
  246. package/dist/senses/bluebubbles/inbound-log.js +113 -0
  247. package/dist/senses/bluebubbles/index.js +1590 -0
  248. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  249. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +43 -12
  250. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
  251. package/dist/senses/bluebubbles/replay.js +129 -0
  252. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  253. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  254. package/dist/senses/cli/bracketed-paste.js +82 -0
  255. package/dist/senses/cli/image-paste.js +287 -0
  256. package/dist/senses/cli/image-ref-navigation.js +75 -0
  257. package/dist/senses/cli/ink-app.js +156 -0
  258. package/dist/senses/cli/inline-diff.js +64 -0
  259. package/dist/senses/cli/input-keys.js +174 -0
  260. package/dist/senses/cli/kill-ring.js +86 -0
  261. package/dist/senses/cli/message-list.js +51 -0
  262. package/dist/senses/cli/ouro-tui.js +605 -0
  263. package/dist/senses/cli/spinner-imperative.js +135 -0
  264. package/dist/senses/cli/spinner.js +101 -0
  265. package/dist/senses/cli/status-line.js +60 -0
  266. package/dist/senses/cli/streaming-markdown.js +526 -0
  267. package/dist/senses/cli/tool-display.js +83 -0
  268. package/dist/senses/cli/tool-render.js +85 -0
  269. package/dist/senses/cli/tui-store.js +240 -0
  270. package/dist/senses/cli/virtual-list.js +35 -0
  271. package/dist/senses/cli-entry.js +1 -1
  272. package/dist/senses/cli-layout.js +187 -0
  273. package/dist/senses/cli.js +595 -246
  274. package/dist/senses/commands.js +65 -1
  275. package/dist/senses/continuity.js +94 -0
  276. package/dist/senses/habit-turn-message.js +108 -0
  277. package/dist/senses/inner-dialog-worker.js +112 -19
  278. package/dist/senses/inner-dialog.js +633 -86
  279. package/dist/senses/pipeline.js +567 -0
  280. package/dist/senses/shared-turn.js +199 -0
  281. package/dist/senses/surface-tool.js +68 -0
  282. package/dist/senses/teams.js +665 -160
  283. package/dist/senses/trust-gate.js +112 -2
  284. package/package.json +28 -7
  285. package/skills/agent-commerce.md +106 -0
  286. package/skills/browser-navigation.md +110 -0
  287. package/skills/commerce-setup-guide.md +116 -0
  288. package/skills/commerce-setup.md +84 -0
  289. package/skills/configure-dev-tools.md +81 -0
  290. package/skills/travel-planning.md +138 -0
  291. package/dist/heart/daemon/subagent-installer.js +0 -134
  292. package/dist/senses/bluebubbles-entry.js +0 -11
  293. package/dist/senses/bluebubbles.js +0 -544
  294. package/dist/senses/debug-activity.js +0 -108
  295. package/subagents/README.md +0 -73
  296. package/subagents/work-doer.md +0 -235
  297. package/subagents/work-merger.md +0 -618
  298. package/subagents/work-planner.md +0 -382
  299. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  300. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  301. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  302. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  303. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  304. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  305. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  306. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  307. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  308. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  309. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  310. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  311. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  312. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  313. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  314. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  315. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeErrorMessage = sanitizeErrorMessage;
4
+ exports.pingProvider = pingProvider;
5
+ exports.runHealthInventory = runHealthInventory;
6
+ const identity_1 = require("./identity");
7
+ const anthropic_1 = require("./providers/anthropic");
8
+ const azure_1 = require("./providers/azure");
9
+ const minimax_1 = require("./providers/minimax");
10
+ const openai_codex_1 = require("./providers/openai-codex");
11
+ const github_copilot_1 = require("./providers/github-copilot");
12
+ const auth_flow_1 = require("./auth/auth-flow");
13
+ const runtime_1 = require("../nerves/runtime");
14
+ const PING_TIMEOUT_MS = 10_000;
15
+ /**
16
+ * Strip raw JSON/HTML API response bodies from error messages.
17
+ * SDK errors often include the full response: "400 {"type":"error",...}" or "403 <html>...".
18
+ * Extract just the HTTP status and a short human-readable summary.
19
+ */
20
+ function sanitizeErrorMessage(message) {
21
+ const statusMatch = message.match(/^(\d{3})\s/);
22
+ if (!statusMatch)
23
+ return message;
24
+ const status = statusMatch[1];
25
+ const body = message.slice(status.length).trim();
26
+ // HTML response (Cloudflare challenge, error pages, etc.)
27
+ if (body.startsWith("<") || body.includes("<!DOCTYPE") || body.includes("<html")) {
28
+ return `HTTP ${status}`;
29
+ }
30
+ // JSON response
31
+ if (body.startsWith("{")) {
32
+ try {
33
+ const json = JSON.parse(body);
34
+ const inner = json?.error?.message;
35
+ if (typeof inner === "string" && inner && inner !== "Error") {
36
+ return `${status} ${inner}`;
37
+ }
38
+ }
39
+ catch { /* not valid JSON */ }
40
+ return `HTTP ${status}`;
41
+ }
42
+ // Already clean (e.g., "401 Provided authentication token is expired.")
43
+ return message;
44
+ }
45
+ function hasEmptyCredentials(provider, config) {
46
+ const record = config;
47
+ return identity_1.PROVIDER_CREDENTIALS[provider].required.some((key) => !record[key]);
48
+ }
49
+ function createRuntimeForPing(provider, _config) {
50
+ // The provider constructors read credentials from the active config via getXxxConfig().
51
+ // For ping, this is acceptable because verifyProviderCredentials patches the runtime
52
+ // config before calling ping. The model string is a default — for anthropic the ping
53
+ // overrides it with haiku anyway, and for others it's used in a minimal API call.
54
+ const DEFAULT_MODELS = {
55
+ anthropic: "claude-haiku-4-5-20251001",
56
+ azure: "gpt-4o",
57
+ minimax: "MiniMax-M2.7",
58
+ "openai-codex": "codex-mini-latest",
59
+ "github-copilot": "gpt-4o",
60
+ };
61
+ /* v8 ignore next -- fallback: all known providers are in DEFAULT_MODELS @preserve */
62
+ const model = DEFAULT_MODELS[provider] ?? "unknown";
63
+ switch (provider) {
64
+ case "anthropic":
65
+ return (0, anthropic_1.createAnthropicProviderRuntime)(model);
66
+ case "azure":
67
+ return (0, azure_1.createAzureProviderRuntime)(model);
68
+ case "minimax":
69
+ return (0, minimax_1.createMinimaxProviderRuntime)(model);
70
+ case "openai-codex":
71
+ return (0, openai_codex_1.createOpenAICodexProviderRuntime)(model);
72
+ case "github-copilot":
73
+ return (0, github_copilot_1.createGithubCopilotProviderRuntime)(model);
74
+ /* v8 ignore next 2 -- exhaustive: all providers handled above @preserve */
75
+ default:
76
+ throw new Error(`unsupported provider for ping: ${provider}`);
77
+ }
78
+ }
79
+ async function pingProvider(provider, config) {
80
+ if (hasEmptyCredentials(provider, config)) {
81
+ return { ok: false, classification: "auth-failure", message: "no credentials configured" };
82
+ }
83
+ let runtime;
84
+ try {
85
+ runtime = createRuntimeForPing(provider, config);
86
+ /* v8 ignore start -- factory creation failure: tested via individual provider init tests @preserve */
87
+ }
88
+ catch (error) {
89
+ return {
90
+ ok: false,
91
+ classification: "auth-failure",
92
+ message: error instanceof Error ? error.message : String(error),
93
+ };
94
+ }
95
+ /* v8 ignore stop */
96
+ try {
97
+ const controller = new AbortController();
98
+ /* v8 ignore next -- timeout callback: only fires after 10s, tests resolve faster @preserve */
99
+ const timeout = setTimeout(() => controller.abort(), PING_TIMEOUT_MS);
100
+ try {
101
+ // Minimal API call — no thinking, no reasoning, no tools.
102
+ if (provider === "anthropic") {
103
+ // Use haiku for the ping — setup tokens may not have access to newer
104
+ // models, but if haiku works, the credentials are valid.
105
+ // Override the beta header to exclude thinking (which requires a
106
+ // thinking param in the request body).
107
+ const client = runtime.client;
108
+ await client.messages.create({ model: "claude-haiku-4-5-20251001", max_tokens: 1, messages: [{ role: "user", content: "ping" }] }, { signal: controller.signal, headers: { "anthropic-beta": "claude-code-20250219,oauth-2025-04-20" } });
109
+ }
110
+ else if (provider === "openai-codex") {
111
+ // Codex uses the Responses API (chatgpt.com/backend-api/codex/responses),
112
+ // not the Chat Completions API. Ping via responses endpoint.
113
+ const client = runtime.client;
114
+ await client.responses.create({ model: runtime.model, input: "ping", store: false }, { signal: controller.signal });
115
+ }
116
+ else {
117
+ // OpenAI-compatible providers (azure, minimax, github-copilot)
118
+ const client = runtime.client;
119
+ await client.chat.completions.create({ model: runtime.model, max_tokens: 1, messages: [{ role: "user", content: "ping" }] }, { signal: controller.signal });
120
+ }
121
+ return { ok: true };
122
+ }
123
+ finally {
124
+ clearTimeout(timeout);
125
+ }
126
+ }
127
+ catch (error) {
128
+ const err = error instanceof Error ? error : /* v8 ignore next -- defensive @preserve */ new Error(String(error));
129
+ let classification;
130
+ try {
131
+ classification = runtime.classifyError(err);
132
+ }
133
+ catch {
134
+ /* v8 ignore next -- defensive: classifyError should not throw @preserve */
135
+ classification = "unknown";
136
+ }
137
+ (0, runtime_1.emitNervesEvent)({
138
+ component: "engine",
139
+ event: "engine.provider_ping_fail",
140
+ message: `provider ping failed: ${provider}`,
141
+ meta: { provider, classification, error: err.message },
142
+ });
143
+ return { ok: false, classification, message: sanitizeErrorMessage(err.message) };
144
+ }
145
+ }
146
+ const PINGABLE_PROVIDERS = ["anthropic", "openai-codex", "azure", "minimax", "github-copilot"];
147
+ async function runHealthInventory(agentName, currentProvider, deps = {}) {
148
+ /* v8 ignore next -- default: tests inject ping dep @preserve */
149
+ const ping = deps.ping ?? pingProvider;
150
+ const { secrets } = (0, auth_flow_1.loadAgentSecrets)(agentName);
151
+ const providers = PINGABLE_PROVIDERS.filter((p) => p !== currentProvider);
152
+ const results = await Promise.all(providers.map(async (provider) => {
153
+ const config = secrets.providers[provider];
154
+ const result = await ping(provider, config);
155
+ return [provider, result];
156
+ }));
157
+ const inventory = {};
158
+ for (const [provider, result] of results) {
159
+ inventory[provider] = result;
160
+ }
161
+ return inventory;
162
+ }
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.needsRefresh = needsRefresh;
37
+ exports.refreshAnthropicToken = refreshAnthropicToken;
38
+ exports.persistTokenState = persistTokenState;
39
+ exports.ensureFreshToken = ensureFreshToken;
40
+ /* v8 ignore start -- OAuth token lifecycle: requires live API calls, tested via integration @preserve */
41
+ const fs = __importStar(require("fs"));
42
+ const runtime_1 = require("../../nerves/runtime");
43
+ const identity_1 = require("../identity");
44
+ const OAUTH_TOKEN_ENDPOINT = "https://console.anthropic.com/v1/oauth/token";
45
+ const OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
46
+ const REFRESH_MARGIN_MS = 5 * 60 * 1000; // refresh 5 minutes before expiry
47
+ /**
48
+ * Check if the Anthropic OAuth token needs refreshing.
49
+ * Returns true if no expiresAt is set (legacy token) or if within 5 min of expiry.
50
+ */
51
+ function needsRefresh(expiresAt) {
52
+ if (!expiresAt)
53
+ return true; // legacy token with no expiry — always try refresh
54
+ return Date.now() > expiresAt - REFRESH_MARGIN_MS;
55
+ }
56
+ /**
57
+ * Refresh an Anthropic OAuth access token using the refresh token.
58
+ * Returns the new token state or null if refresh fails.
59
+ */
60
+ async function refreshAnthropicToken(refreshToken, fetchImpl = fetch) {
61
+ try {
62
+ const response = await fetchImpl(OAUTH_TOKEN_ENDPOINT, {
63
+ method: "POST",
64
+ headers: { "Content-Type": "application/json" },
65
+ body: JSON.stringify({
66
+ grant_type: "refresh_token",
67
+ refresh_token: refreshToken,
68
+ client_id: OAUTH_CLIENT_ID,
69
+ }),
70
+ });
71
+ if (!response.ok) {
72
+ (0, runtime_1.emitNervesEvent)({
73
+ level: "warn",
74
+ component: "engine",
75
+ event: "engine.anthropic_token_refresh_failed",
76
+ message: `token refresh failed: ${response.status}`,
77
+ meta: { status: response.status },
78
+ });
79
+ return null;
80
+ }
81
+ const json = await response.json();
82
+ if (!json.access_token) {
83
+ (0, runtime_1.emitNervesEvent)({
84
+ level: "warn",
85
+ component: "engine",
86
+ event: "engine.anthropic_token_refresh_failed",
87
+ message: "token refresh returned no access_token",
88
+ meta: {},
89
+ });
90
+ return null;
91
+ }
92
+ const state = {
93
+ accessToken: json.access_token,
94
+ refreshToken: json.refresh_token ?? refreshToken, // keep old if not returned
95
+ expiresAt: Date.now() + (json.expires_in ?? 28800) * 1000, // default 8h
96
+ };
97
+ (0, runtime_1.emitNervesEvent)({
98
+ component: "engine",
99
+ event: "engine.anthropic_token_refreshed",
100
+ message: "anthropic OAuth token refreshed",
101
+ meta: { expiresAt: new Date(state.expiresAt).toISOString() },
102
+ });
103
+ return state;
104
+ }
105
+ catch (error) {
106
+ (0, runtime_1.emitNervesEvent)({
107
+ level: "warn",
108
+ component: "engine",
109
+ event: "engine.anthropic_token_refresh_error",
110
+ message: "token refresh threw",
111
+ meta: { error: error instanceof Error ? error.message : String(error) },
112
+ });
113
+ return null;
114
+ }
115
+ }
116
+ /**
117
+ * Persist refreshed token state back to secrets.json.
118
+ */
119
+ function persistTokenState(agentName, state) {
120
+ try {
121
+ const secretsPath = (0, identity_1.getAgentSecretsPath)(agentName);
122
+ const raw = fs.readFileSync(secretsPath, "utf-8");
123
+ const secrets = JSON.parse(raw);
124
+ secrets.providers = secrets.providers ?? {};
125
+ secrets.providers.anthropic = secrets.providers.anthropic ?? {};
126
+ secrets.providers.anthropic.setupToken = state.accessToken;
127
+ secrets.providers.anthropic.refreshToken = state.refreshToken;
128
+ secrets.providers.anthropic.expiresAt = state.expiresAt;
129
+ fs.writeFileSync(secretsPath, JSON.stringify(secrets, null, 2) + "\n", "utf-8");
130
+ /* v8 ignore start -- defensive: persistence failure must not crash the provider @preserve */
131
+ }
132
+ catch (error) {
133
+ (0, runtime_1.emitNervesEvent)({
134
+ level: "warn",
135
+ component: "engine",
136
+ event: "engine.anthropic_token_persist_error",
137
+ message: "failed to persist refreshed token",
138
+ meta: { error: error instanceof Error ? error.message : String(error) },
139
+ });
140
+ }
141
+ /* v8 ignore stop */
142
+ }
143
+ /**
144
+ * Ensure the Anthropic token is fresh. If expired, refresh and persist.
145
+ * Returns the current valid access token, or null if refresh failed and
146
+ * the existing token is expired.
147
+ */
148
+ async function ensureFreshToken(currentToken, refreshToken, expiresAt, agentName, fetchImpl) {
149
+ if (!needsRefresh(expiresAt)) {
150
+ return currentToken; // still fresh
151
+ }
152
+ if (!refreshToken) {
153
+ // No refresh token — use the current token as-is (may be expired)
154
+ return currentToken;
155
+ }
156
+ const newState = await refreshAnthropicToken(refreshToken, fetchImpl);
157
+ if (!newState) {
158
+ return currentToken; // refresh failed — try the old token
159
+ }
160
+ persistTokenState(agentName, newState);
161
+ return newState.accessToken;
162
+ }
163
+ /* v8 ignore stop */
@@ -1,14 +1,51 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.toAnthropicMessages = toAnthropicMessages;
40
+ exports.classifyAnthropicError = classifyAnthropicError;
6
41
  exports.createAnthropicProviderRuntime = createAnthropicProviderRuntime;
7
42
  const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
8
43
  const config_1 = require("../config");
9
44
  const identity_1 = require("../identity");
10
45
  const runtime_1 = require("../../nerves/runtime");
11
46
  const streaming_1 = require("../streaming");
47
+ const model_capabilities_1 = require("../model-capabilities");
48
+ const error_classification_1 = require("./error-classification");
12
49
  const ANTHROPIC_SETUP_TOKEN_PREFIX = "sk-ant-oat01-";
13
50
  const ANTHROPIC_SETUP_TOKEN_MIN_LENGTH = 80;
14
51
  const ANTHROPIC_OAUTH_BETA_HEADER = "claude-code-20250219,oauth-2025-04-20,fine-grained-tool-streaming-2025-05-14,interleaved-thinking-2025-05-14";
@@ -22,10 +59,10 @@ function getAnthropicSetupTokenInstructions() {
22
59
  const agentName = getAnthropicAgentNameForGuidance();
23
60
  return [
24
61
  "Fix:",
25
- ` 1. Run \`npm run auth:claude-setup-token -- --agent ${agentName}\``,
26
- " (or run `claude setup-token` and paste the token manually)",
62
+ ` 1. Run \`ouro auth --agent ${agentName}\``,
27
63
  ` 2. Open ${getAnthropicSecretsPathForGuidance()}`,
28
64
  " 3. Confirm providers.anthropic.setupToken is set",
65
+ " 4. After reauth, retry the failed ouro command or reconnect this session.",
29
66
  ].join("\n");
30
67
  }
31
68
  function getAnthropicReauthGuidance(reason) {
@@ -93,6 +130,18 @@ function toAnthropicMessages(messages) {
93
130
  if (msg.role === "assistant") {
94
131
  const assistant = msg;
95
132
  const blocks = [];
133
+ // Restore thinking blocks before text/tool_use blocks
134
+ const thinkingBlocks = assistant._thinking_blocks;
135
+ if (thinkingBlocks) {
136
+ for (const tb of thinkingBlocks) {
137
+ if (tb.type === "thinking") {
138
+ blocks.push({ type: "thinking", thinking: tb.thinking, signature: tb.signature });
139
+ }
140
+ else {
141
+ blocks.push({ type: "redacted_thinking", data: tb.data });
142
+ }
143
+ }
144
+ }
96
145
  const text = toAnthropicTextContent(assistant.content);
97
146
  if (text) {
98
147
  blocks.push({ type: "text", text });
@@ -173,53 +222,64 @@ function mergeAnthropicToolArguments(current, partial) {
173
222
  }
174
223
  return current + partial;
175
224
  }
225
+ function classifyAnthropicError(error) {
226
+ return (0, error_classification_1.classifyHttpError)(error, {
227
+ isAuthFailure: isAnthropicAuthFailure,
228
+ isServerError: (e) => e.status === 529,
229
+ });
230
+ }
176
231
  function isAnthropicAuthFailure(error) {
177
- if (!(error instanceof Error))
178
- return false;
179
- const status = error.status;
180
- if (status === 401 || status === 403)
181
- return true;
182
232
  const lower = error.message.toLowerCase();
183
233
  return (lower.includes("oauth authentication") ||
184
234
  lower.includes("authentication failed") ||
185
235
  lower.includes("unauthorized") ||
186
236
  lower.includes("invalid api key"));
187
237
  }
188
- function withAnthropicAuthGuidance(error) {
189
- const base = error instanceof Error ? error.message : String(error);
190
- if (isAnthropicAuthFailure(error)) {
191
- return new Error(getAnthropicReauthGuidance(`Anthropic authentication failed (${base}).`));
192
- }
193
- return error instanceof Error ? error : new Error(String(error));
194
- }
195
238
  async function streamAnthropicMessages(client, model, request) {
196
239
  const { system, messages } = toAnthropicMessages(request.messages);
197
240
  const anthropicTools = toAnthropicTools(request.activeTools);
241
+ const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
242
+ const maxTokens = modelCaps.maxOutputTokens ?? 16384;
198
243
  const params = {
199
244
  model,
200
- max_tokens: 4096,
245
+ max_tokens: maxTokens,
201
246
  messages,
202
247
  stream: true,
248
+ thinking: { type: "adaptive" },
249
+ output_config: { effort: request.reasoningEffort ?? "medium" },
203
250
  };
204
- if (system)
205
- params.system = system;
251
+ // The Anthropic API requires a Claude Code identification block in the system
252
+ // prompt when using OAuth setup tokens (sk-ant-oat01). Without it, Opus/Sonnet
253
+ // 4.6 requests are rejected with 400. This is the API's validation that the
254
+ // token is being used by a Claude Code client.
255
+ const claudeCodePreamble = { type: "text", text: "You are Claude Code, Anthropic's official CLI for Claude." };
256
+ if (system) {
257
+ params.system = [claudeCodePreamble, { type: "text", text: system }];
258
+ }
259
+ else {
260
+ params.system = [claudeCodePreamble];
261
+ }
206
262
  if (anthropicTools.length > 0)
207
263
  params.tools = anthropicTools;
208
264
  if (request.toolChoiceRequired && anthropicTools.length > 0) {
209
- params.tool_choice = { type: "any" };
265
+ // Thinking (adaptive or enabled) only supports tool_choice "auto" or "none".
266
+ // "any" forces tool use which is incompatible with extended thinking.
267
+ params.tool_choice = params.thinking ? { type: "auto" } : /* v8 ignore next -- no-thinking path: thinking always set for 4.6 models @preserve */ { type: "any" };
210
268
  }
211
269
  let response;
212
270
  try {
213
271
  response = await client.messages.create(params, request.signal ? { signal: request.signal } : {});
214
272
  }
215
273
  catch (error) {
216
- throw withAnthropicAuthGuidance(error);
274
+ throw error instanceof Error ? error : new Error(String(error));
217
275
  }
218
276
  let content = "";
219
277
  let streamStarted = false;
220
278
  let usage;
221
279
  const toolCalls = new Map();
222
- const answerStreamer = new streaming_1.FinalAnswerStreamer(request.callbacks);
280
+ const thinkingBlocks = new Map();
281
+ const redactedBlocks = new Map();
282
+ const answerStreamer = new streaming_1.SettleStreamer(request.callbacks, request.eagerSettleStreaming);
223
283
  try {
224
284
  for await (const event of response) {
225
285
  if (request.signal?.aborted)
@@ -227,8 +287,14 @@ async function streamAnthropicMessages(client, model, request) {
227
287
  const eventType = String(event.type ?? "");
228
288
  if (eventType === "content_block_start") {
229
289
  const block = event.content_block;
230
- if (block?.type === "tool_use") {
231
- const index = Number(event.index);
290
+ const index = Number(event.index);
291
+ if (block?.type === "thinking") {
292
+ thinkingBlocks.set(index, { type: "thinking", thinking: "", signature: "" });
293
+ }
294
+ else if (block?.type === "redacted_thinking") {
295
+ redactedBlocks.set(index, { type: "redacted_thinking", data: String(block.data ?? "") });
296
+ }
297
+ else if (block?.type === "tool_use") {
232
298
  const rawInput = block.input;
233
299
  const input = rawInput && typeof rawInput === "object"
234
300
  ? JSON.stringify(rawInput)
@@ -239,9 +305,9 @@ async function streamAnthropicMessages(client, model, request) {
239
305
  name,
240
306
  arguments: input,
241
307
  });
242
- // Activate eager streaming for sole final_answer tool call
243
- /* v8 ignore next -- final_answer streaming activation, tested via FinalAnswerStreamer unit tests @preserve */
244
- if (name === "final_answer" && toolCalls.size === 1) {
308
+ // Activate eager streaming for sole settle tool call
309
+ /* v8 ignore next -- settle streaming activation, tested via SettleStreamer unit tests @preserve */
310
+ if (name === "settle" && toolCalls.size === 1) {
245
311
  answerStreamer.activate();
246
312
  }
247
313
  }
@@ -265,7 +331,19 @@ async function streamAnthropicMessages(client, model, request) {
265
331
  request.callbacks.onModelStreamStart();
266
332
  streamStarted = true;
267
333
  }
268
- request.callbacks.onReasoningChunk(String(delta?.thinking ?? ""));
334
+ const thinkingText = String(delta?.thinking ?? "");
335
+ request.callbacks.onReasoningChunk(thinkingText);
336
+ const thinkingIndex = Number(event.index);
337
+ const thinkingBlock = thinkingBlocks.get(thinkingIndex);
338
+ if (thinkingBlock)
339
+ thinkingBlock.thinking += thinkingText;
340
+ continue;
341
+ }
342
+ if (deltaType === "signature_delta") {
343
+ const sigIndex = Number(event.index);
344
+ const sigBlock = thinkingBlocks.get(sigIndex);
345
+ if (sigBlock)
346
+ sigBlock.signature += String(delta?.signature ?? "");
269
347
  continue;
270
348
  }
271
349
  if (deltaType === "input_json_delta") {
@@ -274,8 +352,8 @@ async function streamAnthropicMessages(client, model, request) {
274
352
  if (existing) {
275
353
  const partialJson = String(delta?.partial_json ?? "");
276
354
  existing.arguments = mergeAnthropicToolArguments(existing.arguments, partialJson);
277
- /* v8 ignore next -- final_answer delta streaming, tested via FinalAnswerStreamer unit tests @preserve */
278
- if (existing.name === "final_answer" && toolCalls.size === 1) {
355
+ /* v8 ignore next -- settle delta streaming, tested via SettleStreamer unit tests @preserve */
356
+ if (existing.name === "settle" && toolCalls.size === 1) {
279
357
  answerStreamer.processDelta(partialJson);
280
358
  }
281
359
  }
@@ -299,17 +377,25 @@ async function streamAnthropicMessages(client, model, request) {
299
377
  }
300
378
  }
301
379
  catch (error) {
302
- throw withAnthropicAuthGuidance(error);
380
+ throw error instanceof Error ? error : /* v8 ignore next -- defensive: stream errors are always Error @preserve */ new Error(String(error));
303
381
  }
382
+ // Collect all thinking blocks (regular + redacted) sorted by index to preserve ordering
383
+ const allThinkingIndices = [...thinkingBlocks.keys(), ...redactedBlocks.keys()].sort((a, b) => a - b);
384
+ const outputItems = allThinkingIndices.map((idx) => {
385
+ const tb = thinkingBlocks.get(idx);
386
+ if (tb)
387
+ return tb;
388
+ return redactedBlocks.get(idx);
389
+ });
304
390
  return {
305
391
  content,
306
392
  toolCalls: [...toolCalls.values()],
307
- outputItems: [],
393
+ outputItems,
308
394
  usage,
309
- finalAnswerStreamed: answerStreamer.streamed,
395
+ settleStreamed: answerStreamer.streamed,
310
396
  };
311
397
  }
312
- function createAnthropicProviderRuntime() {
398
+ function createAnthropicProviderRuntime(model) {
313
399
  (0, runtime_1.emitNervesEvent)({
314
400
  component: "engine",
315
401
  event: "engine.provider_init",
@@ -317,30 +403,67 @@ function createAnthropicProviderRuntime() {
317
403
  meta: { provider: "anthropic" },
318
404
  });
319
405
  const anthropicConfig = (0, config_1.getAnthropicConfig)();
320
- if (!(anthropicConfig.model && anthropicConfig.setupToken)) {
321
- throw new Error(getAnthropicReauthGuidance("provider 'anthropic' is selected in agent.json but providers.anthropic.model/setupToken is incomplete in secrets.json."));
406
+ if (!anthropicConfig.setupToken) {
407
+ throw new Error(getAnthropicReauthGuidance("provider 'anthropic' is selected in agent.json but providers.anthropic.setupToken is missing in secrets.json."));
322
408
  }
409
+ const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
410
+ const capabilities = new Set();
411
+ if (modelCaps.reasoningEffort)
412
+ capabilities.add("reasoning-effort");
323
413
  const credential = resolveAnthropicSetupTokenCredential();
324
- const client = new sdk_1.default({
325
- authToken: credential.token,
326
- timeout: 30000,
327
- maxRetries: 0,
328
- defaultHeaders: {
329
- "anthropic-beta": ANTHROPIC_OAUTH_BETA_HEADER,
330
- },
331
- });
414
+ const refreshToken = anthropicConfig.refreshToken;
415
+ const expiresAt = anthropicConfig.expiresAt;
416
+ function createClient(token) {
417
+ return new sdk_1.default({
418
+ authToken: token,
419
+ maxRetries: 0,
420
+ defaultHeaders: {
421
+ "anthropic-beta": ANTHROPIC_OAUTH_BETA_HEADER,
422
+ "anthropic-dangerous-direct-browser-access": "true",
423
+ "user-agent": "claude-cli/2.1.2 (external, cli)",
424
+ "x-app": "cli",
425
+ },
426
+ });
427
+ }
428
+ let currentToken = credential.token;
429
+ let client = createClient(currentToken);
430
+ /* v8 ignore start -- token refresh: dynamic import + ensureFreshToken, tested via integration @preserve */
431
+ async function ensureClient() {
432
+ try {
433
+ const { ensureFreshToken } = await Promise.resolve().then(() => __importStar(require("./anthropic-token")));
434
+ const { getAgentName } = await Promise.resolve().then(() => __importStar(require("../identity")));
435
+ const freshToken = await ensureFreshToken(currentToken, refreshToken, expiresAt, getAgentName());
436
+ if (freshToken !== currentToken) {
437
+ currentToken = freshToken;
438
+ client = createClient(freshToken);
439
+ }
440
+ }
441
+ catch {
442
+ // refresh failed — use existing client
443
+ }
444
+ return client;
445
+ }
446
+ /* v8 ignore stop */
332
447
  return {
333
448
  id: "anthropic",
334
- model: anthropicConfig.model,
335
- client,
449
+ model,
450
+ /* v8 ignore next -- getter: returns mutable client ref @preserve */
451
+ get client() { return client; },
452
+ capabilities,
453
+ supportedReasoningEfforts: modelCaps.reasoningEffort,
336
454
  resetTurnState(_messages) {
337
455
  // Anthropic request payload is derived from canonical messages each turn.
338
456
  },
339
457
  appendToolOutput(_callId, _output) {
340
458
  // Anthropic uses canonical messages for tool_result tracking.
341
459
  },
342
- streamTurn(request) {
343
- return streamAnthropicMessages(client, anthropicConfig.model, request);
460
+ async streamTurn(request) {
461
+ const freshClient = await ensureClient();
462
+ return streamAnthropicMessages(freshClient, model, request);
463
+ },
464
+ /* v8 ignore next 3 -- delegation: classification logic tested via classifyAnthropicError @preserve */
465
+ classifyError(error) {
466
+ return classifyAnthropicError(error);
344
467
  },
345
468
  };
346
469
  }