@ouro.bot/cli 0.1.0-alpha.16 → 0.1.0-alpha.161
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 +3 -2
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +3 -3
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
- package/README.md +187 -191
- package/changelog.json +1088 -0
- package/dist/heart/active-work.js +633 -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 +40 -30
- package/dist/heart/core.js +608 -123
- package/dist/heart/cross-chat-delivery.js +146 -0
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/auth-flow.js +477 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/daemon-cli.js +2467 -205
- package/dist/heart/daemon/daemon-entry.js +131 -4
- package/dist/heart/daemon/daemon-health.js +136 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
- package/dist/heart/daemon/daemon-tombstone.js +123 -0
- package/dist/heart/daemon/daemon.js +445 -17
- package/dist/heart/daemon/habit-migration.js +181 -0
- package/dist/heart/daemon/habit-parser.js +119 -0
- package/dist/heart/daemon/habit-scheduler.js +369 -0
- package/dist/heart/daemon/hatch-animation.js +10 -3
- package/dist/heart/daemon/hatch-flow.js +30 -111
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/launchd.js +159 -0
- package/dist/heart/daemon/log-tailer.js +4 -3
- package/dist/heart/daemon/mcp-server.js +591 -0
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/os-cron-deps.js +134 -0
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-path-installer.js +78 -34
- package/dist/heart/daemon/ouro-version-manager.js +171 -0
- package/dist/heart/daemon/outlook-http.js +369 -0
- package/dist/heart/daemon/outlook-read.js +1281 -0
- package/dist/heart/daemon/outlook-render.js +1032 -0
- package/dist/heart/daemon/outlook-types.js +7 -0
- package/dist/heart/daemon/outlook-view.js +194 -0
- package/dist/heart/daemon/process-manager.js +75 -0
- package/dist/heart/daemon/run-hooks.js +39 -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/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +50 -2
- package/dist/heart/daemon/session-id-resolver.js +131 -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 +2 -2
- package/dist/heart/daemon/specialist-prompt.js +13 -8
- package/dist/heart/daemon/specialist-tools.js +53 -4
- package/dist/heart/daemon/staged-restart.js +114 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- 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 +136 -55
- package/dist/heart/kicks.js +2 -20
- package/dist/heart/migrate-config.js +127 -0
- 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 +172 -0
- package/dist/heart/providers/anthropic-token.js +163 -0
- package/dist/heart/providers/anthropic.js +196 -36
- package/dist/heart/providers/azure.js +116 -10
- package/dist/heart/providers/github-copilot.js +157 -0
- package/dist/heart/providers/minimax.js +33 -3
- package/dist/heart/providers/openai-codex.js +51 -16
- package/dist/heart/session-activity.js +172 -0
- package/dist/heart/session-recall.js +216 -0
- package/dist/heart/streaming.js +117 -33
- package/dist/heart/target-resolution.js +127 -0
- package/dist/heart/tool-activity-callbacks.js +36 -0
- package/dist/heart/tool-description.js +135 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/mind/associative-recall.js +122 -32
- package/dist/mind/bundle-manifest.js +14 -0
- package/dist/mind/context.js +125 -14
- package/dist/mind/{memory.js → diary.js} +70 -56
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +56 -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/journal-index.js +161 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/obligations.js +134 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +651 -91
- 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/event-buffer.js +111 -0
- package/dist/nerves/index.js +63 -3
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-CXQG0mVx.js +61 -0
- package/dist/outlook-ui/assets/index-Gq7EdfkO.css +1 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-semantic.js +6 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- 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 +58 -12
- package/dist/repertoire/coding/tools.js +176 -4
- package/dist/repertoire/guardrails.js +291 -0
- package/dist/repertoire/mcp-client.js +254 -0
- package/dist/repertoire/mcp-manager.js +198 -0
- package/dist/repertoire/skills.js +14 -23
- package/dist/repertoire/tasks/board.js +43 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +28 -10
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +11 -28
- package/dist/repertoire/tools-base.js +992 -273
- package/dist/repertoire/tools-bluebubbles.js +94 -0
- package/dist/repertoire/tools-github.js +1 -6
- package/dist/repertoire/tools-teams.js +12 -59
- package/dist/repertoire/tools.js +281 -101
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +97 -0
- package/dist/senses/bluebubbles-client.js +258 -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 +1040 -45
- package/dist/senses/cli-entry.js +1 -1
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +419 -152
- package/dist/senses/commands.js +38 -1
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +112 -19
- package/dist/senses/inner-dialog.js +592 -84
- package/dist/senses/pipeline.js +502 -0
- package/dist/senses/shared-turn.js +196 -0
- package/dist/senses/surface-tool.js +95 -0
- package/dist/senses/teams.js +667 -120
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +13 -5
- package/skills/configure-dev-tools.md +81 -0
- package/subagents/README.md +4 -70
- package/dist/heart/daemon/subagent-installer.js +0 -134
- package/subagents/work-doer.md +0 -233
- package/subagents/work-merger.md +0 -624
- package/subagents/work-planner.md +0 -373
|
@@ -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(model) {
|
|
96
|
+
const azureConfig = (0, config_1.getAzureConfig)();
|
|
97
|
+
const useApiKey = !!azureConfig.apiKey;
|
|
98
|
+
const authMethod = useApiKey ? "key" : "managed-identity";
|
|
9
99
|
(0, runtime_1.emitNervesEvent)({
|
|
10
100
|
component: "engine",
|
|
11
101
|
event: "engine.provider_init",
|
|
12
102
|
message: "azure provider init",
|
|
13
|
-
meta: { provider: "azure" },
|
|
103
|
+
meta: { provider: "azure", authMethod },
|
|
14
104
|
});
|
|
15
|
-
|
|
16
|
-
if (!(azureConfig.apiKey && azureConfig.endpoint && azureConfig.deployment && azureConfig.modelName)) {
|
|
105
|
+
if (!(azureConfig.endpoint && azureConfig.deployment)) {
|
|
17
106
|
throw new Error("provider 'azure' is selected in agent.json but providers.azure is incomplete in secrets.json.");
|
|
18
107
|
}
|
|
19
|
-
const
|
|
20
|
-
|
|
108
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
|
|
109
|
+
const capabilities = new Set();
|
|
110
|
+
if (modelCaps.reasoningEffort)
|
|
111
|
+
capabilities.add("reasoning-effort");
|
|
112
|
+
const clientOptions = {
|
|
21
113
|
endpoint: azureConfig.endpoint.replace(/\/openai.*$/, ""),
|
|
22
114
|
deployment: azureConfig.deployment,
|
|
23
115
|
apiVersion: azureConfig.apiVersion,
|
|
24
116
|
timeout: 30000,
|
|
25
117
|
maxRetries: 0,
|
|
26
|
-
}
|
|
118
|
+
};
|
|
119
|
+
if (useApiKey) {
|
|
120
|
+
clientOptions.apiKey = azureConfig.apiKey;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const managedIdentityClientId = azureConfig.managedIdentityClientId || undefined;
|
|
124
|
+
clientOptions.azureADTokenProvider = createAzureTokenProvider(managedIdentityClientId);
|
|
125
|
+
}
|
|
126
|
+
const client = new openai_1.AzureOpenAI(clientOptions);
|
|
27
127
|
let nativeInput = null;
|
|
28
128
|
let nativeInstructions = "";
|
|
29
129
|
return {
|
|
30
130
|
id: "azure",
|
|
31
|
-
model
|
|
131
|
+
model,
|
|
32
132
|
client,
|
|
133
|
+
capabilities,
|
|
134
|
+
supportedReasoningEfforts: modelCaps.reasoningEffort,
|
|
33
135
|
resetTurnState(messages) {
|
|
34
136
|
const { instructions, input } = (0, streaming_1.toResponsesInput)(messages);
|
|
35
137
|
nativeInput = input;
|
|
@@ -48,7 +150,7 @@ function createAzureProviderRuntime() {
|
|
|
48
150
|
input: nativeInput,
|
|
49
151
|
instructions: nativeInstructions,
|
|
50
152
|
tools: (0, streaming_1.toResponsesTools)(request.activeTools),
|
|
51
|
-
reasoning: { effort: "medium", summary: "detailed" },
|
|
153
|
+
reasoning: { effort: request.reasoningEffort ?? "medium", summary: "detailed" },
|
|
52
154
|
stream: true,
|
|
53
155
|
store: false,
|
|
54
156
|
include: ["reasoning.encrypted_content"],
|
|
@@ -57,10 +159,14 @@ function createAzureProviderRuntime() {
|
|
|
57
159
|
params.metadata = { trace_id: request.traceId };
|
|
58
160
|
if (request.toolChoiceRequired)
|
|
59
161
|
params.tool_choice = "required";
|
|
60
|
-
const result = await (0, streaming_1.streamResponsesApi)(this.client, params, request.callbacks, request.signal);
|
|
162
|
+
const result = await (0, streaming_1.streamResponsesApi)(this.client, params, request.callbacks, request.signal, request.eagerSettleStreaming);
|
|
61
163
|
for (const item of result.outputItems)
|
|
62
164
|
nativeInput.push(item);
|
|
63
165
|
return result;
|
|
64
166
|
},
|
|
167
|
+
/* v8 ignore next 3 -- delegation: classification logic tested via classifyAzureError @preserve */
|
|
168
|
+
classifyError(error) {
|
|
169
|
+
return classifyAzureError(error);
|
|
170
|
+
},
|
|
65
171
|
};
|
|
66
172
|
}
|
|
@@ -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(model) {
|
|
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 = (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 = model.startsWith("claude");
|
|
52
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(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,
|
|
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.eagerSettleStreaming);
|
|
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,
|
|
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.eagerSettleStreaming);
|
|
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,12 +3,36 @@ 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(model) {
|
|
12
36
|
(0, runtime_1.emitNervesEvent)({
|
|
13
37
|
component: "engine",
|
|
14
38
|
event: "engine.provider_init",
|
|
@@ -19,6 +43,8 @@ function createMinimaxProviderRuntime() {
|
|
|
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)(model);
|
|
22
48
|
const client = new openai_1.default({
|
|
23
49
|
apiKey: minimaxConfig.apiKey,
|
|
24
50
|
baseURL: "https://api.minimaxi.chat/v1",
|
|
@@ -27,8 +53,9 @@ function createMinimaxProviderRuntime() {
|
|
|
27
53
|
});
|
|
28
54
|
return {
|
|
29
55
|
id: "minimax",
|
|
30
|
-
model
|
|
56
|
+
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.eagerSettleStreaming);
|
|
78
|
+
},
|
|
79
|
+
classifyError(error) {
|
|
80
|
+
return classifyMinimaxError(error);
|
|
51
81
|
},
|
|
52
82
|
};
|
|
53
83
|
}
|
|
@@ -3,12 +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.classifyOpenAICodexError = classifyOpenAICodexError;
|
|
6
7
|
exports.createOpenAICodexProviderRuntime = createOpenAICodexProviderRuntime;
|
|
7
8
|
const openai_1 = __importDefault(require("openai"));
|
|
8
9
|
const config_1 = require("../config");
|
|
9
10
|
const identity_1 = require("../identity");
|
|
10
11
|
const runtime_1 = require("../../nerves/runtime");
|
|
11
12
|
const streaming_1 = require("../streaming");
|
|
13
|
+
const model_capabilities_1 = require("../model-capabilities");
|
|
12
14
|
const OPENAI_CODEX_AUTH_FAILURE_MARKERS = [
|
|
13
15
|
"authentication failed",
|
|
14
16
|
"unauthorized",
|
|
@@ -27,11 +29,11 @@ function getOpenAICodexOAuthInstructions() {
|
|
|
27
29
|
const agentName = getOpenAICodexAgentNameForGuidance();
|
|
28
30
|
return [
|
|
29
31
|
"Fix:",
|
|
30
|
-
` 1. Run \`
|
|
31
|
-
" (or run `codex login` and set the OAuth token manually)",
|
|
32
|
+
` 1. Run \`ouro auth --agent ${agentName}\``,
|
|
32
33
|
` 2. Open ${getOpenAICodexSecretsPathForGuidance()}`,
|
|
33
34
|
" 3. Confirm providers.openai-codex.oauthAccessToken is set",
|
|
34
35
|
" 4. This provider uses chatgpt.com/backend-api/codex/responses (not api.openai.com/responses).",
|
|
36
|
+
" 5. After reauth, retry the failed ouro command or reconnect this session.",
|
|
35
37
|
].join("\n");
|
|
36
38
|
}
|
|
37
39
|
function getOpenAICodexReauthGuidance(reason) {
|
|
@@ -41,6 +43,33 @@ function getOpenAICodexReauthGuidance(reason) {
|
|
|
41
43
|
getOpenAICodexOAuthInstructions(),
|
|
42
44
|
].join("\n");
|
|
43
45
|
}
|
|
46
|
+
/* v8 ignore start -- shared network error utility, tested via classification tests @preserve */
|
|
47
|
+
function isNetworkError(error) {
|
|
48
|
+
const code = error.code || "";
|
|
49
|
+
if (["ECONNRESET", "ECONNREFUSED", "ENOTFOUND", "ETIMEDOUT", "EPIPE",
|
|
50
|
+
"EAI_AGAIN", "EHOSTUNREACH", "ENETUNREACH", "ECONNABORTED"].includes(code))
|
|
51
|
+
return true;
|
|
52
|
+
const msg = error.message || "";
|
|
53
|
+
return msg.includes("fetch failed") || msg.includes("socket hang up") || msg.includes("getaddrinfo");
|
|
54
|
+
}
|
|
55
|
+
/* v8 ignore stop */
|
|
56
|
+
function classifyOpenAICodexError(error) {
|
|
57
|
+
const status = error.status;
|
|
58
|
+
if (status === 401 || status === 403 || isOpenAICodexAuthFailure(error))
|
|
59
|
+
return "auth-failure";
|
|
60
|
+
if (status === 429) {
|
|
61
|
+
const lower = error.message.toLowerCase();
|
|
62
|
+
if (lower.includes("usage") || lower.includes("quota") || lower.includes("exceeded your"))
|
|
63
|
+
return "usage-limit";
|
|
64
|
+
return "rate-limit";
|
|
65
|
+
}
|
|
66
|
+
if (status && status >= 500)
|
|
67
|
+
return "server-error";
|
|
68
|
+
if (isNetworkError(error))
|
|
69
|
+
return "network-error";
|
|
70
|
+
return "unknown";
|
|
71
|
+
}
|
|
72
|
+
/* v8 ignore start -- auth detection: only called from classifyOpenAICodexError which always passes Error @preserve */
|
|
44
73
|
function isOpenAICodexAuthFailure(error) {
|
|
45
74
|
if (!(error instanceof Error))
|
|
46
75
|
return false;
|
|
@@ -50,13 +79,7 @@ function isOpenAICodexAuthFailure(error) {
|
|
|
50
79
|
const lower = error.message.toLowerCase();
|
|
51
80
|
return OPENAI_CODEX_AUTH_FAILURE_MARKERS.some((marker) => lower.includes(marker));
|
|
52
81
|
}
|
|
53
|
-
|
|
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
|
-
}
|
|
82
|
+
/* v8 ignore stop */
|
|
60
83
|
function decodeJwtPayload(token) {
|
|
61
84
|
const parts = token.split(".");
|
|
62
85
|
if (parts.length < 2)
|
|
@@ -87,7 +110,7 @@ function getChatGPTAccountIdFromToken(token) {
|
|
|
87
110
|
return "";
|
|
88
111
|
return accountId.trim();
|
|
89
112
|
}
|
|
90
|
-
function createOpenAICodexProviderRuntime() {
|
|
113
|
+
function createOpenAICodexProviderRuntime(model) {
|
|
91
114
|
(0, runtime_1.emitNervesEvent)({
|
|
92
115
|
component: "engine",
|
|
93
116
|
event: "engine.provider_init",
|
|
@@ -95,8 +118,8 @@ function createOpenAICodexProviderRuntime() {
|
|
|
95
118
|
meta: { provider: "openai-codex" },
|
|
96
119
|
});
|
|
97
120
|
const codexConfig = (0, config_1.getOpenAICodexConfig)();
|
|
98
|
-
if (!
|
|
99
|
-
throw new Error(getOpenAICodexReauthGuidance("provider 'openai-codex' is selected in agent.json but providers.openai-codex.
|
|
121
|
+
if (!codexConfig.oauthAccessToken) {
|
|
122
|
+
throw new Error(getOpenAICodexReauthGuidance("provider 'openai-codex' is selected in agent.json but providers.openai-codex.oauthAccessToken is missing in secrets.json."));
|
|
100
123
|
}
|
|
101
124
|
const token = codexConfig.oauthAccessToken.trim();
|
|
102
125
|
if (!token) {
|
|
@@ -106,6 +129,12 @@ function createOpenAICodexProviderRuntime() {
|
|
|
106
129
|
if (!chatgptAccountId) {
|
|
107
130
|
throw new Error(getOpenAICodexReauthGuidance("OpenAI Codex OAuth access token is missing a chatgpt_account_id claim required for chatgpt.com/backend-api/codex."));
|
|
108
131
|
}
|
|
132
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
|
|
133
|
+
const capabilities = new Set();
|
|
134
|
+
if (modelCaps.reasoningEffort)
|
|
135
|
+
capabilities.add("reasoning-effort");
|
|
136
|
+
if (modelCaps.phase)
|
|
137
|
+
capabilities.add("phase-annotation");
|
|
109
138
|
const client = new openai_1.default({
|
|
110
139
|
apiKey: token,
|
|
111
140
|
baseURL: OPENAI_CODEX_BACKEND_BASE_URL,
|
|
@@ -121,8 +150,10 @@ function createOpenAICodexProviderRuntime() {
|
|
|
121
150
|
let nativeInstructions = "";
|
|
122
151
|
return {
|
|
123
152
|
id: "openai-codex",
|
|
124
|
-
model
|
|
153
|
+
model,
|
|
125
154
|
client,
|
|
155
|
+
capabilities,
|
|
156
|
+
supportedReasoningEfforts: modelCaps.reasoningEffort,
|
|
126
157
|
resetTurnState(messages) {
|
|
127
158
|
const { instructions, input } = (0, streaming_1.toResponsesInput)(messages);
|
|
128
159
|
nativeInput = input;
|
|
@@ -141,7 +172,7 @@ function createOpenAICodexProviderRuntime() {
|
|
|
141
172
|
input: nativeInput,
|
|
142
173
|
instructions: nativeInstructions,
|
|
143
174
|
tools: (0, streaming_1.toResponsesTools)(request.activeTools),
|
|
144
|
-
reasoning: { effort: "medium", summary: "detailed" },
|
|
175
|
+
reasoning: { effort: request.reasoningEffort ?? "medium", summary: "detailed" },
|
|
145
176
|
stream: true,
|
|
146
177
|
store: false,
|
|
147
178
|
include: ["reasoning.encrypted_content"],
|
|
@@ -149,14 +180,18 @@ function createOpenAICodexProviderRuntime() {
|
|
|
149
180
|
if (request.toolChoiceRequired)
|
|
150
181
|
params.tool_choice = "required";
|
|
151
182
|
try {
|
|
152
|
-
const result = await (0, streaming_1.streamResponsesApi)(this.client, params, request.callbacks, request.signal);
|
|
183
|
+
const result = await (0, streaming_1.streamResponsesApi)(this.client, params, request.callbacks, request.signal, request.eagerSettleStreaming);
|
|
153
184
|
for (const item of result.outputItems)
|
|
154
185
|
nativeInput.push(item);
|
|
155
186
|
return result;
|
|
156
187
|
}
|
|
157
188
|
catch (error) {
|
|
158
|
-
throw
|
|
189
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
159
190
|
}
|
|
160
191
|
},
|
|
192
|
+
/* v8 ignore next 3 -- delegation: classification logic tested via classifyOpenAICodexError @preserve */
|
|
193
|
+
classifyError(error) {
|
|
194
|
+
return classifyOpenAICodexError(error);
|
|
195
|
+
},
|
|
161
196
|
};
|
|
162
197
|
}
|