@ouro.bot/cli 0.1.0-alpha.20 → 0.1.0-alpha.201
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 +1254 -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 +2444 -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,217 @@
|
|
|
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.runWithSyncContext = runWithSyncContext;
|
|
37
|
+
exports.trackSyncWrite = trackSyncWrite;
|
|
38
|
+
exports.drainSyncWrites = drainSyncWrites;
|
|
39
|
+
exports.preTurnPull = preTurnPull;
|
|
40
|
+
exports.postTurnPush = postTurnPush;
|
|
41
|
+
const node_async_hooks_1 = require("node:async_hooks");
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const runtime_1 = require("../nerves/runtime");
|
|
46
|
+
/**
|
|
47
|
+
* Turn-scoped write tracker using AsyncLocalStorage.
|
|
48
|
+
* Each turn runs inside its own async context (via runWithSyncContext),
|
|
49
|
+
* so concurrent turns from different senses never share or clobber each
|
|
50
|
+
* other's tracked writes.
|
|
51
|
+
*
|
|
52
|
+
* Continuity writers (episodes, obligations, cares, intentions, diary)
|
|
53
|
+
* call trackSyncWrite() after every fs write. drainSyncWrites() returns
|
|
54
|
+
* the current turn's accumulated set and clears it.
|
|
55
|
+
*/
|
|
56
|
+
const syncContext = new node_async_hooks_1.AsyncLocalStorage();
|
|
57
|
+
/**
|
|
58
|
+
* Run a function inside its own sync-write tracking context.
|
|
59
|
+
* All trackSyncWrite / drainSyncWrites calls within `fn` (including
|
|
60
|
+
* across awaits) operate on a private Set scoped to this invocation.
|
|
61
|
+
*/
|
|
62
|
+
function runWithSyncContext(fn) {
|
|
63
|
+
return syncContext.run(new Set(), fn);
|
|
64
|
+
}
|
|
65
|
+
/** Register an absolute file path written during this turn. No-op if called outside a sync context. */
|
|
66
|
+
function trackSyncWrite(absolutePath) {
|
|
67
|
+
syncContext.getStore()?.add(absolutePath);
|
|
68
|
+
}
|
|
69
|
+
/** Return all paths written this turn and clear the set. Returns [] if called outside a sync context. */
|
|
70
|
+
function drainSyncWrites() {
|
|
71
|
+
const store = syncContext.getStore();
|
|
72
|
+
if (!store)
|
|
73
|
+
return [];
|
|
74
|
+
const paths = [...store];
|
|
75
|
+
store.clear();
|
|
76
|
+
return paths;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Pre-turn pull: sync the agent bundle from remote before assembling the start-of-turn packet.
|
|
80
|
+
*/
|
|
81
|
+
function preTurnPull(agentRoot, config) {
|
|
82
|
+
(0, runtime_1.emitNervesEvent)({
|
|
83
|
+
component: "heart",
|
|
84
|
+
event: "heart.sync_pull_start",
|
|
85
|
+
message: "pre-turn pull starting",
|
|
86
|
+
meta: { agentRoot, remote: config.remote },
|
|
87
|
+
});
|
|
88
|
+
try {
|
|
89
|
+
(0, child_process_1.execFileSync)("git", ["pull", config.remote], {
|
|
90
|
+
cwd: agentRoot,
|
|
91
|
+
stdio: "pipe",
|
|
92
|
+
timeout: 30000,
|
|
93
|
+
});
|
|
94
|
+
(0, runtime_1.emitNervesEvent)({
|
|
95
|
+
component: "heart",
|
|
96
|
+
event: "heart.sync_pull_end",
|
|
97
|
+
message: "pre-turn pull complete",
|
|
98
|
+
meta: { agentRoot },
|
|
99
|
+
});
|
|
100
|
+
return { ok: true };
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
104
|
+
(0, runtime_1.emitNervesEvent)({
|
|
105
|
+
component: "heart",
|
|
106
|
+
event: "heart.sync_pull_error",
|
|
107
|
+
message: "pre-turn pull failed",
|
|
108
|
+
meta: { agentRoot, error },
|
|
109
|
+
});
|
|
110
|
+
return { ok: false, error };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Post-turn push: commit and push files written during this turn.
|
|
115
|
+
* Receives an explicit list of absolute paths (from drainSyncWrites) instead of
|
|
116
|
+
* discovering changes via git status. Empty list = no changes = skip.
|
|
117
|
+
*/
|
|
118
|
+
function postTurnPush(agentRoot, config, writtenPaths) {
|
|
119
|
+
(0, runtime_1.emitNervesEvent)({
|
|
120
|
+
component: "heart",
|
|
121
|
+
event: "heart.sync_push_start",
|
|
122
|
+
message: "post-turn push starting",
|
|
123
|
+
meta: { agentRoot, remote: config.remote },
|
|
124
|
+
});
|
|
125
|
+
if (writtenPaths.length === 0) {
|
|
126
|
+
(0, runtime_1.emitNervesEvent)({
|
|
127
|
+
component: "heart",
|
|
128
|
+
event: "heart.sync_push_end",
|
|
129
|
+
message: "post-turn push: no changes to sync",
|
|
130
|
+
meta: { agentRoot },
|
|
131
|
+
});
|
|
132
|
+
return { ok: true };
|
|
133
|
+
}
|
|
134
|
+
// Convert absolute paths to relative (for git add)
|
|
135
|
+
const relativePaths = writtenPaths
|
|
136
|
+
.map((p) => path.relative(agentRoot, p))
|
|
137
|
+
.filter((p) => p.length > 0 && !p.startsWith(".."));
|
|
138
|
+
if (relativePaths.length === 0) {
|
|
139
|
+
(0, runtime_1.emitNervesEvent)({
|
|
140
|
+
component: "heart",
|
|
141
|
+
event: "heart.sync_push_end",
|
|
142
|
+
message: "post-turn push: no in-bundle paths to sync",
|
|
143
|
+
meta: { agentRoot },
|
|
144
|
+
});
|
|
145
|
+
return { ok: true };
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
// Stage only the specific files written during this turn
|
|
149
|
+
(0, child_process_1.execFileSync)("git", ["add", "--", ...relativePaths], {
|
|
150
|
+
cwd: agentRoot,
|
|
151
|
+
stdio: "pipe",
|
|
152
|
+
timeout: 10000,
|
|
153
|
+
});
|
|
154
|
+
(0, child_process_1.execFileSync)("git", ["commit", "-m", "sync: post-turn update"], {
|
|
155
|
+
cwd: agentRoot,
|
|
156
|
+
stdio: "pipe",
|
|
157
|
+
timeout: 10000,
|
|
158
|
+
});
|
|
159
|
+
try {
|
|
160
|
+
(0, child_process_1.execFileSync)("git", ["push", config.remote], {
|
|
161
|
+
cwd: agentRoot,
|
|
162
|
+
stdio: "pipe",
|
|
163
|
+
timeout: 30000,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// Push rejected -- try pull-rebase-push
|
|
168
|
+
try {
|
|
169
|
+
(0, child_process_1.execFileSync)("git", ["pull", "--rebase", config.remote], {
|
|
170
|
+
cwd: agentRoot,
|
|
171
|
+
stdio: "pipe",
|
|
172
|
+
timeout: 30000,
|
|
173
|
+
});
|
|
174
|
+
(0, child_process_1.execFileSync)("git", ["push", config.remote], {
|
|
175
|
+
cwd: agentRoot,
|
|
176
|
+
stdio: "pipe",
|
|
177
|
+
timeout: 30000,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
catch (retryErr) {
|
|
181
|
+
// Second failure -- write pending-sync.json
|
|
182
|
+
const retryError = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
183
|
+
const pendingSyncPath = path.join(agentRoot, "state", "pending-sync.json");
|
|
184
|
+
fs.mkdirSync(path.join(agentRoot, "state"), { recursive: true });
|
|
185
|
+
fs.writeFileSync(pendingSyncPath, JSON.stringify({
|
|
186
|
+
error: retryError,
|
|
187
|
+
failedAt: new Date().toISOString(),
|
|
188
|
+
paths: relativePaths,
|
|
189
|
+
}, null, 2), "utf-8");
|
|
190
|
+
(0, runtime_1.emitNervesEvent)({
|
|
191
|
+
component: "heart",
|
|
192
|
+
event: "heart.sync_push_error",
|
|
193
|
+
message: "post-turn push failed after retry",
|
|
194
|
+
meta: { agentRoot, error: retryError },
|
|
195
|
+
});
|
|
196
|
+
return { ok: false, error: retryError };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
(0, runtime_1.emitNervesEvent)({
|
|
200
|
+
component: "heart",
|
|
201
|
+
event: "heart.sync_push_end",
|
|
202
|
+
message: "post-turn push complete",
|
|
203
|
+
meta: { agentRoot, changedCount: relativePaths.length },
|
|
204
|
+
});
|
|
205
|
+
return { ok: true };
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
209
|
+
(0, runtime_1.emitNervesEvent)({
|
|
210
|
+
component: "heart",
|
|
211
|
+
event: "heart.sync_push_error",
|
|
212
|
+
message: "post-turn push failed",
|
|
213
|
+
meta: { agentRoot, error },
|
|
214
|
+
});
|
|
215
|
+
return { ok: false, error };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listTargetSessionCandidates = listTargetSessionCandidates;
|
|
4
|
+
exports.formatTargetSessionCandidates = formatTargetSessionCandidates;
|
|
5
|
+
const session_recall_1 = require("./session-recall");
|
|
6
|
+
const session_activity_1 = require("./session-activity");
|
|
7
|
+
const trust_explanation_1 = require("../mind/friends/trust-explanation");
|
|
8
|
+
const runtime_1 = require("../nerves/runtime");
|
|
9
|
+
function synthesizeFriendRecord(candidate) {
|
|
10
|
+
return {
|
|
11
|
+
id: candidate.friendId,
|
|
12
|
+
name: candidate.friendName,
|
|
13
|
+
role: "stranger",
|
|
14
|
+
trustLevel: "stranger",
|
|
15
|
+
connections: [],
|
|
16
|
+
externalIds: [],
|
|
17
|
+
tenantMemberships: [],
|
|
18
|
+
toolPreferences: {},
|
|
19
|
+
notes: {},
|
|
20
|
+
totalTokens: 0,
|
|
21
|
+
createdAt: new Date(0).toISOString(),
|
|
22
|
+
updatedAt: new Date(0).toISOString(),
|
|
23
|
+
schemaVersion: 1,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function deliveryPriority(mode) {
|
|
27
|
+
if (mode === "deliver_now")
|
|
28
|
+
return 0;
|
|
29
|
+
if (mode === "queue_only")
|
|
30
|
+
return 1;
|
|
31
|
+
return 2;
|
|
32
|
+
}
|
|
33
|
+
function activityPriority(source) {
|
|
34
|
+
return source === "friend-facing" ? 0 : 1;
|
|
35
|
+
}
|
|
36
|
+
function describeDelivery(candidate) {
|
|
37
|
+
if (candidate.channel === "mcp") {
|
|
38
|
+
// MCP can't push (no proactive API), but can queue — dev tool picks up via check_response
|
|
39
|
+
return { mode: "queue_only", reason: "MCP session — message queued for dev tool to pick up via check_response" };
|
|
40
|
+
}
|
|
41
|
+
if (candidate.channel !== "bluebubbles" && candidate.channel !== "teams") {
|
|
42
|
+
return { mode: "blocked", reason: "this channel does not support proactive outward delivery yet" };
|
|
43
|
+
}
|
|
44
|
+
if (candidate.trust.level === "family" || candidate.trust.level === "friend") {
|
|
45
|
+
return { mode: "deliver_now", reason: "directly trusted target on a proactive-delivery channel" };
|
|
46
|
+
}
|
|
47
|
+
return { mode: "queue_only", reason: "visible as a live chat, but immediate delivery still needs explicit cross-chat authorization" };
|
|
48
|
+
}
|
|
49
|
+
async function listTargetSessionCandidates(input) {
|
|
50
|
+
(0, runtime_1.emitNervesEvent)({
|
|
51
|
+
component: "engine",
|
|
52
|
+
event: "engine.target_resolution_start",
|
|
53
|
+
message: "listing live target session candidates",
|
|
54
|
+
meta: {
|
|
55
|
+
sessionsDir: input.sessionsDir,
|
|
56
|
+
currentSession: input.currentSession
|
|
57
|
+
? `${input.currentSession.friendId}/${input.currentSession.channel}/${input.currentSession.key}`
|
|
58
|
+
: null,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
const activity = (0, session_activity_1.listSessionActivity)({
|
|
62
|
+
sessionsDir: input.sessionsDir,
|
|
63
|
+
friendsDir: input.friendsDir,
|
|
64
|
+
agentName: input.agentName,
|
|
65
|
+
currentSession: input.currentSession ?? null,
|
|
66
|
+
}).filter((entry) => entry.channel !== "inner");
|
|
67
|
+
const candidates = [];
|
|
68
|
+
for (const entry of activity) {
|
|
69
|
+
const friend = await input.friendStore.get(entry.friendId) ?? synthesizeFriendRecord(entry);
|
|
70
|
+
const trust = (0, trust_explanation_1.describeTrustContext)({
|
|
71
|
+
friend,
|
|
72
|
+
channel: entry.channel,
|
|
73
|
+
});
|
|
74
|
+
const recall = await (0, session_recall_1.recallSession)({
|
|
75
|
+
sessionPath: entry.sessionPath,
|
|
76
|
+
friendId: entry.friendId,
|
|
77
|
+
channel: entry.channel,
|
|
78
|
+
key: entry.key,
|
|
79
|
+
messageCount: 6,
|
|
80
|
+
summarize: input.summarize,
|
|
81
|
+
trustLevel: trust.level,
|
|
82
|
+
});
|
|
83
|
+
const snapshot = recall.kind === "ok"
|
|
84
|
+
? recall.snapshot
|
|
85
|
+
: recall.kind === "empty"
|
|
86
|
+
? "recent focus: no recent visible messages"
|
|
87
|
+
: "recent focus: session transcript unavailable";
|
|
88
|
+
const delivery = describeDelivery({
|
|
89
|
+
channel: entry.channel,
|
|
90
|
+
trust,
|
|
91
|
+
});
|
|
92
|
+
candidates.push({
|
|
93
|
+
friendId: entry.friendId,
|
|
94
|
+
friendName: entry.friendName,
|
|
95
|
+
channel: entry.channel,
|
|
96
|
+
key: entry.key,
|
|
97
|
+
sessionPath: entry.sessionPath,
|
|
98
|
+
snapshot,
|
|
99
|
+
trust,
|
|
100
|
+
delivery,
|
|
101
|
+
lastActivityAt: entry.lastActivityAt,
|
|
102
|
+
lastActivityMs: entry.lastActivityMs,
|
|
103
|
+
activitySource: entry.activitySource,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return candidates.sort((a, b) => {
|
|
107
|
+
const deliveryDiff = deliveryPriority(a.delivery.mode) - deliveryPriority(b.delivery.mode);
|
|
108
|
+
if (deliveryDiff !== 0)
|
|
109
|
+
return deliveryDiff;
|
|
110
|
+
const sourceDiff = activityPriority(a.activitySource) - activityPriority(b.activitySource);
|
|
111
|
+
if (sourceDiff !== 0)
|
|
112
|
+
return sourceDiff;
|
|
113
|
+
return b.lastActivityMs - a.lastActivityMs;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function formatTargetSessionCandidates(candidates) {
|
|
117
|
+
if (candidates.length === 0)
|
|
118
|
+
return "";
|
|
119
|
+
const lines = ["## candidate target chats"];
|
|
120
|
+
for (const candidate of candidates) {
|
|
121
|
+
lines.push(`- ${candidate.friendName} [${candidate.friendId}] via ${candidate.channel}/${candidate.key}`);
|
|
122
|
+
lines.push(` trust: ${candidate.trust.level} (${candidate.trust.basis}) — ${candidate.trust.summary}`);
|
|
123
|
+
lines.push(` delivery: ${candidate.delivery.mode} — ${candidate.delivery.reason}`);
|
|
124
|
+
lines.push(` snapshot: ${candidate.snapshot}`);
|
|
125
|
+
}
|
|
126
|
+
return lines.join("\n");
|
|
127
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TEMPO_BUDGETS = void 0;
|
|
4
|
+
exports.deriveTempo = deriveTempo;
|
|
5
|
+
exports.getTokenBudget = getTokenBudget;
|
|
6
|
+
exports.detectTempoShift = detectTempoShift;
|
|
7
|
+
const runtime_1 = require("../nerves/runtime");
|
|
8
|
+
exports.TEMPO_BUDGETS = {
|
|
9
|
+
brief: { min: 150, max: 250 },
|
|
10
|
+
standard: { min: 450, max: 700 },
|
|
11
|
+
dense: { min: 900, max: 1100 },
|
|
12
|
+
crisis: { min: 700, max: 1000 },
|
|
13
|
+
};
|
|
14
|
+
const FIVE_MINUTES_MS = 5 * 60 * 1000;
|
|
15
|
+
const TWO_HOURS_MS = 2 * 60 * 60 * 1000;
|
|
16
|
+
function deriveMode(inputs) {
|
|
17
|
+
if (inputs.hasBlockers)
|
|
18
|
+
return "crisis";
|
|
19
|
+
if (inputs.openObligations > 3 || inputs.recentEpisodeCount > 10)
|
|
20
|
+
return "dense";
|
|
21
|
+
if (inputs.activeSessions > 0)
|
|
22
|
+
return "standard";
|
|
23
|
+
return "brief";
|
|
24
|
+
}
|
|
25
|
+
function deriveSignificance(inputs) {
|
|
26
|
+
if (inputs.highSalienceEpisodes > 0 || inputs.atRiskCareCount > 0)
|
|
27
|
+
return "high";
|
|
28
|
+
if (inputs.activeCareCount > 0)
|
|
29
|
+
return "medium";
|
|
30
|
+
return "low";
|
|
31
|
+
}
|
|
32
|
+
function deriveReentryDepth(inputs) {
|
|
33
|
+
if (inputs.lastActivityAgeMs < FIVE_MINUTES_MS)
|
|
34
|
+
return "warm";
|
|
35
|
+
if (inputs.lastActivityAgeMs < TWO_HOURS_MS)
|
|
36
|
+
return "cooled";
|
|
37
|
+
return "cold";
|
|
38
|
+
}
|
|
39
|
+
function computeEffectiveBudget(mode, significance, reentryDepth) {
|
|
40
|
+
const base = exports.TEMPO_BUDGETS[mode];
|
|
41
|
+
// Crisis always uses crisis budget regardless
|
|
42
|
+
if (mode === "crisis")
|
|
43
|
+
return { ...base };
|
|
44
|
+
const range = base.max - base.min;
|
|
45
|
+
// Start at the mode minimum
|
|
46
|
+
let effectiveMin = base.min;
|
|
47
|
+
// Significance pushes up within range
|
|
48
|
+
if (significance === "high") {
|
|
49
|
+
effectiveMin += Math.round(range * 0.5);
|
|
50
|
+
}
|
|
51
|
+
else if (significance === "medium") {
|
|
52
|
+
effectiveMin += Math.round(range * 0.25);
|
|
53
|
+
}
|
|
54
|
+
// Cold re-entry pushes up (need more context to re-orient)
|
|
55
|
+
if (reentryDepth === "cold") {
|
|
56
|
+
effectiveMin += Math.round(range * 0.3);
|
|
57
|
+
}
|
|
58
|
+
else if (reentryDepth === "cooled") {
|
|
59
|
+
effectiveMin += Math.round(range * 0.1);
|
|
60
|
+
}
|
|
61
|
+
// Clamp within mode range
|
|
62
|
+
effectiveMin = Math.min(effectiveMin, base.max);
|
|
63
|
+
return { min: effectiveMin, max: base.max };
|
|
64
|
+
}
|
|
65
|
+
function deriveTempo(inputs) {
|
|
66
|
+
const mode = deriveMode(inputs);
|
|
67
|
+
const significance = deriveSignificance(inputs);
|
|
68
|
+
const reentryDepth = deriveReentryDepth(inputs);
|
|
69
|
+
const effectiveBudget = computeEffectiveBudget(mode, significance, reentryDepth);
|
|
70
|
+
(0, runtime_1.emitNervesEvent)({
|
|
71
|
+
component: "heart",
|
|
72
|
+
event: "heart.tempo_derived",
|
|
73
|
+
message: `tempo derived: ${mode}/${significance}/${reentryDepth}`,
|
|
74
|
+
meta: {
|
|
75
|
+
mode,
|
|
76
|
+
significance,
|
|
77
|
+
reentryDepth,
|
|
78
|
+
effectiveMin: effectiveBudget.min,
|
|
79
|
+
effectiveMax: effectiveBudget.max,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
return { mode, significance, reentryDepth, effectiveBudget };
|
|
83
|
+
}
|
|
84
|
+
function getTokenBudget(state) {
|
|
85
|
+
return state.effectiveBudget;
|
|
86
|
+
}
|
|
87
|
+
function detectTempoShift(previous, current) {
|
|
88
|
+
if (!previous)
|
|
89
|
+
return true;
|
|
90
|
+
return (previous.mode !== current.mode
|
|
91
|
+
|| previous.significance !== current.significance
|
|
92
|
+
|| previous.reentryDepth !== current.reentryDepth);
|
|
93
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildTemporalView = buildTemporalView;
|
|
4
|
+
const runtime_1 = require("../nerves/runtime");
|
|
5
|
+
const episodes_1 = require("../mind/episodes");
|
|
6
|
+
const obligations_1 = require("./obligations");
|
|
7
|
+
const cares_1 = require("./cares");
|
|
8
|
+
const intentions_1 = require("./intentions");
|
|
9
|
+
const presence_1 = require("./presence");
|
|
10
|
+
function buildTemporalView(agentRoot, options) {
|
|
11
|
+
const episodeLimit = options?.episodeLimit ?? 20;
|
|
12
|
+
const tempo = options?.tempo ?? "brief";
|
|
13
|
+
const recentEpisodes = options?.preloaded?.recentEpisodes ?? (0, episodes_1.readRecentEpisodes)(agentRoot, { limit: episodeLimit });
|
|
14
|
+
const activeObligations = options?.preloaded?.activeObligations ?? (0, obligations_1.readPendingObligations)(agentRoot);
|
|
15
|
+
const activeCares = options?.preloaded?.activeCares ?? (0, cares_1.readActiveCares)(agentRoot);
|
|
16
|
+
const openIntentions = (0, intentions_1.readOpenIntentions)(agentRoot);
|
|
17
|
+
const peerPresence = (0, presence_1.readPeerPresence)(agentRoot);
|
|
18
|
+
const view = {
|
|
19
|
+
recentEpisodes,
|
|
20
|
+
activeObligations,
|
|
21
|
+
activeCares,
|
|
22
|
+
openIntentions,
|
|
23
|
+
peerPresence,
|
|
24
|
+
tempo,
|
|
25
|
+
assembledAt: new Date().toISOString(),
|
|
26
|
+
};
|
|
27
|
+
(0, runtime_1.emitNervesEvent)({
|
|
28
|
+
component: "heart",
|
|
29
|
+
event: "heart.temporal_view_assembled",
|
|
30
|
+
message: `temporal view assembled: ${recentEpisodes.length} episodes, ${activeObligations.length} obligations, ${activeCares.length} cares, ${openIntentions.length} intentions`,
|
|
31
|
+
meta: {
|
|
32
|
+
episodeCount: recentEpisodes.length,
|
|
33
|
+
obligationCount: activeObligations.length,
|
|
34
|
+
careCount: activeCares.length,
|
|
35
|
+
intentionCount: openIntentions.length,
|
|
36
|
+
peerCount: peerPresence.length,
|
|
37
|
+
tempo,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
return view;
|
|
41
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createToolActivityCallbacks = createToolActivityCallbacks;
|
|
4
|
+
const tool_description_1 = require("./tool-description");
|
|
5
|
+
const runtime_1 = require("../nerves/runtime");
|
|
6
|
+
function createToolActivityCallbacks(options) {
|
|
7
|
+
(0, runtime_1.emitNervesEvent)({
|
|
8
|
+
component: "engine",
|
|
9
|
+
event: "engine.tool_activity_callbacks_created",
|
|
10
|
+
message: "tool activity callbacks initialized",
|
|
11
|
+
meta: {},
|
|
12
|
+
});
|
|
13
|
+
// Track the last description so we can reference it in END messages
|
|
14
|
+
let lastDescription = null;
|
|
15
|
+
return {
|
|
16
|
+
onToolStart(name, args) {
|
|
17
|
+
const description = (0, tool_description_1.humanReadableToolDescription)(name, args);
|
|
18
|
+
if (description === null)
|
|
19
|
+
return; // hidden tool (settle, rest, descend)
|
|
20
|
+
lastDescription = description;
|
|
21
|
+
options.onDescription(description);
|
|
22
|
+
},
|
|
23
|
+
onToolEnd(name, summary, success) {
|
|
24
|
+
const desc = lastDescription ?? name;
|
|
25
|
+
// Strip trailing "..." from description for the result line
|
|
26
|
+
const cleanDesc = desc.endsWith("...") ? desc.slice(0, -3) : desc;
|
|
27
|
+
if (!success) {
|
|
28
|
+
options.onFailure(`\u2717 ${cleanDesc} — ${summary}`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (options.isDebug()) {
|
|
32
|
+
options.onResult(`\u2713 ${cleanDesc}`);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.humanReadableToolDescription = humanReadableToolDescription;
|
|
4
|
+
const runtime_1 = require("../nerves/runtime");
|
|
5
|
+
function basename(filePath) {
|
|
6
|
+
const idx = filePath.lastIndexOf("/");
|
|
7
|
+
return idx >= 0 ? filePath.slice(idx + 1) : filePath;
|
|
8
|
+
}
|
|
9
|
+
function truncate(text, max) {
|
|
10
|
+
if (text.length <= max)
|
|
11
|
+
return text;
|
|
12
|
+
// Cut at last space before maxLen to avoid mid-word truncation
|
|
13
|
+
const slice = text.slice(0, max - 1);
|
|
14
|
+
const lastSpace = slice.lastIndexOf(" ");
|
|
15
|
+
if (lastSpace > 0)
|
|
16
|
+
return text.slice(0, lastSpace) + "\u2026";
|
|
17
|
+
// No space found (single long word) — hard truncate
|
|
18
|
+
return slice + "\u2026";
|
|
19
|
+
}
|
|
20
|
+
const TOOL_DESCRIPTIONS = {
|
|
21
|
+
// File operations
|
|
22
|
+
shell: (args) => {
|
|
23
|
+
const cmd = args.command;
|
|
24
|
+
if (!cmd)
|
|
25
|
+
return "running a command...";
|
|
26
|
+
return `running ${truncate(cmd, 50)}...`;
|
|
27
|
+
},
|
|
28
|
+
read_file: (args) => {
|
|
29
|
+
const fp = args.path || args.file_path;
|
|
30
|
+
if (!fp)
|
|
31
|
+
return "reading a file...";
|
|
32
|
+
return `reading ${basename(fp)}...`;
|
|
33
|
+
},
|
|
34
|
+
write_file: (args) => {
|
|
35
|
+
const fp = args.path || args.file_path;
|
|
36
|
+
if (!fp)
|
|
37
|
+
return "writing a file...";
|
|
38
|
+
return `writing ${basename(fp)}...`;
|
|
39
|
+
},
|
|
40
|
+
edit_file: (args) => {
|
|
41
|
+
const fp = args.path || args.file_path;
|
|
42
|
+
if (!fp)
|
|
43
|
+
return "editing a file...";
|
|
44
|
+
return `editing ${basename(fp)}...`;
|
|
45
|
+
},
|
|
46
|
+
glob: (args) => {
|
|
47
|
+
const p = args.pattern;
|
|
48
|
+
if (!p)
|
|
49
|
+
return "searching for files...";
|
|
50
|
+
return `searching for ${truncate(p, 40)}...`;
|
|
51
|
+
},
|
|
52
|
+
grep: (args) => {
|
|
53
|
+
const p = args.pattern;
|
|
54
|
+
if (!p)
|
|
55
|
+
return "searching code...";
|
|
56
|
+
return `searching code for '${truncate(p, 40)}'...`;
|
|
57
|
+
},
|
|
58
|
+
// Memory and knowledge
|
|
59
|
+
recall: (args) => {
|
|
60
|
+
const q = args.query;
|
|
61
|
+
if (!q)
|
|
62
|
+
return "searching memory...";
|
|
63
|
+
return `searching memory for '${truncate(q, 40)}'...`;
|
|
64
|
+
},
|
|
65
|
+
diary_write: (args) => {
|
|
66
|
+
const about = args.about;
|
|
67
|
+
return about ? `noting something about ${truncate(about, 30)}...` : "noting something down...";
|
|
68
|
+
},
|
|
69
|
+
save_friend_note: () => "making a note about you...",
|
|
70
|
+
get_friend_note: () => "checking my notes...",
|
|
71
|
+
load_skill: (args) => {
|
|
72
|
+
const name = args.name || args.skill;
|
|
73
|
+
return name ? `loading ${name} skill...` : "loading a skill...";
|
|
74
|
+
},
|
|
75
|
+
// Session and context
|
|
76
|
+
query_session: (args) => {
|
|
77
|
+
const mode = args.mode;
|
|
78
|
+
if (mode === "search")
|
|
79
|
+
return `searching session for '${truncate(args.query || "", 30)}'...`;
|
|
80
|
+
if (mode === "status")
|
|
81
|
+
return "checking inner dialog status...";
|
|
82
|
+
return "checking session history...";
|
|
83
|
+
},
|
|
84
|
+
web_search: (args) => {
|
|
85
|
+
const q = args.query;
|
|
86
|
+
return q ? `searching the web for '${truncate(q, 35)}'...` : "searching the web...";
|
|
87
|
+
},
|
|
88
|
+
coding_spawn: (args) => {
|
|
89
|
+
const runner = args.runner;
|
|
90
|
+
return runner ? `starting ${runner} coding session...` : "starting coding session...";
|
|
91
|
+
},
|
|
92
|
+
coding_status: () => "checking coding sessions...",
|
|
93
|
+
coding_tail: () => "reading coding output...",
|
|
94
|
+
coding_kill: () => "stopping coding session...",
|
|
95
|
+
bridge_manage: () => "managing conversation bridge...",
|
|
96
|
+
// Communication
|
|
97
|
+
send_message: (args) => {
|
|
98
|
+
const to = args.to;
|
|
99
|
+
return to ? `sending a message to ${to}...` : "sending a message...";
|
|
100
|
+
},
|
|
101
|
+
surface: () => "sharing a thought...",
|
|
102
|
+
// Metacognitive (agent's inner life)
|
|
103
|
+
ponder: (args) => {
|
|
104
|
+
const thought = args.thought;
|
|
105
|
+
return thought ? `thinking about ${truncate(thought, 40)}...` : "thinking deeper...";
|
|
106
|
+
},
|
|
107
|
+
observe: () => null,
|
|
108
|
+
claude: () => "reasoning...",
|
|
109
|
+
set_reasoning_effort: (args) => {
|
|
110
|
+
const level = args.level;
|
|
111
|
+
return level ? `setting thinking depth to ${level}...` : "adjusting thinking depth...";
|
|
112
|
+
},
|
|
113
|
+
// Hidden — these ARE the response or end-of-turn
|
|
114
|
+
settle: () => null,
|
|
115
|
+
rest: () => null,
|
|
116
|
+
descend: () => null,
|
|
117
|
+
};
|
|
118
|
+
function humanReadableToolDescription(name, args) {
|
|
119
|
+
(0, runtime_1.emitNervesEvent)({
|
|
120
|
+
component: "engine",
|
|
121
|
+
event: "engine.tool_description",
|
|
122
|
+
message: "generated human-readable tool description",
|
|
123
|
+
meta: { tool: name },
|
|
124
|
+
});
|
|
125
|
+
const builder = TOOL_DESCRIPTIONS[name];
|
|
126
|
+
if (builder)
|
|
127
|
+
return builder(args);
|
|
128
|
+
// MCP tools: mcp__server__toolname — extract last segment
|
|
129
|
+
if (name.startsWith("mcp__")) {
|
|
130
|
+
const parts = name.split("__");
|
|
131
|
+
const toolName = parts[parts.length - 1];
|
|
132
|
+
return `using ${toolName}...`;
|
|
133
|
+
}
|
|
134
|
+
return `using ${name}...`;
|
|
135
|
+
}
|