@ouro.bot/cli 0.1.0-alpha.2 → 0.1.0-alpha.200

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 (215) hide show
  1. package/README.md +187 -191
  2. package/SerpentGuide.ouro/agent.json +82 -0
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +6 -3
  4. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +2 -2
  5. package/assets/ouroboros.png +0 -0
  6. package/changelog.json +1248 -0
  7. package/dist/heart/active-work.js +832 -0
  8. package/dist/heart/bridges/manager.js +358 -0
  9. package/dist/heart/bridges/state-machine.js +135 -0
  10. package/dist/heart/bridges/store.js +123 -0
  11. package/dist/heart/cares.js +179 -0
  12. package/dist/heart/commitments.js +111 -0
  13. package/dist/heart/config.js +114 -28
  14. package/dist/heart/core.js +689 -120
  15. package/dist/heart/cross-chat-delivery.js +146 -0
  16. package/dist/heart/daemon/agent-config-check.js +149 -0
  17. package/dist/heart/daemon/agent-discovery.js +81 -0
  18. package/dist/heart/daemon/agent-service.js +360 -0
  19. package/dist/heart/daemon/auth-flow.js +477 -0
  20. package/dist/heart/daemon/cadence.js +70 -0
  21. package/dist/heart/daemon/daemon-cli.js +2897 -193
  22. package/dist/heart/daemon/daemon-entry.js +194 -8
  23. package/dist/heart/daemon/daemon-health.js +136 -0
  24. package/dist/heart/daemon/daemon-runtime-sync.js +231 -0
  25. package/dist/heart/daemon/daemon-tombstone.js +123 -0
  26. package/dist/heart/daemon/daemon.js +488 -13
  27. package/dist/heart/daemon/habit-migration.js +181 -0
  28. package/dist/heart/daemon/habit-parser.js +119 -0
  29. package/dist/heart/daemon/habit-scheduler.js +369 -0
  30. package/dist/heart/daemon/hatch-animation.js +35 -0
  31. package/dist/heart/daemon/hatch-flow.js +32 -122
  32. package/dist/heart/daemon/hatch-specialist.js +7 -2
  33. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  34. package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
  35. package/dist/heart/daemon/inner-status.js +89 -0
  36. package/dist/heart/daemon/launchd.js +165 -0
  37. package/dist/heart/daemon/log-tailer.js +4 -3
  38. package/dist/heart/daemon/mcp-server.js +591 -0
  39. package/dist/heart/daemon/message-router.js +17 -8
  40. package/dist/heart/daemon/os-cron-deps.js +134 -0
  41. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  42. package/dist/heart/daemon/ouro-bot-wrapper.js +4 -3
  43. package/dist/heart/daemon/ouro-path-installer.js +221 -0
  44. package/dist/heart/daemon/ouro-uti.js +11 -2
  45. package/dist/heart/daemon/ouro-version-manager.js +171 -0
  46. package/dist/heart/daemon/outlook-http.js +439 -0
  47. package/dist/heart/daemon/outlook-read.js +1618 -0
  48. package/dist/heart/daemon/outlook-render.js +1032 -0
  49. package/dist/heart/daemon/outlook-types.js +7 -0
  50. package/dist/heart/daemon/outlook-view.js +194 -0
  51. package/dist/heart/daemon/process-manager.js +94 -1
  52. package/dist/heart/daemon/run-hooks.js +39 -0
  53. package/dist/heart/daemon/runtime-logging.js +61 -14
  54. package/dist/heart/daemon/runtime-metadata.js +219 -0
  55. package/dist/heart/daemon/runtime-mode.js +67 -0
  56. package/dist/heart/daemon/safe-mode.js +161 -0
  57. package/dist/heart/daemon/sense-manager.js +314 -0
  58. package/dist/heart/daemon/session-id-resolver.js +131 -0
  59. package/dist/heart/daemon/skill-management-installer.js +94 -0
  60. package/dist/heart/daemon/socket-client.js +202 -0
  61. package/dist/heart/daemon/specialist-orchestrator.js +129 -0
  62. package/dist/heart/daemon/specialist-prompt.js +101 -0
  63. package/dist/heart/daemon/specialist-tools.js +283 -0
  64. package/dist/heart/daemon/staged-restart.js +138 -0
  65. package/dist/heart/daemon/task-scheduler.js +3 -25
  66. package/dist/heart/daemon/thoughts.js +507 -0
  67. package/dist/heart/daemon/update-checker.js +111 -0
  68. package/dist/heart/daemon/update-hooks.js +138 -0
  69. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  70. package/dist/heart/delegation.js +62 -0
  71. package/dist/heart/identity.js +220 -52
  72. package/dist/heart/intentions.js +173 -0
  73. package/dist/heart/kicks.js +2 -20
  74. package/dist/heart/migrate-config.js +127 -0
  75. package/dist/heart/model-capabilities.js +48 -0
  76. package/dist/heart/obligations.js +225 -0
  77. package/dist/heart/presence.js +185 -0
  78. package/dist/heart/progress-story.js +42 -0
  79. package/dist/heart/provider-failover.js +88 -0
  80. package/dist/heart/provider-ping.js +178 -0
  81. package/dist/heart/providers/anthropic-token.js +163 -0
  82. package/dist/heart/providers/anthropic.js +199 -36
  83. package/dist/heart/providers/azure.js +116 -10
  84. package/dist/heart/providers/github-copilot.js +157 -0
  85. package/dist/heart/providers/minimax.js +33 -3
  86. package/dist/heart/providers/openai-codex.js +51 -16
  87. package/dist/heart/sense-truth.js +61 -0
  88. package/dist/heart/session-activity.js +172 -0
  89. package/dist/heart/session-recall.js +216 -0
  90. package/dist/heart/start-of-turn-packet.js +232 -0
  91. package/dist/heart/streaming.js +120 -33
  92. package/dist/heart/sync.js +217 -0
  93. package/dist/heart/target-resolution.js +127 -0
  94. package/dist/heart/tempo.js +93 -0
  95. package/dist/heart/temporal-view.js +41 -0
  96. package/dist/heart/tool-activity-callbacks.js +36 -0
  97. package/dist/heart/tool-description.js +135 -0
  98. package/dist/heart/tool-loop.js +200 -0
  99. package/dist/heart/turn-coordinator.js +28 -0
  100. package/dist/mind/associative-recall.js +122 -32
  101. package/dist/mind/bundle-manifest.js +77 -1
  102. package/dist/mind/context.js +125 -14
  103. package/dist/mind/{memory.js → diary.js} +69 -56
  104. package/dist/mind/episodes.js +119 -0
  105. package/dist/mind/file-state.js +179 -0
  106. package/dist/mind/first-impressions.js +16 -2
  107. package/dist/mind/friends/channel.js +64 -0
  108. package/dist/mind/friends/group-context.js +144 -0
  109. package/dist/mind/friends/store-file.js +36 -0
  110. package/dist/mind/friends/trust-explanation.js +74 -0
  111. package/dist/mind/friends/types.js +9 -1
  112. package/dist/mind/journal-index.js +161 -0
  113. package/dist/mind/obligation-steering.js +221 -0
  114. package/dist/mind/obligations.js +138 -0
  115. package/dist/mind/pending.js +76 -9
  116. package/dist/mind/phrases.js +1 -0
  117. package/dist/mind/prompt.js +861 -105
  118. package/dist/mind/scrutiny.js +173 -0
  119. package/dist/mind/token-estimate.js +8 -12
  120. package/dist/nerves/cli-logging.js +15 -2
  121. package/dist/nerves/coverage/audit.js +1 -1
  122. package/dist/nerves/coverage/run-artifacts.js +1 -1
  123. package/dist/nerves/event-buffer.js +111 -0
  124. package/dist/nerves/index.js +63 -3
  125. package/dist/nerves/observation.js +20 -0
  126. package/dist/nerves/runtime.js +5 -1
  127. package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
  128. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  129. package/dist/outlook-ui/index.html +15 -0
  130. package/dist/repertoire/ado-client.js +4 -2
  131. package/dist/repertoire/ado-semantic.js +11 -5
  132. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  133. package/dist/repertoire/coding/context-pack.js +330 -0
  134. package/dist/repertoire/coding/feedback.js +301 -0
  135. package/dist/repertoire/coding/index.js +4 -1
  136. package/dist/repertoire/coding/manager.js +210 -4
  137. package/dist/repertoire/coding/spawner.js +58 -12
  138. package/dist/repertoire/coding/tools.js +209 -7
  139. package/dist/repertoire/data/ado-endpoints.json +188 -0
  140. package/dist/repertoire/guardrails.js +291 -0
  141. package/dist/repertoire/mcp-client.js +254 -0
  142. package/dist/repertoire/mcp-manager.js +251 -0
  143. package/dist/repertoire/shell-sessions.js +133 -0
  144. package/dist/repertoire/skills.js +14 -23
  145. package/dist/repertoire/tasks/board.js +43 -5
  146. package/dist/repertoire/tasks/fix.js +182 -0
  147. package/dist/repertoire/tasks/index.js +28 -10
  148. package/dist/repertoire/tasks/lifecycle.js +2 -2
  149. package/dist/repertoire/tasks/parser.js +3 -2
  150. package/dist/repertoire/tasks/scanner.js +194 -37
  151. package/dist/repertoire/tasks/transitions.js +11 -28
  152. package/dist/repertoire/tools-base.js +1360 -271
  153. package/dist/repertoire/tools-bluebubbles.js +94 -0
  154. package/dist/repertoire/tools-github.js +1 -6
  155. package/dist/repertoire/tools-teams.js +65 -59
  156. package/dist/repertoire/tools.js +318 -91
  157. package/dist/scripts/claude-code-hook.js +41 -0
  158. package/dist/scripts/claude-code-stop-hook.js +47 -0
  159. package/dist/senses/attention-queue.js +97 -0
  160. package/dist/senses/bluebubbles-client.js +532 -0
  161. package/dist/senses/bluebubbles-entry.js +13 -0
  162. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  163. package/dist/senses/bluebubbles-media.js +339 -0
  164. package/dist/senses/bluebubbles-model.js +261 -0
  165. package/dist/senses/bluebubbles-mutation-log.js +116 -0
  166. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  167. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  168. package/dist/senses/bluebubbles.js +1327 -0
  169. package/dist/senses/cli/adapter.js +274 -0
  170. package/dist/senses/cli/ink-app.js +156 -0
  171. package/dist/senses/cli/inline-diff.js +64 -0
  172. package/dist/senses/cli/message-list.js +51 -0
  173. package/dist/senses/cli/ouro-tui.js +349 -0
  174. package/dist/senses/cli/spinner-imperative.js +135 -0
  175. package/dist/senses/cli/spinner.js +101 -0
  176. package/dist/senses/cli/status-line.js +60 -0
  177. package/dist/senses/cli/streaming-markdown.js +526 -0
  178. package/dist/senses/cli/tool-display.js +83 -0
  179. package/dist/senses/cli/tool-render.js +85 -0
  180. package/dist/senses/cli/tui-store.js +198 -0
  181. package/dist/senses/cli/virtual-list.js +35 -0
  182. package/dist/senses/cli-entry.js +1 -1
  183. package/dist/senses/cli-layout.js +187 -0
  184. package/dist/senses/cli.js +687 -262
  185. package/dist/senses/commands.js +65 -1
  186. package/dist/senses/continuity.js +94 -0
  187. package/dist/senses/habit-turn-message.js +108 -0
  188. package/dist/senses/inner-dialog-worker.js +112 -19
  189. package/dist/senses/inner-dialog.js +592 -84
  190. package/dist/senses/pipeline.js +693 -0
  191. package/dist/senses/shared-turn.js +196 -0
  192. package/dist/senses/surface-tool.js +95 -0
  193. package/dist/senses/teams.js +817 -151
  194. package/dist/senses/trust-gate.js +112 -2
  195. package/package.json +24 -7
  196. package/skills/configure-dev-tools.md +81 -0
  197. package/subagents/README.md +4 -70
  198. package/AdoptionSpecialist.ouro/agent.json +0 -20
  199. package/dist/heart/daemon/subagent-installer.js +0 -125
  200. package/dist/inner-worker-entry.js +0 -4
  201. package/subagents/work-doer.md +0 -233
  202. package/subagents/work-merger.md +0 -624
  203. package/subagents/work-planner.md +0 -373
  204. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  205. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  206. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  207. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  208. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  209. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  210. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  211. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  212. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  213. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  214. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  215. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
