@ouro.bot/cli 0.1.0-alpha.1 → 0.1.0-alpha.100
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/agent.json +70 -9
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +5 -2
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
- package/README.md +147 -205
- package/assets/ouroboros.png +0 -0
- package/changelog.json +596 -0
- package/dist/heart/active-work.js +251 -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 +109 -0
- package/dist/heart/config.js +102 -23
- package/dist/heart/core.js +512 -94
- 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 +1935 -185
- package/dist/heart/daemon/daemon-entry.js +55 -6
- package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
- package/dist/heart/daemon/daemon.js +218 -9
- package/dist/heart/daemon/hatch-animation.js +35 -0
- package/dist/heart/daemon/hatch-flow.js +10 -83
- package/dist/heart/daemon/hatch-specialist.js +6 -1
- 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 +147 -0
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/os-cron.js +260 -0
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-bot-wrapper.js +4 -3
- package/dist/heart/daemon/ouro-path-installer.js +260 -0
- 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 +32 -2
- package/dist/heart/daemon/run-hooks.js +37 -0
- package/dist/heart/daemon/runtime-logging.js +61 -14
- 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 +307 -0
- 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 +129 -0
- package/dist/heart/daemon/specialist-prompt.js +99 -0
- package/dist/heart/daemon/specialist-tools.js +283 -0
- package/dist/heart/daemon/staged-restart.js +114 -0
- package/dist/heart/daemon/task-scheduler.js +4 -1
- 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 +153 -23
- package/dist/heart/kicks.js +1 -19
- package/dist/heart/model-capabilities.js +48 -0
- package/dist/heart/obligations.js +191 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/providers/anthropic.js +77 -9
- package/dist/heart/providers/azure.js +86 -7
- package/dist/heart/providers/github-copilot.js +149 -0
- package/dist/heart/providers/minimax.js +4 -0
- package/dist/heart/providers/openai-codex.js +12 -3
- package/dist/heart/safe-workspace.js +381 -0
- package/dist/heart/sense-truth.js +61 -0
- package/dist/heart/session-activity.js +169 -0
- package/dist/heart/session-recall.js +116 -0
- package/dist/heart/streaming.js +103 -22
- package/dist/heart/target-resolution.js +123 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/mind/associative-recall.js +37 -4
- package/dist/mind/bundle-manifest.js +70 -0
- package/dist/mind/context.js +141 -11
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +43 -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 +9 -1
- package/dist/mind/memory.js +89 -26
- package/dist/mind/obligation-steering.js +31 -0
- package/dist/mind/pending.js +160 -0
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt-refresh.js +20 -0
- package/dist/mind/prompt.js +499 -8
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +15 -2
- package/dist/nerves/coverage/file-completeness.js +14 -4
- 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/feedback.js +210 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +69 -4
- package/dist/repertoire/coding/spawner.js +21 -3
- package/dist/repertoire/coding/tools.js +105 -2
- 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 +770 -213
- 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 +484 -0
- package/dist/senses/bluebubbles-entry.js +13 -0
- package/dist/senses/bluebubbles-inbound-log.js +109 -0
- package/dist/senses/bluebubbles-media.js +339 -0
- package/dist/senses/bluebubbles-model.js +261 -0
- package/dist/senses/bluebubbles-mutation-log.js +116 -0
- package/dist/senses/bluebubbles-runtime-state.js +109 -0
- package/dist/senses/bluebubbles-session-cleanup.js +72 -0
- package/dist/senses/bluebubbles.js +1181 -0
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +452 -99
- 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 +387 -70
- package/dist/senses/pipeline.js +307 -0
- package/dist/senses/session-lock.js +119 -0
- package/dist/senses/teams.js +574 -129
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +16 -4
- package/subagents/README.md +4 -68
- package/dist/heart/daemon/subagent-installer.js +0 -125
- package/dist/inner-worker-entry.js +0 -4
- package/subagents/work-doer.md +0 -233
- package/subagents/work-merger.md +0 -593
- package/subagents/work-planner.md +0 -373
|
@@ -0,0 +1,191 @@
|
|
|
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.isOpenObligationStatus = isOpenObligationStatus;
|
|
37
|
+
exports.isOpenObligation = isOpenObligation;
|
|
38
|
+
exports.createObligation = createObligation;
|
|
39
|
+
exports.readObligations = readObligations;
|
|
40
|
+
exports.readPendingObligations = readPendingObligations;
|
|
41
|
+
exports.advanceObligation = advanceObligation;
|
|
42
|
+
exports.fulfillObligation = fulfillObligation;
|
|
43
|
+
exports.findPendingObligationForOrigin = findPendingObligationForOrigin;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const runtime_1 = require("../nerves/runtime");
|
|
47
|
+
function obligationsDir(agentRoot) {
|
|
48
|
+
return path.join(agentRoot, "state", "obligations");
|
|
49
|
+
}
|
|
50
|
+
function obligationFilePath(agentRoot, id) {
|
|
51
|
+
return path.join(obligationsDir(agentRoot), `${id}.json`);
|
|
52
|
+
}
|
|
53
|
+
function generateId() {
|
|
54
|
+
const timestamp = Date.now();
|
|
55
|
+
const random = Math.random().toString(36).slice(2, 10);
|
|
56
|
+
return `${timestamp}-${random}`;
|
|
57
|
+
}
|
|
58
|
+
function isOpenObligationStatus(status) {
|
|
59
|
+
return status !== "fulfilled";
|
|
60
|
+
}
|
|
61
|
+
function isOpenObligation(obligation) {
|
|
62
|
+
return isOpenObligationStatus(obligation.status);
|
|
63
|
+
}
|
|
64
|
+
function createObligation(agentRoot, input) {
|
|
65
|
+
const now = new Date().toISOString();
|
|
66
|
+
const id = generateId();
|
|
67
|
+
const obligation = {
|
|
68
|
+
id,
|
|
69
|
+
origin: input.origin,
|
|
70
|
+
...(input.bridgeId ? { bridgeId: input.bridgeId } : {}),
|
|
71
|
+
content: input.content,
|
|
72
|
+
status: "pending",
|
|
73
|
+
createdAt: now,
|
|
74
|
+
updatedAt: now,
|
|
75
|
+
};
|
|
76
|
+
const dir = obligationsDir(agentRoot);
|
|
77
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
78
|
+
fs.writeFileSync(obligationFilePath(agentRoot, id), JSON.stringify(obligation, null, 2), "utf-8");
|
|
79
|
+
(0, runtime_1.emitNervesEvent)({
|
|
80
|
+
component: "engine",
|
|
81
|
+
event: "engine.obligation_created",
|
|
82
|
+
message: "obligation created",
|
|
83
|
+
meta: {
|
|
84
|
+
obligationId: id,
|
|
85
|
+
friendId: input.origin.friendId,
|
|
86
|
+
channel: input.origin.channel,
|
|
87
|
+
key: input.origin.key,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
return obligation;
|
|
91
|
+
}
|
|
92
|
+
function readObligations(agentRoot) {
|
|
93
|
+
const dir = obligationsDir(agentRoot);
|
|
94
|
+
if (!fs.existsSync(dir))
|
|
95
|
+
return [];
|
|
96
|
+
let entries;
|
|
97
|
+
try {
|
|
98
|
+
entries = fs.readdirSync(dir);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
/* v8 ignore next -- defensive: readdirSync race after existsSync @preserve */
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
const jsonFiles = entries.filter((entry) => entry.endsWith(".json")).sort();
|
|
105
|
+
const obligations = [];
|
|
106
|
+
for (const file of jsonFiles) {
|
|
107
|
+
try {
|
|
108
|
+
const raw = fs.readFileSync(path.join(dir, file), "utf-8");
|
|
109
|
+
const parsed = JSON.parse(raw);
|
|
110
|
+
if (typeof parsed.id === "string" && typeof parsed.content === "string") {
|
|
111
|
+
obligations.push(parsed);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// skip malformed files
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return obligations;
|
|
119
|
+
}
|
|
120
|
+
function readPendingObligations(agentRoot) {
|
|
121
|
+
return readObligations(agentRoot).filter(isOpenObligation);
|
|
122
|
+
}
|
|
123
|
+
function advanceObligation(agentRoot, obligationId, update) {
|
|
124
|
+
const filePath = obligationFilePath(agentRoot, obligationId);
|
|
125
|
+
let obligation;
|
|
126
|
+
try {
|
|
127
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
128
|
+
obligation = JSON.parse(raw);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const previousStatus = obligation.status;
|
|
134
|
+
if (update.status) {
|
|
135
|
+
obligation.status = update.status;
|
|
136
|
+
if (update.status === "fulfilled") {
|
|
137
|
+
obligation.fulfilledAt = new Date().toISOString();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (update.currentSurface) {
|
|
141
|
+
obligation.currentSurface = update.currentSurface;
|
|
142
|
+
}
|
|
143
|
+
if (typeof update.latestNote === "string") {
|
|
144
|
+
obligation.latestNote = update.latestNote;
|
|
145
|
+
}
|
|
146
|
+
obligation.updatedAt = new Date().toISOString();
|
|
147
|
+
fs.writeFileSync(filePath, JSON.stringify(obligation, null, 2), "utf-8");
|
|
148
|
+
(0, runtime_1.emitNervesEvent)({
|
|
149
|
+
component: "engine",
|
|
150
|
+
event: "engine.obligation_advanced",
|
|
151
|
+
message: "obligation advanced",
|
|
152
|
+
meta: {
|
|
153
|
+
obligationId,
|
|
154
|
+
previousStatus,
|
|
155
|
+
status: obligation.status,
|
|
156
|
+
friendId: obligation.origin.friendId,
|
|
157
|
+
channel: obligation.origin.channel,
|
|
158
|
+
key: obligation.origin.key,
|
|
159
|
+
surfaceKind: obligation.currentSurface?.kind ?? null,
|
|
160
|
+
surfaceLabel: obligation.currentSurface?.label ?? null,
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function fulfillObligation(agentRoot, obligationId) {
|
|
165
|
+
advanceObligation(agentRoot, obligationId, { status: "fulfilled" });
|
|
166
|
+
const filePath = obligationFilePath(agentRoot, obligationId);
|
|
167
|
+
let obligation;
|
|
168
|
+
try {
|
|
169
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
170
|
+
obligation = JSON.parse(raw);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
(0, runtime_1.emitNervesEvent)({
|
|
176
|
+
component: "engine",
|
|
177
|
+
event: "engine.obligation_fulfilled",
|
|
178
|
+
message: "obligation fulfilled",
|
|
179
|
+
meta: {
|
|
180
|
+
obligationId,
|
|
181
|
+
friendId: obligation.origin.friendId,
|
|
182
|
+
channel: obligation.origin.channel,
|
|
183
|
+
key: obligation.origin.key,
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
function findPendingObligationForOrigin(agentRoot, origin) {
|
|
188
|
+
return readPendingObligations(agentRoot).find((ob) => ob.origin.friendId === origin.friendId
|
|
189
|
+
&& ob.origin.channel === origin.channel
|
|
190
|
+
&& ob.origin.key === origin.key);
|
|
191
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildProgressStory = buildProgressStory;
|
|
4
|
+
exports.renderProgressStory = renderProgressStory;
|
|
5
|
+
const runtime_1 = require("../nerves/runtime");
|
|
6
|
+
function labelForScope(scope) {
|
|
7
|
+
return scope === "inner-delegation" ? "inner work" : "shared work";
|
|
8
|
+
}
|
|
9
|
+
function compactDetail(text) {
|
|
10
|
+
if (typeof text !== "string")
|
|
11
|
+
return null;
|
|
12
|
+
const trimmed = text.trim();
|
|
13
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
14
|
+
}
|
|
15
|
+
function buildProgressStory(input) {
|
|
16
|
+
const detailLines = [
|
|
17
|
+
compactDetail(input.objective),
|
|
18
|
+
compactDetail(input.outcomeText),
|
|
19
|
+
compactDetail(input.bridgeId ? `bridge: ${input.bridgeId}` : null),
|
|
20
|
+
compactDetail(input.taskName ? `task: ${input.taskName}` : null),
|
|
21
|
+
].filter((line) => Boolean(line));
|
|
22
|
+
const story = {
|
|
23
|
+
statusLine: `${labelForScope(input.scope)}: ${input.phase}`,
|
|
24
|
+
detailLines,
|
|
25
|
+
};
|
|
26
|
+
(0, runtime_1.emitNervesEvent)({
|
|
27
|
+
component: "engine",
|
|
28
|
+
event: "engine.progress_story_build",
|
|
29
|
+
message: "built shared progress story",
|
|
30
|
+
meta: {
|
|
31
|
+
scope: input.scope,
|
|
32
|
+
phase: input.phase,
|
|
33
|
+
detailLines: detailLines.length,
|
|
34
|
+
hasBridge: Boolean(input.bridgeId),
|
|
35
|
+
hasTask: Boolean(input.taskName),
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
return story;
|
|
39
|
+
}
|
|
40
|
+
function renderProgressStory(story) {
|
|
41
|
+
return [story.statusLine, ...story.detailLines].join("\n");
|
|
42
|
+
}
|
|
@@ -3,11 +3,14 @@ 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;
|
|
6
7
|
exports.createAnthropicProviderRuntime = createAnthropicProviderRuntime;
|
|
7
8
|
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
8
9
|
const config_1 = require("../config");
|
|
9
10
|
const identity_1 = require("../identity");
|
|
10
11
|
const runtime_1 = require("../../nerves/runtime");
|
|
12
|
+
const streaming_1 = require("../streaming");
|
|
13
|
+
const model_capabilities_1 = require("../model-capabilities");
|
|
11
14
|
const ANTHROPIC_SETUP_TOKEN_PREFIX = "sk-ant-oat01-";
|
|
12
15
|
const ANTHROPIC_SETUP_TOKEN_MIN_LENGTH = 80;
|
|
13
16
|
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 +24,10 @@ function getAnthropicSetupTokenInstructions() {
|
|
|
21
24
|
const agentName = getAnthropicAgentNameForGuidance();
|
|
22
25
|
return [
|
|
23
26
|
"Fix:",
|
|
24
|
-
` 1. Run \`
|
|
25
|
-
" (or run `claude setup-token` and paste the token manually)",
|
|
27
|
+
` 1. Run \`ouro auth --agent ${agentName}\``,
|
|
26
28
|
` 2. Open ${getAnthropicSecretsPathForGuidance()}`,
|
|
27
29
|
" 3. Confirm providers.anthropic.setupToken is set",
|
|
30
|
+
" 4. After reauth, retry the failed ouro command or reconnect this session.",
|
|
28
31
|
].join("\n");
|
|
29
32
|
}
|
|
30
33
|
function getAnthropicReauthGuidance(reason) {
|
|
@@ -92,12 +95,27 @@ function toAnthropicMessages(messages) {
|
|
|
92
95
|
if (msg.role === "assistant") {
|
|
93
96
|
const assistant = msg;
|
|
94
97
|
const blocks = [];
|
|
98
|
+
// Restore thinking blocks before text/tool_use blocks
|
|
99
|
+
const thinkingBlocks = assistant._thinking_blocks;
|
|
100
|
+
if (thinkingBlocks) {
|
|
101
|
+
for (const tb of thinkingBlocks) {
|
|
102
|
+
if (tb.type === "thinking") {
|
|
103
|
+
blocks.push({ type: "thinking", thinking: tb.thinking, signature: tb.signature });
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
blocks.push({ type: "redacted_thinking", data: tb.data });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
95
110
|
const text = toAnthropicTextContent(assistant.content);
|
|
96
111
|
if (text) {
|
|
97
112
|
blocks.push({ type: "text", text });
|
|
98
113
|
}
|
|
99
114
|
if (assistant.tool_calls) {
|
|
100
115
|
for (const toolCall of assistant.tool_calls) {
|
|
116
|
+
/* v8 ignore next -- type narrowing: OpenAI SDK only emits function tool_calls @preserve */
|
|
117
|
+
if (toolCall.type !== "function")
|
|
118
|
+
continue;
|
|
101
119
|
blocks.push({
|
|
102
120
|
type: "tool_use",
|
|
103
121
|
id: toolCall.id,
|
|
@@ -191,11 +209,14 @@ function withAnthropicAuthGuidance(error) {
|
|
|
191
209
|
async function streamAnthropicMessages(client, model, request) {
|
|
192
210
|
const { system, messages } = toAnthropicMessages(request.messages);
|
|
193
211
|
const anthropicTools = toAnthropicTools(request.activeTools);
|
|
212
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
|
|
213
|
+
const maxTokens = modelCaps.maxOutputTokens ?? 16384;
|
|
194
214
|
const params = {
|
|
195
215
|
model,
|
|
196
|
-
max_tokens:
|
|
216
|
+
max_tokens: maxTokens,
|
|
197
217
|
messages,
|
|
198
218
|
stream: true,
|
|
219
|
+
thinking: { type: "adaptive", effort: request.reasoningEffort ?? "medium" },
|
|
199
220
|
};
|
|
200
221
|
if (system)
|
|
201
222
|
params.system = system;
|
|
@@ -215,6 +236,9 @@ async function streamAnthropicMessages(client, model, request) {
|
|
|
215
236
|
let streamStarted = false;
|
|
216
237
|
let usage;
|
|
217
238
|
const toolCalls = new Map();
|
|
239
|
+
const thinkingBlocks = new Map();
|
|
240
|
+
const redactedBlocks = new Map();
|
|
241
|
+
const answerStreamer = new streaming_1.FinalAnswerStreamer(request.callbacks);
|
|
218
242
|
try {
|
|
219
243
|
for await (const event of response) {
|
|
220
244
|
if (request.signal?.aborted)
|
|
@@ -222,17 +246,29 @@ async function streamAnthropicMessages(client, model, request) {
|
|
|
222
246
|
const eventType = String(event.type ?? "");
|
|
223
247
|
if (eventType === "content_block_start") {
|
|
224
248
|
const block = event.content_block;
|
|
225
|
-
|
|
226
|
-
|
|
249
|
+
const index = Number(event.index);
|
|
250
|
+
if (block?.type === "thinking") {
|
|
251
|
+
thinkingBlocks.set(index, { type: "thinking", thinking: "", signature: "" });
|
|
252
|
+
}
|
|
253
|
+
else if (block?.type === "redacted_thinking") {
|
|
254
|
+
redactedBlocks.set(index, { type: "redacted_thinking", data: String(block.data ?? "") });
|
|
255
|
+
}
|
|
256
|
+
else if (block?.type === "tool_use") {
|
|
227
257
|
const rawInput = block.input;
|
|
228
258
|
const input = rawInput && typeof rawInput === "object"
|
|
229
259
|
? JSON.stringify(rawInput)
|
|
230
260
|
: "";
|
|
261
|
+
const name = String(block.name ?? "");
|
|
231
262
|
toolCalls.set(index, {
|
|
232
263
|
id: String(block.id ?? ""),
|
|
233
|
-
name
|
|
264
|
+
name,
|
|
234
265
|
arguments: input,
|
|
235
266
|
});
|
|
267
|
+
// Activate eager streaming for sole final_answer tool call
|
|
268
|
+
/* v8 ignore next -- final_answer streaming activation, tested via FinalAnswerStreamer unit tests @preserve */
|
|
269
|
+
if (name === "final_answer" && toolCalls.size === 1) {
|
|
270
|
+
answerStreamer.activate();
|
|
271
|
+
}
|
|
236
272
|
}
|
|
237
273
|
continue;
|
|
238
274
|
}
|
|
@@ -254,14 +290,31 @@ async function streamAnthropicMessages(client, model, request) {
|
|
|
254
290
|
request.callbacks.onModelStreamStart();
|
|
255
291
|
streamStarted = true;
|
|
256
292
|
}
|
|
257
|
-
|
|
293
|
+
const thinkingText = String(delta?.thinking ?? "");
|
|
294
|
+
request.callbacks.onReasoningChunk(thinkingText);
|
|
295
|
+
const thinkingIndex = Number(event.index);
|
|
296
|
+
const thinkingBlock = thinkingBlocks.get(thinkingIndex);
|
|
297
|
+
if (thinkingBlock)
|
|
298
|
+
thinkingBlock.thinking += thinkingText;
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (deltaType === "signature_delta") {
|
|
302
|
+
const sigIndex = Number(event.index);
|
|
303
|
+
const sigBlock = thinkingBlocks.get(sigIndex);
|
|
304
|
+
if (sigBlock)
|
|
305
|
+
sigBlock.signature += String(delta?.signature ?? "");
|
|
258
306
|
continue;
|
|
259
307
|
}
|
|
260
308
|
if (deltaType === "input_json_delta") {
|
|
261
309
|
const index = Number(event.index);
|
|
262
310
|
const existing = toolCalls.get(index);
|
|
263
311
|
if (existing) {
|
|
264
|
-
|
|
312
|
+
const partialJson = String(delta?.partial_json ?? "");
|
|
313
|
+
existing.arguments = mergeAnthropicToolArguments(existing.arguments, partialJson);
|
|
314
|
+
/* v8 ignore next -- final_answer delta streaming, tested via FinalAnswerStreamer unit tests @preserve */
|
|
315
|
+
if (existing.name === "final_answer" && toolCalls.size === 1) {
|
|
316
|
+
answerStreamer.processDelta(partialJson);
|
|
317
|
+
}
|
|
265
318
|
}
|
|
266
319
|
continue;
|
|
267
320
|
}
|
|
@@ -285,11 +338,20 @@ async function streamAnthropicMessages(client, model, request) {
|
|
|
285
338
|
catch (error) {
|
|
286
339
|
throw withAnthropicAuthGuidance(error);
|
|
287
340
|
}
|
|
341
|
+
// Collect all thinking blocks (regular + redacted) sorted by index to preserve ordering
|
|
342
|
+
const allThinkingIndices = [...thinkingBlocks.keys(), ...redactedBlocks.keys()].sort((a, b) => a - b);
|
|
343
|
+
const outputItems = allThinkingIndices.map((idx) => {
|
|
344
|
+
const tb = thinkingBlocks.get(idx);
|
|
345
|
+
if (tb)
|
|
346
|
+
return tb;
|
|
347
|
+
return redactedBlocks.get(idx);
|
|
348
|
+
});
|
|
288
349
|
return {
|
|
289
350
|
content,
|
|
290
351
|
toolCalls: [...toolCalls.values()],
|
|
291
|
-
outputItems
|
|
352
|
+
outputItems,
|
|
292
353
|
usage,
|
|
354
|
+
finalAnswerStreamed: answerStreamer.streamed,
|
|
293
355
|
};
|
|
294
356
|
}
|
|
295
357
|
function createAnthropicProviderRuntime() {
|
|
@@ -303,6 +365,10 @@ function createAnthropicProviderRuntime() {
|
|
|
303
365
|
if (!(anthropicConfig.model && anthropicConfig.setupToken)) {
|
|
304
366
|
throw new Error(getAnthropicReauthGuidance("provider 'anthropic' is selected in agent.json but providers.anthropic.model/setupToken is incomplete in secrets.json."));
|
|
305
367
|
}
|
|
368
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(anthropicConfig.model);
|
|
369
|
+
const capabilities = new Set();
|
|
370
|
+
if (modelCaps.reasoningEffort)
|
|
371
|
+
capabilities.add("reasoning-effort");
|
|
306
372
|
const credential = resolveAnthropicSetupTokenCredential();
|
|
307
373
|
const client = new sdk_1.default({
|
|
308
374
|
authToken: credential.token,
|
|
@@ -316,6 +382,8 @@ function createAnthropicProviderRuntime() {
|
|
|
316
382
|
id: "anthropic",
|
|
317
383
|
model: anthropicConfig.model,
|
|
318
384
|
client,
|
|
385
|
+
capabilities,
|
|
386
|
+
supportedReasoningEfforts: modelCaps.reasoningEffort,
|
|
319
387
|
resetTurnState(_messages) {
|
|
320
388
|
// Anthropic request payload is derived from canonical messages each turn.
|
|
321
389
|
},
|
|
@@ -1,35 +1,114 @@
|
|
|
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.createAzureTokenProvider = createAzureTokenProvider;
|
|
3
37
|
exports.createAzureProviderRuntime = createAzureProviderRuntime;
|
|
4
38
|
const openai_1 = require("openai");
|
|
5
39
|
const config_1 = require("../config");
|
|
6
40
|
const runtime_1 = require("../../nerves/runtime");
|
|
7
41
|
const streaming_1 = require("../streaming");
|
|
42
|
+
const model_capabilities_1 = require("../model-capabilities");
|
|
43
|
+
const COGNITIVE_SERVICES_SCOPE = "https://cognitiveservices.azure.com/.default";
|
|
44
|
+
// @azure/identity is imported dynamically (below) rather than at the top level
|
|
45
|
+
// because it's a heavy package (~30+ transitive deps) and we only need it when
|
|
46
|
+
// using the managed-identity auth path. API-key users and other providers
|
|
47
|
+
// shouldn't pay the cold-start cost.
|
|
48
|
+
function createAzureTokenProvider(managedIdentityClientId) {
|
|
49
|
+
let credential = null;
|
|
50
|
+
return async () => {
|
|
51
|
+
try {
|
|
52
|
+
if (!credential) {
|
|
53
|
+
const { DefaultAzureCredential } = await Promise.resolve().then(() => __importStar(require("@azure/identity")));
|
|
54
|
+
const credentialOptions = managedIdentityClientId
|
|
55
|
+
? { managedIdentityClientId }
|
|
56
|
+
: undefined;
|
|
57
|
+
credential = new DefaultAzureCredential(credentialOptions);
|
|
58
|
+
}
|
|
59
|
+
const tokenResponse = await credential.getToken(COGNITIVE_SERVICES_SCOPE);
|
|
60
|
+
return tokenResponse.token;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
64
|
+
throw new Error(`Azure OpenAI authentication failed: ${detail}\n` +
|
|
65
|
+
"To fix this, either:\n" +
|
|
66
|
+
" 1. Set providers.azure.apiKey in secrets.json, or\n" +
|
|
67
|
+
" 2. Run 'az login' to authenticate with your Azure account (for local dev), or\n" +
|
|
68
|
+
" 3. Attach a managed identity to your App Service and set providers.azure.managedIdentityClientId in secrets.json (for deployed environments)");
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
8
72
|
function createAzureProviderRuntime() {
|
|
73
|
+
const azureConfig = (0, config_1.getAzureConfig)();
|
|
74
|
+
const useApiKey = !!azureConfig.apiKey;
|
|
75
|
+
const authMethod = useApiKey ? "key" : "managed-identity";
|
|
9
76
|
(0, runtime_1.emitNervesEvent)({
|
|
10
77
|
component: "engine",
|
|
11
78
|
event: "engine.provider_init",
|
|
12
79
|
message: "azure provider init",
|
|
13
|
-
meta: { provider: "azure" },
|
|
80
|
+
meta: { provider: "azure", authMethod },
|
|
14
81
|
});
|
|
15
|
-
|
|
16
|
-
if (!(azureConfig.apiKey && azureConfig.endpoint && azureConfig.deployment && azureConfig.modelName)) {
|
|
82
|
+
if (!(azureConfig.endpoint && azureConfig.deployment && azureConfig.modelName)) {
|
|
17
83
|
throw new Error("provider 'azure' is selected in agent.json but providers.azure is incomplete in secrets.json.");
|
|
18
84
|
}
|
|
19
|
-
const
|
|
20
|
-
|
|
85
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(azureConfig.modelName);
|
|
86
|
+
const capabilities = new Set();
|
|
87
|
+
if (modelCaps.reasoningEffort)
|
|
88
|
+
capabilities.add("reasoning-effort");
|
|
89
|
+
const clientOptions = {
|
|
21
90
|
endpoint: azureConfig.endpoint.replace(/\/openai.*$/, ""),
|
|
22
91
|
deployment: azureConfig.deployment,
|
|
23
92
|
apiVersion: azureConfig.apiVersion,
|
|
24
93
|
timeout: 30000,
|
|
25
94
|
maxRetries: 0,
|
|
26
|
-
}
|
|
95
|
+
};
|
|
96
|
+
if (useApiKey) {
|
|
97
|
+
clientOptions.apiKey = azureConfig.apiKey;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
const managedIdentityClientId = azureConfig.managedIdentityClientId || undefined;
|
|
101
|
+
clientOptions.azureADTokenProvider = createAzureTokenProvider(managedIdentityClientId);
|
|
102
|
+
}
|
|
103
|
+
const client = new openai_1.AzureOpenAI(clientOptions);
|
|
27
104
|
let nativeInput = null;
|
|
28
105
|
let nativeInstructions = "";
|
|
29
106
|
return {
|
|
30
107
|
id: "azure",
|
|
31
108
|
model: azureConfig.modelName,
|
|
32
109
|
client,
|
|
110
|
+
capabilities,
|
|
111
|
+
supportedReasoningEfforts: modelCaps.reasoningEffort,
|
|
33
112
|
resetTurnState(messages) {
|
|
34
113
|
const { instructions, input } = (0, streaming_1.toResponsesInput)(messages);
|
|
35
114
|
nativeInput = input;
|
|
@@ -48,7 +127,7 @@ function createAzureProviderRuntime() {
|
|
|
48
127
|
input: nativeInput,
|
|
49
128
|
instructions: nativeInstructions,
|
|
50
129
|
tools: (0, streaming_1.toResponsesTools)(request.activeTools),
|
|
51
|
-
reasoning: { effort: "medium", summary: "detailed" },
|
|
130
|
+
reasoning: { effort: request.reasoningEffort ?? "medium", summary: "detailed" },
|
|
52
131
|
stream: true,
|
|
53
132
|
store: false,
|
|
54
133
|
include: ["reasoning.encrypted_content"],
|