@ouro.bot/cli 0.1.0-alpha.17 → 0.1.0-alpha.170

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/AdoptionSpecialist.ouro/agent.json +3 -2
  2. package/AdoptionSpecialist.ouro/psyche/SOUL.md +3 -3
  3. package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
  4. package/README.md +187 -191
  5. package/changelog.json +1145 -0
  6. package/dist/heart/active-work.js +633 -0
  7. package/dist/heart/bridges/manager.js +358 -0
  8. package/dist/heart/bridges/state-machine.js +135 -0
  9. package/dist/heart/bridges/store.js +123 -0
  10. package/dist/heart/commitments.js +105 -0
  11. package/dist/heart/config.js +40 -30
  12. package/dist/heart/core.js +608 -123
  13. package/dist/heart/cross-chat-delivery.js +146 -0
  14. package/dist/heart/daemon/agent-discovery.js +81 -0
  15. package/dist/heart/daemon/agent-service.js +360 -0
  16. package/dist/heart/daemon/auth-flow.js +477 -0
  17. package/dist/heart/daemon/cadence.js +70 -0
  18. package/dist/heart/daemon/daemon-cli.js +2473 -206
  19. package/dist/heart/daemon/daemon-entry.js +140 -4
  20. package/dist/heart/daemon/daemon-health.js +136 -0
  21. package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
  22. package/dist/heart/daemon/daemon-tombstone.js +123 -0
  23. package/dist/heart/daemon/daemon.js +446 -17
  24. package/dist/heart/daemon/habit-migration.js +181 -0
  25. package/dist/heart/daemon/habit-parser.js +119 -0
  26. package/dist/heart/daemon/habit-scheduler.js +369 -0
  27. package/dist/heart/daemon/hatch-animation.js +10 -3
  28. package/dist/heart/daemon/hatch-flow.js +30 -111
  29. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  30. package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
  31. package/dist/heart/daemon/inner-status.js +89 -0
  32. package/dist/heart/daemon/launchd.js +161 -0
  33. package/dist/heart/daemon/log-tailer.js +4 -3
  34. package/dist/heart/daemon/mcp-server.js +591 -0
  35. package/dist/heart/daemon/message-router.js +17 -8
  36. package/dist/heart/daemon/os-cron-deps.js +134 -0
  37. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  38. package/dist/heart/daemon/ouro-path-installer.js +78 -34
  39. package/dist/heart/daemon/ouro-version-manager.js +171 -0
  40. package/dist/heart/daemon/outlook-http.js +399 -0
  41. package/dist/heart/daemon/outlook-read.js +1291 -0
  42. package/dist/heart/daemon/outlook-render.js +1032 -0
  43. package/dist/heart/daemon/outlook-types.js +7 -0
  44. package/dist/heart/daemon/outlook-view.js +194 -0
  45. package/dist/heart/daemon/process-manager.js +75 -0
  46. package/dist/heart/daemon/run-hooks.js +39 -0
  47. package/dist/heart/daemon/runtime-logging.js +58 -15
  48. package/dist/heart/daemon/runtime-metadata.js +219 -0
  49. package/dist/heart/daemon/runtime-mode.js +67 -0
  50. package/dist/heart/daemon/safe-mode.js +161 -0
  51. package/dist/heart/daemon/sense-manager.js +50 -2
  52. package/dist/heart/daemon/session-id-resolver.js +131 -0
  53. package/dist/heart/daemon/skill-management-installer.js +94 -0
  54. package/dist/heart/daemon/socket-client.js +202 -0
  55. package/dist/heart/daemon/specialist-orchestrator.js +2 -2
  56. package/dist/heart/daemon/specialist-prompt.js +13 -8
  57. package/dist/heart/daemon/specialist-tools.js +53 -4
  58. package/dist/heart/daemon/staged-restart.js +114 -0
  59. package/dist/heart/daemon/task-scheduler.js +3 -25
  60. package/dist/heart/daemon/thoughts.js +507 -0
  61. package/dist/heart/daemon/update-checker.js +111 -0
  62. package/dist/heart/daemon/update-hooks.js +138 -0
  63. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  64. package/dist/heart/delegation.js +62 -0
  65. package/dist/heart/identity.js +136 -55
  66. package/dist/heart/kicks.js +2 -20
  67. package/dist/heart/migrate-config.js +127 -0
  68. package/dist/heart/model-capabilities.js +48 -0
  69. package/dist/heart/obligations.js +197 -0
  70. package/dist/heart/progress-story.js +42 -0
  71. package/dist/heart/provider-failover.js +88 -0
  72. package/dist/heart/provider-ping.js +172 -0
  73. package/dist/heart/providers/anthropic-token.js +163 -0
  74. package/dist/heart/providers/anthropic.js +196 -36
  75. package/dist/heart/providers/azure.js +116 -10
  76. package/dist/heart/providers/github-copilot.js +157 -0
  77. package/dist/heart/providers/minimax.js +33 -3
  78. package/dist/heart/providers/openai-codex.js +51 -16
  79. package/dist/heart/session-activity.js +172 -0
  80. package/dist/heart/session-recall.js +216 -0
  81. package/dist/heart/streaming.js +62 -32
  82. package/dist/heart/target-resolution.js +127 -0
  83. package/dist/heart/tool-activity-callbacks.js +36 -0
  84. package/dist/heart/tool-description.js +135 -0
  85. package/dist/heart/tool-loop.js +200 -0
  86. package/dist/heart/turn-coordinator.js +28 -0
  87. package/dist/mind/associative-recall.js +122 -32
  88. package/dist/mind/bundle-manifest.js +14 -0
  89. package/dist/mind/context.js +125 -14
  90. package/dist/mind/{memory.js → diary.js} +70 -56
  91. package/dist/mind/first-impressions.js +16 -2
  92. package/dist/mind/friends/channel.js +56 -0
  93. package/dist/mind/friends/group-context.js +144 -0
  94. package/dist/mind/friends/store-file.js +19 -0
  95. package/dist/mind/friends/trust-explanation.js +74 -0
  96. package/dist/mind/friends/types.js +8 -0
  97. package/dist/mind/journal-index.js +161 -0
  98. package/dist/mind/obligation-steering.js +221 -0
  99. package/dist/mind/obligations.js +134 -0
  100. package/dist/mind/pending.js +76 -9
  101. package/dist/mind/phrases.js +1 -0
  102. package/dist/mind/prompt.js +649 -89
  103. package/dist/mind/token-estimate.js +8 -12
  104. package/dist/nerves/cli-logging.js +15 -2
  105. package/dist/nerves/coverage/run-artifacts.js +1 -1
  106. package/dist/nerves/event-buffer.js +111 -0
  107. package/dist/nerves/index.js +63 -3
  108. package/dist/nerves/observation.js +20 -0
  109. package/dist/nerves/runtime.js +5 -1
  110. package/dist/outlook-ui/assets/index-CBueh0d3.css +1 -0
  111. package/dist/outlook-ui/assets/index-GtHoFpRM.js +61 -0
  112. package/dist/outlook-ui/index.html +15 -0
  113. package/dist/repertoire/ado-semantic.js +6 -0
  114. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  115. package/dist/repertoire/coding/context-pack.js +254 -0
  116. package/dist/repertoire/coding/feedback.js +197 -30
  117. package/dist/repertoire/coding/manager.js +149 -2
  118. package/dist/repertoire/coding/spawner.js +55 -9
  119. package/dist/repertoire/coding/tools.js +135 -2
  120. package/dist/repertoire/guardrails.js +291 -0
  121. package/dist/repertoire/mcp-client.js +254 -0
  122. package/dist/repertoire/mcp-manager.js +198 -0
  123. package/dist/repertoire/skills.js +14 -23
  124. package/dist/repertoire/tasks/board.js +43 -5
  125. package/dist/repertoire/tasks/fix.js +182 -0
  126. package/dist/repertoire/tasks/index.js +28 -10
  127. package/dist/repertoire/tasks/lifecycle.js +2 -2
  128. package/dist/repertoire/tasks/parser.js +3 -2
  129. package/dist/repertoire/tasks/scanner.js +194 -37
  130. package/dist/repertoire/tasks/transitions.js +11 -28
  131. package/dist/repertoire/tools-base.js +991 -272
  132. package/dist/repertoire/tools-bluebubbles.js +94 -0
  133. package/dist/repertoire/tools-github.js +1 -6
  134. package/dist/repertoire/tools-teams.js +12 -59
  135. package/dist/repertoire/tools.js +281 -122
  136. package/dist/scripts/claude-code-hook.js +41 -0
  137. package/dist/scripts/claude-code-stop-hook.js +47 -0
  138. package/dist/senses/attention-queue.js +97 -0
  139. package/dist/senses/bluebubbles-client.js +102 -3
  140. package/dist/senses/bluebubbles-entry.js +2 -0
  141. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  142. package/dist/senses/bluebubbles-media.js +118 -23
  143. package/dist/senses/bluebubbles-model.js +12 -4
  144. package/dist/senses/bluebubbles-mutation-log.js +45 -5
  145. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  146. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  147. package/dist/senses/bluebubbles.js +1008 -102
  148. package/dist/senses/cli-entry.js +1 -1
  149. package/dist/senses/cli-layout.js +187 -0
  150. package/dist/senses/cli.js +419 -152
  151. package/dist/senses/commands.js +38 -1
  152. package/dist/senses/continuity.js +94 -0
  153. package/dist/senses/habit-turn-message.js +108 -0
  154. package/dist/senses/inner-dialog-worker.js +112 -19
  155. package/dist/senses/inner-dialog.js +592 -84
  156. package/dist/senses/pipeline.js +502 -0
  157. package/dist/senses/shared-turn.js +196 -0
  158. package/dist/senses/surface-tool.js +95 -0
  159. package/dist/senses/teams.js +667 -120
  160. package/dist/senses/trust-gate.js +112 -2
  161. package/package.json +13 -5
  162. package/skills/configure-dev-tools.md +81 -0
  163. package/subagents/README.md +4 -70
  164. package/dist/heart/daemon/subagent-installer.js +0 -134
  165. package/dist/senses/debug-activity.js +0 -107
  166. package/subagents/work-doer.md +0 -235
  167. package/subagents/work-merger.md +0 -618
  168. package/subagents/work-planner.md +0 -382
