@ouro.bot/cli 0.1.0-alpha.12 → 0.1.0-alpha.121
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.
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +2 -2
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
- package/README.md +147 -205
- package/assets/ouroboros.png +0 -0
- package/changelog.json +737 -0
- package/dist/heart/active-work.js +622 -0
- package/dist/heart/bridges/manager.js +358 -0
- package/dist/heart/bridges/state-machine.js +135 -0
- package/dist/heart/bridges/store.js +123 -0
- package/dist/heart/commitments.js +105 -0
- package/dist/heart/config.js +68 -23
- package/dist/heart/core.js +528 -100
- package/dist/heart/cross-chat-delivery.js +146 -0
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/auth-flow.js +430 -0
- package/dist/heart/daemon/daemon-cli.js +1601 -207
- package/dist/heart/daemon/daemon-entry.js +43 -2
- package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
- package/dist/heart/daemon/daemon.js +226 -1
- package/dist/heart/daemon/hatch-animation.js +10 -3
- package/dist/heart/daemon/hatch-flow.js +7 -82
- package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
- package/dist/heart/daemon/launchd.js +159 -0
- package/dist/heart/daemon/log-tailer.js +4 -3
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/ouro-bot-entry.js +0 -0
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-entry.js +0 -0
- package/dist/heart/daemon/ouro-path-installer.js +59 -15
- package/dist/heart/daemon/ouro-uti.js +11 -2
- package/dist/heart/daemon/ouro-version-manager.js +171 -0
- package/dist/heart/daemon/process-manager.js +13 -0
- package/dist/heart/daemon/run-hooks.js +37 -0
- package/dist/heart/daemon/runtime-logging.js +58 -15
- package/dist/heart/daemon/runtime-metadata.js +219 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/sense-manager.js +43 -2
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +202 -0
- package/dist/heart/daemon/specialist-orchestrator.js +37 -94
- package/dist/heart/daemon/specialist-prompt.js +50 -12
- package/dist/heart/daemon/specialist-tools.js +211 -60
- package/dist/heart/daemon/staged-restart.js +114 -0
- package/dist/heart/daemon/thoughts.js +507 -0
- package/dist/heart/daemon/update-checker.js +111 -0
- package/dist/heart/daemon/update-hooks.js +138 -0
- package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/identity.js +64 -21
- package/dist/heart/kicks.js +1 -19
- package/dist/heart/model-capabilities.js +48 -0
- package/dist/heart/obligations.js +197 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-failover.js +88 -0
- package/dist/heart/provider-ping.js +151 -0
- package/dist/heart/providers/anthropic.js +107 -20
- package/dist/heart/providers/azure.js +115 -9
- package/dist/heart/providers/github-copilot.js +157 -0
- package/dist/heart/providers/minimax.js +33 -3
- package/dist/heart/providers/openai-codex.js +49 -14
- package/dist/heart/safe-workspace.js +381 -0
- package/dist/heart/session-activity.js +169 -0
- package/dist/heart/session-recall.js +216 -0
- package/dist/heart/streaming.js +108 -24
- package/dist/heart/target-resolution.js +123 -0
- package/dist/heart/tool-loop.js +194 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/mind/associative-recall.js +14 -2
- package/dist/mind/bundle-manifest.js +70 -0
- package/dist/mind/context.js +60 -14
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +35 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/store-file.js +19 -0
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +8 -0
- package/dist/mind/memory.js +27 -26
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +459 -77
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +15 -2
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/index.js +12 -0
- package/dist/repertoire/ado-client.js +4 -2
- package/dist/repertoire/coding/context-pack.js +254 -0
- package/dist/repertoire/coding/feedback.js +301 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +210 -4
- package/dist/repertoire/coding/spawner.js +39 -9
- package/dist/repertoire/coding/tools.js +171 -4
- package/dist/repertoire/data/ado-endpoints.json +188 -0
- package/dist/repertoire/guardrails.js +290 -0
- package/dist/repertoire/mcp-client.js +254 -0
- package/dist/repertoire/mcp-manager.js +195 -0
- package/dist/repertoire/skills.js +3 -26
- package/dist/repertoire/tasks/board.js +12 -0
- package/dist/repertoire/tasks/index.js +23 -9
- package/dist/repertoire/tasks/transitions.js +1 -2
- package/dist/repertoire/tools-base.js +925 -250
- package/dist/repertoire/tools-bluebubbles.js +93 -0
- package/dist/repertoire/tools-teams.js +58 -25
- package/dist/repertoire/tools.js +106 -53
- package/dist/senses/bluebubbles-client.js +210 -5
- package/dist/senses/bluebubbles-entry.js +2 -0
- package/dist/senses/bluebubbles-inbound-log.js +109 -0
- package/dist/senses/bluebubbles-media.js +339 -0
- package/dist/senses/bluebubbles-model.js +12 -4
- package/dist/senses/bluebubbles-mutation-log.js +45 -5
- package/dist/senses/bluebubbles-runtime-state.js +109 -0
- package/dist/senses/bluebubbles-session-cleanup.js +72 -0
- package/dist/senses/bluebubbles.js +912 -45
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +477 -170
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/debug-activity.js +154 -0
- package/dist/senses/inner-dialog-worker.js +47 -18
- package/dist/senses/inner-dialog.js +388 -83
- package/dist/senses/pipeline.js +444 -0
- package/dist/senses/teams.js +607 -129
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +14 -3
- package/subagents/README.md +4 -70
- package/dist/heart/daemon/specialist-session.js +0 -177
- package/dist/heart/daemon/subagent-installer.js +0 -134
- package/dist/inner-worker-entry.js +0 -4
- package/subagents/work-doer.md +0 -233
- package/subagents/work-merger.md +0 -624
- package/subagents/work-planner.md +0 -373
|
@@ -3,11 +3,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.toAnthropicMessages = toAnthropicMessages;
|
|
7
|
+
exports.classifyAnthropicError = classifyAnthropicError;
|
|
6
8
|
exports.createAnthropicProviderRuntime = createAnthropicProviderRuntime;
|
|
7
9
|
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
8
10
|
const config_1 = require("../config");
|
|
9
11
|
const identity_1 = require("../identity");
|
|
10
12
|
const runtime_1 = require("../../nerves/runtime");
|
|
13
|
+
const streaming_1 = require("../streaming");
|
|
14
|
+
const model_capabilities_1 = require("../model-capabilities");
|
|
11
15
|
const ANTHROPIC_SETUP_TOKEN_PREFIX = "sk-ant-oat01-";
|
|
12
16
|
const ANTHROPIC_SETUP_TOKEN_MIN_LENGTH = 80;
|
|
13
17
|
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 +25,10 @@ function getAnthropicSetupTokenInstructions() {
|
|
|
21
25
|
const agentName = getAnthropicAgentNameForGuidance();
|
|
22
26
|
return [
|
|
23
27
|
"Fix:",
|
|
24
|
-
` 1. Run \`
|
|
25
|
-
" (or run `claude setup-token` and paste the token manually)",
|
|
28
|
+
` 1. Run \`ouro auth --agent ${agentName}\``,
|
|
26
29
|
` 2. Open ${getAnthropicSecretsPathForGuidance()}`,
|
|
27
30
|
" 3. Confirm providers.anthropic.setupToken is set",
|
|
31
|
+
" 4. After reauth, retry the failed ouro command or reconnect this session.",
|
|
28
32
|
].join("\n");
|
|
29
33
|
}
|
|
30
34
|
function getAnthropicReauthGuidance(reason) {
|
|
@@ -92,6 +96,18 @@ function toAnthropicMessages(messages) {
|
|
|
92
96
|
if (msg.role === "assistant") {
|
|
93
97
|
const assistant = msg;
|
|
94
98
|
const blocks = [];
|
|
99
|
+
// Restore thinking blocks before text/tool_use blocks
|
|
100
|
+
const thinkingBlocks = assistant._thinking_blocks;
|
|
101
|
+
if (thinkingBlocks) {
|
|
102
|
+
for (const tb of thinkingBlocks) {
|
|
103
|
+
if (tb.type === "thinking") {
|
|
104
|
+
blocks.push({ type: "thinking", thinking: tb.thinking, signature: tb.signature });
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
blocks.push({ type: "redacted_thinking", data: tb.data });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
95
111
|
const text = toAnthropicTextContent(assistant.content);
|
|
96
112
|
if (text) {
|
|
97
113
|
blocks.push({ type: "text", text });
|
|
@@ -172,6 +188,29 @@ function mergeAnthropicToolArguments(current, partial) {
|
|
|
172
188
|
}
|
|
173
189
|
return current + partial;
|
|
174
190
|
}
|
|
191
|
+
/* v8 ignore start -- shared network error utility, tested via classification tests @preserve */
|
|
192
|
+
function isNetworkError(error) {
|
|
193
|
+
const code = error.code || "";
|
|
194
|
+
if (["ECONNRESET", "ECONNREFUSED", "ENOTFOUND", "ETIMEDOUT", "EPIPE",
|
|
195
|
+
"EAI_AGAIN", "EHOSTUNREACH", "ENETUNREACH", "ECONNABORTED"].includes(code))
|
|
196
|
+
return true;
|
|
197
|
+
const msg = error.message || "";
|
|
198
|
+
return msg.includes("fetch failed") || msg.includes("socket hang up") || msg.includes("getaddrinfo");
|
|
199
|
+
}
|
|
200
|
+
/* v8 ignore stop */
|
|
201
|
+
function classifyAnthropicError(error) {
|
|
202
|
+
const status = error.status;
|
|
203
|
+
if (status === 401 || status === 403 || isAnthropicAuthFailure(error))
|
|
204
|
+
return "auth-failure";
|
|
205
|
+
if (status === 429)
|
|
206
|
+
return "rate-limit";
|
|
207
|
+
if (status === 529 || (status && status >= 500))
|
|
208
|
+
return "server-error";
|
|
209
|
+
if (isNetworkError(error))
|
|
210
|
+
return "network-error";
|
|
211
|
+
return "unknown";
|
|
212
|
+
}
|
|
213
|
+
/* v8 ignore start -- auth detection: only called from classifyAnthropicError which always passes Error @preserve */
|
|
175
214
|
function isAnthropicAuthFailure(error) {
|
|
176
215
|
if (!(error instanceof Error))
|
|
177
216
|
return false;
|
|
@@ -184,21 +223,18 @@ function isAnthropicAuthFailure(error) {
|
|
|
184
223
|
lower.includes("unauthorized") ||
|
|
185
224
|
lower.includes("invalid api key"));
|
|
186
225
|
}
|
|
187
|
-
|
|
188
|
-
const base = error instanceof Error ? error.message : String(error);
|
|
189
|
-
if (isAnthropicAuthFailure(error)) {
|
|
190
|
-
return new Error(getAnthropicReauthGuidance(`Anthropic authentication failed (${base}).`));
|
|
191
|
-
}
|
|
192
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
193
|
-
}
|
|
226
|
+
/* v8 ignore stop */
|
|
194
227
|
async function streamAnthropicMessages(client, model, request) {
|
|
195
228
|
const { system, messages } = toAnthropicMessages(request.messages);
|
|
196
229
|
const anthropicTools = toAnthropicTools(request.activeTools);
|
|
230
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
|
|
231
|
+
const maxTokens = modelCaps.maxOutputTokens ?? 16384;
|
|
197
232
|
const params = {
|
|
198
233
|
model,
|
|
199
|
-
max_tokens:
|
|
234
|
+
max_tokens: maxTokens,
|
|
200
235
|
messages,
|
|
201
236
|
stream: true,
|
|
237
|
+
thinking: { type: "adaptive", effort: request.reasoningEffort ?? "medium" },
|
|
202
238
|
};
|
|
203
239
|
if (system)
|
|
204
240
|
params.system = system;
|
|
@@ -212,12 +248,15 @@ async function streamAnthropicMessages(client, model, request) {
|
|
|
212
248
|
response = await client.messages.create(params, request.signal ? { signal: request.signal } : {});
|
|
213
249
|
}
|
|
214
250
|
catch (error) {
|
|
215
|
-
throw
|
|
251
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
216
252
|
}
|
|
217
253
|
let content = "";
|
|
218
254
|
let streamStarted = false;
|
|
219
255
|
let usage;
|
|
220
256
|
const toolCalls = new Map();
|
|
257
|
+
const thinkingBlocks = new Map();
|
|
258
|
+
const redactedBlocks = new Map();
|
|
259
|
+
const answerStreamer = new streaming_1.FinalAnswerStreamer(request.callbacks, request.eagerFinalAnswerStreaming);
|
|
221
260
|
try {
|
|
222
261
|
for await (const event of response) {
|
|
223
262
|
if (request.signal?.aborted)
|
|
@@ -225,17 +264,29 @@ async function streamAnthropicMessages(client, model, request) {
|
|
|
225
264
|
const eventType = String(event.type ?? "");
|
|
226
265
|
if (eventType === "content_block_start") {
|
|
227
266
|
const block = event.content_block;
|
|
228
|
-
|
|
229
|
-
|
|
267
|
+
const index = Number(event.index);
|
|
268
|
+
if (block?.type === "thinking") {
|
|
269
|
+
thinkingBlocks.set(index, { type: "thinking", thinking: "", signature: "" });
|
|
270
|
+
}
|
|
271
|
+
else if (block?.type === "redacted_thinking") {
|
|
272
|
+
redactedBlocks.set(index, { type: "redacted_thinking", data: String(block.data ?? "") });
|
|
273
|
+
}
|
|
274
|
+
else if (block?.type === "tool_use") {
|
|
230
275
|
const rawInput = block.input;
|
|
231
276
|
const input = rawInput && typeof rawInput === "object"
|
|
232
277
|
? JSON.stringify(rawInput)
|
|
233
278
|
: "";
|
|
279
|
+
const name = String(block.name ?? "");
|
|
234
280
|
toolCalls.set(index, {
|
|
235
281
|
id: String(block.id ?? ""),
|
|
236
|
-
name
|
|
282
|
+
name,
|
|
237
283
|
arguments: input,
|
|
238
284
|
});
|
|
285
|
+
// Activate eager streaming for sole final_answer tool call
|
|
286
|
+
/* v8 ignore next -- final_answer streaming activation, tested via FinalAnswerStreamer unit tests @preserve */
|
|
287
|
+
if (name === "final_answer" && toolCalls.size === 1) {
|
|
288
|
+
answerStreamer.activate();
|
|
289
|
+
}
|
|
239
290
|
}
|
|
240
291
|
continue;
|
|
241
292
|
}
|
|
@@ -257,14 +308,31 @@ async function streamAnthropicMessages(client, model, request) {
|
|
|
257
308
|
request.callbacks.onModelStreamStart();
|
|
258
309
|
streamStarted = true;
|
|
259
310
|
}
|
|
260
|
-
|
|
311
|
+
const thinkingText = String(delta?.thinking ?? "");
|
|
312
|
+
request.callbacks.onReasoningChunk(thinkingText);
|
|
313
|
+
const thinkingIndex = Number(event.index);
|
|
314
|
+
const thinkingBlock = thinkingBlocks.get(thinkingIndex);
|
|
315
|
+
if (thinkingBlock)
|
|
316
|
+
thinkingBlock.thinking += thinkingText;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (deltaType === "signature_delta") {
|
|
320
|
+
const sigIndex = Number(event.index);
|
|
321
|
+
const sigBlock = thinkingBlocks.get(sigIndex);
|
|
322
|
+
if (sigBlock)
|
|
323
|
+
sigBlock.signature += String(delta?.signature ?? "");
|
|
261
324
|
continue;
|
|
262
325
|
}
|
|
263
326
|
if (deltaType === "input_json_delta") {
|
|
264
327
|
const index = Number(event.index);
|
|
265
328
|
const existing = toolCalls.get(index);
|
|
266
329
|
if (existing) {
|
|
267
|
-
|
|
330
|
+
const partialJson = String(delta?.partial_json ?? "");
|
|
331
|
+
existing.arguments = mergeAnthropicToolArguments(existing.arguments, partialJson);
|
|
332
|
+
/* v8 ignore next -- final_answer delta streaming, tested via FinalAnswerStreamer unit tests @preserve */
|
|
333
|
+
if (existing.name === "final_answer" && toolCalls.size === 1) {
|
|
334
|
+
answerStreamer.processDelta(partialJson);
|
|
335
|
+
}
|
|
268
336
|
}
|
|
269
337
|
continue;
|
|
270
338
|
}
|
|
@@ -286,26 +354,39 @@ async function streamAnthropicMessages(client, model, request) {
|
|
|
286
354
|
}
|
|
287
355
|
}
|
|
288
356
|
catch (error) {
|
|
289
|
-
throw
|
|
357
|
+
throw error instanceof Error ? error : /* v8 ignore next -- defensive: stream errors are always Error @preserve */ new Error(String(error));
|
|
290
358
|
}
|
|
359
|
+
// Collect all thinking blocks (regular + redacted) sorted by index to preserve ordering
|
|
360
|
+
const allThinkingIndices = [...thinkingBlocks.keys(), ...redactedBlocks.keys()].sort((a, b) => a - b);
|
|
361
|
+
const outputItems = allThinkingIndices.map((idx) => {
|
|
362
|
+
const tb = thinkingBlocks.get(idx);
|
|
363
|
+
if (tb)
|
|
364
|
+
return tb;
|
|
365
|
+
return redactedBlocks.get(idx);
|
|
366
|
+
});
|
|
291
367
|
return {
|
|
292
368
|
content,
|
|
293
369
|
toolCalls: [...toolCalls.values()],
|
|
294
|
-
outputItems
|
|
370
|
+
outputItems,
|
|
295
371
|
usage,
|
|
372
|
+
finalAnswerStreamed: answerStreamer.streamed,
|
|
296
373
|
};
|
|
297
374
|
}
|
|
298
|
-
function createAnthropicProviderRuntime() {
|
|
375
|
+
function createAnthropicProviderRuntime(config) {
|
|
299
376
|
(0, runtime_1.emitNervesEvent)({
|
|
300
377
|
component: "engine",
|
|
301
378
|
event: "engine.provider_init",
|
|
302
379
|
message: "anthropic provider init",
|
|
303
380
|
meta: { provider: "anthropic" },
|
|
304
381
|
});
|
|
305
|
-
const anthropicConfig = (0, config_1.getAnthropicConfig)();
|
|
382
|
+
const anthropicConfig = config ?? (0, config_1.getAnthropicConfig)();
|
|
306
383
|
if (!(anthropicConfig.model && anthropicConfig.setupToken)) {
|
|
307
384
|
throw new Error(getAnthropicReauthGuidance("provider 'anthropic' is selected in agent.json but providers.anthropic.model/setupToken is incomplete in secrets.json."));
|
|
308
385
|
}
|
|
386
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(anthropicConfig.model);
|
|
387
|
+
const capabilities = new Set();
|
|
388
|
+
if (modelCaps.reasoningEffort)
|
|
389
|
+
capabilities.add("reasoning-effort");
|
|
309
390
|
const credential = resolveAnthropicSetupTokenCredential();
|
|
310
391
|
const client = new sdk_1.default({
|
|
311
392
|
authToken: credential.token,
|
|
@@ -319,6 +400,8 @@ function createAnthropicProviderRuntime() {
|
|
|
319
400
|
id: "anthropic",
|
|
320
401
|
model: anthropicConfig.model,
|
|
321
402
|
client,
|
|
403
|
+
capabilities,
|
|
404
|
+
supportedReasoningEfforts: modelCaps.reasoningEffort,
|
|
322
405
|
resetTurnState(_messages) {
|
|
323
406
|
// Anthropic request payload is derived from canonical messages each turn.
|
|
324
407
|
},
|
|
@@ -328,5 +411,9 @@ function createAnthropicProviderRuntime() {
|
|
|
328
411
|
streamTurn(request) {
|
|
329
412
|
return streamAnthropicMessages(client, anthropicConfig.model, request);
|
|
330
413
|
},
|
|
414
|
+
/* v8 ignore next 3 -- delegation: classification logic tested via classifyAnthropicError @preserve */
|
|
415
|
+
classifyError(error) {
|
|
416
|
+
return classifyAnthropicError(error);
|
|
417
|
+
},
|
|
331
418
|
};
|
|
332
419
|
}
|
|
@@ -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
|
-
|
|
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(config) {
|
|
96
|
+
const azureConfig = config ?? (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
|
-
|
|
16
|
-
if (!(azureConfig.apiKey && azureConfig.endpoint && azureConfig.deployment && azureConfig.modelName)) {
|
|
105
|
+
if (!(azureConfig.endpoint && azureConfig.deployment && azureConfig.modelName)) {
|
|
17
106
|
throw new Error("provider 'azure' is selected in agent.json but providers.azure is incomplete in secrets.json.");
|
|
18
107
|
}
|
|
19
|
-
const
|
|
20
|
-
|
|
108
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(azureConfig.modelName);
|
|
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
131
|
model: azureConfig.modelName,
|
|
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.eagerFinalAnswerStreaming);
|
|
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
|
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.classifyGithubCopilotError = classifyGithubCopilotError;
|
|
7
|
+
exports.createGithubCopilotProviderRuntime = createGithubCopilotProviderRuntime;
|
|
8
|
+
const openai_1 = __importDefault(require("openai"));
|
|
9
|
+
const config_1 = require("../config");
|
|
10
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
11
|
+
const streaming_1 = require("../streaming");
|
|
12
|
+
const model_capabilities_1 = require("../model-capabilities");
|
|
13
|
+
/* v8 ignore start -- duplicated from shared provider utils, tested there @preserve */
|
|
14
|
+
function isNetworkError(error) {
|
|
15
|
+
const code = error.code || "";
|
|
16
|
+
if (["ECONNRESET", "ECONNREFUSED", "ENOTFOUND", "ETIMEDOUT", "EPIPE",
|
|
17
|
+
"EAI_AGAIN", "EHOSTUNREACH", "ENETUNREACH", "ECONNABORTED"].includes(code))
|
|
18
|
+
return true;
|
|
19
|
+
const msg = error.message || "";
|
|
20
|
+
return msg.includes("fetch failed") || msg.includes("socket hang up") || msg.includes("getaddrinfo");
|
|
21
|
+
}
|
|
22
|
+
/* v8 ignore stop */
|
|
23
|
+
/* v8 ignore start -- duplicated classification pattern, tested via provider unit tests @preserve */
|
|
24
|
+
function classifyGithubCopilotError(error) {
|
|
25
|
+
const status = error.status;
|
|
26
|
+
if (status === 401 || status === 403)
|
|
27
|
+
return "auth-failure";
|
|
28
|
+
if (status === 429)
|
|
29
|
+
return "rate-limit";
|
|
30
|
+
if (status && status >= 500)
|
|
31
|
+
return "server-error";
|
|
32
|
+
if (isNetworkError(error))
|
|
33
|
+
return "network-error";
|
|
34
|
+
return "unknown";
|
|
35
|
+
}
|
|
36
|
+
/* v8 ignore stop */
|
|
37
|
+
function createGithubCopilotProviderRuntime(injectedConfig) {
|
|
38
|
+
(0, runtime_1.emitNervesEvent)({
|
|
39
|
+
component: "engine",
|
|
40
|
+
event: "engine.provider_init",
|
|
41
|
+
message: "github-copilot provider init",
|
|
42
|
+
meta: { provider: "github-copilot" },
|
|
43
|
+
});
|
|
44
|
+
const config = injectedConfig ?? (0, config_1.getGithubCopilotConfig)();
|
|
45
|
+
if (!config.githubToken) {
|
|
46
|
+
throw new Error("provider 'github-copilot' is selected in agent.json but providers.github-copilot.githubToken is missing in secrets.json.");
|
|
47
|
+
}
|
|
48
|
+
if (!config.baseUrl) {
|
|
49
|
+
throw new Error("provider 'github-copilot' is selected in agent.json but providers.github-copilot.baseUrl is missing in secrets.json.");
|
|
50
|
+
}
|
|
51
|
+
const isCompletionsModel = config.model.startsWith("claude");
|
|
52
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(config.model);
|
|
53
|
+
const capabilities = new Set();
|
|
54
|
+
/* v8 ignore next -- branch: capability detection tested via unit test @preserve */
|
|
55
|
+
if (modelCaps.reasoningEffort)
|
|
56
|
+
capabilities.add("reasoning-effort");
|
|
57
|
+
const client = new openai_1.default({
|
|
58
|
+
apiKey: config.githubToken,
|
|
59
|
+
baseURL: config.baseUrl,
|
|
60
|
+
timeout: 30000,
|
|
61
|
+
maxRetries: 0,
|
|
62
|
+
});
|
|
63
|
+
if (isCompletionsModel) {
|
|
64
|
+
// Chat completions path (Claude models via Copilot)
|
|
65
|
+
return {
|
|
66
|
+
id: "github-copilot",
|
|
67
|
+
model: config.model,
|
|
68
|
+
client,
|
|
69
|
+
capabilities,
|
|
70
|
+
supportedReasoningEfforts: modelCaps.reasoningEffort,
|
|
71
|
+
resetTurnState(_messages) {
|
|
72
|
+
// No provider-owned turn state for chat-completions path.
|
|
73
|
+
},
|
|
74
|
+
appendToolOutput(_callId, _output) {
|
|
75
|
+
// Chat-completions providers rely on canonical messages only.
|
|
76
|
+
},
|
|
77
|
+
/* v8 ignore start -- streamTurn: tested via mock assertions in github-copilot.test.ts @preserve */
|
|
78
|
+
async streamTurn(request) {
|
|
79
|
+
const params = {
|
|
80
|
+
messages: request.messages,
|
|
81
|
+
tools: request.activeTools,
|
|
82
|
+
stream: true,
|
|
83
|
+
};
|
|
84
|
+
if (this.model)
|
|
85
|
+
params.model = this.model;
|
|
86
|
+
if (request.traceId)
|
|
87
|
+
params.metadata = { trace_id: request.traceId };
|
|
88
|
+
if (request.toolChoiceRequired)
|
|
89
|
+
params.tool_choice = "required";
|
|
90
|
+
try {
|
|
91
|
+
return await (0, streaming_1.streamChatCompletion)(this.client, params, request.callbacks, request.signal, request.eagerFinalAnswerStreaming);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
/* v8 ignore stop */
|
|
98
|
+
/* v8 ignore next 3 -- delegation: classification logic tested via classifyGithubCopilotError @preserve */
|
|
99
|
+
classifyError(error) {
|
|
100
|
+
return classifyGithubCopilotError(error);
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// Responses API path (GPT models via Copilot)
|
|
105
|
+
let nativeInput = null;
|
|
106
|
+
let nativeInstructions = "";
|
|
107
|
+
return {
|
|
108
|
+
id: "github-copilot",
|
|
109
|
+
model: config.model,
|
|
110
|
+
client,
|
|
111
|
+
capabilities,
|
|
112
|
+
supportedReasoningEfforts: modelCaps.reasoningEffort,
|
|
113
|
+
/* v8 ignore start -- responses path: tested via mock assertions in github-copilot.test.ts @preserve */
|
|
114
|
+
resetTurnState(messages) {
|
|
115
|
+
const { instructions, input } = (0, streaming_1.toResponsesInput)(messages);
|
|
116
|
+
nativeInput = input;
|
|
117
|
+
nativeInstructions = instructions;
|
|
118
|
+
},
|
|
119
|
+
appendToolOutput(callId, output) {
|
|
120
|
+
if (!nativeInput)
|
|
121
|
+
return;
|
|
122
|
+
nativeInput.push({ type: "function_call_output", call_id: callId, output });
|
|
123
|
+
},
|
|
124
|
+
async streamTurn(request) {
|
|
125
|
+
if (!nativeInput)
|
|
126
|
+
this.resetTurnState(request.messages);
|
|
127
|
+
const params = {
|
|
128
|
+
model: this.model,
|
|
129
|
+
input: nativeInput,
|
|
130
|
+
instructions: nativeInstructions,
|
|
131
|
+
tools: (0, streaming_1.toResponsesTools)(request.activeTools),
|
|
132
|
+
reasoning: { effort: request.reasoningEffort ?? "medium", summary: "detailed" },
|
|
133
|
+
stream: true,
|
|
134
|
+
store: false,
|
|
135
|
+
include: ["reasoning.encrypted_content"],
|
|
136
|
+
};
|
|
137
|
+
if (request.traceId)
|
|
138
|
+
params.metadata = { trace_id: request.traceId };
|
|
139
|
+
if (request.toolChoiceRequired)
|
|
140
|
+
params.tool_choice = "required";
|
|
141
|
+
try {
|
|
142
|
+
const result = await (0, streaming_1.streamResponsesApi)(this.client, params, request.callbacks, request.signal, request.eagerFinalAnswerStreaming);
|
|
143
|
+
for (const item of result.outputItems)
|
|
144
|
+
nativeInput.push(item);
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
/* v8 ignore stop */
|
|
152
|
+
/* v8 ignore next 3 -- delegation: classification logic tested via classifyGithubCopilotError @preserve */
|
|
153
|
+
classifyError(error) {
|
|
154
|
+
return classifyGithubCopilotError(error);
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
@@ -3,22 +3,48 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.classifyMinimaxError = classifyMinimaxError;
|
|
6
7
|
exports.createMinimaxProviderRuntime = createMinimaxProviderRuntime;
|
|
7
8
|
const openai_1 = __importDefault(require("openai"));
|
|
8
9
|
const config_1 = require("../config");
|
|
9
10
|
const runtime_1 = require("../../nerves/runtime");
|
|
11
|
+
/* v8 ignore start -- shared network error utility, tested via classification tests @preserve */
|
|
12
|
+
function isNetworkError(error) {
|
|
13
|
+
const code = error.code || "";
|
|
14
|
+
if (["ECONNRESET", "ECONNREFUSED", "ENOTFOUND", "ETIMEDOUT", "EPIPE",
|
|
15
|
+
"EAI_AGAIN", "EHOSTUNREACH", "ENETUNREACH", "ECONNABORTED"].includes(code))
|
|
16
|
+
return true;
|
|
17
|
+
const msg = error.message || "";
|
|
18
|
+
return msg.includes("fetch failed") || msg.includes("socket hang up") || msg.includes("getaddrinfo");
|
|
19
|
+
}
|
|
20
|
+
/* v8 ignore stop */
|
|
21
|
+
function classifyMinimaxError(error) {
|
|
22
|
+
const status = error.status;
|
|
23
|
+
if (status === 401 || status === 403)
|
|
24
|
+
return "auth-failure";
|
|
25
|
+
if (status === 429)
|
|
26
|
+
return "rate-limit";
|
|
27
|
+
if (status && status >= 500)
|
|
28
|
+
return "server-error";
|
|
29
|
+
if (isNetworkError(error))
|
|
30
|
+
return "network-error";
|
|
31
|
+
return "unknown";
|
|
32
|
+
}
|
|
10
33
|
const streaming_1 = require("../streaming");
|
|
11
|
-
|
|
34
|
+
const model_capabilities_1 = require("../model-capabilities");
|
|
35
|
+
function createMinimaxProviderRuntime(config) {
|
|
12
36
|
(0, runtime_1.emitNervesEvent)({
|
|
13
37
|
component: "engine",
|
|
14
38
|
event: "engine.provider_init",
|
|
15
39
|
message: "minimax provider init",
|
|
16
40
|
meta: { provider: "minimax" },
|
|
17
41
|
});
|
|
18
|
-
const minimaxConfig = (0, config_1.getMinimaxConfig)();
|
|
42
|
+
const minimaxConfig = config ?? (0, config_1.getMinimaxConfig)();
|
|
19
43
|
if (!minimaxConfig.apiKey) {
|
|
20
44
|
throw new Error("provider 'minimax' is selected in agent.json but providers.minimax.apiKey is missing in secrets.json.");
|
|
21
45
|
}
|
|
46
|
+
// Registry consulted; MiniMax models return empty defaults (no capabilities to derive)
|
|
47
|
+
(0, model_capabilities_1.getModelCapabilities)(minimaxConfig.model);
|
|
22
48
|
const client = new openai_1.default({
|
|
23
49
|
apiKey: minimaxConfig.apiKey,
|
|
24
50
|
baseURL: "https://api.minimaxi.chat/v1",
|
|
@@ -29,6 +55,7 @@ function createMinimaxProviderRuntime() {
|
|
|
29
55
|
id: "minimax",
|
|
30
56
|
model: minimaxConfig.model,
|
|
31
57
|
client,
|
|
58
|
+
capabilities: new Set(),
|
|
32
59
|
resetTurnState(_messages) {
|
|
33
60
|
// No provider-owned turn state for chat-completions providers.
|
|
34
61
|
},
|
|
@@ -47,7 +74,10 @@ function createMinimaxProviderRuntime() {
|
|
|
47
74
|
params.metadata = { trace_id: request.traceId };
|
|
48
75
|
if (request.toolChoiceRequired)
|
|
49
76
|
params.tool_choice = "required";
|
|
50
|
-
return (0, streaming_1.streamChatCompletion)(this.client, params, request.callbacks, request.signal);
|
|
77
|
+
return (0, streaming_1.streamChatCompletion)(this.client, params, request.callbacks, request.signal, request.eagerFinalAnswerStreaming);
|
|
78
|
+
},
|
|
79
|
+
classifyError(error) {
|
|
80
|
+
return classifyMinimaxError(error);
|
|
51
81
|
},
|
|
52
82
|
};
|
|
53
83
|
}
|