@ouro.bot/cli 0.1.0-alpha.20 → 0.1.0-alpha.200
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 +1248 -0
- package/dist/heart/active-work.js +832 -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/cares.js +179 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config.js +54 -30
- package/dist/heart/core.js +620 -124
- package/dist/heart/cross-chat-delivery.js +146 -0
- package/dist/heart/daemon/agent-config-check.js +149 -0
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/auth-flow.js +477 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/daemon-cli.js +2443 -217
- package/dist/heart/daemon/daemon-entry.js +182 -4
- package/dist/heart/daemon/daemon-health.js +136 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +231 -0
- package/dist/heart/daemon/daemon-tombstone.js +123 -0
- package/dist/heart/daemon/daemon.js +460 -18
- package/dist/heart/daemon/habit-migration.js +181 -0
- package/dist/heart/daemon/habit-parser.js +119 -0
- package/dist/heart/daemon/habit-scheduler.js +369 -0
- package/dist/heart/daemon/hatch-flow.js +31 -112
- package/dist/heart/daemon/hatch-specialist.js +3 -3
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/launchd.js +165 -0
- package/dist/heart/daemon/log-tailer.js +4 -3
- package/dist/heart/daemon/mcp-server.js +591 -0
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/os-cron-deps.js +134 -0
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-path-installer.js +78 -34
- package/dist/heart/daemon/ouro-version-manager.js +171 -0
- package/dist/heart/daemon/outlook-http.js +439 -0
- package/dist/heart/daemon/outlook-read.js +1618 -0
- package/dist/heart/daemon/outlook-render.js +1032 -0
- package/dist/heart/daemon/outlook-types.js +7 -0
- package/dist/heart/daemon/outlook-view.js +194 -0
- package/dist/heart/daemon/process-manager.js +93 -0
- package/dist/heart/daemon/run-hooks.js +39 -0
- package/dist/heart/daemon/runtime-logging.js +58 -15
- package/dist/heart/daemon/runtime-metadata.js +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 +50 -2
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +202 -0
- package/dist/heart/daemon/specialist-prompt.js +10 -7
- package/dist/heart/daemon/specialist-tools.js +49 -3
- package/dist/heart/daemon/staged-restart.js +138 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/thoughts.js +507 -0
- package/dist/heart/daemon/update-checker.js +111 -0
- package/dist/heart/daemon/update-hooks.js +138 -0
- package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/identity.js +147 -55
- package/dist/heart/intentions.js +173 -0
- package/dist/heart/kicks.js +2 -20
- package/dist/heart/migrate-config.js +127 -0
- package/dist/heart/model-capabilities.js +48 -0
- package/dist/heart/obligations.js +225 -0
- package/dist/heart/presence.js +185 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-failover.js +88 -0
- package/dist/heart/provider-ping.js +178 -0
- package/dist/heart/providers/anthropic-token.js +163 -0
- package/dist/heart/providers/anthropic.js +187 -41
- package/dist/heart/providers/azure.js +116 -10
- package/dist/heart/providers/github-copilot.js +157 -0
- package/dist/heart/providers/minimax.js +33 -3
- package/dist/heart/providers/openai-codex.js +51 -16
- package/dist/heart/session-activity.js +172 -0
- package/dist/heart/session-recall.js +216 -0
- package/dist/heart/start-of-turn-packet.js +232 -0
- package/dist/heart/streaming.js +36 -27
- package/dist/heart/sync.js +217 -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-coordinator.js +28 -0
- package/dist/mind/associative-recall.js +122 -32
- package/dist/mind/bundle-manifest.js +19 -1
- package/dist/mind/context.js +125 -14
- package/dist/mind/{memory.js → diary.js} +69 -56
- package/dist/mind/episodes.js +119 -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/store-file.js +36 -0
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +8 -0
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/obligations.js +138 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +785 -103
- 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/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +63 -3
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-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-semantic.js +11 -5
- 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/guardrails.js +291 -0
- package/dist/repertoire/mcp-client.js +254 -0
- package/dist/repertoire/mcp-manager.js +251 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +14 -23
- package/dist/repertoire/tasks/board.js +43 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +28 -10
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +11 -28
- package/dist/repertoire/tools-base.js +1345 -320
- package/dist/repertoire/tools-bluebubbles.js +94 -0
- package/dist/repertoire/tools-github.js +1 -6
- package/dist/repertoire/tools-teams.js +12 -59
- package/dist/repertoire/tools.js +318 -124
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +97 -0
- package/dist/senses/bluebubbles-client.js +102 -3
- package/dist/senses/bluebubbles-entry.js +2 -0
- package/dist/senses/bluebubbles-inbound-log.js +109 -0
- package/dist/senses/bluebubbles-media.js +118 -23
- package/dist/senses/bluebubbles-model.js +12 -4
- package/dist/senses/bluebubbles-mutation-log.js +45 -5
- package/dist/senses/bluebubbles-runtime-state.js +109 -0
- package/dist/senses/bluebubbles-session-cleanup.js +72 -0
- package/dist/senses/bluebubbles.js +1008 -102
- package/dist/senses/cli/adapter.js +274 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +349 -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 +198 -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 +508 -243
- 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 +592 -84
- package/dist/senses/pipeline.js +693 -0
- package/dist/senses/shared-turn.js +196 -0
- package/dist/senses/surface-tool.js +95 -0
- package/dist/senses/teams.js +667 -120
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +16 -6
- package/skills/configure-dev-tools.md +81 -0
- package/subagents/README.md +4 -70
- package/dist/heart/daemon/subagent-installer.js +0 -134
- package/dist/senses/debug-activity.js +0 -107
- 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
|
@@ -0,0 +1,200 @@
|
|
|
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.GLOBAL_CIRCUIT_BREAKER_LIMIT = exports.PING_PONG_WINDOW = exports.GENERIC_REPEAT_LIMIT = exports.POLL_NO_PROGRESS_LIMIT = exports.TOOL_LOOP_HISTORY_LIMIT = void 0;
|
|
37
|
+
exports.createToolLoopState = createToolLoopState;
|
|
38
|
+
exports.recordToolOutcome = recordToolOutcome;
|
|
39
|
+
exports.detectToolLoop = detectToolLoop;
|
|
40
|
+
const crypto = __importStar(require("crypto"));
|
|
41
|
+
const runtime_1 = require("../nerves/runtime");
|
|
42
|
+
exports.TOOL_LOOP_HISTORY_LIMIT = 30;
|
|
43
|
+
exports.POLL_NO_PROGRESS_LIMIT = 3;
|
|
44
|
+
exports.GENERIC_REPEAT_LIMIT = 4;
|
|
45
|
+
exports.PING_PONG_WINDOW = 6;
|
|
46
|
+
exports.GLOBAL_CIRCUIT_BREAKER_LIMIT = 24;
|
|
47
|
+
function stableStringify(value) {
|
|
48
|
+
if (value === null || typeof value !== "object") {
|
|
49
|
+
return JSON.stringify(value);
|
|
50
|
+
}
|
|
51
|
+
/* v8 ignore next -- stableStringify currently receives only objects/strings from normalized loop inputs @preserve */
|
|
52
|
+
if (Array.isArray(value)) {
|
|
53
|
+
return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
|
|
54
|
+
}
|
|
55
|
+
const record = value;
|
|
56
|
+
return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(",")}}`;
|
|
57
|
+
}
|
|
58
|
+
function digest(value) {
|
|
59
|
+
return crypto.createHash("sha256").update(stableStringify(value)).digest("hex");
|
|
60
|
+
}
|
|
61
|
+
function normalizeArgs(toolName, args) {
|
|
62
|
+
if (toolName === "query_active_work") {
|
|
63
|
+
return { toolName };
|
|
64
|
+
}
|
|
65
|
+
if (toolName === "coding_status" || toolName === "coding_tail") {
|
|
66
|
+
return {
|
|
67
|
+
toolName,
|
|
68
|
+
sessionId: args.sessionId ?? "",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (toolName === "query_session") {
|
|
72
|
+
return {
|
|
73
|
+
toolName,
|
|
74
|
+
mode: args.mode ?? "",
|
|
75
|
+
friendId: args.friendId ?? "",
|
|
76
|
+
channel: args.channel ?? "",
|
|
77
|
+
key: args.key ?? "",
|
|
78
|
+
query: args.query ?? "",
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
toolName,
|
|
83
|
+
args,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function normalizeOutcome(result, success) {
|
|
87
|
+
return {
|
|
88
|
+
success,
|
|
89
|
+
result: result.replace(/\s+/g, " ").trim(),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function isKnownPollTool(toolName, args) {
|
|
93
|
+
return toolName === "query_active_work"
|
|
94
|
+
|| toolName === "coding_status"
|
|
95
|
+
|| toolName === "coding_tail"
|
|
96
|
+
|| (toolName === "query_session" && (args.mode ?? "").trim() === "status");
|
|
97
|
+
}
|
|
98
|
+
function emitDetection(detector, toolName, count, message, pairedToolName) {
|
|
99
|
+
(0, runtime_1.emitNervesEvent)({
|
|
100
|
+
level: "warn",
|
|
101
|
+
component: "engine",
|
|
102
|
+
event: "engine.tool_loop_detected",
|
|
103
|
+
message: "tool loop guard detected repeated non-progress work",
|
|
104
|
+
meta: {
|
|
105
|
+
detector,
|
|
106
|
+
toolName,
|
|
107
|
+
count,
|
|
108
|
+
pairedToolName: pairedToolName ?? null,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
stuck: true,
|
|
113
|
+
detector,
|
|
114
|
+
count,
|
|
115
|
+
message,
|
|
116
|
+
pairedToolName,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function countTrailingRepeats(history, toolName, callHash) {
|
|
120
|
+
let count = 0;
|
|
121
|
+
let outcomeHash;
|
|
122
|
+
for (let index = history.length - 1; index >= 0; index--) {
|
|
123
|
+
const record = history[index];
|
|
124
|
+
if (record.toolName !== toolName || record.callHash !== callHash) {
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
if (!outcomeHash) {
|
|
128
|
+
outcomeHash = record.outcomeHash;
|
|
129
|
+
}
|
|
130
|
+
if (record.outcomeHash !== outcomeHash) {
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
count += 1;
|
|
134
|
+
}
|
|
135
|
+
return { count, outcomeHash };
|
|
136
|
+
}
|
|
137
|
+
function detectPingPong(history, toolName, callHash) {
|
|
138
|
+
if (history.length < exports.PING_PONG_WINDOW) {
|
|
139
|
+
return { stuck: false };
|
|
140
|
+
}
|
|
141
|
+
const recent = history.slice(-exports.PING_PONG_WINDOW);
|
|
142
|
+
const first = recent[0];
|
|
143
|
+
const second = recent[1];
|
|
144
|
+
if (!first.isKnownPoll || !second.isKnownPoll) {
|
|
145
|
+
return { stuck: false };
|
|
146
|
+
}
|
|
147
|
+
if (first.toolName === second.toolName && first.callHash === second.callHash) {
|
|
148
|
+
return { stuck: false };
|
|
149
|
+
}
|
|
150
|
+
for (let index = 0; index < recent.length; index++) {
|
|
151
|
+
const expected = index % 2 === 0 ? first : second;
|
|
152
|
+
const actual = recent[index];
|
|
153
|
+
if (actual.toolName !== expected.toolName
|
|
154
|
+
|| actual.callHash !== expected.callHash
|
|
155
|
+
|| actual.outcomeHash !== expected.outcomeHash) {
|
|
156
|
+
return { stuck: false };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const matchesPair = (toolName === first.toolName && callHash === first.callHash)
|
|
160
|
+
|| (toolName === second.toolName && callHash === second.callHash);
|
|
161
|
+
if (!matchesPair) {
|
|
162
|
+
return { stuck: false };
|
|
163
|
+
}
|
|
164
|
+
const pairedToolName = toolName === first.toolName ? second.toolName : first.toolName;
|
|
165
|
+
return emitDetection("ping_pong", toolName, exports.PING_PONG_WINDOW, `repeated ${first.toolName}/${second.toolName} polling is not changing. stop cycling between status checks and either act on the current state, change approach, or answer truthfully with what is known.`, pairedToolName);
|
|
166
|
+
}
|
|
167
|
+
function createToolLoopState() {
|
|
168
|
+
return { history: [] };
|
|
169
|
+
}
|
|
170
|
+
function recordToolOutcome(state, toolName, args, result, success) {
|
|
171
|
+
state.history.push({
|
|
172
|
+
toolName,
|
|
173
|
+
callHash: digest(normalizeArgs(toolName, args)),
|
|
174
|
+
outcomeHash: digest(normalizeOutcome(result, success)),
|
|
175
|
+
isKnownPoll: isKnownPollTool(toolName, args),
|
|
176
|
+
});
|
|
177
|
+
if (state.history.length > exports.TOOL_LOOP_HISTORY_LIMIT) {
|
|
178
|
+
state.history.splice(0, state.history.length - exports.TOOL_LOOP_HISTORY_LIMIT);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Tools that must never be blocked by the circuit breaker.
|
|
182
|
+
// settle = end the turn, surface = deliver results outward.
|
|
183
|
+
// ponder = continue thinking (inner dialog) or hand off to inner dialog (outer).
|
|
184
|
+
// rest = end inner dialog turn (added in Unit 8b).
|
|
185
|
+
// Blocking these traps the agent: it can think all it wants but can never speak or stop.
|
|
186
|
+
const CIRCUIT_BREAKER_EXEMPT = new Set(["settle", "surface", "ponder", "rest"]);
|
|
187
|
+
function detectToolLoop(state, toolName, args) {
|
|
188
|
+
if (state.history.length >= exports.GLOBAL_CIRCUIT_BREAKER_LIMIT && !CIRCUIT_BREAKER_EXEMPT.has(toolName)) {
|
|
189
|
+
return emitDetection("global_circuit_breaker", toolName, state.history.length, `this turn has already made ${state.history.length} tool calls. stop thrashing, use the current evidence, and either change approach or answer truthfully with the best grounded status.`);
|
|
190
|
+
}
|
|
191
|
+
const callHash = digest(normalizeArgs(toolName, args));
|
|
192
|
+
const trailing = countTrailingRepeats(state.history, toolName, callHash);
|
|
193
|
+
if (isKnownPollTool(toolName, args) && trailing.count >= exports.POLL_NO_PROGRESS_LIMIT) {
|
|
194
|
+
return emitDetection("known_poll_no_progress", toolName, trailing.count, `repeated ${toolName} calls have returned the same state ${trailing.count} times. stop polling and either act on the current state, wait for a meaningful change, or answer truthfully with what is known.`);
|
|
195
|
+
}
|
|
196
|
+
if (trailing.count >= exports.GENERIC_REPEAT_LIMIT) {
|
|
197
|
+
return emitDetection("generic_repeat", toolName, trailing.count, `repeating ${toolName} with the same inputs is not producing new information. change approach, use the evidence already gathered, or answer truthfully with what is known.`);
|
|
198
|
+
}
|
|
199
|
+
return detectPingPong(state.history, toolName, callHash);
|
|
200
|
+
}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createTurnCoordinator = createTurnCoordinator;
|
|
4
|
+
exports.withSharedTurnLock = withSharedTurnLock;
|
|
5
|
+
exports.tryBeginSharedTurn = tryBeginSharedTurn;
|
|
6
|
+
exports.endSharedTurn = endSharedTurn;
|
|
7
|
+
exports.isSharedTurnActive = isSharedTurnActive;
|
|
8
|
+
exports.enqueueSharedFollowUp = enqueueSharedFollowUp;
|
|
9
|
+
exports.drainSharedFollowUps = drainSharedFollowUps;
|
|
4
10
|
const runtime_1 = require("../nerves/runtime");
|
|
11
|
+
function scopedKey(scope, key) {
|
|
12
|
+
return `${scope}:${key}`;
|
|
13
|
+
}
|
|
5
14
|
function createTurnCoordinator() {
|
|
6
15
|
const turnLocks = new Map();
|
|
7
16
|
const activeTurns = new Set();
|
|
@@ -60,3 +69,22 @@ function createTurnCoordinator() {
|
|
|
60
69
|
},
|
|
61
70
|
};
|
|
62
71
|
}
|
|
72
|
+
const _sharedTurnCoordinator = createTurnCoordinator();
|
|
73
|
+
function withSharedTurnLock(scope, key, fn) {
|
|
74
|
+
return _sharedTurnCoordinator.withTurnLock(scopedKey(scope, key), fn);
|
|
75
|
+
}
|
|
76
|
+
function tryBeginSharedTurn(scope, key) {
|
|
77
|
+
return _sharedTurnCoordinator.tryBeginTurn(scopedKey(scope, key));
|
|
78
|
+
}
|
|
79
|
+
function endSharedTurn(scope, key) {
|
|
80
|
+
_sharedTurnCoordinator.endTurn(scopedKey(scope, key));
|
|
81
|
+
}
|
|
82
|
+
function isSharedTurnActive(scope, key) {
|
|
83
|
+
return _sharedTurnCoordinator.isTurnActive(scopedKey(scope, key));
|
|
84
|
+
}
|
|
85
|
+
function enqueueSharedFollowUp(scope, key, followUp) {
|
|
86
|
+
_sharedTurnCoordinator.enqueueFollowUp(scopedKey(scope, key), followUp);
|
|
87
|
+
}
|
|
88
|
+
function drainSharedFollowUps(scope, key) {
|
|
89
|
+
return _sharedTurnCoordinator.drainFollowUps(scopedKey(scope, key));
|
|
90
|
+
}
|
|
@@ -35,12 +35,13 @@ 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
42
|
const config_1 = require("../heart/config");
|
|
42
|
-
const identity_1 = require("../heart/identity");
|
|
43
43
|
const runtime_1 = require("../nerves/runtime");
|
|
44
|
+
const diary_1 = require("./diary");
|
|
44
45
|
const DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small";
|
|
45
46
|
const DEFAULT_MIN_SCORE = 0.5;
|
|
46
47
|
const DEFAULT_TOP_K = 3;
|
|
@@ -80,14 +81,26 @@ function createDefaultProvider() {
|
|
|
80
81
|
}
|
|
81
82
|
return new OpenAIEmbeddingProvider(apiKey);
|
|
82
83
|
}
|
|
83
|
-
function readFacts(
|
|
84
|
-
const factsPath = path.join(
|
|
84
|
+
function readFacts(diaryRoot) {
|
|
85
|
+
const factsPath = path.join(diaryRoot, "facts.jsonl");
|
|
85
86
|
if (!fs.existsSync(factsPath))
|
|
86
87
|
return [];
|
|
87
88
|
const raw = fs.readFileSync(factsPath, "utf8").trim();
|
|
88
89
|
if (!raw)
|
|
89
90
|
return [];
|
|
90
|
-
|
|
91
|
+
const facts = [];
|
|
92
|
+
for (const line of raw.split("\n")) {
|
|
93
|
+
const trimmed = line.trim();
|
|
94
|
+
if (!trimmed)
|
|
95
|
+
continue;
|
|
96
|
+
try {
|
|
97
|
+
facts.push(JSON.parse(trimmed));
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Skip corrupt lines (e.g. partial write from a crash).
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return facts;
|
|
91
104
|
}
|
|
92
105
|
function getLatestUserText(messages) {
|
|
93
106
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -133,6 +146,40 @@ async function recallFactsForQuery(query, facts, provider, options) {
|
|
|
133
146
|
.sort((left, right) => right.score - left.score)
|
|
134
147
|
.slice(0, topK);
|
|
135
148
|
}
|
|
149
|
+
function readJournalIndex(journalDir) {
|
|
150
|
+
const indexPath = path.join(journalDir, ".index.json");
|
|
151
|
+
try {
|
|
152
|
+
const raw = fs.readFileSync(indexPath, "utf8");
|
|
153
|
+
const parsed = JSON.parse(raw);
|
|
154
|
+
if (!Array.isArray(parsed))
|
|
155
|
+
return [];
|
|
156
|
+
return parsed;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function searchJournalIndex(queryEmbedding, entries, options) {
|
|
163
|
+
const minScore = options?.minScore ?? DEFAULT_MIN_SCORE;
|
|
164
|
+
const topK = options?.topK ?? DEFAULT_TOP_K;
|
|
165
|
+
return entries
|
|
166
|
+
.filter((entry) => Array.isArray(entry.embedding) && entry.embedding.length > 0)
|
|
167
|
+
.map((entry) => ({
|
|
168
|
+
filename: entry.filename,
|
|
169
|
+
preview: entry.preview,
|
|
170
|
+
score: cosineSimilarity(queryEmbedding, entry.embedding),
|
|
171
|
+
}))
|
|
172
|
+
.filter((entry) => entry.score >= minScore)
|
|
173
|
+
.sort((left, right) => right.score - left.score)
|
|
174
|
+
.slice(0, topK);
|
|
175
|
+
}
|
|
176
|
+
function resolveJournalDir(diaryRoot, explicitJournalDir) {
|
|
177
|
+
if (explicitJournalDir)
|
|
178
|
+
return explicitJournalDir;
|
|
179
|
+
// journal/ is a sibling of diary/ at the agent root level
|
|
180
|
+
const agentRoot = path.dirname(diaryRoot);
|
|
181
|
+
return path.join(agentRoot, "journal");
|
|
182
|
+
}
|
|
136
183
|
async function injectAssociativeRecall(messages, options) {
|
|
137
184
|
try {
|
|
138
185
|
if (messages[0]?.role !== "system" || typeof messages[0].content !== "string")
|
|
@@ -140,37 +187,80 @@ async function injectAssociativeRecall(messages, options) {
|
|
|
140
187
|
const query = getLatestUserText(messages);
|
|
141
188
|
if (!query)
|
|
142
189
|
return;
|
|
143
|
-
const
|
|
144
|
-
const facts = readFacts(
|
|
145
|
-
|
|
190
|
+
const diaryRoot = options?.diaryRoot ?? (0, diary_1.resolveDiaryRoot)();
|
|
191
|
+
const facts = readFacts(diaryRoot);
|
|
192
|
+
const journalDir = resolveJournalDir(diaryRoot, options?.journalDir);
|
|
193
|
+
const journalEntries = readJournalIndex(journalDir);
|
|
194
|
+
if (facts.length === 0 && journalEntries.length === 0)
|
|
146
195
|
return;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
196
|
+
// Build combined result lines tagged by source
|
|
197
|
+
const resultLines = [];
|
|
198
|
+
let queryEmbedding;
|
|
199
|
+
// Search diary entries
|
|
200
|
+
if (facts.length > 0) {
|
|
201
|
+
let recalled;
|
|
202
|
+
try {
|
|
203
|
+
const provider = options?.provider ?? createDefaultProvider();
|
|
204
|
+
recalled = await recallFactsForQuery(query, facts, provider, options);
|
|
205
|
+
// Compute query embedding for journal search while provider is available
|
|
206
|
+
if (journalEntries.length > 0) {
|
|
207
|
+
const [qe] = await provider.embed([query.trim()]);
|
|
208
|
+
queryEmbedding = qe;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
// Embeddings unavailable — fall back to substring matching
|
|
213
|
+
const lowerQuery = query.toLowerCase();
|
|
214
|
+
const topK = options?.topK ?? DEFAULT_TOP_K;
|
|
215
|
+
recalled = facts
|
|
216
|
+
.filter((fact) => fact.text.toLowerCase().includes(lowerQuery))
|
|
217
|
+
.slice(0, topK)
|
|
218
|
+
.map((fact) => ({ ...fact, score: 1 }));
|
|
219
|
+
if (recalled.length > 0) {
|
|
220
|
+
(0, runtime_1.emitNervesEvent)({
|
|
221
|
+
level: "warn",
|
|
222
|
+
component: "mind",
|
|
223
|
+
event: "mind.associative_recall_fallback",
|
|
224
|
+
message: "embeddings unavailable, used substring fallback",
|
|
225
|
+
meta: { matchCount: recalled.length },
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
for (const fact of recalled) {
|
|
230
|
+
resultLines.push({
|
|
231
|
+
text: `[diary] ${fact.text} [score=${fact.score.toFixed(3)} source=${fact.source}]`,
|
|
232
|
+
score: fact.score,
|
|
167
233
|
});
|
|
168
234
|
}
|
|
169
235
|
}
|
|
170
|
-
|
|
236
|
+
// Search journal entries (works whether diary had results or not)
|
|
237
|
+
if (journalEntries.length > 0) {
|
|
238
|
+
try {
|
|
239
|
+
if (!queryEmbedding) {
|
|
240
|
+
const provider = options?.provider ?? createDefaultProvider();
|
|
241
|
+
const [qe] = await provider.embed([query.trim()]);
|
|
242
|
+
queryEmbedding = qe;
|
|
243
|
+
}
|
|
244
|
+
if (queryEmbedding) {
|
|
245
|
+
const journalResults = searchJournalIndex(queryEmbedding, journalEntries, options);
|
|
246
|
+
for (const entry of journalResults) {
|
|
247
|
+
resultLines.push({
|
|
248
|
+
text: `[journal] ${entry.filename}: ${entry.preview} [score=${entry.score.toFixed(3)}]`,
|
|
249
|
+
score: entry.score,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
// Embeddings unavailable — no journal fallback
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (resultLines.length === 0)
|
|
171
259
|
return;
|
|
172
|
-
|
|
173
|
-
|
|
260
|
+
// Sort all results by score descending
|
|
261
|
+
resultLines.sort((left, right) => right.score - left.score);
|
|
262
|
+
const recallSection = resultLines
|
|
263
|
+
.map((entry, index) => `${index + 1}. ${entry.text}`)
|
|
174
264
|
.join("\n");
|
|
175
265
|
messages[0] = {
|
|
176
266
|
role: "system",
|
|
@@ -180,7 +270,7 @@ async function injectAssociativeRecall(messages, options) {
|
|
|
180
270
|
component: "mind",
|
|
181
271
|
event: "mind.associative_recall",
|
|
182
272
|
message: "associative recall injected",
|
|
183
|
-
meta: { count:
|
|
273
|
+
meta: { count: resultLines.length },
|
|
184
274
|
});
|
|
185
275
|
}
|
|
186
276
|
catch (error) {
|
|
@@ -190,7 +280,7 @@ async function injectAssociativeRecall(messages, options) {
|
|
|
190
280
|
event: "mind.associative_recall_error",
|
|
191
281
|
message: "associative recall failed",
|
|
192
282
|
meta: {
|
|
193
|
-
reason: error instanceof Error ? error.message : String(error)
|
|
283
|
+
reason: error instanceof Error ? error.message : /* v8 ignore start -- defensive: non-Error catch branch @preserve */ String(error) /* v8 ignore stop */,
|
|
194
284
|
},
|
|
195
285
|
});
|
|
196
286
|
}
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.CANONICAL_BUNDLE_MANIFEST = void 0;
|
|
37
|
+
exports.getChangelogPath = getChangelogPath;
|
|
37
38
|
exports.getPackageVersion = getPackageVersion;
|
|
38
39
|
exports.createBundleMeta = createBundleMeta;
|
|
39
40
|
exports.backfillBundleMeta = backfillBundleMeta;
|
|
@@ -51,13 +52,30 @@ exports.CANONICAL_BUNDLE_MANIFEST = [
|
|
|
51
52
|
{ path: "psyche/LORE.md", kind: "file" },
|
|
52
53
|
{ path: "psyche/TACIT.md", kind: "file" },
|
|
53
54
|
{ path: "psyche/ASPIRATIONS.md", kind: "file" },
|
|
54
|
-
{ 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" },
|
|
55
62
|
{ path: "friends", kind: "dir" },
|
|
63
|
+
{ path: "state", kind: "dir" },
|
|
56
64
|
{ path: "tasks", kind: "dir" },
|
|
57
65
|
{ path: "skills", kind: "dir" },
|
|
58
66
|
{ path: "senses", kind: "dir" },
|
|
59
67
|
{ path: "senses/teams", kind: "dir" },
|
|
60
68
|
];
|
|
69
|
+
function getChangelogPath() {
|
|
70
|
+
const changelogPath = path.resolve(__dirname, "../../changelog.json");
|
|
71
|
+
(0, runtime_1.emitNervesEvent)({
|
|
72
|
+
component: "mind",
|
|
73
|
+
event: "mind.changelog_path_resolved",
|
|
74
|
+
message: "resolved changelog path",
|
|
75
|
+
meta: { path: changelogPath },
|
|
76
|
+
});
|
|
77
|
+
return changelogPath;
|
|
78
|
+
}
|
|
61
79
|
function getPackageVersion() {
|
|
62
80
|
const packageJsonPath = path.resolve(__dirname, "../../package.json");
|
|
63
81
|
const raw = fs.readFileSync(packageJsonPath, "utf-8");
|