@ouro.bot/cli 0.1.0-alpha.28 → 0.1.0-alpha.280
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 +187 -191
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +1 -1
- package/changelog.json +1696 -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/presence.js +185 -0
- package/dist/heart/active-work.js +832 -0
- package/dist/heart/agent-entry.js +37 -2
- 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/commitments.js +111 -0
- package/dist/heart/config-registry.js +304 -0
- package/dist/heart/config.js +63 -30
- package/dist/heart/core.js +644 -196
- 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/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +574 -0
- package/dist/heart/daemon/cli-exec.js +1932 -0
- package/dist/heart/daemon/cli-parse.js +762 -0
- package/dist/heart/daemon/cli-render.js +503 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/daemon-cli.js +29 -1155
- package/dist/heart/daemon/daemon-entry.js +234 -3
- package/dist/heart/daemon/daemon-health.js +136 -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 +702 -57
- 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/inner-status.js +89 -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 +180 -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/task-scheduler.js +3 -25
- package/dist/heart/daemon/thoughts.js +510 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/habits/habit-migration.js +181 -0
- package/dist/heart/habits/habit-parser.js +119 -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 +1618 -0
- package/dist/heart/outlook/outlook-render.js +1032 -0
- package/dist/heart/outlook/outlook-types.js +7 -0
- package/dist/heart/outlook/outlook-view.js +194 -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 +172 -0
- package/dist/heart/session-recall.js +216 -0
- package/dist/heart/start-of-turn-packet.js +330 -0
- package/dist/heart/streaming.js +36 -27
- package/dist/heart/sync.js +277 -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-loop.js +200 -0
- package/dist/heart/turn-context.js +358 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/heart/versioning/ouro-bot-global-installer.js +128 -0
- 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 +126 -66
- package/dist/mind/bundle-manifest.js +8 -1
- package/dist/mind/context.js +125 -14
- package/dist/mind/{memory.js → diary.js} +68 -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 +874 -109
- 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 +50 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +220 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-Ck8agNeO.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/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 +149 -2
- 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 +515 -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 +369 -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 +11 -28
- package/dist/repertoire/tools-base.js +43 -771
- package/dist/repertoire/tools-bluebubbles.js +201 -0
- package/dist/repertoire/tools-bridge.js +141 -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 +62 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-memory.js +347 -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 +155 -130
- 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 +97 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -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 +110 -0
- package/dist/senses/bluebubbles/index.js +1410 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +140 -23
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +20 -5
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
- package/dist/senses/bluebubbles/runtime-state.js +109 -0
- package/dist/senses/bluebubbles/session-cleanup.js +72 -0
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +211 -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 +595 -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 +569 -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 +593 -85
- package/dist/senses/pipeline.js +552 -0
- package/dist/senses/shared-turn.js +199 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams.js +664 -165
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +14 -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 -421
- 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
package/dist/mind/context.js
CHANGED
|
@@ -36,7 +36,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.trimMessages = trimMessages;
|
|
37
37
|
exports.validateSessionMessages = validateSessionMessages;
|
|
38
38
|
exports.repairSessionMessages = repairSessionMessages;
|
|
39
|
+
exports.migrateToolNames = migrateToolNames;
|
|
39
40
|
exports.saveSession = saveSession;
|
|
41
|
+
exports.appendSyntheticAssistantMessage = appendSyntheticAssistantMessage;
|
|
40
42
|
exports.loadSession = loadSession;
|
|
41
43
|
exports.postTurn = postTurn;
|
|
42
44
|
exports.deleteSession = deleteSession;
|
|
@@ -50,17 +52,17 @@ function buildTrimmableBlocks(messages) {
|
|
|
50
52
|
let i = 0;
|
|
51
53
|
while (i < messages.length) {
|
|
52
54
|
const msg = messages[i];
|
|
53
|
-
if (msg
|
|
55
|
+
if (msg.role === "system") {
|
|
54
56
|
i++;
|
|
55
57
|
continue;
|
|
56
58
|
}
|
|
57
59
|
// Tool coherence block: assistant message with tool_calls + immediately following tool results
|
|
58
|
-
if (msg
|
|
60
|
+
if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
|
|
59
61
|
const indices = [i];
|
|
60
62
|
i++;
|
|
61
63
|
while (i < messages.length) {
|
|
62
64
|
const next = messages[i];
|
|
63
|
-
if (next
|
|
65
|
+
if (next.role !== "tool")
|
|
64
66
|
break;
|
|
65
67
|
indices.push(i);
|
|
66
68
|
i++;
|
|
@@ -78,13 +80,13 @@ function buildTrimmableBlocks(messages) {
|
|
|
78
80
|
function getSystemMessageIndices(messages) {
|
|
79
81
|
const indices = [];
|
|
80
82
|
for (let i = 0; i < messages.length; i++) {
|
|
81
|
-
if (messages[i]
|
|
83
|
+
if (messages[i].role === "system")
|
|
82
84
|
indices.push(i);
|
|
83
85
|
}
|
|
84
86
|
return indices;
|
|
85
87
|
}
|
|
86
88
|
function buildTrimmedMessages(messages, kept) {
|
|
87
|
-
return messages.filter((m, idx) => m
|
|
89
|
+
return messages.filter((m, idx) => m.role === "system" || kept.has(idx));
|
|
88
90
|
}
|
|
89
91
|
function trimMessages(messages, maxTokens, contextMargin, actualTokenCount) {
|
|
90
92
|
const targetTokens = Math.floor(maxTokens * (1 - contextMargin / 100));
|
|
@@ -132,7 +134,7 @@ function trimMessages(messages, maxTokens, contextMargin, actualTokenCount) {
|
|
|
132
134
|
let remaining = actualTokenCount;
|
|
133
135
|
const kept = new Set();
|
|
134
136
|
for (let i = 0; i < messages.length; i++) {
|
|
135
|
-
if (messages[i]
|
|
137
|
+
if (messages[i].role !== "system")
|
|
136
138
|
kept.add(i);
|
|
137
139
|
}
|
|
138
140
|
// Drop oldest blocks until we fall under target.
|
|
@@ -146,7 +148,7 @@ function trimMessages(messages, maxTokens, contextMargin, actualTokenCount) {
|
|
|
146
148
|
let trimmed = buildTrimmedMessages(messages, kept);
|
|
147
149
|
// If we're still above budget after dropping everything trimmable, preserve system only.
|
|
148
150
|
if (remaining > targetTokens) {
|
|
149
|
-
trimmed = messages.filter((m) => m
|
|
151
|
+
trimmed = messages.filter((m) => m.role === "system");
|
|
150
152
|
}
|
|
151
153
|
const estimatedAfter = (0, token_estimate_1.estimateTokensForMessages)(trimmed);
|
|
152
154
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -219,7 +221,7 @@ function repairSessionMessages(messages) {
|
|
|
219
221
|
result.push(msg);
|
|
220
222
|
}
|
|
221
223
|
(0, runtime_1.emitNervesEvent)({
|
|
222
|
-
level: "
|
|
224
|
+
level: "info",
|
|
223
225
|
event: "mind.session_invariant_repair",
|
|
224
226
|
component: "mind",
|
|
225
227
|
message: "repaired session invariant violations",
|
|
@@ -227,11 +229,79 @@ function repairSessionMessages(messages) {
|
|
|
227
229
|
});
|
|
228
230
|
return result;
|
|
229
231
|
}
|
|
230
|
-
function
|
|
232
|
+
function stripOrphanedToolResults(messages) {
|
|
233
|
+
const validCallIds = new Set();
|
|
234
|
+
for (const msg of messages) {
|
|
235
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.tool_calls))
|
|
236
|
+
continue;
|
|
237
|
+
for (const toolCall of msg.tool_calls)
|
|
238
|
+
validCallIds.add(toolCall.id);
|
|
239
|
+
}
|
|
240
|
+
let removed = 0;
|
|
241
|
+
const repaired = messages.filter((msg) => {
|
|
242
|
+
if (msg.role !== "tool")
|
|
243
|
+
return true;
|
|
244
|
+
const keep = validCallIds.has(msg.tool_call_id);
|
|
245
|
+
if (!keep)
|
|
246
|
+
removed++;
|
|
247
|
+
return keep;
|
|
248
|
+
});
|
|
249
|
+
if (removed > 0) {
|
|
250
|
+
(0, runtime_1.emitNervesEvent)({
|
|
251
|
+
level: "info",
|
|
252
|
+
event: "mind.session_orphan_tool_result_repair",
|
|
253
|
+
component: "mind",
|
|
254
|
+
message: "removed orphaned tool results from session history",
|
|
255
|
+
meta: { removed },
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return repaired;
|
|
259
|
+
}
|
|
260
|
+
// Tool renames that have shipped. Old names in session history confuse the
|
|
261
|
+
// model into calling tools that no longer exist. Applied on session load so
|
|
262
|
+
// the transcript uses the current vocabulary.
|
|
263
|
+
const TOOL_NAME_MIGRATIONS = {
|
|
264
|
+
final_answer: "settle",
|
|
265
|
+
no_response: "observe",
|
|
266
|
+
go_inward: "ponder",
|
|
267
|
+
descend: "ponder",
|
|
268
|
+
memory_save: "diary_write",
|
|
269
|
+
memory_search: "recall",
|
|
270
|
+
};
|
|
271
|
+
function migrateToolNames(messages) {
|
|
272
|
+
let migrated = 0;
|
|
273
|
+
const result = messages.map((msg) => {
|
|
274
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.tool_calls) || msg.tool_calls.length === 0)
|
|
275
|
+
return msg;
|
|
276
|
+
let changed = false;
|
|
277
|
+
const updatedCalls = msg.tool_calls.map((tc) => {
|
|
278
|
+
if (tc.type !== "function")
|
|
279
|
+
return tc;
|
|
280
|
+
const newName = TOOL_NAME_MIGRATIONS[tc.function.name];
|
|
281
|
+
if (!newName)
|
|
282
|
+
return tc;
|
|
283
|
+
changed = true;
|
|
284
|
+
migrated++;
|
|
285
|
+
return { ...tc, function: { ...tc.function, name: newName } };
|
|
286
|
+
});
|
|
287
|
+
return changed ? { ...msg, tool_calls: updatedCalls } : msg;
|
|
288
|
+
});
|
|
289
|
+
if (migrated > 0) {
|
|
290
|
+
(0, runtime_1.emitNervesEvent)({
|
|
291
|
+
level: "info",
|
|
292
|
+
event: "mind.session_tool_name_migration",
|
|
293
|
+
component: "mind",
|
|
294
|
+
message: "migrated deprecated tool names in session history",
|
|
295
|
+
meta: { migrated },
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
return result;
|
|
299
|
+
}
|
|
300
|
+
function saveSession(filePath, messages, lastUsage, state) {
|
|
231
301
|
const violations = validateSessionMessages(messages);
|
|
232
302
|
if (violations.length > 0) {
|
|
233
303
|
(0, runtime_1.emitNervesEvent)({
|
|
234
|
-
level: "
|
|
304
|
+
level: "info",
|
|
235
305
|
event: "mind.session_invariant_violation",
|
|
236
306
|
component: "mind",
|
|
237
307
|
message: "session invariant violated on save",
|
|
@@ -239,12 +309,41 @@ function saveSession(filePath, messages, lastUsage) {
|
|
|
239
309
|
});
|
|
240
310
|
messages = repairSessionMessages(messages);
|
|
241
311
|
}
|
|
312
|
+
messages = stripOrphanedToolResults(messages);
|
|
242
313
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
243
314
|
const envelope = { version: 1, messages };
|
|
244
315
|
if (lastUsage)
|
|
245
316
|
envelope.lastUsage = lastUsage;
|
|
317
|
+
if (state?.mustResolveBeforeHandoff === true || typeof state?.lastFriendActivityAt === "string") {
|
|
318
|
+
envelope.state = {
|
|
319
|
+
...(state?.mustResolveBeforeHandoff === true ? { mustResolveBeforeHandoff: true } : {}),
|
|
320
|
+
...(typeof state?.lastFriendActivityAt === "string" ? { lastFriendActivityAt: state.lastFriendActivityAt } : {}),
|
|
321
|
+
};
|
|
322
|
+
}
|
|
246
323
|
fs.writeFileSync(filePath, JSON.stringify(envelope, null, 2));
|
|
247
324
|
}
|
|
325
|
+
function appendSyntheticAssistantMessage(filePath, content) {
|
|
326
|
+
try {
|
|
327
|
+
if (!fs.existsSync(filePath))
|
|
328
|
+
return false;
|
|
329
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
330
|
+
const data = JSON.parse(raw);
|
|
331
|
+
if (data.version !== 1 || !Array.isArray(data.messages))
|
|
332
|
+
return false;
|
|
333
|
+
data.messages.push({ role: "assistant", content });
|
|
334
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
335
|
+
(0, runtime_1.emitNervesEvent)({
|
|
336
|
+
component: "mind",
|
|
337
|
+
event: "mind.session_synthetic_message_appended",
|
|
338
|
+
message: "appended synthetic assistant message to session",
|
|
339
|
+
meta: { path: filePath, contentLength: content.length },
|
|
340
|
+
});
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
248
347
|
function loadSession(filePath) {
|
|
249
348
|
try {
|
|
250
349
|
const raw = fs.readFileSync(filePath, "utf-8");
|
|
@@ -255,7 +354,7 @@ function loadSession(filePath) {
|
|
|
255
354
|
const violations = validateSessionMessages(messages);
|
|
256
355
|
if (violations.length > 0) {
|
|
257
356
|
(0, runtime_1.emitNervesEvent)({
|
|
258
|
-
level: "
|
|
357
|
+
level: "info",
|
|
259
358
|
event: "mind.session_invariant_violation",
|
|
260
359
|
component: "mind",
|
|
261
360
|
message: "session invariant violated on load",
|
|
@@ -263,13 +362,25 @@ function loadSession(filePath) {
|
|
|
263
362
|
});
|
|
264
363
|
messages = repairSessionMessages(messages);
|
|
265
364
|
}
|
|
266
|
-
|
|
365
|
+
messages = stripOrphanedToolResults(messages);
|
|
366
|
+
messages = migrateToolNames(messages);
|
|
367
|
+
const rawState = data?.state && typeof data.state === "object" && data.state !== null
|
|
368
|
+
? data.state
|
|
369
|
+
: undefined;
|
|
370
|
+
const state = rawState && (rawState.mustResolveBeforeHandoff === true
|
|
371
|
+
|| typeof rawState.lastFriendActivityAt === "string")
|
|
372
|
+
? {
|
|
373
|
+
...(rawState.mustResolveBeforeHandoff === true ? { mustResolveBeforeHandoff: true } : {}),
|
|
374
|
+
...(typeof rawState.lastFriendActivityAt === "string" ? { lastFriendActivityAt: rawState.lastFriendActivityAt } : {}),
|
|
375
|
+
}
|
|
376
|
+
: undefined;
|
|
377
|
+
return { messages, lastUsage: data.lastUsage, state };
|
|
267
378
|
}
|
|
268
379
|
catch {
|
|
269
380
|
return null;
|
|
270
381
|
}
|
|
271
382
|
}
|
|
272
|
-
function postTurn(messages, sessPath, usage, hooks) {
|
|
383
|
+
function postTurn(messages, sessPath, usage, hooks, state) {
|
|
273
384
|
if (hooks?.beforeTrim) {
|
|
274
385
|
try {
|
|
275
386
|
hooks.beforeTrim([...messages]);
|
|
@@ -289,7 +400,7 @@ function postTurn(messages, sessPath, usage, hooks) {
|
|
|
289
400
|
const { maxTokens, contextMargin } = (0, config_1.getContextConfig)();
|
|
290
401
|
const trimmed = trimMessages(messages, maxTokens, contextMargin, usage?.input_tokens);
|
|
291
402
|
messages.splice(0, messages.length, ...trimmed);
|
|
292
|
-
saveSession(sessPath, messages, usage);
|
|
403
|
+
saveSession(sessPath, messages, usage, state);
|
|
293
404
|
}
|
|
294
405
|
function deleteSession(filePath) {
|
|
295
406
|
try {
|
|
@@ -33,52 +33,24 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
37
|
-
exports.
|
|
38
|
-
exports.
|
|
39
|
-
exports.
|
|
40
|
-
exports.
|
|
36
|
+
exports.ensureDiaryStorePaths = ensureDiaryStorePaths;
|
|
37
|
+
exports.appendEntriesWithDedup = appendEntriesWithDedup;
|
|
38
|
+
exports.resolveDiaryRoot = resolveDiaryRoot;
|
|
39
|
+
exports.readDiaryEntries = readDiaryEntries;
|
|
40
|
+
exports.saveDiaryEntry = saveDiaryEntry;
|
|
41
41
|
exports.backfillEmbeddings = backfillEmbeddings;
|
|
42
|
-
exports.
|
|
42
|
+
exports.searchDiaryEntries = searchDiaryEntries;
|
|
43
43
|
const fs = __importStar(require("fs"));
|
|
44
44
|
const path = __importStar(require("path"));
|
|
45
45
|
const crypto_1 = require("crypto");
|
|
46
|
-
const config_1 = require("../heart/config");
|
|
47
46
|
const identity_1 = require("../heart/identity");
|
|
48
47
|
const runtime_1 = require("../nerves/runtime");
|
|
48
|
+
const associative_recall_1 = require("./associative-recall");
|
|
49
|
+
const embedding_provider_1 = require("./embedding-provider");
|
|
49
50
|
const DEDUP_THRESHOLD = 0.6;
|
|
51
|
+
const SEMANTIC_DEDUP_THRESHOLD = 0.95;
|
|
50
52
|
const ENTITY_TOKEN = /[a-z0-9]+/g;
|
|
51
|
-
|
|
52
|
-
class OpenAIEmbeddingProvider {
|
|
53
|
-
apiKey;
|
|
54
|
-
model;
|
|
55
|
-
constructor(apiKey, model = DEFAULT_EMBEDDING_MODEL) {
|
|
56
|
-
this.apiKey = apiKey;
|
|
57
|
-
this.model = model;
|
|
58
|
-
}
|
|
59
|
-
async embed(texts) {
|
|
60
|
-
const response = await fetch("https://api.openai.com/v1/embeddings", {
|
|
61
|
-
method: "POST",
|
|
62
|
-
headers: {
|
|
63
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
64
|
-
"Content-Type": "application/json",
|
|
65
|
-
},
|
|
66
|
-
body: JSON.stringify({
|
|
67
|
-
model: this.model,
|
|
68
|
-
input: texts,
|
|
69
|
-
}),
|
|
70
|
-
});
|
|
71
|
-
if (!response.ok) {
|
|
72
|
-
throw new Error(`embedding request failed: ${response.status} ${response.statusText}`);
|
|
73
|
-
}
|
|
74
|
-
const payload = (await response.json());
|
|
75
|
-
if (!payload.data || payload.data.length !== texts.length) {
|
|
76
|
-
throw new Error("embedding response missing expected vectors");
|
|
77
|
-
}
|
|
78
|
-
return payload.data.map((entry) => entry.embedding);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
function ensureMemoryStorePaths(rootDir) {
|
|
53
|
+
function ensureDiaryStorePaths(rootDir) {
|
|
82
54
|
const factsPath = path.join(rootDir, "facts.jsonl");
|
|
83
55
|
const entitiesPath = path.join(rootDir, "entities.json");
|
|
84
56
|
const dailyDir = path.join(rootDir, "daily");
|
|
@@ -90,8 +62,8 @@ function ensureMemoryStorePaths(rootDir) {
|
|
|
90
62
|
fs.writeFileSync(entitiesPath, "{}\n", "utf8");
|
|
91
63
|
(0, runtime_1.emitNervesEvent)({
|
|
92
64
|
component: "mind",
|
|
93
|
-
event: "mind.
|
|
94
|
-
message: "
|
|
65
|
+
event: "mind.diary_paths_ready",
|
|
66
|
+
message: "diary store paths ready",
|
|
95
67
|
meta: { rootDir },
|
|
96
68
|
});
|
|
97
69
|
return { rootDir, factsPath, entitiesPath, dailyDir };
|
|
@@ -114,15 +86,22 @@ function overlapScore(left, right) {
|
|
|
114
86
|
}
|
|
115
87
|
return common / Math.min(leftWords.size, rightWords.size);
|
|
116
88
|
}
|
|
117
|
-
function
|
|
89
|
+
function readExistingEntries(factsPath) {
|
|
118
90
|
if (!fs.existsSync(factsPath))
|
|
119
91
|
return [];
|
|
120
92
|
const raw = fs.readFileSync(factsPath, "utf8").trim();
|
|
121
93
|
if (!raw)
|
|
122
94
|
return [];
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
95
|
+
const facts = [];
|
|
96
|
+
for (const line of raw.split("\n")) {
|
|
97
|
+
try {
|
|
98
|
+
facts.push(JSON.parse(line));
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Skip corrupt lines (e.g. partial write from a crash).
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return facts;
|
|
126
105
|
}
|
|
127
106
|
function readEntityIndex(entitiesPath) {
|
|
128
107
|
if (!fs.existsSync(entitiesPath))
|
|
@@ -170,13 +149,24 @@ function appendDailyFact(dailyDir, fact) {
|
|
|
170
149
|
const dayPath = path.join(dailyDir, `${day}.jsonl`);
|
|
171
150
|
fs.appendFileSync(dayPath, `${JSON.stringify(fact)}\n`, "utf8");
|
|
172
151
|
}
|
|
173
|
-
function
|
|
174
|
-
const existing =
|
|
152
|
+
function appendEntriesWithDedup(stores, incoming, options) {
|
|
153
|
+
const existing = readExistingEntries(stores.factsPath);
|
|
175
154
|
const all = [...existing];
|
|
176
155
|
let added = 0;
|
|
177
156
|
let skipped = 0;
|
|
157
|
+
const semanticThreshold = options?.semanticThreshold;
|
|
178
158
|
for (const fact of incoming) {
|
|
179
|
-
const duplicate = all.some((prior) =>
|
|
159
|
+
const duplicate = all.some((prior) => {
|
|
160
|
+
if (overlapScore(prior.text, fact.text) > DEDUP_THRESHOLD)
|
|
161
|
+
return true;
|
|
162
|
+
if (semanticThreshold !== undefined &&
|
|
163
|
+
Array.isArray(fact.embedding) && fact.embedding.length > 0 &&
|
|
164
|
+
Array.isArray(prior.embedding) && prior.embedding.length > 0 &&
|
|
165
|
+
fact.embedding.length === prior.embedding.length) {
|
|
166
|
+
return (0, associative_recall_1.cosineSimilarity)(fact.embedding, prior.embedding) > semanticThreshold;
|
|
167
|
+
}
|
|
168
|
+
return false;
|
|
169
|
+
});
|
|
180
170
|
if (duplicate) {
|
|
181
171
|
skipped++;
|
|
182
172
|
continue;
|
|
@@ -189,44 +179,20 @@ function appendFactsWithDedup(stores, incoming) {
|
|
|
189
179
|
}
|
|
190
180
|
(0, runtime_1.emitNervesEvent)({
|
|
191
181
|
component: "mind",
|
|
192
|
-
event: "mind.
|
|
193
|
-
message: "
|
|
182
|
+
event: "mind.diary_write",
|
|
183
|
+
message: "diary write completed",
|
|
194
184
|
meta: { added, skipped },
|
|
195
185
|
});
|
|
196
186
|
return { added, skipped };
|
|
197
187
|
}
|
|
198
|
-
function cosineSimilarity(left, right) {
|
|
199
|
-
if (left.length === 0 || right.length === 0 || left.length !== right.length)
|
|
200
|
-
return 0;
|
|
201
|
-
let dot = 0;
|
|
202
|
-
let leftNorm = 0;
|
|
203
|
-
let rightNorm = 0;
|
|
204
|
-
for (let i = 0; i < left.length; i += 1) {
|
|
205
|
-
dot += left[i] * right[i];
|
|
206
|
-
leftNorm += left[i] * left[i];
|
|
207
|
-
rightNorm += right[i] * right[i];
|
|
208
|
-
}
|
|
209
|
-
if (leftNorm === 0 || rightNorm === 0)
|
|
210
|
-
return 0;
|
|
211
|
-
return dot / (Math.sqrt(leftNorm) * Math.sqrt(rightNorm));
|
|
212
|
-
}
|
|
213
|
-
exports.__memoryTestUtils = {
|
|
214
|
-
cosineSimilarity,
|
|
215
|
-
};
|
|
216
|
-
function createDefaultEmbeddingProvider() {
|
|
217
|
-
const apiKey = (0, config_1.getOpenAIEmbeddingsApiKey)().trim();
|
|
218
|
-
if (!apiKey)
|
|
219
|
-
return null;
|
|
220
|
-
return new OpenAIEmbeddingProvider(apiKey);
|
|
221
|
-
}
|
|
222
188
|
async function buildEmbedding(text, embeddingProvider) {
|
|
223
|
-
const provider = embeddingProvider ?? createDefaultEmbeddingProvider();
|
|
189
|
+
const provider = embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
|
|
224
190
|
if (!provider) {
|
|
225
191
|
(0, runtime_1.emitNervesEvent)({
|
|
226
192
|
level: "warn",
|
|
227
193
|
component: "mind",
|
|
228
|
-
event: "mind.
|
|
229
|
-
message: "embedding provider unavailable for
|
|
194
|
+
event: "mind.diary_embedding_unavailable",
|
|
195
|
+
message: "embedding provider unavailable for diary write",
|
|
230
196
|
meta: { reason: "missing_openai_embeddings_key" },
|
|
231
197
|
});
|
|
232
198
|
return [];
|
|
@@ -239,8 +205,8 @@ async function buildEmbedding(text, embeddingProvider) {
|
|
|
239
205
|
(0, runtime_1.emitNervesEvent)({
|
|
240
206
|
level: "warn",
|
|
241
207
|
component: "mind",
|
|
242
|
-
event: "mind.
|
|
243
|
-
message: "embedding provider unavailable for
|
|
208
|
+
event: "mind.diary_embedding_unavailable",
|
|
209
|
+
message: "embedding provider unavailable for diary write",
|
|
244
210
|
meta: {
|
|
245
211
|
reason: error instanceof Error ? error.message : String(error),
|
|
246
212
|
},
|
|
@@ -248,13 +214,19 @@ async function buildEmbedding(text, embeddingProvider) {
|
|
|
248
214
|
return [];
|
|
249
215
|
}
|
|
250
216
|
}
|
|
251
|
-
function
|
|
252
|
-
|
|
217
|
+
function resolveDiaryRoot(explicitRoot) {
|
|
218
|
+
if (explicitRoot)
|
|
219
|
+
return explicitRoot;
|
|
220
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
221
|
+
return path.join(agentRoot, "diary");
|
|
222
|
+
}
|
|
223
|
+
function readDiaryEntries(diaryRoot) {
|
|
224
|
+
return readExistingEntries(path.join(resolveDiaryRoot(diaryRoot), "facts.jsonl"));
|
|
253
225
|
}
|
|
254
|
-
async function
|
|
226
|
+
async function saveDiaryEntry(options) {
|
|
255
227
|
const text = options.text.trim();
|
|
256
|
-
const
|
|
257
|
-
const stores =
|
|
228
|
+
const diaryRoot = resolveDiaryRoot(options.diaryRoot);
|
|
229
|
+
const stores = ensureDiaryStorePaths(diaryRoot);
|
|
258
230
|
const embedding = await buildEmbedding(text, options.embeddingProvider);
|
|
259
231
|
const fact = {
|
|
260
232
|
id: options.idFactory ? options.idFactory() : (0, crypto_1.randomUUID)(),
|
|
@@ -264,23 +236,23 @@ async function saveMemoryFact(options) {
|
|
|
264
236
|
createdAt: (options.now ?? (() => new Date()))().toISOString(),
|
|
265
237
|
embedding,
|
|
266
238
|
};
|
|
267
|
-
return
|
|
239
|
+
return appendEntriesWithDedup(stores, [fact], { semanticThreshold: SEMANTIC_DEDUP_THRESHOLD });
|
|
268
240
|
}
|
|
269
241
|
async function backfillEmbeddings(options) {
|
|
270
|
-
const
|
|
271
|
-
const factsPath = path.join(
|
|
242
|
+
const diaryRoot = resolveDiaryRoot(options?.diaryRoot);
|
|
243
|
+
const factsPath = path.join(diaryRoot, "facts.jsonl");
|
|
272
244
|
if (!fs.existsSync(factsPath))
|
|
273
245
|
return { total: 0, backfilled: 0, failed: 0 };
|
|
274
|
-
const facts =
|
|
246
|
+
const facts = readExistingEntries(factsPath);
|
|
275
247
|
const needsEmbedding = facts.filter((f) => !Array.isArray(f.embedding) || f.embedding.length === 0);
|
|
276
248
|
if (needsEmbedding.length === 0)
|
|
277
249
|
return { total: facts.length, backfilled: 0, failed: 0 };
|
|
278
|
-
const provider = options?.embeddingProvider ?? createDefaultEmbeddingProvider();
|
|
250
|
+
const provider = options?.embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
|
|
279
251
|
if (!provider) {
|
|
280
252
|
(0, runtime_1.emitNervesEvent)({
|
|
281
253
|
level: "warn",
|
|
282
254
|
component: "mind",
|
|
283
|
-
event: "mind.
|
|
255
|
+
event: "mind.diary_backfill_skipped",
|
|
284
256
|
message: "embedding provider unavailable for backfill",
|
|
285
257
|
meta: { needsEmbedding: needsEmbedding.length },
|
|
286
258
|
});
|
|
@@ -306,7 +278,7 @@ async function backfillEmbeddings(options) {
|
|
|
306
278
|
(0, runtime_1.emitNervesEvent)({
|
|
307
279
|
level: "warn",
|
|
308
280
|
component: "mind",
|
|
309
|
-
event: "mind.
|
|
281
|
+
event: "mind.diary_backfill_batch_error",
|
|
310
282
|
message: "embedding backfill batch failed",
|
|
311
283
|
meta: {
|
|
312
284
|
batchStart: i,
|
|
@@ -321,7 +293,7 @@ async function backfillEmbeddings(options) {
|
|
|
321
293
|
fs.writeFileSync(factsPath, lines, "utf8");
|
|
322
294
|
(0, runtime_1.emitNervesEvent)({
|
|
323
295
|
component: "mind",
|
|
324
|
-
event: "mind.
|
|
296
|
+
event: "mind.diary_backfill_complete",
|
|
325
297
|
message: "embedding backfill completed",
|
|
326
298
|
meta: { total: facts.length, backfilled, failed },
|
|
327
299
|
});
|
|
@@ -341,7 +313,7 @@ function uniqueFacts(facts) {
|
|
|
341
313
|
}
|
|
342
314
|
return unique;
|
|
343
315
|
}
|
|
344
|
-
async function
|
|
316
|
+
async function searchDiaryEntries(query, facts, embeddingProvider) {
|
|
345
317
|
const trimmed = query.trim();
|
|
346
318
|
if (!trimmed)
|
|
347
319
|
return [];
|
|
@@ -351,7 +323,7 @@ async function searchMemoryFacts(query, facts, embeddingProvider) {
|
|
|
351
323
|
if (embeddedFacts.length === 0) {
|
|
352
324
|
return substringFallback();
|
|
353
325
|
}
|
|
354
|
-
const provider = embeddingProvider ?? createDefaultEmbeddingProvider();
|
|
326
|
+
const provider = embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
|
|
355
327
|
if (!provider) {
|
|
356
328
|
return substringFallback();
|
|
357
329
|
}
|
|
@@ -365,7 +337,7 @@ async function searchMemoryFacts(query, facts, embeddingProvider) {
|
|
|
365
337
|
.filter((fact) => fact.embedding.length === queryEmbedding.length)
|
|
366
338
|
.map((fact) => ({
|
|
367
339
|
fact,
|
|
368
|
-
score: cosineSimilarity(queryEmbedding, fact.embedding),
|
|
340
|
+
score: (0, associative_recall_1.cosineSimilarity)(queryEmbedding, fact.embedding),
|
|
369
341
|
}))
|
|
370
342
|
.filter((entry) => entry.score > 0)
|
|
371
343
|
.sort((left, right) => right.score - left.score)
|
|
@@ -377,8 +349,8 @@ async function searchMemoryFacts(query, facts, embeddingProvider) {
|
|
|
377
349
|
(0, runtime_1.emitNervesEvent)({
|
|
378
350
|
level: "warn",
|
|
379
351
|
component: "mind",
|
|
380
|
-
event: "mind.
|
|
381
|
-
message: "embedding provider unavailable for
|
|
352
|
+
event: "mind.diary_embedding_unavailable",
|
|
353
|
+
message: "embedding provider unavailable for diary search",
|
|
382
354
|
meta: {
|
|
383
355
|
reason: error instanceof Error ? error.message : String(error),
|
|
384
356
|
},
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared OpenAI embedding provider.
|
|
4
|
+
*
|
|
5
|
+
* Both diary.ts and associative-recall.ts need to call the OpenAI embeddings
|
|
6
|
+
* API. This module provides the shared implementation so neither duplicates
|
|
7
|
+
* the fetch logic.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.OpenAIEmbeddingProvider = void 0;
|
|
11
|
+
exports.createDefaultEmbeddingProvider = createDefaultEmbeddingProvider;
|
|
12
|
+
const config_1 = require("../heart/config");
|
|
13
|
+
const runtime_1 = require("../nerves/runtime");
|
|
14
|
+
const DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small";
|
|
15
|
+
class OpenAIEmbeddingProvider {
|
|
16
|
+
apiKey;
|
|
17
|
+
model;
|
|
18
|
+
constructor(apiKey, model = DEFAULT_EMBEDDING_MODEL) {
|
|
19
|
+
this.apiKey = apiKey;
|
|
20
|
+
this.model = model;
|
|
21
|
+
}
|
|
22
|
+
async embed(texts) {
|
|
23
|
+
const response = await fetch("https://api.openai.com/v1/embeddings", {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
model: this.model,
|
|
31
|
+
input: texts,
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`embedding request failed: ${response.status} ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
const payload = (await response.json());
|
|
38
|
+
if (!payload.data || payload.data.length !== texts.length) {
|
|
39
|
+
throw new Error("embedding response missing expected vectors");
|
|
40
|
+
}
|
|
41
|
+
return payload.data.map((entry) => entry.embedding);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.OpenAIEmbeddingProvider = OpenAIEmbeddingProvider;
|
|
45
|
+
/**
|
|
46
|
+
* Create a default embedding provider from the configured API key.
|
|
47
|
+
* Returns null if no key is configured.
|
|
48
|
+
*/
|
|
49
|
+
function createDefaultEmbeddingProvider() {
|
|
50
|
+
const apiKey = (0, config_1.getOpenAIEmbeddingsApiKey)().trim();
|
|
51
|
+
if (!apiKey)
|
|
52
|
+
return null;
|
|
53
|
+
(0, runtime_1.emitNervesEvent)({
|
|
54
|
+
component: "mind",
|
|
55
|
+
event: "mind.embedding_provider_created",
|
|
56
|
+
message: "default embedding provider created",
|
|
57
|
+
meta: { model: DEFAULT_EMBEDDING_MODEL },
|
|
58
|
+
});
|
|
59
|
+
return new OpenAIEmbeddingProvider(apiKey);
|
|
60
|
+
}
|