@@ -1,13 +1,50 @@
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");
46
+ const streaming_1 = require("../streaming");
47
+ const model_capabilities_1 = require("../model-capabilities");
11
48
  const ANTHROPIC_SETUP_TOKEN_PREFIX = "sk-ant-oat01-";
12
49
  const ANTHROPIC_SETUP_TOKEN_MIN_LENGTH = 80;
13
50
  const ANTHROPIC_OAUTH_BETA_HEADER = "claude-code-20250219,oauth-2025-04-20,fine-grained-tool-streaming-2025-05-14,interleaved-thinking-2025-05-14";
@@ -21,10 +58,10 @@ function getAnthropicSetupTokenInstructions() {
21
58
  const agentName = getAnthropicAgentNameForGuidance();
22
59
  return [
23
60
  "Fix:",
24
- ` 1. Run \`npm run auth:claude-setup-token -- --agent ${agentName}\``,
25
- " (or run `claude setup-token` and paste the token manually)",
61
+ ` 1. Run \`ouro auth --agent ${agentName}\``,
26
62
  ` 2. Open ${getAnthropicSecretsPathForGuidance()}`,
27
63
  " 3. Confirm providers.anthropic.setupToken is set",
64
+ " 4. After reauth, retry the failed ouro command or reconnect this session.",
28
65
  ].join("\n");
29
66
  }
