@ouro.bot/cli 0.0.1-alpha.0 → 0.1.0-alpha.1
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 +20 -0
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +22 -0
- package/AdoptionSpecialist.ouro/psyche/identities/basilisk.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/jafar.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/jormungandr.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/kaa.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/medusa.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/nagini.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/ouroboros.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/python.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/quetzalcoatl.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/sir-hiss.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/the-serpent.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/the-snake.md +31 -0
- package/README.md +224 -6
- package/dist/heart/agent-entry.js +17 -0
- package/dist/heart/api-error.js +34 -0
- package/dist/heart/config.js +296 -0
- package/dist/heart/core.js +485 -0
- package/dist/heart/daemon/daemon-cli.js +626 -0
- package/dist/heart/daemon/daemon-entry.js +74 -0
- package/dist/heart/daemon/daemon.js +310 -0
- package/dist/heart/daemon/hatch-flow.js +284 -0
- package/dist/heart/daemon/hatch-specialist.js +107 -0
- package/dist/heart/daemon/health-monitor.js +79 -0
- package/dist/heart/daemon/message-router.js +98 -0
- package/dist/heart/daemon/ouro-bot-entry.js +23 -0
- package/dist/heart/daemon/ouro-bot-wrapper.js +90 -0
- package/dist/heart/daemon/ouro-entry.js +23 -0
- package/dist/heart/daemon/ouro-uti.js +212 -0
- package/dist/heart/daemon/process-manager.js +220 -0
- package/dist/heart/daemon/runtime-logging.js +98 -0
- package/dist/heart/daemon/subagent-installer.js +125 -0
- package/dist/heart/daemon/task-scheduler.js +237 -0
- package/dist/heart/harness.js +26 -0
- package/dist/heart/identity.js +270 -0
- package/dist/heart/kicks.js +144 -0
- package/dist/heart/primitives.js +4 -0
- package/dist/heart/providers/anthropic.js +329 -0
- package/dist/heart/providers/azure.js +66 -0
- package/dist/heart/providers/minimax.js +53 -0
- package/dist/heart/providers/openai-codex.js +162 -0
- package/dist/heart/streaming.js +412 -0
- package/dist/heart/turn-coordinator.js +62 -0
- package/dist/inner-worker-entry.js +4 -0
- package/dist/mind/associative-recall.js +176 -0
- package/dist/mind/bundle-manifest.js +118 -0
- package/dist/mind/context.js +218 -0
- package/dist/mind/first-impressions.js +43 -0
- package/dist/mind/format.js +56 -0
- package/dist/mind/friends/channel.js +41 -0
- package/dist/mind/friends/resolver.js +84 -0
- package/dist/mind/friends/store-file.js +171 -0
- package/dist/mind/friends/store.js +4 -0
- package/dist/mind/friends/tokens.js +26 -0
- package/dist/mind/friends/types.js +21 -0
- package/dist/mind/memory.js +326 -0
- package/dist/mind/phrases.js +43 -0
- package/dist/mind/prompt.js +254 -0
- package/dist/mind/token-estimate.js +119 -0
- package/dist/nerves/cli-logging.js +31 -0
- package/dist/nerves/coverage/audit-rules.js +81 -0
- package/dist/nerves/coverage/audit.js +200 -0
- package/dist/nerves/coverage/cli-main.js +5 -0
- package/dist/nerves/coverage/cli.js +51 -0
- package/dist/nerves/coverage/contract.js +23 -0
- package/dist/nerves/coverage/file-completeness.js +46 -0
- package/dist/nerves/coverage/run-artifacts.js +77 -0
- package/dist/nerves/coverage/source-scanner.js +34 -0
- package/dist/nerves/index.js +152 -0
- package/dist/nerves/runtime.js +38 -0
- package/dist/repertoire/ado-client.js +211 -0
- package/dist/repertoire/ado-context.js +73 -0
- package/dist/repertoire/ado-semantic.js +841 -0
- package/dist/repertoire/ado-templates.js +146 -0
- package/dist/repertoire/coding/index.js +36 -0
- package/dist/repertoire/coding/manager.js +489 -0
- package/dist/repertoire/coding/monitor.js +60 -0
- package/dist/repertoire/coding/reporter.js +45 -0
- package/dist/repertoire/coding/spawner.js +102 -0
- package/dist/repertoire/coding/tools.js +167 -0
- package/dist/repertoire/coding/types.js +2 -0
- package/dist/repertoire/data/ado-endpoints.json +122 -0
- package/dist/repertoire/data/graph-endpoints.json +212 -0
- package/dist/repertoire/github-client.js +64 -0
- package/dist/repertoire/graph-client.js +118 -0
- package/dist/repertoire/skills.js +156 -0
- package/dist/repertoire/tasks/board.js +122 -0
- package/dist/repertoire/tasks/index.js +210 -0
- package/dist/repertoire/tasks/lifecycle.js +80 -0
- package/dist/repertoire/tasks/middleware.js +65 -0
- package/dist/repertoire/tasks/parser.js +173 -0
- package/dist/repertoire/tasks/scanner.js +132 -0
- package/dist/repertoire/tasks/transitions.js +145 -0
- package/dist/repertoire/tasks/types.js +2 -0
- package/dist/repertoire/tools-base.js +622 -0
- package/dist/repertoire/tools-github.js +53 -0
- package/dist/repertoire/tools-teams.js +308 -0
- package/dist/repertoire/tools.js +199 -0
- package/dist/senses/cli-entry.js +15 -0
- package/dist/senses/cli.js +523 -0
- package/dist/senses/commands.js +98 -0
- package/dist/senses/inner-dialog-worker.js +61 -0
- package/dist/senses/inner-dialog.js +216 -0
- package/dist/senses/teams-entry.js +15 -0
- package/dist/senses/teams.js +695 -0
- package/dist/senses/trust-gate.js +150 -0
- package/package.json +34 -11
- package/subagents/README.md +71 -0
- package/subagents/work-doer.md +233 -0
- package/subagents/work-merger.md +593 -0
- package/subagents/work-planner.md +373 -0
- package/bin/ouro.js +0 -6
|
@@ -0,0 +1,329 @@
|
|
|
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.createAnthropicProviderRuntime = createAnthropicProviderRuntime;
|
|
7
|
+
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
8
|
+
const config_1 = require("../config");
|
|
9
|
+
const identity_1 = require("../identity");
|
|
10
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
11
|
+
const ANTHROPIC_SETUP_TOKEN_PREFIX = "sk-ant-oat01-";
|
|
12
|
+
const ANTHROPIC_SETUP_TOKEN_MIN_LENGTH = 80;
|
|
13
|
+
const ANTHROPIC_OAUTH_BETA_HEADER = "claude-code-20250219,oauth-2025-04-20,fine-grained-tool-streaming-2025-05-14,interleaved-thinking-2025-05-14";
|
|
14
|
+
function getAnthropicSecretsPathForGuidance() {
|
|
15
|
+
return (0, identity_1.getAgentSecretsPath)();
|
|
16
|
+
}
|
|
17
|
+
function getAnthropicAgentNameForGuidance() {
|
|
18
|
+
return (0, identity_1.getAgentName)();
|
|
19
|
+
}
|
|
20
|
+
function getAnthropicSetupTokenInstructions() {
|
|
21
|
+
const agentName = getAnthropicAgentNameForGuidance();
|
|
22
|
+
return [
|
|
23
|
+
"Fix:",
|
|
24
|
+
` 1. Run \`npm run auth:claude-setup-token -- --agent ${agentName}\``,
|
|
25
|
+
" (or run `claude setup-token` and paste the token manually)",
|
|
26
|
+
` 2. Open ${getAnthropicSecretsPathForGuidance()}`,
|
|
27
|
+
" 3. Confirm providers.anthropic.setupToken is set",
|
|
28
|
+
].join("\n");
|
|
29
|
+
}
|
|
30
|
+
function getAnthropicReauthGuidance(reason) {
|
|
31
|
+
return [
|
|
32
|
+
"Anthropic configuration error.",
|
|
33
|
+
reason,
|
|
34
|
+
getAnthropicSetupTokenInstructions(),
|
|
35
|
+
].join("\n");
|
|
36
|
+
}
|
|
37
|
+
function resolveAnthropicSetupTokenCredential() {
|
|
38
|
+
const anthropicConfig = (0, config_1.getAnthropicConfig)();
|
|
39
|
+
const token = anthropicConfig.setupToken?.trim();
|
|
40
|
+
if (!token) {
|
|
41
|
+
throw new Error(getAnthropicReauthGuidance("Anthropic provider is selected but no setup-token credential was found."));
|
|
42
|
+
}
|
|
43
|
+
if (!token.startsWith(ANTHROPIC_SETUP_TOKEN_PREFIX)) {
|
|
44
|
+
throw new Error(getAnthropicReauthGuidance(`Anthropic credential is not a setup-token (expected prefix ${ANTHROPIC_SETUP_TOKEN_PREFIX}).`));
|
|
45
|
+
}
|
|
46
|
+
if (token.length < ANTHROPIC_SETUP_TOKEN_MIN_LENGTH) {
|
|
47
|
+
throw new Error(getAnthropicReauthGuidance("Anthropic setup-token looks too short."));
|
|
48
|
+
}
|
|
49
|
+
return { token };
|
|
50
|
+
}
|
|
51
|
+
function toAnthropicTextContent(content) {
|
|
52
|
+
if (typeof content === "string")
|
|
53
|
+
return content;
|
|
54
|
+
if (!Array.isArray(content))
|
|
55
|
+
return "";
|
|
56
|
+
return content
|
|
57
|
+
.filter((part) => (typeof part === "object" &&
|
|
58
|
+
part !== null &&
|
|
59
|
+
part.type === "text"))
|
|
60
|
+
.map((part) => (typeof part.text === "string" ? part.text : ""))
|
|
61
|
+
.join("\n");
|
|
62
|
+
}
|
|
63
|
+
function parseToolCallInput(argumentsJson) {
|
|
64
|
+
if (!argumentsJson.trim())
|
|
65
|
+
return {};
|
|
66
|
+
try {
|
|
67
|
+
const parsed = JSON.parse(argumentsJson);
|
|
68
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return {};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function toAnthropicMessages(messages) {
|
|
75
|
+
let system;
|
|
76
|
+
const converted = [];
|
|
77
|
+
for (const msg of messages) {
|
|
78
|
+
if (msg.role === "system") {
|
|
79
|
+
if (!system) {
|
|
80
|
+
const text = toAnthropicTextContent(msg.content);
|
|
81
|
+
system = text || undefined;
|
|
82
|
+
}
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (msg.role === "user") {
|
|
86
|
+
converted.push({
|
|
87
|
+
role: "user",
|
|
88
|
+
content: toAnthropicTextContent(msg.content),
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (msg.role === "assistant") {
|
|
93
|
+
const assistant = msg;
|
|
94
|
+
const blocks = [];
|
|
95
|
+
const text = toAnthropicTextContent(assistant.content);
|
|
96
|
+
if (text) {
|
|
97
|
+
blocks.push({ type: "text", text });
|
|
98
|
+
}
|
|
99
|
+
if (assistant.tool_calls) {
|
|
100
|
+
for (const toolCall of assistant.tool_calls) {
|
|
101
|
+
blocks.push({
|
|
102
|
+
type: "tool_use",
|
|
103
|
+
id: toolCall.id,
|
|
104
|
+
name: toolCall.function.name,
|
|
105
|
+
input: parseToolCallInput(toolCall.function.arguments),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (blocks.length === 0) {
|
|
110
|
+
blocks.push({ type: "text", text: "" });
|
|
111
|
+
}
|
|
112
|
+
converted.push({ role: "assistant", content: blocks });
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (msg.role === "tool") {
|
|
116
|
+
const tool = msg;
|
|
117
|
+
converted.push({
|
|
118
|
+
role: "user",
|
|
119
|
+
content: [
|
|
120
|
+
{
|
|
121
|
+
type: "tool_result",
|
|
122
|
+
tool_use_id: tool.tool_call_id,
|
|
123
|
+
content: toAnthropicTextContent(tool.content),
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { system, messages: converted };
|
|
130
|
+
}
|
|
131
|
+
function toAnthropicTools(tools) {
|
|
132
|
+
return tools.map((tool) => ({
|
|
133
|
+
name: tool.function.name,
|
|
134
|
+
description: tool.function.description ?? "",
|
|
135
|
+
input_schema: tool.function.parameters ?? { type: "object", properties: {} },
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
function toAnthropicUsage(raw) {
|
|
139
|
+
const inputTokens = Number(raw.input_tokens ?? 0) || 0;
|
|
140
|
+
const cacheCreateTokens = Number(raw.cache_creation_input_tokens ?? 0) || 0;
|
|
141
|
+
const cacheReadTokens = Number(raw.cache_read_input_tokens ?? 0) || 0;
|
|
142
|
+
const outputTokens = Number(raw.output_tokens ?? 0) || 0;
|
|
143
|
+
const totalInputTokens = inputTokens + cacheCreateTokens + cacheReadTokens;
|
|
144
|
+
return {
|
|
145
|
+
input_tokens: totalInputTokens,
|
|
146
|
+
output_tokens: outputTokens,
|
|
147
|
+
reasoning_tokens: 0,
|
|
148
|
+
total_tokens: totalInputTokens + outputTokens,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function mergeAnthropicToolArguments(current, partial) {
|
|
152
|
+
if (!partial)
|
|
153
|
+
return current;
|
|
154
|
+
const trimmedCurrent = current.trim();
|
|
155
|
+
const trimmedPartial = partial.trim();
|
|
156
|
+
// If streaming restarts with a full JSON object/array fragment, trust it.
|
|
157
|
+
if (trimmedPartial.startsWith("{") || trimmedPartial.startsWith("[")) {
|
|
158
|
+
return partial;
|
|
159
|
+
}
|
|
160
|
+
// Anthropic can emit block.input as a complete object and then emit
|
|
161
|
+
// additional members as ',\"k\":v' deltas; merge those safely.
|
|
162
|
+
if (trimmedCurrent.startsWith("{") && trimmedCurrent.endsWith("}")) {
|
|
163
|
+
const inner = trimmedCurrent.slice(1, -1).trim();
|
|
164
|
+
let suffix = partial;
|
|
165
|
+
if (!inner && suffix.startsWith(",")) {
|
|
166
|
+
suffix = suffix.slice(1);
|
|
167
|
+
}
|
|
168
|
+
return `{${inner}${suffix}}`;
|
|
169
|
+
}
|
|
170
|
+
return current + partial;
|
|
171
|
+
}
|
|
172
|
+
function isAnthropicAuthFailure(error) {
|
|
173
|
+
if (!(error instanceof Error))
|
|
174
|
+
return false;
|
|
175
|
+
const status = error.status;
|
|
176
|
+
if (status === 401 || status === 403)
|
|
177
|
+
return true;
|
|
178
|
+
const lower = error.message.toLowerCase();
|
|
179
|
+
return (lower.includes("oauth authentication") ||
|
|
180
|
+
lower.includes("authentication failed") ||
|
|
181
|
+
lower.includes("unauthorized") ||
|
|
182
|
+
lower.includes("invalid api key"));
|
|
183
|
+
}
|
|
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
|
+
}
|
|
191
|
+
async function streamAnthropicMessages(client, model, request) {
|
|
192
|
+
const { system, messages } = toAnthropicMessages(request.messages);
|
|
193
|
+
const anthropicTools = toAnthropicTools(request.activeTools);
|
|
194
|
+
const params = {
|
|
195
|
+
model,
|
|
196
|
+
max_tokens: 4096,
|
|
197
|
+
messages,
|
|
198
|
+
stream: true,
|
|
199
|
+
};
|
|
200
|
+
if (system)
|
|
201
|
+
params.system = system;
|
|
202
|
+
if (anthropicTools.length > 0)
|
|
203
|
+
params.tools = anthropicTools;
|
|
204
|
+
if (request.toolChoiceRequired && anthropicTools.length > 0) {
|
|
205
|
+
params.tool_choice = { type: "any" };
|
|
206
|
+
}
|
|
207
|
+
let response;
|
|
208
|
+
try {
|
|
209
|
+
response = await client.messages.create(params, request.signal ? { signal: request.signal } : {});
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
throw withAnthropicAuthGuidance(error);
|
|
213
|
+
}
|
|
214
|
+
let content = "";
|
|
215
|
+
let streamStarted = false;
|
|
216
|
+
let usage;
|
|
217
|
+
const toolCalls = new Map();
|
|
218
|
+
try {
|
|
219
|
+
for await (const event of response) {
|
|
220
|
+
if (request.signal?.aborted)
|
|
221
|
+
break;
|
|
222
|
+
const eventType = String(event.type ?? "");
|
|
223
|
+
if (eventType === "content_block_start") {
|
|
224
|
+
const block = event.content_block;
|
|
225
|
+
if (block?.type === "tool_use") {
|
|
226
|
+
const index = Number(event.index);
|
|
227
|
+
const rawInput = block.input;
|
|
228
|
+
const input = rawInput && typeof rawInput === "object"
|
|
229
|
+
? JSON.stringify(rawInput)
|
|
230
|
+
: "";
|
|
231
|
+
toolCalls.set(index, {
|
|
232
|
+
id: String(block.id ?? ""),
|
|
233
|
+
name: String(block.name ?? ""),
|
|
234
|
+
arguments: input,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (eventType === "content_block_delta") {
|
|
240
|
+
const delta = event.delta;
|
|
241
|
+
const deltaType = String(delta?.type ?? "");
|
|
242
|
+
if (deltaType === "text_delta") {
|
|
243
|
+
if (!streamStarted) {
|
|
244
|
+
request.callbacks.onModelStreamStart();
|
|
245
|
+
streamStarted = true;
|
|
246
|
+
}
|
|
247
|
+
const text = String(delta?.text ?? "");
|
|
248
|
+
content += text;
|
|
249
|
+
request.callbacks.onTextChunk(text);
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (deltaType === "thinking_delta") {
|
|
253
|
+
if (!streamStarted) {
|
|
254
|
+
request.callbacks.onModelStreamStart();
|
|
255
|
+
streamStarted = true;
|
|
256
|
+
}
|
|
257
|
+
request.callbacks.onReasoningChunk(String(delta?.thinking ?? ""));
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (deltaType === "input_json_delta") {
|
|
261
|
+
const index = Number(event.index);
|
|
262
|
+
const existing = toolCalls.get(index);
|
|
263
|
+
if (existing) {
|
|
264
|
+
existing.arguments = mergeAnthropicToolArguments(existing.arguments, String(delta?.partial_json ?? ""));
|
|
265
|
+
}
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (eventType === "content_block_stop") {
|
|
270
|
+
const index = Number(event.index);
|
|
271
|
+
const existing = toolCalls.get(index);
|
|
272
|
+
if (existing && existing.arguments.trim().length === 0) {
|
|
273
|
+
existing.arguments = "{}";
|
|
274
|
+
}
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (eventType === "message_delta") {
|
|
278
|
+
const rawUsage = event.usage;
|
|
279
|
+
if (rawUsage && typeof rawUsage === "object") {
|
|
280
|
+
usage = toAnthropicUsage(rawUsage);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
throw withAnthropicAuthGuidance(error);
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
content,
|
|
290
|
+
toolCalls: [...toolCalls.values()],
|
|
291
|
+
outputItems: [],
|
|
292
|
+
usage,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function createAnthropicProviderRuntime() {
|
|
296
|
+
(0, runtime_1.emitNervesEvent)({
|
|
297
|
+
component: "engine",
|
|
298
|
+
event: "engine.provider_init",
|
|
299
|
+
message: "anthropic provider init",
|
|
300
|
+
meta: { provider: "anthropic" },
|
|
301
|
+
});
|
|
302
|
+
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."));
|
|
305
|
+
}
|
|
306
|
+
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
|
+
});
|
|
315
|
+
return {
|
|
316
|
+
id: "anthropic",
|
|
317
|
+
model: anthropicConfig.model,
|
|
318
|
+
client,
|
|
319
|
+
resetTurnState(_messages) {
|
|
320
|
+
// Anthropic request payload is derived from canonical messages each turn.
|
|
321
|
+
},
|
|
322
|
+
appendToolOutput(_callId, _output) {
|
|
323
|
+
// Anthropic uses canonical messages for tool_result tracking.
|
|
324
|
+
},
|
|
325
|
+
streamTurn(request) {
|
|
326
|
+
return streamAnthropicMessages(client, anthropicConfig.model, request);
|
|
327
|
+
},
|
|
328
|
+
};
|
|
329
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAzureProviderRuntime = createAzureProviderRuntime;
|
|
4
|
+
const openai_1 = require("openai");
|
|
5
|
+
const config_1 = require("../config");
|
|
6
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
7
|
+
const streaming_1 = require("../streaming");
|
|
8
|
+
function createAzureProviderRuntime() {
|
|
9
|
+
(0, runtime_1.emitNervesEvent)({
|
|
10
|
+
component: "engine",
|
|
11
|
+
event: "engine.provider_init",
|
|
12
|
+
message: "azure provider init",
|
|
13
|
+
meta: { provider: "azure" },
|
|
14
|
+
});
|
|
15
|
+
const azureConfig = (0, config_1.getAzureConfig)();
|
|
16
|
+
if (!(azureConfig.apiKey && azureConfig.endpoint && azureConfig.deployment && azureConfig.modelName)) {
|
|
17
|
+
throw new Error("provider 'azure' is selected in agent.json but providers.azure is incomplete in secrets.json.");
|
|
18
|
+
}
|
|
19
|
+
const client = new openai_1.AzureOpenAI({
|
|
20
|
+
apiKey: azureConfig.apiKey,
|
|
21
|
+
endpoint: azureConfig.endpoint.replace(/\/openai.*$/, ""),
|
|
22
|
+
deployment: azureConfig.deployment,
|
|
23
|
+
apiVersion: azureConfig.apiVersion,
|
|
24
|
+
timeout: 30000,
|
|
25
|
+
maxRetries: 0,
|
|
26
|
+
});
|
|
27
|
+
let nativeInput = null;
|
|
28
|
+
let nativeInstructions = "";
|
|
29
|
+
return {
|
|
30
|
+
id: "azure",
|
|
31
|
+
model: azureConfig.modelName,
|
|
32
|
+
client,
|
|
33
|
+
resetTurnState(messages) {
|
|
34
|
+
const { instructions, input } = (0, streaming_1.toResponsesInput)(messages);
|
|
35
|
+
nativeInput = input;
|
|
36
|
+
nativeInstructions = instructions;
|
|
37
|
+
},
|
|
38
|
+
appendToolOutput(callId, output) {
|
|
39
|
+
if (!nativeInput)
|
|
40
|
+
return;
|
|
41
|
+
nativeInput.push({ type: "function_call_output", call_id: callId, output });
|
|
42
|
+
},
|
|
43
|
+
async streamTurn(request) {
|
|
44
|
+
if (!nativeInput)
|
|
45
|
+
this.resetTurnState(request.messages);
|
|
46
|
+
const params = {
|
|
47
|
+
model: this.model,
|
|
48
|
+
input: nativeInput,
|
|
49
|
+
instructions: nativeInstructions,
|
|
50
|
+
tools: (0, streaming_1.toResponsesTools)(request.activeTools),
|
|
51
|
+
reasoning: { effort: "medium", summary: "detailed" },
|
|
52
|
+
stream: true,
|
|
53
|
+
store: false,
|
|
54
|
+
include: ["reasoning.encrypted_content"],
|
|
55
|
+
};
|
|
56
|
+
if (request.traceId)
|
|
57
|
+
params.metadata = { trace_id: request.traceId };
|
|
58
|
+
if (request.toolChoiceRequired)
|
|
59
|
+
params.tool_choice = "required";
|
|
60
|
+
const result = await (0, streaming_1.streamResponsesApi)(this.client, params, request.callbacks, request.signal);
|
|
61
|
+
for (const item of result.outputItems)
|
|
62
|
+
nativeInput.push(item);
|
|
63
|
+
return result;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
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.createMinimaxProviderRuntime = createMinimaxProviderRuntime;
|
|
7
|
+
const openai_1 = __importDefault(require("openai"));
|
|
8
|
+
const config_1 = require("../config");
|
|
9
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
10
|
+
const streaming_1 = require("../streaming");
|
|
11
|
+
function createMinimaxProviderRuntime() {
|
|
12
|
+
(0, runtime_1.emitNervesEvent)({
|
|
13
|
+
component: "engine",
|
|
14
|
+
event: "engine.provider_init",
|
|
15
|
+
message: "minimax provider init",
|
|
16
|
+
meta: { provider: "minimax" },
|
|
17
|
+
});
|
|
18
|
+
const minimaxConfig = (0, config_1.getMinimaxConfig)();
|
|
19
|
+
if (!minimaxConfig.apiKey) {
|
|
20
|
+
throw new Error("provider 'minimax' is selected in agent.json but providers.minimax.apiKey is missing in secrets.json.");
|
|
21
|
+
}
|
|
22
|
+
const client = new openai_1.default({
|
|
23
|
+
apiKey: minimaxConfig.apiKey,
|
|
24
|
+
baseURL: "https://api.minimaxi.chat/v1",
|
|
25
|
+
timeout: 30000,
|
|
26
|
+
maxRetries: 0,
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
id: "minimax",
|
|
30
|
+
model: minimaxConfig.model,
|
|
31
|
+
client,
|
|
32
|
+
resetTurnState(_messages) {
|
|
33
|
+
// No provider-owned turn state for chat-completions providers.
|
|
34
|
+
},
|
|
35
|
+
appendToolOutput(_callId, _output) {
|
|
36
|
+
// Chat-completions providers rely on canonical messages only.
|
|
37
|
+
},
|
|
38
|
+
streamTurn(request) {
|
|
39
|
+
const params = {
|
|
40
|
+
messages: request.messages,
|
|
41
|
+
tools: request.activeTools,
|
|
42
|
+
stream: true,
|
|
43
|
+
};
|
|
44
|
+
if (this.model)
|
|
45
|
+
params.model = this.model;
|
|
46
|
+
if (request.traceId)
|
|
47
|
+
params.metadata = { trace_id: request.traceId };
|
|
48
|
+
if (request.toolChoiceRequired)
|
|
49
|
+
params.tool_choice = "required";
|
|
50
|
+
return (0, streaming_1.streamChatCompletion)(this.client, params, request.callbacks, request.signal);
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
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.createOpenAICodexProviderRuntime = createOpenAICodexProviderRuntime;
|
|
7
|
+
const openai_1 = __importDefault(require("openai"));
|
|
8
|
+
const config_1 = require("../config");
|
|
9
|
+
const identity_1 = require("../identity");
|
|
10
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
11
|
+
const streaming_1 = require("../streaming");
|
|
12
|
+
const OPENAI_CODEX_AUTH_FAILURE_MARKERS = [
|
|
13
|
+
"authentication failed",
|
|
14
|
+
"unauthorized",
|
|
15
|
+
"invalid api key",
|
|
16
|
+
"invalid x-api-key",
|
|
17
|
+
"invalid bearer token",
|
|
18
|
+
];
|
|
19
|
+
const OPENAI_CODEX_BACKEND_BASE_URL = "https://chatgpt.com/backend-api/codex";
|
|
20
|
+
function getOpenAICodexSecretsPathForGuidance() {
|
|
21
|
+
return (0, identity_1.getAgentSecretsPath)();
|
|
22
|
+
}
|
|
23
|
+
function getOpenAICodexAgentNameForGuidance() {
|
|
24
|
+
return (0, identity_1.getAgentName)();
|
|
25
|
+
}
|
|
26
|
+
function getOpenAICodexOAuthInstructions() {
|
|
27
|
+
const agentName = getOpenAICodexAgentNameForGuidance();
|
|
28
|
+
return [
|
|
29
|
+
"Fix:",
|
|
30
|
+
` 1. Run \`npm run auth:openai-codex -- --agent ${agentName}\``,
|
|
31
|
+
" (or run `codex login` and set the OAuth token manually)",
|
|
32
|
+
` 2. Open ${getOpenAICodexSecretsPathForGuidance()}`,
|
|
33
|
+
" 3. Confirm providers.openai-codex.oauthAccessToken is set",
|
|
34
|
+
" 4. This provider uses chatgpt.com/backend-api/codex/responses (not api.openai.com/responses).",
|
|
35
|
+
].join("\n");
|
|
36
|
+
}
|
|
37
|
+
function getOpenAICodexReauthGuidance(reason) {
|
|
38
|
+
return [
|
|
39
|
+
"OpenAI Codex configuration error.",
|
|
40
|
+
reason,
|
|
41
|
+
getOpenAICodexOAuthInstructions(),
|
|
42
|
+
].join("\n");
|
|
43
|
+
}
|
|
44
|
+
function isOpenAICodexAuthFailure(error) {
|
|
45
|
+
if (!(error instanceof Error))
|
|
46
|
+
return false;
|
|
47
|
+
const status = error.status;
|
|
48
|
+
if (status === 401 || status === 403)
|
|
49
|
+
return true;
|
|
50
|
+
const lower = error.message.toLowerCase();
|
|
51
|
+
return OPENAI_CODEX_AUTH_FAILURE_MARKERS.some((marker) => lower.includes(marker));
|
|
52
|
+
}
|
|
53
|
+
function withOpenAICodexAuthGuidance(error) {
|
|
54
|
+
const base = error instanceof Error ? error.message : String(error);
|
|
55
|
+
if (isOpenAICodexAuthFailure(error)) {
|
|
56
|
+
return new Error(getOpenAICodexReauthGuidance(`OpenAI Codex authentication failed (${base}).`));
|
|
57
|
+
}
|
|
58
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
59
|
+
}
|
|
60
|
+
function decodeJwtPayload(token) {
|
|
61
|
+
const parts = token.split(".");
|
|
62
|
+
if (parts.length < 2)
|
|
63
|
+
return null;
|
|
64
|
+
try {
|
|
65
|
+
const padded = parts[1]
|
|
66
|
+
.replace(/-/g, "+")
|
|
67
|
+
.replace(/_/g, "/")
|
|
68
|
+
.padEnd(Math.ceil(parts[1].length / 4) * 4, "=");
|
|
69
|
+
const payload = JSON.parse(Buffer.from(padded, "base64").toString("utf8"));
|
|
70
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
71
|
+
return null;
|
|
72
|
+
return payload;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function getChatGPTAccountIdFromToken(token) {
|
|
79
|
+
const payload = decodeJwtPayload(token);
|
|
80
|
+
if (!payload)
|
|
81
|
+
return "";
|
|
82
|
+
const authClaim = payload["https://api.openai.com/auth"];
|
|
83
|
+
if (!authClaim || typeof authClaim !== "object" || Array.isArray(authClaim))
|
|
84
|
+
return "";
|
|
85
|
+
const accountId = authClaim.chatgpt_account_id;
|
|
86
|
+
if (typeof accountId !== "string")
|
|
87
|
+
return "";
|
|
88
|
+
return accountId.trim();
|
|
89
|
+
}
|
|
90
|
+
function createOpenAICodexProviderRuntime() {
|
|
91
|
+
(0, runtime_1.emitNervesEvent)({
|
|
92
|
+
component: "engine",
|
|
93
|
+
event: "engine.provider_init",
|
|
94
|
+
message: "openai-codex provider init",
|
|
95
|
+
meta: { provider: "openai-codex" },
|
|
96
|
+
});
|
|
97
|
+
const codexConfig = (0, config_1.getOpenAICodexConfig)();
|
|
98
|
+
if (!(codexConfig.model && codexConfig.oauthAccessToken)) {
|
|
99
|
+
throw new Error(getOpenAICodexReauthGuidance("provider 'openai-codex' is selected in agent.json but providers.openai-codex.model/oauthAccessToken is incomplete in secrets.json."));
|
|
100
|
+
}
|
|
101
|
+
const token = codexConfig.oauthAccessToken.trim();
|
|
102
|
+
if (!token) {
|
|
103
|
+
throw new Error(getOpenAICodexReauthGuidance("OpenAI Codex OAuth access token is empty."));
|
|
104
|
+
}
|
|
105
|
+
const chatgptAccountId = getChatGPTAccountIdFromToken(token);
|
|
106
|
+
if (!chatgptAccountId) {
|
|
107
|
+
throw new Error(getOpenAICodexReauthGuidance("OpenAI Codex OAuth access token is missing a chatgpt_account_id claim required for chatgpt.com/backend-api/codex."));
|
|
108
|
+
}
|
|
109
|
+
const client = new openai_1.default({
|
|
110
|
+
apiKey: token,
|
|
111
|
+
baseURL: OPENAI_CODEX_BACKEND_BASE_URL,
|
|
112
|
+
defaultHeaders: {
|
|
113
|
+
"chatgpt-account-id": chatgptAccountId,
|
|
114
|
+
"OpenAI-Beta": "responses=experimental",
|
|
115
|
+
originator: "ouroboros",
|
|
116
|
+
},
|
|
117
|
+
timeout: 30000,
|
|
118
|
+
maxRetries: 0,
|
|
119
|
+
});
|
|
120
|
+
let nativeInput = null;
|
|
121
|
+
let nativeInstructions = "";
|
|
122
|
+
return {
|
|
123
|
+
id: "openai-codex",
|
|
124
|
+
model: codexConfig.model,
|
|
125
|
+
client,
|
|
126
|
+
resetTurnState(messages) {
|
|
127
|
+
const { instructions, input } = (0, streaming_1.toResponsesInput)(messages);
|
|
128
|
+
nativeInput = input;
|
|
129
|
+
nativeInstructions = instructions;
|
|
130
|
+
},
|
|
131
|
+
appendToolOutput(callId, output) {
|
|
132
|
+
if (!nativeInput)
|
|
133
|
+
return;
|
|
134
|
+
nativeInput.push({ type: "function_call_output", call_id: callId, output });
|
|
135
|
+
},
|
|
136
|
+
async streamTurn(request) {
|
|
137
|
+
if (!nativeInput)
|
|
138
|
+
this.resetTurnState(request.messages);
|
|
139
|
+
const params = {
|
|
140
|
+
model: this.model,
|
|
141
|
+
input: nativeInput,
|
|
142
|
+
instructions: nativeInstructions,
|
|
143
|
+
tools: (0, streaming_1.toResponsesTools)(request.activeTools),
|
|
144
|
+
reasoning: { effort: "medium", summary: "detailed" },
|
|
145
|
+
stream: true,
|
|
146
|
+
store: false,
|
|
147
|
+
include: ["reasoning.encrypted_content"],
|
|
148
|
+
};
|
|
149
|
+
if (request.toolChoiceRequired)
|
|
150
|
+
params.tool_choice = "required";
|
|
151
|
+
try {
|
|
152
|
+
const result = await (0, streaming_1.streamResponsesApi)(this.client, params, request.callbacks, request.signal);
|
|
153
|
+
for (const item of result.outputItems)
|
|
154
|
+
nativeInput.push(item);
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
throw withOpenAICodexAuthGuidance(error);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|