@ouro.bot/cli 0.1.0-alpha.27 → 0.1.0-alpha.271
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 +1637 -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 +447 -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 +557 -0
- package/dist/heart/daemon/cli-exec.js +1877 -0
- package/dist/heart/daemon/cli-parse.js +759 -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 +214 -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 +664 -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 +39 -8
- package/dist/heart/daemon/log-tailer.js +4 -3
- 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 +123 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +58 -15
- 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 +160 -58
- 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 +171 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +30 -6
- package/dist/heart/{daemon → versioning}/update-checker.js +12 -2
- package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +41 -3
- 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 +16 -2
- 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 +777 -109
- package/dist/mind/scrutiny.js +173 -0
- package/dist/mind/token-estimate.js +8 -12
- 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 +64 -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} +145 -10
- 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 +455 -0
- 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 +578 -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-media.js +0 -244
- 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}/update-hooks.js +0 -0
|
@@ -35,59 +35,42 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.cosineSimilarity = cosineSimilarity;
|
|
37
37
|
exports.recallFactsForQuery = recallFactsForQuery;
|
|
38
|
+
exports.searchJournalIndex = searchJournalIndex;
|
|
38
39
|
exports.injectAssociativeRecall = injectAssociativeRecall;
|
|
39
40
|
const fs = __importStar(require("fs"));
|
|
40
41
|
const path = __importStar(require("path"));
|
|
41
|
-
const config_1 = require("../heart/config");
|
|
42
|
-
const identity_1 = require("../heart/identity");
|
|
43
42
|
const runtime_1 = require("../nerves/runtime");
|
|
44
|
-
const
|
|
43
|
+
const diary_1 = require("./diary");
|
|
44
|
+
const embedding_provider_1 = require("./embedding-provider");
|
|
45
45
|
const DEFAULT_MIN_SCORE = 0.5;
|
|
46
46
|
const DEFAULT_TOP_K = 3;
|
|
47
|
-
class OpenAIEmbeddingProvider {
|
|
48
|
-
apiKey;
|
|
49
|
-
model;
|
|
50
|
-
constructor(apiKey, model = DEFAULT_EMBEDDING_MODEL) {
|
|
51
|
-
this.apiKey = apiKey;
|
|
52
|
-
this.model = model;
|
|
53
|
-
}
|
|
54
|
-
async embed(texts) {
|
|
55
|
-
const response = await fetch("https://api.openai.com/v1/embeddings", {
|
|
56
|
-
method: "POST",
|
|
57
|
-
headers: {
|
|
58
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
59
|
-
"Content-Type": "application/json",
|
|
60
|
-
},
|
|
61
|
-
body: JSON.stringify({
|
|
62
|
-
model: this.model,
|
|
63
|
-
input: texts,
|
|
64
|
-
}),
|
|
65
|
-
});
|
|
66
|
-
if (!response.ok) {
|
|
67
|
-
throw new Error(`embedding request failed: ${response.status} ${response.statusText}`);
|
|
68
|
-
}
|
|
69
|
-
const payload = (await response.json());
|
|
70
|
-
if (!payload.data || payload.data.length !== texts.length) {
|
|
71
|
-
throw new Error("embedding response missing expected vectors");
|
|
72
|
-
}
|
|
73
|
-
return payload.data.map((entry) => entry.embedding);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
47
|
function createDefaultProvider() {
|
|
77
|
-
const
|
|
78
|
-
if (!
|
|
48
|
+
const provider = (0, embedding_provider_1.createDefaultEmbeddingProvider)();
|
|
49
|
+
if (!provider) {
|
|
79
50
|
throw new Error("openaiEmbeddingsApiKey not configured");
|
|
80
51
|
}
|
|
81
|
-
return
|
|
52
|
+
return provider;
|
|
82
53
|
}
|
|
83
|
-
function readFacts(
|
|
84
|
-
const factsPath = path.join(
|
|
54
|
+
function readFacts(diaryRoot) {
|
|
55
|
+
const factsPath = path.join(diaryRoot, "facts.jsonl");
|
|
85
56
|
if (!fs.existsSync(factsPath))
|
|
86
57
|
return [];
|
|
87
58
|
const raw = fs.readFileSync(factsPath, "utf8").trim();
|
|
88
59
|
if (!raw)
|
|
89
60
|
return [];
|
|
90
|
-
|
|
61
|
+
const facts = [];
|
|
62
|
+
for (const line of raw.split("\n")) {
|
|
63
|
+
const trimmed = line.trim();
|
|
64
|
+
if (!trimmed)
|
|
65
|
+
continue;
|
|
66
|
+
try {
|
|
67
|
+
facts.push(JSON.parse(trimmed));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Skip corrupt lines (e.g. partial write from a crash).
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return facts;
|
|
91
74
|
}
|
|
92
75
|
function getLatestUserText(messages) {
|
|
93
76
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -133,6 +116,40 @@ async function recallFactsForQuery(query, facts, provider, options) {
|
|
|
133
116
|
.sort((left, right) => right.score - left.score)
|
|
134
117
|
.slice(0, topK);
|
|
135
118
|
}
|
|
119
|
+
function readJournalIndex(journalDir) {
|
|
120
|
+
const indexPath = path.join(journalDir, ".index.json");
|
|
121
|
+
try {
|
|
122
|
+
const raw = fs.readFileSync(indexPath, "utf8");
|
|
123
|
+
const parsed = JSON.parse(raw);
|
|
124
|
+
if (!Array.isArray(parsed))
|
|
125
|
+
return [];
|
|
126
|
+
return parsed;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function searchJournalIndex(queryEmbedding, entries, options) {
|
|
133
|
+
const minScore = options?.minScore ?? DEFAULT_MIN_SCORE;
|
|
134
|
+
const topK = options?.topK ?? DEFAULT_TOP_K;
|
|
135
|
+
return entries
|
|
136
|
+
.filter((entry) => Array.isArray(entry.embedding) && entry.embedding.length > 0)
|
|
137
|
+
.map((entry) => ({
|
|
138
|
+
filename: entry.filename,
|
|
139
|
+
preview: entry.preview,
|
|
140
|
+
score: cosineSimilarity(queryEmbedding, entry.embedding),
|
|
141
|
+
}))
|
|
142
|
+
.filter((entry) => entry.score >= minScore)
|
|
143
|
+
.sort((left, right) => right.score - left.score)
|
|
144
|
+
.slice(0, topK);
|
|
145
|
+
}
|
|
146
|
+
function resolveJournalDir(diaryRoot, explicitJournalDir) {
|
|
147
|
+
if (explicitJournalDir)
|
|
148
|
+
return explicitJournalDir;
|
|
149
|
+
// journal/ is a sibling of diary/ at the agent root level
|
|
150
|
+
const agentRoot = path.dirname(diaryRoot);
|
|
151
|
+
return path.join(agentRoot, "journal");
|
|
152
|
+
}
|
|
136
153
|
async function injectAssociativeRecall(messages, options) {
|
|
137
154
|
try {
|
|
138
155
|
if (messages[0]?.role !== "system" || typeof messages[0].content !== "string")
|
|
@@ -140,37 +157,80 @@ async function injectAssociativeRecall(messages, options) {
|
|
|
140
157
|
const query = getLatestUserText(messages);
|
|
141
158
|
if (!query)
|
|
142
159
|
return;
|
|
143
|
-
const
|
|
144
|
-
const facts = readFacts(
|
|
145
|
-
|
|
160
|
+
const diaryRoot = options?.diaryRoot ?? (0, diary_1.resolveDiaryRoot)();
|
|
161
|
+
const facts = readFacts(diaryRoot);
|
|
162
|
+
const journalDir = resolveJournalDir(diaryRoot, options?.journalDir);
|
|
163
|
+
const journalEntries = readJournalIndex(journalDir);
|
|
164
|
+
if (facts.length === 0 && journalEntries.length === 0)
|
|
146
165
|
return;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
// Build combined result lines tagged by source
|
|
167
|
+
const resultLines = [];
|
|
168
|
+
let queryEmbedding;
|
|
169
|
+
// Search diary entries
|
|
170
|
+
if (facts.length > 0) {
|
|
171
|
+
let recalled;
|
|
172
|
+
try {
|
|
173
|
+
const provider = options?.provider ?? createDefaultProvider();
|
|
174
|
+
recalled = await recallFactsForQuery(query, facts, provider, options);
|
|
175
|
+
// Compute query embedding for journal search while provider is available
|
|
176
|
+
if (journalEntries.length > 0) {
|
|
177
|
+
const [qe] = await provider.embed([query.trim()]);
|
|
178
|
+
queryEmbedding = qe;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Embeddings unavailable — fall back to substring matching
|
|
183
|
+
const lowerQuery = query.toLowerCase();
|
|
184
|
+
const topK = options?.topK ?? DEFAULT_TOP_K;
|
|
185
|
+
recalled = facts
|
|
186
|
+
.filter((fact) => fact.text.toLowerCase().includes(lowerQuery))
|
|
187
|
+
.slice(0, topK)
|
|
188
|
+
.map((fact) => ({ ...fact, score: 1 }));
|
|
189
|
+
if (recalled.length > 0) {
|
|
190
|
+
(0, runtime_1.emitNervesEvent)({
|
|
191
|
+
level: "warn",
|
|
192
|
+
component: "mind",
|
|
193
|
+
event: "mind.associative_recall_fallback",
|
|
194
|
+
message: "embeddings unavailable, used substring fallback",
|
|
195
|
+
meta: { matchCount: recalled.length },
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
for (const fact of recalled) {
|
|
200
|
+
resultLines.push({
|
|
201
|
+
text: `[diary] ${fact.text} [score=${fact.score.toFixed(3)} source=${fact.source}]`,
|
|
202
|
+
score: fact.score,
|
|
167
203
|
});
|
|
168
204
|
}
|
|
169
205
|
}
|
|
170
|
-
|
|
206
|
+
// Search journal entries (works whether diary had results or not)
|
|
207
|
+
if (journalEntries.length > 0) {
|
|
208
|
+
try {
|
|
209
|
+
if (!queryEmbedding) {
|
|
210
|
+
const provider = options?.provider ?? createDefaultProvider();
|
|
211
|
+
const [qe] = await provider.embed([query.trim()]);
|
|
212
|
+
queryEmbedding = qe;
|
|
213
|
+
}
|
|
214
|
+
if (queryEmbedding) {
|
|
215
|
+
const journalResults = searchJournalIndex(queryEmbedding, journalEntries, options);
|
|
216
|
+
for (const entry of journalResults) {
|
|
217
|
+
resultLines.push({
|
|
218
|
+
text: `[journal] ${entry.filename}: ${entry.preview} [score=${entry.score.toFixed(3)}]`,
|
|
219
|
+
score: entry.score,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// Embeddings unavailable — no journal fallback
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (resultLines.length === 0)
|
|
171
229
|
return;
|
|
172
|
-
|
|
173
|
-
|
|
230
|
+
// Sort all results by score descending
|
|
231
|
+
resultLines.sort((left, right) => right.score - left.score);
|
|
232
|
+
const recallSection = resultLines
|
|
233
|
+
.map((entry, index) => `${index + 1}. ${entry.text}`)
|
|
174
234
|
.join("\n");
|
|
175
235
|
messages[0] = {
|
|
176
236
|
role: "system",
|
|
@@ -180,7 +240,7 @@ async function injectAssociativeRecall(messages, options) {
|
|
|
180
240
|
component: "mind",
|
|
181
241
|
event: "mind.associative_recall",
|
|
182
242
|
message: "associative recall injected",
|
|
183
|
-
meta: { count:
|
|
243
|
+
meta: { count: resultLines.length },
|
|
184
244
|
});
|
|
185
245
|
}
|
|
186
246
|
catch (error) {
|
|
@@ -190,7 +250,7 @@ async function injectAssociativeRecall(messages, options) {
|
|
|
190
250
|
event: "mind.associative_recall_error",
|
|
191
251
|
message: "associative recall failed",
|
|
192
252
|
meta: {
|
|
193
|
-
reason: error instanceof Error ? error.message : String(error)
|
|
253
|
+
reason: error instanceof Error ? error.message : /* v8 ignore start -- defensive: non-Error catch branch @preserve */ String(error) /* v8 ignore stop */,
|
|
194
254
|
},
|
|
195
255
|
});
|
|
196
256
|
}
|
|
@@ -52,8 +52,15 @@ exports.CANONICAL_BUNDLE_MANIFEST = [
|
|
|
52
52
|
{ path: "psyche/LORE.md", kind: "file" },
|
|
53
53
|
{ path: "psyche/TACIT.md", kind: "file" },
|
|
54
54
|
{ path: "psyche/ASPIRATIONS.md", kind: "file" },
|
|
55
|
-
{ path: "
|
|
55
|
+
{ path: "arc", kind: "dir" },
|
|
56
|
+
{ path: "arc/episodes", kind: "dir" },
|
|
57
|
+
{ path: "arc/obligations", kind: "dir" },
|
|
58
|
+
{ path: "arc/cares", kind: "dir" },
|
|
59
|
+
{ path: "arc/intentions", kind: "dir" },
|
|
60
|
+
{ path: "diary", kind: "dir" },
|
|
61
|
+
{ path: "journal", kind: "dir" },
|
|
56
62
|
{ path: "friends", kind: "dir" },
|
|
63
|
+
{ path: "state", kind: "dir" },
|
|
57
64
|
{ path: "tasks", kind: "dir" },
|
|
58
65
|
{ path: "skills", kind: "dir" },
|
|
59
66
|
{ path: "senses", kind: "dir" },
|
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 {
|