30
67
  function getAnthropicReauthGuidance(reason) {
@@ -92,12 +129,27 @@ function toAnthropicMessages(messages) {
92
129
  if (msg.role === "assistant") {
93
130
  const assistant = msg;
94
131
  const blocks = [];
132
+ // Restore thinking blocks before text/tool_use blocks
133
+ const thinkingBlocks = assistant._thinking_blocks;
134
+ if (thinkingBlocks) {
135
+ for (const tb of thinkingBlocks) {
136
+ if (tb.type === "thinking") {
137
+ blocks.push({ type: "thinking", thinking: tb.thinking, signature: tb.signature });
138
+ }
139
+ else {
140
+ blocks.push({ type: "redacted_thinking", data: tb.data });
141
+ }
142
+ }
143
+ }
95
144
  const text = toAnthropicTextContent(assistant.content);
96
145
  if (text) {
97
146
  blocks.push({ type: "text", text });
98
147
  }
99
148
  if (assistant.tool_calls) {
100
149
  for (const toolCall of assistant.tool_calls) {
150
+ /* v8 ignore next -- type narrowing: OpenAI SDK only emits function tool_calls @preserve */
151
+ if (toolCall.type !== "function")
152
+ continue;
101
153
  blocks.push({
102
154
  type: "tool_use",
103
155
  id: toolCall.id,
@@ -169,6 +221,29 @@ function mergeAnthropicToolArguments(current, partial) {
169
221
  }
170
222
  return current + partial;
171
223
  }
224
+ /* v8 ignore start -- shared network error utility, tested via classification tests @preserve */
225
+ function isNetworkError(error) {
226
+ const code = error.code || "";
227
+ if (["ECONNRESET", "ECONNREFUSED", "ENOTFOUND", "ETIMEDOUT", "EPIPE",
228
+ "EAI_AGAIN", "EHOSTUNREACH", "ENETUNREACH", "ECONNABORTED"].includes(code))
229
+ return true;
230
+ const msg = error.message || "";
231
+ return msg.includes("fetch failed") || msg.includes("socket hang up") || msg.includes("getaddrinfo");
232
+ }
233
+ /* v8 ignore stop */
234
+ function classifyAnthropicError(error) {
235
+ const status = error.status;
236
+ if (status === 401 || status === 403 || isAnthropicAuthFailure(error))
237
+ return "auth-failure";
238
+ if (status === 429)
239
+ return "rate-limit";
240
+ if (status === 529 || (status && status >= 500))
241
+ return "server-error";
242
+ if (isNetworkError(error))
243
+ return "network-error";
244
+ return "unknown";
245
+ }
246
+ /* v8 ignore start -- auth detection: only called from classifyAnthropicError which always passes Error @preserve */
172
247
  function isAnthropicAuthFailure(error) {
173
248
  if (!(error instanceof Error))
174
249
  return false;
@@ -181,40 +256,52 @@ function isAnthropicAuthFailure(error) {
181
256
  lower.includes("unauthorized") ||
182
257
  lower.includes("invalid api key"));
183
258
  }
184
- function withAnthropicAuthGuidance(error) {
185
- const base = error instanceof Error ? error.message : String(error);
186
- if (isAnthropicAuthFailure(error)) {
187
- return new Error(getAnthropicReauthGuidance(`Anthropic authentication failed (${base}).`));
188
- }
189
- return error instanceof Error ? error : new Error(String(error));
190
- }
259
+ /* v8 ignore stop */
191
260
  async function streamAnthropicMessages(client, model, request) {
192
261
  const { system, messages } = toAnthropicMessages(request.messages);
193
262
  const anthropicTools = toAnthropicTools(request.activeTools);
263
+ const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
264
+ const maxTokens = modelCaps.maxOutputTokens ?? 16384;
194
265
  const params = {
195
266
  model,
196
- max_tokens: 4096,
267
+ max_tokens: maxTokens,
197
268
  messages,
198
269
  stream: true,
270
+ thinking: { type: "adaptive" },
271
+ output_config: { effort: request.reasoningEffort ?? "medium" },
199
272
  };
200
- if (system)
201
- params.system = system;
273
+ // The Anthropic API requires a Claude Code identification block in the system
274
+ // prompt when using OAuth setup tokens (sk-ant-oat01). Without it, Opus/Sonnet
275
+ // 4.6 requests are rejected with 400. This is the API's validation that the
276
+ // token is being used by a Claude Code client.
277
+ const claudeCodePreamble = { type: "text", text: "You are Claude Code, Anthropic's official CLI for Claude." };
278
+ if (system) {
279
+ params.system = [claudeCodePreamble, { type: "text", text: system }];
280
+ }
281
+ else {
282
+ params.system = [claudeCodePreamble];
283
+ }
202
284
  if (anthropicTools.length > 0)
203
285
  params.tools = anthropicTools;
204
286
  if (request.toolChoiceRequired && anthropicTools.length > 0) {
205
- params.tool_choice = { type: "any" };
287
+ // Thinking (adaptive or enabled) only supports tool_choice "auto" or "none".
288
+ // "any" forces tool use which is incompatible with extended thinking.
289
+ params.tool_choice = params.thinking ? { type: "auto" } : /* v8 ignore next -- no-thinking path: thinking always set for 4.6 models @preserve */ { type: "any" };
206
290
  }
207
291
  let response;
208
292
  try {
209
293
  response = await client.messages.create(params, request.signal ? { signal: request.signal } : {});
210
294
  }
211
295
  catch (error) {
212
- throw withAnthropicAuthGuidance(error);
296
+ throw error instanceof Error ? error : new Error(String(error));
213
297
  }
214
298
  let content = "";
215
299
  let streamStarted = false;
216
300
  let usage;
217
301
  const toolCalls = new Map();
302
+ const thinkingBlocks = new Map();
303
+ const redactedBlocks = new Map();
304
+ const answerStreamer = new streaming_1.SettleStreamer(request.callbacks, request.eagerSettleStreaming);
218
305
  try {
219
306
  for await (const event of response) {
220
307
  if (request.signal?.aborted)
@@ -222,17 +309,29 @@ async function streamAnthropicMessages(client, model, request) {
222
309
  const eventType = String(event.type ?? "");
223
310
  if (eventType === "content_block_start") {
224
311
  const block = event.content_block;
225
- if (block?.type === "tool_use") {
226
- const index = Number(event.index);
312
+ const index = Number(event.index);
313
+ if (block?.type === "thinking") {
314
+ thinkingBlocks.set(index, { type: "thinking", thinking: "", signature: "" });
315
+ }
316
+ else if (block?.type === "redacted_thinking") {
317
+ redactedBlocks.set(index, { type: "redacted_thinking", data: String(block.data ?? "") });
318
+ }
319
+ else if (block?.type === "tool_use") {
227
320
  const rawInput = block.input;
228
321
  const input = rawInput && typeof rawInput === "object"
229
322
  ? JSON.stringify(rawInput)
230
323
  : "";
324
+ const name = String(block.name ?? "");
231
325
  toolCalls.set(index, {
232
326
  id: String(block.id ?? ""),
233
- name: String(block.name ?? ""),
327
+ name,
234
328
  arguments: input,
235
329
  });
330
+ // Activate eager streaming for sole settle tool call
331
+ /* v8 ignore next -- settle streaming activation, tested via SettleStreamer unit tests @preserve */
332
+ if (name === "settle" && toolCalls.size === 1) {
333
+ answerStreamer.activate();
334
+ }
236
335
  }
237
336
  continue;
238
337
  }
@@ -254,14 +353,31 @@ async function streamAnthropicMessages(client, model, request) {
254
353
  request.callbacks.onModelStreamStart();
255
354
  streamStarted = true;
256
355
  }
257
- request.callbacks.onReasoningChunk(String(delta?.thinking ?? ""));
356
+ const thinkingText = String(delta?.thinking ?? "");
357
+ request.callbacks.onReasoningChunk(thinkingText);
358
+ const thinkingIndex = Number(event.index);
359
+ const thinkingBlock = thinkingBlocks.get(thinkingIndex);
360
+ if (thinkingBlock)
361
+ thinkingBlock.thinking += thinkingText;
362
+ continue;
363
+ }
364
+ if (deltaType === "signature_delta") {
365
+ const sigIndex = Number(event.index);
366
+ const sigBlock = thinkingBlocks.get(sigIndex);
367
+ if (sigBlock)
368
+ sigBlock.signature += String(delta?.signature ?? "");
258
369
  continue;
259
370
  }
260
371
  if (deltaType === "input_json_delta") {
261
372
  const index = Number(event.index);
262
373
  const existing = toolCalls.get(index);
263
374
  if (existing) {
264
- existing.arguments = mergeAnthropicToolArguments(existing.arguments, String(delta?.partial_json ?? ""));
375
+ const partialJson = String(delta?.partial_json ?? "");
376
+ existing.arguments = mergeAnthropicToolArguments(existing.arguments, partialJson);
377
+ /* v8 ignore next -- settle delta streaming, tested via SettleStreamer unit tests @preserve */
378
+ if (existing.name === "settle" && toolCalls.size === 1) {
379
+ answerStreamer.processDelta(partialJson);
380
+ }
265
381
  }
266
382
  continue;
267
383
  }
@@ -283,16 +399,25 @@ async function streamAnthropicMessages(client, model, request) {
283
399
  }
284
400
  }
285
401
  catch (error) {
286
- throw withAnthropicAuthGuidance(error);
402
+ throw error instanceof Error ? error : /* v8 ignore next -- defensive: stream errors are always Error @preserve */ new Error(String(error));
287
403
  }
404
+ // Collect all thinking blocks (regular + redacted) sorted by index to preserve ordering
405
+ const allThinkingIndices = [...thinkingBlocks.keys(), ...redactedBlocks.keys()].sort((a, b) => a - b);
406
+ const outputItems = allThinkingIndices.map((idx) => {
407
+ const tb = thinkingBlocks.get(idx);
408
+ if (tb)
409
+ return tb;
410
+ return redactedBlocks.get(idx);
411
+ });
288
412
  return {
289
413
  content,
290
414
  toolCalls: [...toolCalls.values()],
291
- outputItems: [],
415
+ outputItems,
292
416
  usage,
417
+ settleStreamed: answerStreamer.streamed,
293
418
  };
294
419
  }
295
- function createAnthropicProviderRuntime() {
420
+ function createAnthropicProviderRuntime(model) {
296
421
  (0, runtime_1.emitNervesEvent)({
297
422
  component: "engine",
298
423
  event: "engine.provider_init",
@@ -300,30 +425,68 @@ function createAnthropicProviderRuntime() {
300
425
  meta: { provider: "anthropic" },
301
426
  });
302
427
  const anthropicConfig = (0, config_1.getAnthropicConfig)();
303
- if (!(anthropicConfig.model && anthropicConfig.setupToken)) {
304
- throw new Error(getAnthropicReauthGuidance("provider 'anthropic' is selected in agent.json but providers.anthropic.model/setupToken is incomplete in secrets.json."));
428
+ if (!anthropicConfig.setupToken) {
429
+ throw new Error(getAnthropicReauthGuidance("provider 'anthropic' is selected in agent.json but providers.anthropic.setupToken is missing in secrets.json."));
305
430
  }
431
+ const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
432
+ const capabilities = new Set();
433
+ if (modelCaps.reasoningEffort)
434
+ capabilities.add("reasoning-effort");
306
435
  const credential = resolveAnthropicSetupTokenCredential();
307
- const client = new sdk_1.default({
308
- authToken: credential.token,
309
- timeout: 30000,
310
- maxRetries: 0,
311
- defaultHeaders: {
312
- "anthropic-beta": ANTHROPIC_OAUTH_BETA_HEADER,
313
- },
314
- });
436
+ const refreshToken = anthropicConfig.refreshToken;
437
+ const expiresAt = anthropicConfig.expiresAt;
438
+ function createClient(token) {
439
+ return new sdk_1.default({
440
+ authToken: token,
441
+ timeout: 30000,
442
+ maxRetries: 0,
443
+ defaultHeaders: {
444
+ "anthropic-beta": ANTHROPIC_OAUTH_BETA_HEADER,
445
+ "anthropic-dangerous-direct-browser-access": "true",
446
+ "user-agent": "claude-cli/2.1.2 (external, cli)",
447
+ "x-app": "cli",
448
+ },
449
+ });
450
+ }
451
+ let currentToken = credential.token;
452
+ let client = createClient(currentToken);
453
+ /* v8 ignore start -- token refresh: dynamic import + ensureFreshToken, tested via integration @preserve */
454
+ async function ensureClient() {
455
+ try {
456
+ const { ensureFreshToken } = await Promise.resolve().then(() => __importStar(require("./anthropic-token")));
457
+ const { getAgentName } = await Promise.resolve().then(() => __importStar(require("../identity")));
458
+ const freshToken = await ensureFreshToken(currentToken, refreshToken, expiresAt, getAgentName());
459
+ if (freshToken !== currentToken) {
460
+ currentToken = freshToken;
461
+ client = createClient(freshToken);
462
+ }
463
+ }
464
+ catch {
465
+ // refresh failed — use existing client
466
+ }
467
+ return client;
468
+ }
469
+ /* v8 ignore stop */
315
470
  return {
316
471
  id: "anthropic",
317
- model: anthropicConfig.model,
318
- client,
472
+ model,
473
+ /* v8 ignore next -- getter: returns mutable client ref @preserve */
474
+ get client() { return client; },
475
+ capabilities,
476
+ supportedReasoningEfforts: modelCaps.reasoningEffort,
319
477
  resetTurnState(_messages) {
320
478
  // Anthropic request payload is derived from canonical messages each turn.
321
479
  },
322
480
  appendToolOutput(_callId, _output) {
323
481
  // Anthropic uses canonical messages for tool_result tracking.
324
482
  },
325
- streamTurn(request) {
326
- return streamAnthropicMessages(client, anthropicConfig.model, request);
483
+ async streamTurn(request) {
484
+ const freshClient = await ensureClient();
485
+ return streamAnthropicMessages(freshClient, model, request);
486
+ },
487
+ /* v8 ignore next 3 -- delegation: classification logic tested via classifyAnthropicError @preserve */
488
+ classifyError(error) {
489
+ return classifyAnthropicError(error);
327
490
  },
328
491
  };
329
492
  }
@@ -1,35 +1,137 @@
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
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.classifyAzureError = classifyAzureError;
37
+ exports.createAzureTokenProvider = createAzureTokenProvider;
3
38
  exports.createAzureProviderRuntime = createAzureProviderRuntime;
4
39
  const openai_1 = require("openai");
5
40
  const config_1 = require("../config");
6
41
  const runtime_1 = require("../../nerves/runtime");
7
42
  const streaming_1 = require("../streaming");
8
- function createAzureProviderRuntime() {
43
+ const model_capabilities_1 = require("../model-capabilities");
44
+ const COGNITIVE_SERVICES_SCOPE = "https://cognitiveservices.azure.com/.default";
45
+ /* v8 ignore start -- shared network error utility, tested via classification tests @preserve */
46
+ function isNetworkError(error) {
47
+ const code = error.code || "";
48
+ if (["ECONNRESET", "ECONNREFUSED", "ENOTFOUND", "ETIMEDOUT", "EPIPE",
49
+ "EAI_AGAIN", "EHOSTUNREACH", "ENETUNREACH", "ECONNABORTED"].includes(code))
50
+ return true;
51
+ const msg = error.message || "";
52
+ return msg.includes("fetch failed") || msg.includes("socket hang up") || msg.includes("getaddrinfo");
53
+ }
54
+ /* v8 ignore stop */
55
+ function classifyAzureError(error) {
56
+ const status = error.status;
57
+ if (status === 401 || status === 403)
58
+ return "auth-failure";
59
+ if (status === 429)
60
+ return "rate-limit";
61
+ if (status && status >= 500)
62
+ return "server-error";
63
+ if (isNetworkError(error))
64
+ return "network-error";
65
+ return "unknown";
66
+ }
67
+ // @azure/identity is imported dynamically (below) rather than at the top level
68
+ // because it's a heavy package (~30+ transitive deps) and we only need it when
69
+ // using the managed-identity auth path. API-key users and other providers
70
+ // shouldn't pay the cold-start cost.
71
+ function createAzureTokenProvider(managedIdentityClientId) {
72
+ let credential = null;
73
+ return async () => {
74
+ try {
75
+ if (!credential) {
76
+ const { DefaultAzureCredential } = await Promise.resolve().then(() => __importStar(require("@azure/identity")));
77
+ const credentialOptions = managedIdentityClientId
78
+ ? { managedIdentityClientId }
79
+ : undefined;
80
+ credential = new DefaultAzureCredential(credentialOptions);
81
+ }
82
+ const tokenResponse = await credential.getToken(COGNITIVE_SERVICES_SCOPE);
83
+ return tokenResponse.token;
84
+ }
85
+ catch (err) {
86
+ const detail = err instanceof Error ? err.message : String(err);
87
+ throw new Error(`Azure OpenAI authentication failed: ${detail}\n` +
88
+ "To fix this, either:\n" +
89
+ " 1. Set providers.azure.apiKey in secrets.json, or\n" +
90
+ " 2. Run 'az login' to authenticate with your Azure account (for local dev), or\n" +
91
+ " 3. Attach a managed identity to your App Service and set providers.azure.managedIdentityClientId in secrets.json (for deployed environments)");
92
+ }
93
+ };
94
+ }
95
+ function createAzureProviderRuntime(model) {
96
+ const azureConfig = (0, config_1.getAzureConfig)();
97
+ const useApiKey = !!azureConfig.apiKey;
98
+ const authMethod = useApiKey ? "key" : "managed-identity";
9
99
  (0, runtime_1.emitNervesEvent)({
10
100
  component: "engine",
11
101
  event: "engine.provider_init",
12
102
  message: "azure provider init",
13
- meta: { provider: "azure" },
103
+ meta: { provider: "azure", authMethod },
14
104
  });
15
- const azureConfig = (0, config_1.getAzureConfig)();
16
- if (!(azureConfig.apiKey && azureConfig.endpoint && azureConfig.deployment && azureConfig.modelName)) {
105
+ if (!(azureConfig.endpoint && azureConfig.deployment)) {
17
106
  throw new Error("provider 'azure' is selected in agent.json but providers.azure is incomplete in secrets.json.");
18
107
  }
19
- const client = new openai_1.AzureOpenAI({
20
- apiKey: azureConfig.apiKey,
108
+ const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
109
+ const capabilities = new Set();
110
+ if (modelCaps.reasoningEffort)
111
+ capabilities.add("reasoning-effort");
112
+ const clientOptions = {
21
113
  endpoint: azureConfig.endpoint.replace(/\/openai.*$/, ""),
22
114
  deployment: azureConfig.deployment,
23
115
  apiVersion: azureConfig.apiVersion,
24
116
  timeout: 30000,
25
117
  maxRetries: 0,
26
- });
118
+ };
119
+ if (useApiKey) {
120
+ clientOptions.apiKey = azureConfig.apiKey;
121
+ }
122
+ else {
123
+ const managedIdentityClientId = azureConfig.managedIdentityClientId || undefined;
124
+ clientOptions.azureADTokenProvider = createAzureTokenProvider(managedIdentityClientId);
125
+ }
126
+ const client = new openai_1.AzureOpenAI(clientOptions);
27
127
  let nativeInput = null;
28
128
  let nativeInstructions = "";
29
129
  return {
30
130
  id: "azure",
31
- model: azureConfig.modelName,
131
+ model,
32
132
  client,
133
+ capabilities,
134
+ supportedReasoningEfforts: modelCaps.reasoningEffort,
33
135
  resetTurnState(messages) {
34
136
  const { instructions, input } = (0, streaming_1.toResponsesInput)(messages);
35
137
  nativeInput = input;
@@ -48,7 +150,7 @@ function createAzureProviderRuntime() {
48
150
  input: nativeInput,
49
151
  instructions: nativeInstructions,
50
152
  tools: (0, streaming_1.toResponsesTools)(request.activeTools),
51
- reasoning: { effort: "medium", summary: "detailed" },
153
+ reasoning: { effort: request.reasoningEffort ?? "medium", summary: "detailed" },
52
154
  stream: true,
53
155
  store: false,
54
156
  include: ["reasoning.encrypted_content"],
@@ -57,10 +159,14 @@ function createAzureProviderRuntime() {
57
159
  params.metadata = { trace_id: request.traceId };
58
160
  if (request.toolChoiceRequired)
59
161
  params.tool_choice = "required";
60
- const result = await (0, streaming_1.streamResponsesApi)(this.client, params, request.callbacks, request.signal);
162
+ const result = await (0, streaming_1.streamResponsesApi)(this.client, params, request.callbacks, request.signal, request.eagerSettleStreaming);
61
163
  for (const item of result.outputItems)
62
164
  nativeInput.push(item);
63
165
  return result;
64
166
  },
167
+ /* v8 ignore next 3 -- delegation: classification logic tested via classifyAzureError @preserve */
168
+ classifyError(error) {
169
+ return classifyAzureError(error);
170
+ },
65
171
  };
66
172
  }