@@ -1,35 +1,137 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.classifyAzureError = classifyAzureError;
37
+ exports.createAzureTokenProvider = createAzureTokenProvider;
3
38
  exports.createAzureProviderRuntime = createAzureProviderRuntime;
4
39
  const openai_1 = require("openai");
5
40
  const config_1 = require("../config");
6
41
  const runtime_1 = require("../../nerves/runtime");
7
42
  const streaming_1 = require("../streaming");
8
- function createAzureProviderRuntime() {
43
+ const model_capabilities_1 = require("../model-capabilities");
44
+ const COGNITIVE_SERVICES_SCOPE = "https://cognitiveservices.azure.com/.default";
45
+ /* v8 ignore start -- shared network error utility, tested via classification tests @preserve */
46
+ function isNetworkError(error) {
47
+ const code = error.code || "";
48
+ if (["ECONNRESET", "ECONNREFUSED", "ENOTFOUND", "ETIMEDOUT", "EPIPE",
49
+ "EAI_AGAIN", "EHOSTUNREACH", "ENETUNREACH", "ECONNABORTED"].includes(code))
50
+ return true;
51
+ const msg = error.message || "";
52
+ return msg.includes("fetch failed") || msg.includes("socket hang up") || msg.includes("getaddrinfo");
53
+ }
54
+ /* v8 ignore stop */
55
+ function classifyAzureError(error) {
56
+ const status = error.status;
57
+ if (status === 401 || status === 403)
58
+ return "auth-failure";
59
+ if (status === 429)
60
+ return "rate-limit";
61
+ if (status && status >= 500)
62
+ return "server-error";
63
+ if (isNetworkError(error))
64
+ return "network-error";
65
+ return "unknown";
66
+ }
67
+ // @azure/identity is imported dynamically (below) rather than at the top level
68
+ // because it's a heavy package (~30+ transitive deps) and we only need it when
69
+ // using the managed-identity auth path. API-key users and other providers
70
+ // shouldn't pay the cold-start cost.
71
+ function createAzureTokenProvider(managedIdentityClientId) {
72
+ let credential = null;
73
+ return async () => {
74
+ try {
75
+ if (!credential) {
76
+ const { DefaultAzureCredential } = await Promise.resolve().then(() => __importStar(require("@azure/identity")));
77
+ const credentialOptions = managedIdentityClientId
78
+ ? { managedIdentityClientId }
79
+ : undefined;
80
+ credential = new DefaultAzureCredential(credentialOptions);
81
+ }
82
+ const tokenResponse = await credential.getToken(COGNITIVE_SERVICES_SCOPE);
83
+ return tokenResponse.token;
84
+ }
85
+ catch (err) {
86
+ const detail = err instanceof Error ? err.message : String(err);
87
+ throw new Error(`Azure OpenAI authentication failed: ${detail}\n` +
88
+ "To fix this, either:\n" +
89
+ " 1. Set providers.azure.apiKey in secrets.json, or\n" +
90
+ " 2. Run 'az login' to authenticate with your Azure account (for local dev), or\n" +
91
+ " 3. Attach a managed identity to your App Service and set providers.azure.managedIdentityClientId in secrets.json (for deployed environments)");
92
+ }
93
+ };
94
+ }
95
+ function createAzureProviderRuntime(model) {
96
+ const azureConfig = (0, config_1.getAzureConfig)();
97
+ const useApiKey = !!azureConfig.apiKey;
98
+ const authMethod = useApiKey ? "key" : "managed-identity";
9
99
  (0, runtime_1.emitNervesEvent)({
10
100
  component: "engine",
11
101
  event: "engine.provider_init",
12
102
  message: "azure provider init",
13
- meta: { provider: "azure" },
103
+ meta: { provider: "azure", authMethod },
14
104
  });
15
- const azureConfig = (0, config_1.getAzureConfig)();
16
- if (!(azureConfig.apiKey && azureConfig.endpoint && azureConfig.deployment && azureConfig.modelName)) {
105
+ if (!(azureConfig.endpoint && azureConfig.deployment)) {
17
106
  throw new Error("provider 'azure' is selected in agent.json but providers.azure is incomplete in secrets.json.");
18
107
  }
19
- const client = new openai_1.AzureOpenAI({
20
- apiKey: azureConfig.apiKey,
108
+ const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
109
+ const capabilities = new Set();
110
+ if (modelCaps.reasoningEffort)
111
+ capabilities.add("reasoning-effort");
112
+ const clientOptions = {
21
113
  endpoint: azureConfig.endpoint.replace(/\/openai.*$/, ""),
22
114
  deployment: azureConfig.deployment,
23
115
  apiVersion: azureConfig.apiVersion,
24
116
  timeout: 30000,
25
117
  maxRetries: 0,
26
- });
118
+ };
119
+ if (useApiKey) {
120
+ clientOptions.apiKey = azureConfig.apiKey;
121
+ }
122
+ else {
123
+ const managedIdentityClientId = azureConfig.managedIdentityClientId || undefined;
124
+ clientOptions.azureADTokenProvider = createAzureTokenProvider(managedIdentityClientId);
125
+ }
126
+ const client = new openai_1.AzureOpenAI(clientOptions);
27
127
  let nativeInput = null;
28
128
  let nativeInstructions = "";
29
129
  return {
30
130
  id: "azure",
31
- model: azureConfig.modelName,
131
+ model,
32
132
  client,
133
+ capabilities,
134
+ supportedReasoningEfforts: modelCaps.reasoningEffort,
33
135
  resetTurnState(messages) {
34
136
  const { instructions, input } = (0, streaming_1.toResponsesInput)(messages);
35
137
  nativeInput = input;
@@ -48,7 +150,7 @@ function createAzureProviderRuntime() {
48
150
  input: nativeInput,
49
151
  instructions: nativeInstructions,
50
152
  tools: (0, streaming_1.toResponsesTools)(request.activeTools),
51
- reasoning: { effort: "medium", summary: "detailed" },
153
+ reasoning: { effort: request.reasoningEffort ?? "medium", summary: "detailed" },
52
154
  stream: true,
53
155
  store: false,
54
156
  include: ["reasoning.encrypted_content"],
@@ -57,10 +159,14 @@ function createAzureProviderRuntime() {
57
159
  params.metadata = { trace_id: request.traceId };
58
160
  if (request.toolChoiceRequired)
59
161
  params.tool_choice = "required";
60
- const result = await (0, streaming_1.streamResponsesApi)(this.client, params, request.callbacks, request.signal);
162
+ const result = await (0, streaming_1.streamResponsesApi)(this.client, params, request.callbacks, request.signal, request.eagerSettleStreaming);
61
163
  for (const item of result.outputItems)
62
164
  nativeInput.push(item);
63
165
  return result;
64
166
  },
167
+ /* v8 ignore next 3 -- delegation: classification logic tested via classifyAzureError @preserve */
168
+ classifyError(error) {
169
+ return classifyAzureError(error);
170
+ },
65
171
  };
66
172
  }
@@ -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
- function createMinimaxProviderRuntime() {
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: minimaxConfig.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 \`npm run auth:openai-codex -- --agent ${agentName}\``,
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
- 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
- }
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 (!(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."));
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: codexConfig.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 withOpenAICodexAuthGuidance(error);
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
  }