@ouro.bot/cli 0.1.0-alpha.32 → 0.1.0-alpha.321
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/README.md +188 -190
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +1 -1
- package/changelog.json +1924 -0
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +140 -0
- package/dist/arc/episodes.js +117 -0
- package/dist/arc/intentions.js +133 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +237 -0
- package/dist/arc/packets.js +193 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +65 -0
- package/dist/heart/active-work.js +832 -0
- package/dist/heart/agent-entry.js +37 -2
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/adapter.js +2 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +16 -0
- package/dist/heart/attachments/store.js +103 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +456 -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/bundle-state.js +168 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config-registry.js +304 -0
- package/dist/heart/config.js +63 -30
- package/dist/heart/core.js +669 -195
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +149 -0
- package/dist/heart/daemon/agent-discovery.js +79 -3
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/agentic-repair.js +170 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +596 -0
- package/dist/heart/daemon/cli-exec.js +2238 -0
- package/dist/heart/daemon/cli-help.js +306 -0
- package/dist/heart/daemon/cli-parse.js +824 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +506 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/daemon-cli.js +29 -1171
- package/dist/heart/daemon/daemon-entry.js +333 -3
- package/dist/heart/daemon/daemon-health.js +137 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +153 -12
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +751 -58
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +322 -0
- package/dist/heart/daemon/health-monitor.js +66 -0
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +69 -0
- package/dist/heart/daemon/launchd.js +46 -9
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +105 -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-entry.js +1 -1
- package/dist/heart/daemon/process-manager.js +201 -0
- package/dist/heart/daemon/provider-discovery.js +105 -0
- package/dist/heart/daemon/pulse.js +463 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +101 -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 +72 -3
- 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 +307 -0
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +227 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/thoughts.js +510 -0
- package/dist/heart/daemon/up-progress.js +135 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/habits/habit-migration.js +181 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-scheduler.js +371 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +30 -120
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +10 -7
- package/dist/heart/{daemon → hatch}/specialist-tools.js +49 -3
- package/dist/heart/identity.js +163 -60
- package/dist/heart/kicks.js +2 -20
- package/dist/heart/mcp/mcp-server.js +653 -0
- package/dist/heart/migrate-config.js +127 -0
- package/dist/heart/model-capabilities.js +59 -0
- package/dist/heart/outlook/outlook-http.js +439 -0
- package/dist/heart/outlook/outlook-read.js +28 -0
- package/dist/heart/outlook/outlook-render.js +1032 -0
- package/dist/heart/outlook/outlook-types.js +27 -0
- package/dist/heart/outlook/outlook-view.js +194 -0
- package/dist/heart/outlook/readers/agent-machine.js +355 -0
- package/dist/heart/outlook/readers/continuity-readers.js +332 -0
- package/dist/heart/outlook/readers/runtime-readers.js +660 -0
- package/dist/heart/outlook/readers/sessions.js +231 -0
- package/dist/heart/outlook/readers/shared.js +111 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-failover.js +88 -0
- package/dist/heart/provider-ping.js +162 -0
- package/dist/heart/providers/anthropic-token.js +163 -0
- package/dist/heart/providers/anthropic.js +169 -46
- package/dist/heart/providers/azure.js +98 -11
- package/dist/heart/providers/error-classification.js +63 -0
- package/dist/heart/providers/github-copilot.js +136 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +23 -5
- package/dist/heart/providers/openai-codex.js +33 -22
- package/dist/heart/session-activity.js +190 -0
- package/dist/heart/session-events.js +726 -0
- package/dist/heart/session-recall.js +162 -0
- package/dist/heart/start-of-turn-packet.js +341 -0
- package/dist/heart/streaming.js +36 -27
- package/dist/heart/sync.js +332 -0
- package/dist/heart/target-resolution.js +127 -0
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/tool-activity-callbacks.js +36 -0
- package/dist/heart/tool-description.js +135 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +358 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/{daemon → versioning}/ouro-path-installer.js +78 -35
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +12 -2
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mind/associative-recall.js +137 -66
- package/dist/mind/bundle-manifest.js +8 -1
- package/dist/mind/context.js +89 -93
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +84 -96
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/first-impressions.js +14 -1
- package/dist/mind/friends/channel.js +56 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/resolver.js +37 -0
- package/dist/mind/friends/store-file.js +58 -3
- 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/pending.js +76 -9
- package/dist/mind/prompt.js +950 -113
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +7 -1
- package/dist/nerves/coverage/audit.js +1 -1
- package/dist/nerves/coverage/file-completeness.js +76 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +224 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-IuR4F6y6.js +61 -0
- package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +319 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +79 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +159 -11
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +527 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +375 -0
- package/dist/repertoire/mcp-client.js +255 -0
- package/dist/repertoire/mcp-manager.js +305 -0
- package/dist/repertoire/mcp-tools.js +63 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +14 -23
- package/dist/repertoire/stripe-client.js +131 -0
- 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 +16 -79
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +316 -0
- package/dist/repertoire/tools-base.js +45 -771
- package/dist/repertoire/tools-bluebubbles.js +1 -0
- package/dist/repertoire/tools-bridge.js +141 -0
- package/dist/repertoire/tools-bundle.js +984 -0
- package/dist/repertoire/tools-config.js +185 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-credential.js +182 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flight.js +224 -0
- package/dist/repertoire/tools-flow.js +105 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-memory.js +376 -0
- package/dist/repertoire/tools-session.js +739 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +180 -0
- package/dist/repertoire/tools-surface.js +243 -0
- package/dist/repertoire/tools-teams.js +12 -62
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +110 -0
- package/dist/repertoire/tools.js +144 -138
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +118 -0
- package/dist/repertoire/vault-setup.js +241 -0
- 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 +116 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +143 -9
- package/dist/senses/bluebubbles/entry.js +13 -0
- package/dist/senses/bluebubbles/inbound-log.js +113 -0
- package/dist/senses/bluebubbles/index.js +1436 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +43 -12
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
- package/dist/senses/bluebubbles/replay.js +129 -0
- package/dist/senses/bluebubbles/runtime-state.js +109 -0
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +605 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +83 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +240 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +1 -1
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +595 -246
- package/dist/senses/commands.js +65 -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 +633 -86
- package/dist/senses/pipeline.js +565 -0
- package/dist/senses/shared-turn.js +199 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams.js +666 -166
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +27 -7
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +110 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +81 -0
- package/skills/travel-planning.md +138 -0
- package/dist/heart/daemon/subagent-installer.js +0 -134
- package/dist/senses/bluebubbles-entry.js +0 -11
- package/dist/senses/bluebubbles.js +0 -544
- package/dist/senses/debug-activity.js +0 -108
- package/subagents/README.md +0 -73
- package/subagents/work-doer.md +0 -235
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -382
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.readSessionInventory = readSessionInventory;
|
|
37
|
+
exports.readSessionTranscript = readSessionTranscript;
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const runtime_1 = require("../../../nerves/runtime");
|
|
40
|
+
const identity_1 = require("../../identity");
|
|
41
|
+
const session_events_1 = require("../../session-events");
|
|
42
|
+
const shared_1 = require("./shared");
|
|
43
|
+
/* v8 ignore start — session envelope parsing utilities */
|
|
44
|
+
function parseSessionUsage(raw) {
|
|
45
|
+
if (!raw || typeof raw !== "object")
|
|
46
|
+
return null;
|
|
47
|
+
const record = raw;
|
|
48
|
+
const inputTokens = typeof record.input_tokens === "number" ? record.input_tokens : 0;
|
|
49
|
+
const outputTokens = typeof record.output_tokens === "number" ? record.output_tokens : 0;
|
|
50
|
+
const reasoningTokens = typeof record.reasoning_tokens === "number" ? record.reasoning_tokens : 0;
|
|
51
|
+
const totalTokens = typeof record.total_tokens === "number" ? record.total_tokens : 0;
|
|
52
|
+
if (inputTokens === 0 && outputTokens === 0 && totalTokens === 0)
|
|
53
|
+
return null;
|
|
54
|
+
return { input_tokens: inputTokens, output_tokens: outputTokens, reasoning_tokens: reasoningTokens, total_tokens: totalTokens };
|
|
55
|
+
}
|
|
56
|
+
function parseSessionContinuity(raw) {
|
|
57
|
+
if (!raw)
|
|
58
|
+
return null;
|
|
59
|
+
if (typeof raw !== "object")
|
|
60
|
+
return null;
|
|
61
|
+
const record = raw;
|
|
62
|
+
const continuity = {
|
|
63
|
+
mustResolveBeforeHandoff: record.mustResolveBeforeHandoff === true,
|
|
64
|
+
lastFriendActivityAt: typeof record.lastFriendActivityAt === "string" ? record.lastFriendActivityAt : null,
|
|
65
|
+
};
|
|
66
|
+
if (!continuity.mustResolveBeforeHandoff && continuity.lastFriendActivityAt === null)
|
|
67
|
+
return null;
|
|
68
|
+
return continuity;
|
|
69
|
+
}
|
|
70
|
+
function extractContent(event) {
|
|
71
|
+
if (!event)
|
|
72
|
+
return null;
|
|
73
|
+
const text = (0, session_events_1.extractEventText)(event);
|
|
74
|
+
return text.length > 0 ? text : null;
|
|
75
|
+
}
|
|
76
|
+
function extractToolCallNames(event) {
|
|
77
|
+
if (!event)
|
|
78
|
+
return [];
|
|
79
|
+
return event.toolCalls
|
|
80
|
+
.map((call) => call.function.name)
|
|
81
|
+
.filter((name) => typeof name === "string" && name.length > 0);
|
|
82
|
+
}
|
|
83
|
+
/* v8 ignore stop */
|
|
84
|
+
function estimateTokenCount(messages) {
|
|
85
|
+
let charCount = 0;
|
|
86
|
+
for (const msg of messages) {
|
|
87
|
+
const content = extractContent(msg);
|
|
88
|
+
if (content)
|
|
89
|
+
charCount += content.length;
|
|
90
|
+
if (msg.toolCalls.length > 0)
|
|
91
|
+
charCount += JSON.stringify(msg.toolCalls).length;
|
|
92
|
+
}
|
|
93
|
+
return Math.ceil(charCount / 4);
|
|
94
|
+
}
|
|
95
|
+
/* v8 ignore start — filesystem traversal with defensive isDirectory checks */
|
|
96
|
+
function resolveAllSessionPaths(sessionsDir) {
|
|
97
|
+
const results = [];
|
|
98
|
+
if (!(0, shared_1.safeIsDirectory)(sessionsDir))
|
|
99
|
+
return results;
|
|
100
|
+
for (const friendId of (0, shared_1.safeReaddir)(sessionsDir)) {
|
|
101
|
+
const friendDir = path.join(sessionsDir, friendId);
|
|
102
|
+
if (!(0, shared_1.safeIsDirectory)(friendDir))
|
|
103
|
+
continue;
|
|
104
|
+
for (const channel of (0, shared_1.safeReaddir)(friendDir)) {
|
|
105
|
+
const channelDir = path.join(friendDir, channel);
|
|
106
|
+
if (!(0, shared_1.safeIsDirectory)(channelDir))
|
|
107
|
+
continue;
|
|
108
|
+
for (const file of (0, shared_1.safeReaddir)(channelDir)) {
|
|
109
|
+
if (!file.endsWith(".json"))
|
|
110
|
+
continue;
|
|
111
|
+
const key = file.slice(0, -5);
|
|
112
|
+
results.push({
|
|
113
|
+
friendId,
|
|
114
|
+
channel,
|
|
115
|
+
key,
|
|
116
|
+
sessionPath: path.join(channelDir, file),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return results;
|
|
122
|
+
}
|
|
123
|
+
/* v8 ignore stop */
|
|
124
|
+
/* v8 ignore start — defensive parsing */
|
|
125
|
+
function readSessionInventory(agentName, options = {}) {
|
|
126
|
+
const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
127
|
+
const now = options.now?.() ?? new Date();
|
|
128
|
+
const agentRoot = path.join(bundlesRoot, `${agentName}.ouro`);
|
|
129
|
+
const sessionsDir = path.join(agentRoot, "state", "sessions");
|
|
130
|
+
const friendsDir = path.join(agentRoot, "friends");
|
|
131
|
+
const allSessions = resolveAllSessionPaths(sessionsDir);
|
|
132
|
+
const items = [];
|
|
133
|
+
for (const { friendId, channel, key, sessionPath } of allSessions) {
|
|
134
|
+
if (friendId === "self" && channel === "inner")
|
|
135
|
+
continue;
|
|
136
|
+
const envelope = (0, shared_1.readSessionEnvelope)(sessionPath);
|
|
137
|
+
const events = envelope?.events ?? [];
|
|
138
|
+
const chronology = (0, session_events_1.deriveSessionChronology)(events);
|
|
139
|
+
const lastUsage = parseSessionUsage(envelope?.lastUsage);
|
|
140
|
+
const continuity = parseSessionContinuity(envelope?.state);
|
|
141
|
+
const hasObservedEventTiming = events.some((event) => event.time.authoredAt !== null || event.time.observedAt !== null);
|
|
142
|
+
const lastActivityAt = hasObservedEventTiming
|
|
143
|
+
? (chronology.lastActivityAt ?? continuity?.lastFriendActivityAt ?? (0, shared_1.safeFileMtime)(sessionPath) ?? now.toISOString())
|
|
144
|
+
: (continuity?.lastFriendActivityAt ?? (0, shared_1.safeFileMtime)(sessionPath) ?? now.toISOString());
|
|
145
|
+
const activitySource = hasObservedEventTiming && chronology.lastActivityAt
|
|
146
|
+
? "event-timeline"
|
|
147
|
+
: continuity?.lastFriendActivityAt
|
|
148
|
+
? "friend-facing"
|
|
149
|
+
: "mtime-fallback";
|
|
150
|
+
const userMessages = events.filter((m) => m.role === "user");
|
|
151
|
+
const assistantMessages = events.filter((m) => m.role === "assistant");
|
|
152
|
+
const lastUser = userMessages.length > 0 ? userMessages[userMessages.length - 1] : null;
|
|
153
|
+
const lastAssistant = assistantMessages.length > 0 ? assistantMessages[assistantMessages.length - 1] : null;
|
|
154
|
+
const latestToolCallNames = [];
|
|
155
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
156
|
+
const names = extractToolCallNames(events[i]);
|
|
157
|
+
if (names.length > 0) {
|
|
158
|
+
latestToolCallNames.push(...names);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const friendName = (0, shared_1.resolveFriendName)(friendsDir, friendId);
|
|
163
|
+
const lastMsg = events.length > 0 ? events[events.length - 1] : null;
|
|
164
|
+
const mustResolve = continuity?.mustResolveBeforeHandoff === true;
|
|
165
|
+
let replyState = "idle";
|
|
166
|
+
if (mustResolve) {
|
|
167
|
+
replyState = "on-hold";
|
|
168
|
+
}
|
|
169
|
+
else if (lastMsg?.role === "user") {
|
|
170
|
+
replyState = "needs-reply";
|
|
171
|
+
}
|
|
172
|
+
else if (events.length > 0) {
|
|
173
|
+
replyState = "monitoring";
|
|
174
|
+
}
|
|
175
|
+
items.push({
|
|
176
|
+
friendId,
|
|
177
|
+
friendName,
|
|
178
|
+
channel,
|
|
179
|
+
key,
|
|
180
|
+
sessionPath,
|
|
181
|
+
lastActivityAt,
|
|
182
|
+
activitySource,
|
|
183
|
+
replyState,
|
|
184
|
+
messageCount: events.length,
|
|
185
|
+
lastUsage,
|
|
186
|
+
continuity,
|
|
187
|
+
latestUserExcerpt: (0, shared_1.truncateExcerpt)(extractContent(lastUser)),
|
|
188
|
+
latestAssistantExcerpt: (0, shared_1.truncateExcerpt)(extractContent(lastAssistant)),
|
|
189
|
+
latestToolCallNames,
|
|
190
|
+
estimatedTokens: events.length > 0 ? estimateTokenCount(events) : null,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
items.sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt));
|
|
194
|
+
const ageThreshold = now.getTime() - shared_1.STALE_THRESHOLD_MS;
|
|
195
|
+
const activeCount = items.filter((item) => Date.parse(item.lastActivityAt) >= ageThreshold).length;
|
|
196
|
+
(0, runtime_1.emitNervesEvent)({
|
|
197
|
+
component: "heart",
|
|
198
|
+
event: "heart.outlook_sessions_read",
|
|
199
|
+
message: "reading outlook session inventory",
|
|
200
|
+
meta: { agentName, totalCount: items.length, activeCount },
|
|
201
|
+
});
|
|
202
|
+
return {
|
|
203
|
+
totalCount: items.length,
|
|
204
|
+
activeCount,
|
|
205
|
+
staleCount: items.length - activeCount,
|
|
206
|
+
items,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function readSessionTranscript(agentName, friendId, channel, key, options = {}) {
|
|
210
|
+
const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
211
|
+
const agentRoot = path.join(bundlesRoot, `${agentName}.ouro`);
|
|
212
|
+
const sessionPath = path.join(agentRoot, "state", "sessions", friendId, channel, `${key}.json`);
|
|
213
|
+
const envelope = (0, shared_1.readSessionEnvelope)(sessionPath);
|
|
214
|
+
if (!envelope)
|
|
215
|
+
return null;
|
|
216
|
+
const rawMessages = envelope.events;
|
|
217
|
+
const friendsDir = path.join(agentRoot, "friends");
|
|
218
|
+
const friendName = (0, shared_1.resolveFriendName)(friendsDir, friendId);
|
|
219
|
+
const messages = rawMessages;
|
|
220
|
+
return {
|
|
221
|
+
friendId,
|
|
222
|
+
friendName,
|
|
223
|
+
channel,
|
|
224
|
+
key,
|
|
225
|
+
sessionPath,
|
|
226
|
+
messageCount: messages.length,
|
|
227
|
+
lastUsage: parseSessionUsage(envelope.lastUsage),
|
|
228
|
+
continuity: parseSessionContinuity(envelope.state),
|
|
229
|
+
messages,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.STALE_THRESHOLD_MS = exports.BLOCKED_CODING_STATUSES = exports.ACTIVE_CODING_STATUSES = void 0;
|
|
37
|
+
exports.issue = issue;
|
|
38
|
+
exports.safeReaddir = safeReaddir;
|
|
39
|
+
exports.safeIsDirectory = safeIsDirectory;
|
|
40
|
+
exports.resolveFriendName = resolveFriendName;
|
|
41
|
+
exports.safeFileMtime = safeFileMtime;
|
|
42
|
+
exports.truncateExcerpt = truncateExcerpt;
|
|
43
|
+
exports.readSessionEnvelope = readSessionEnvelope;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const runtime_1 = require("../../../nerves/runtime");
|
|
47
|
+
const session_events_1 = require("../../session-events");
|
|
48
|
+
exports.ACTIVE_CODING_STATUSES = new Set(["spawning", "running", "waiting_input", "stalled"]);
|
|
49
|
+
exports.BLOCKED_CODING_STATUSES = new Set(["waiting_input", "stalled"]);
|
|
50
|
+
exports.STALE_THRESHOLD_MS = 24 * 60 * 60 * 1000;
|
|
51
|
+
function issue(code, detail) {
|
|
52
|
+
return { code, detail };
|
|
53
|
+
}
|
|
54
|
+
function safeReaddir(dir) {
|
|
55
|
+
try {
|
|
56
|
+
return fs.readdirSync(dir);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function safeIsDirectory(filePath) {
|
|
63
|
+
try {
|
|
64
|
+
return fs.statSync(filePath).isDirectory();
|
|
65
|
+
/* v8 ignore start */
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
/* v8 ignore stop */
|
|
71
|
+
}
|
|
72
|
+
/* v8 ignore start — defensive friend name resolution */
|
|
73
|
+
function resolveFriendName(friendsDir, friendId) {
|
|
74
|
+
try {
|
|
75
|
+
const raw = fs.readFileSync(path.join(friendsDir, `${friendId}.json`), "utf-8");
|
|
76
|
+
const parsed = JSON.parse(raw);
|
|
77
|
+
return typeof parsed.name === "string" ? parsed.name : friendId;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return friendId;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/* v8 ignore stop */
|
|
84
|
+
/* v8 ignore start — utility helpers with defensive branches */
|
|
85
|
+
function safeFileMtime(filePath) {
|
|
86
|
+
try {
|
|
87
|
+
return fs.statSync(filePath).mtime.toISOString();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function truncateExcerpt(content, maxLength = 200) {
|
|
94
|
+
if (!content)
|
|
95
|
+
return null;
|
|
96
|
+
if (content.length <= maxLength)
|
|
97
|
+
return content;
|
|
98
|
+
const truncated = content.slice(0, maxLength);
|
|
99
|
+
const lastSpace = truncated.lastIndexOf(" ");
|
|
100
|
+
return (lastSpace > maxLength * 0.6 ? truncated.slice(0, lastSpace) : truncated) + "…";
|
|
101
|
+
}
|
|
102
|
+
/* v8 ignore stop */
|
|
103
|
+
function readSessionEnvelope(sessionPath) {
|
|
104
|
+
(0, runtime_1.emitNervesEvent)({
|
|
105
|
+
component: "heart",
|
|
106
|
+
event: "heart.outlook_session_envelope_read",
|
|
107
|
+
message: "reading outlook session envelope",
|
|
108
|
+
meta: { sessionPath },
|
|
109
|
+
});
|
|
110
|
+
return (0, session_events_1.loadSessionEnvelopeFile)(sessionPath);
|
|
111
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildProgressStory = buildProgressStory;
|
|
4
|
+
exports.renderProgressStory = renderProgressStory;
|
|
5
|
+
const runtime_1 = require("../nerves/runtime");
|
|
6
|
+
function labelForScope(scope) {
|
|
7
|
+
return scope === "inner-delegation" ? "inner work" : "shared work";
|
|
8
|
+
}
|
|
9
|
+
function compactDetail(text) {
|
|
10
|
+
if (typeof text !== "string")
|
|
11
|
+
return null;
|
|
12
|
+
const trimmed = text.trim();
|
|
13
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
14
|
+
}
|
|
15
|
+
function buildProgressStory(input) {
|
|
16
|
+
const detailLines = [
|
|
17
|
+
compactDetail(input.objective),
|
|
18
|
+
compactDetail(input.outcomeText),
|
|
19
|
+
compactDetail(input.bridgeId ? `bridge: ${input.bridgeId}` : null),
|
|
20
|
+
compactDetail(input.taskName ? `task: ${input.taskName}` : null),
|
|
21
|
+
].filter((line) => Boolean(line));
|
|
22
|
+
const story = {
|
|
23
|
+
statusLine: `${labelForScope(input.scope)}: ${input.phase}`,
|
|
24
|
+
detailLines,
|
|
25
|
+
};
|
|
26
|
+
(0, runtime_1.emitNervesEvent)({
|
|
27
|
+
component: "engine",
|
|
28
|
+
event: "engine.progress_story_build",
|
|
29
|
+
message: "built shared progress story",
|
|
30
|
+
meta: {
|
|
31
|
+
scope: input.scope,
|
|
32
|
+
phase: input.phase,
|
|
33
|
+
detailLines: detailLines.length,
|
|
34
|
+
hasBridge: Boolean(input.bridgeId),
|
|
35
|
+
hasTask: Boolean(input.taskName),
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
return story;
|
|
39
|
+
}
|
|
40
|
+
function renderProgressStory(story) {
|
|
41
|
+
return [story.statusLine, ...story.detailLines].join("\n");
|
|
42
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildFailoverContext = buildFailoverContext;
|
|
4
|
+
exports.handleFailoverReply = handleFailoverReply;
|
|
5
|
+
const runtime_1 = require("../nerves/runtime");
|
|
6
|
+
const FAILING_PROVIDER_LABELS = {
|
|
7
|
+
"auth-failure": "its credentials need to be refreshed",
|
|
8
|
+
"usage-limit": "has also hit its usage limit",
|
|
9
|
+
"rate-limit": "is also being rate limited",
|
|
10
|
+
"server-error": "is also experiencing an outage",
|
|
11
|
+
"network-error": "could not be reached",
|
|
12
|
+
"unknown": "could not be reached",
|
|
13
|
+
};
|
|
14
|
+
const CLASSIFICATION_LABELS = {
|
|
15
|
+
"auth-failure": "authentication failed",
|
|
16
|
+
"usage-limit": "hit its usage limit",
|
|
17
|
+
"rate-limit": "is being rate limited",
|
|
18
|
+
"server-error": "is experiencing an outage",
|
|
19
|
+
"network-error": "is unreachable (network error)",
|
|
20
|
+
"unknown": "encountered an error",
|
|
21
|
+
};
|
|
22
|
+
function buildFailoverContext(_errorMessage, classification, currentProvider, currentModel, agentName, inventory, providerModels) {
|
|
23
|
+
const label = CLASSIFICATION_LABELS[classification];
|
|
24
|
+
const providerWithModel = currentModel ? `${currentProvider} (${currentModel})` : currentProvider;
|
|
25
|
+
const errorSummary = `${providerWithModel} ${label}`;
|
|
26
|
+
const workingProviders = [];
|
|
27
|
+
const unconfiguredProviders = [];
|
|
28
|
+
const failingProviders = [];
|
|
29
|
+
for (const [provider, result] of Object.entries(inventory)) {
|
|
30
|
+
if (result.ok) {
|
|
31
|
+
workingProviders.push(provider);
|
|
32
|
+
}
|
|
33
|
+
else if (result.classification === "auth-failure" && result.message === "no credentials configured") {
|
|
34
|
+
unconfiguredProviders.push(provider);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// Configured but ping failed (expired token, provider also down, etc.)
|
|
38
|
+
failingProviders.push({ provider, classification: result.classification });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const lines = [`${errorSummary}.`];
|
|
42
|
+
if (workingProviders.length > 0) {
|
|
43
|
+
const switchDescriptions = workingProviders.map((p) => {
|
|
44
|
+
const model = providerModels[p];
|
|
45
|
+
return model ? `${p} (${model})` : /* v8 ignore next -- defensive: model always present in secrets @preserve */ p;
|
|
46
|
+
});
|
|
47
|
+
const switchOptions = workingProviders.map((p) => `"switch to ${p}"`).join(" or ");
|
|
48
|
+
lines.push(`these providers are ready to go: ${switchDescriptions.join(", ")}.`);
|
|
49
|
+
lines.push(`reply ${switchOptions} to continue.`);
|
|
50
|
+
}
|
|
51
|
+
if (failingProviders.length > 0) {
|
|
52
|
+
for (const { provider, classification } of failingProviders) {
|
|
53
|
+
/* v8 ignore next -- defensive: all classifications have labels @preserve */
|
|
54
|
+
const detail = FAILING_PROVIDER_LABELS[classification] ?? "could not be reached";
|
|
55
|
+
lines.push(`${provider} is configured but ${detail}. run \`ouro auth --agent ${agentName} --provider ${provider}\` to refresh.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (unconfiguredProviders.length > 0) {
|
|
59
|
+
lines.push(`to set up ${unconfiguredProviders.join(", ")}, run \`ouro auth --agent ${agentName}\` in terminal.`);
|
|
60
|
+
}
|
|
61
|
+
if (workingProviders.length === 0 && unconfiguredProviders.length === 0 && failingProviders.length === 0) {
|
|
62
|
+
lines.push(`no other providers are available. run \`ouro auth --agent ${agentName}\` in terminal to configure one.`);
|
|
63
|
+
}
|
|
64
|
+
(0, runtime_1.emitNervesEvent)({
|
|
65
|
+
component: "engine",
|
|
66
|
+
event: "engine.failover_context_built",
|
|
67
|
+
message: "built provider failover context",
|
|
68
|
+
meta: { currentProvider, classification, workingProviders, unconfiguredProviders },
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
errorSummary,
|
|
72
|
+
classification,
|
|
73
|
+
currentProvider,
|
|
74
|
+
agentName,
|
|
75
|
+
workingProviders,
|
|
76
|
+
unconfiguredProviders,
|
|
77
|
+
userMessage: lines.join(" "),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function handleFailoverReply(reply, context) {
|
|
81
|
+
const lower = reply.toLowerCase().trim();
|
|
82
|
+
for (const provider of context.workingProviders) {
|
|
83
|
+
if (lower.includes(`switch to ${provider}`) || lower === provider) {
|
|
84
|
+
return { action: "switch", provider };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { action: "dismiss" };
|
|
88
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanitizeErrorMessage = sanitizeErrorMessage;
|
|
4
|
+
exports.pingProvider = pingProvider;
|
|
5
|
+
exports.runHealthInventory = runHealthInventory;
|
|
6
|
+
const identity_1 = require("./identity");
|
|
7
|
+
const anthropic_1 = require("./providers/anthropic");
|
|
8
|
+
const azure_1 = require("./providers/azure");
|
|
9
|
+
const minimax_1 = require("./providers/minimax");
|
|
10
|
+
const openai_codex_1 = require("./providers/openai-codex");
|
|
11
|
+
const github_copilot_1 = require("./providers/github-copilot");
|
|
12
|
+
const auth_flow_1 = require("./auth/auth-flow");
|
|
13
|
+
const runtime_1 = require("../nerves/runtime");
|
|
14
|
+
const PING_TIMEOUT_MS = 10_000;
|
|
15
|
+
/**
|
|
16
|
+
* Strip raw JSON/HTML API response bodies from error messages.
|
|
17
|
+
* SDK errors often include the full response: "400 {"type":"error",...}" or "403 <html>...".
|
|
18
|
+
* Extract just the HTTP status and a short human-readable summary.
|
|
19
|
+
*/
|
|
20
|
+
function sanitizeErrorMessage(message) {
|
|
21
|
+
const statusMatch = message.match(/^(\d{3})\s/);
|
|
22
|
+
if (!statusMatch)
|
|
23
|
+
return message;
|
|
24
|
+
const status = statusMatch[1];
|
|
25
|
+
const body = message.slice(status.length).trim();
|
|
26
|
+
// HTML response (Cloudflare challenge, error pages, etc.)
|
|
27
|
+
if (body.startsWith("<") || body.includes("<!DOCTYPE") || body.includes("<html")) {
|
|
28
|
+
return `HTTP ${status}`;
|
|
29
|
+
}
|
|
30
|
+
// JSON response
|
|
31
|
+
if (body.startsWith("{")) {
|
|
32
|
+
try {
|
|
33
|
+
const json = JSON.parse(body);
|
|
34
|
+
const inner = json?.error?.message;
|
|
35
|
+
if (typeof inner === "string" && inner && inner !== "Error") {
|
|
36
|
+
return `${status} ${inner}`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch { /* not valid JSON */ }
|
|
40
|
+
return `HTTP ${status}`;
|
|
41
|
+
}
|
|
42
|
+
// Already clean (e.g., "401 Provided authentication token is expired.")
|
|
43
|
+
return message;
|
|
44
|
+
}
|
|
45
|
+
function hasEmptyCredentials(provider, config) {
|
|
46
|
+
const record = config;
|
|
47
|
+
return identity_1.PROVIDER_CREDENTIALS[provider].required.some((key) => !record[key]);
|
|
48
|
+
}
|
|
49
|
+
function createRuntimeForPing(provider, _config) {
|
|
50
|
+
// The provider constructors read credentials from the active config via getXxxConfig().
|
|
51
|
+
// For ping, this is acceptable because verifyProviderCredentials patches the runtime
|
|
52
|
+
// config before calling ping. The model string is a default — for anthropic the ping
|
|
53
|
+
// overrides it with haiku anyway, and for others it's used in a minimal API call.
|
|
54
|
+
const DEFAULT_MODELS = {
|
|
55
|
+
anthropic: "claude-haiku-4-5-20251001",
|
|
56
|
+
azure: "gpt-4o",
|
|
57
|
+
minimax: "MiniMax-M2.7",
|
|
58
|
+
"openai-codex": "codex-mini-latest",
|
|
59
|
+
"github-copilot": "gpt-4o",
|
|
60
|
+
};
|
|
61
|
+
/* v8 ignore next -- fallback: all known providers are in DEFAULT_MODELS @preserve */
|
|
62
|
+
const model = DEFAULT_MODELS[provider] ?? "unknown";
|
|
63
|
+
switch (provider) {
|
|
64
|
+
case "anthropic":
|
|
65
|
+
return (0, anthropic_1.createAnthropicProviderRuntime)(model);
|
|
66
|
+
case "azure":
|
|
67
|
+
return (0, azure_1.createAzureProviderRuntime)(model);
|
|
68
|
+
case "minimax":
|
|
69
|
+
return (0, minimax_1.createMinimaxProviderRuntime)(model);
|
|
70
|
+
case "openai-codex":
|
|
71
|
+
return (0, openai_codex_1.createOpenAICodexProviderRuntime)(model);
|
|
72
|
+
case "github-copilot":
|
|
73
|
+
return (0, github_copilot_1.createGithubCopilotProviderRuntime)(model);
|
|
74
|
+
/* v8 ignore next 2 -- exhaustive: all providers handled above @preserve */
|
|
75
|
+
default:
|
|
76
|
+
throw new Error(`unsupported provider for ping: ${provider}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function pingProvider(provider, config) {
|
|
80
|
+
if (hasEmptyCredentials(provider, config)) {
|
|
81
|
+
return { ok: false, classification: "auth-failure", message: "no credentials configured" };
|
|
82
|
+
}
|
|
83
|
+
let runtime;
|
|
84
|
+
try {
|
|
85
|
+
runtime = createRuntimeForPing(provider, config);
|
|
86
|
+
/* v8 ignore start -- factory creation failure: tested via individual provider init tests @preserve */
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
classification: "auth-failure",
|
|
92
|
+
message: error instanceof Error ? error.message : String(error),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/* v8 ignore stop */
|
|
96
|
+
try {
|
|
97
|
+
const controller = new AbortController();
|
|
98
|
+
/* v8 ignore next -- timeout callback: only fires after 10s, tests resolve faster @preserve */
|
|
99
|
+
const timeout = setTimeout(() => controller.abort(), PING_TIMEOUT_MS);
|
|
100
|
+
try {
|
|
101
|
+
// Minimal API call — no thinking, no reasoning, no tools.
|
|
102
|
+
if (provider === "anthropic") {
|
|
103
|
+
// Use haiku for the ping — setup tokens may not have access to newer
|
|
104
|
+
// models, but if haiku works, the credentials are valid.
|
|
105
|
+
// Override the beta header to exclude thinking (which requires a
|
|
106
|
+
// thinking param in the request body).
|
|
107
|
+
const client = runtime.client;
|
|
108
|
+
await client.messages.create({ model: "claude-haiku-4-5-20251001", max_tokens: 1, messages: [{ role: "user", content: "ping" }] }, { signal: controller.signal, headers: { "anthropic-beta": "claude-code-20250219,oauth-2025-04-20" } });
|
|
109
|
+
}
|
|
110
|
+
else if (provider === "openai-codex") {
|
|
111
|
+
// Codex uses the Responses API (chatgpt.com/backend-api/codex/responses),
|
|
112
|
+
// not the Chat Completions API. Ping via responses endpoint.
|
|
113
|
+
const client = runtime.client;
|
|
114
|
+
await client.responses.create({ model: runtime.model, input: "ping", store: false }, { signal: controller.signal });
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// OpenAI-compatible providers (azure, minimax, github-copilot)
|
|
118
|
+
const client = runtime.client;
|
|
119
|
+
await client.chat.completions.create({ model: runtime.model, max_tokens: 1, messages: [{ role: "user", content: "ping" }] }, { signal: controller.signal });
|
|
120
|
+
}
|
|
121
|
+
return { ok: true };
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
clearTimeout(timeout);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
const err = error instanceof Error ? error : /* v8 ignore next -- defensive @preserve */ new Error(String(error));
|
|
129
|
+
let classification;
|
|
130
|
+
try {
|
|
131
|
+
classification = runtime.classifyError(err);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
/* v8 ignore next -- defensive: classifyError should not throw @preserve */
|
|
135
|
+
classification = "unknown";
|
|
136
|
+
}
|
|
137
|
+
(0, runtime_1.emitNervesEvent)({
|
|
138
|
+
component: "engine",
|
|
139
|
+
event: "engine.provider_ping_fail",
|
|
140
|
+
message: `provider ping failed: ${provider}`,
|
|
141
|
+
meta: { provider, classification, error: err.message },
|
|
142
|
+
});
|
|
143
|
+
return { ok: false, classification, message: sanitizeErrorMessage(err.message) };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const PINGABLE_PROVIDERS = ["anthropic", "openai-codex", "azure", "minimax", "github-copilot"];
|
|
147
|
+
async function runHealthInventory(agentName, currentProvider, deps = {}) {
|
|
148
|
+
/* v8 ignore next -- default: tests inject ping dep @preserve */
|
|
149
|
+
const ping = deps.ping ?? pingProvider;
|
|
150
|
+
const { secrets } = (0, auth_flow_1.loadAgentSecrets)(agentName);
|
|
151
|
+
const providers = PINGABLE_PROVIDERS.filter((p) => p !== currentProvider);
|
|
152
|
+
const results = await Promise.all(providers.map(async (provider) => {
|
|
153
|
+
const config = secrets.providers[provider];
|
|
154
|
+
const result = await ping(provider, config);
|
|
155
|
+
return [provider, result];
|
|
156
|
+
}));
|
|
157
|
+
const inventory = {};
|
|
158
|
+
for (const [provider, result] of results) {
|
|
159
|
+
inventory[provider] = result;
|
|
160
|
+
}
|
|
161
|
+
return inventory;
|
|
162
|
+
}
|