@ouro.bot/cli 0.1.0-alpha.5 → 0.1.0-alpha.50
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/AdoptionSpecialist.ouro/agent.json +70 -9
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +5 -2
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
- package/README.md +117 -188
- package/assets/ouroboros.png +0 -0
- package/changelog.json +242 -0
- package/dist/heart/active-work.js +157 -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/config.js +81 -8
- package/dist/heart/core.js +145 -50
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/daemon-cli.js +1099 -164
- package/dist/heart/daemon/daemon-entry.js +14 -5
- package/dist/heart/daemon/daemon-runtime-sync.js +90 -0
- package/dist/heart/daemon/daemon.js +184 -9
- package/dist/heart/daemon/hatch-animation.js +10 -3
- package/dist/heart/daemon/hatch-flow.js +3 -20
- package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
- package/dist/heart/daemon/launchd.js +151 -0
- package/dist/heart/daemon/message-router.js +15 -6
- package/dist/heart/daemon/ouro-bot-entry.js +0 -0
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-entry.js +0 -0
- package/dist/heart/daemon/ouro-path-installer.js +178 -0
- package/dist/heart/daemon/ouro-uti.js +11 -2
- package/dist/heart/daemon/process-manager.js +1 -1
- package/dist/heart/daemon/run-hooks.js +37 -0
- package/dist/heart/daemon/runtime-metadata.js +118 -0
- package/dist/heart/daemon/sense-manager.js +290 -0
- package/dist/heart/daemon/socket-client.js +202 -0
- package/dist/heart/daemon/specialist-orchestrator.js +53 -84
- package/dist/heart/daemon/specialist-prompt.js +64 -5
- package/dist/heart/daemon/specialist-tools.js +213 -58
- package/dist/heart/daemon/staged-restart.js +114 -0
- package/dist/heart/daemon/subagent-installer.js +48 -7
- package/dist/heart/daemon/thoughts.js +379 -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 +82 -4
- package/dist/heart/kicks.js +1 -19
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/providers/anthropic.js +16 -2
- package/dist/heart/sense-truth.js +61 -0
- package/dist/heart/session-activity.js +169 -0
- package/dist/heart/session-recall.js +116 -0
- package/dist/heart/streaming.js +96 -21
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/mind/associative-recall.js +14 -2
- package/dist/mind/bundle-manifest.js +70 -0
- package/dist/mind/context.js +27 -11
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +43 -0
- package/dist/mind/friends/store-file.js +19 -0
- package/dist/mind/friends/types.js +9 -1
- package/dist/mind/memory.js +10 -3
- package/dist/mind/pending.js +72 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +266 -77
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +15 -2
- package/dist/repertoire/ado-client.js +4 -2
- package/dist/repertoire/coding/feedback.js +134 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +62 -4
- package/dist/repertoire/coding/spawner.js +3 -3
- package/dist/repertoire/coding/tools.js +41 -2
- package/dist/repertoire/data/ado-endpoints.json +188 -0
- package/dist/repertoire/tasks/board.js +12 -0
- package/dist/repertoire/tasks/index.js +23 -9
- package/dist/repertoire/tasks/transitions.js +1 -2
- package/dist/repertoire/tools-base.js +462 -245
- package/dist/repertoire/tools-bluebubbles.js +93 -0
- package/dist/repertoire/tools-teams.js +58 -25
- package/dist/repertoire/tools.js +57 -35
- package/dist/senses/bluebubbles-client.js +484 -0
- package/dist/senses/bluebubbles-entry.js +13 -0
- package/dist/senses/bluebubbles-inbound-log.js +109 -0
- package/dist/senses/bluebubbles-media.js +338 -0
- package/dist/senses/bluebubbles-model.js +261 -0
- package/dist/senses/bluebubbles-mutation-log.js +116 -0
- package/dist/senses/bluebubbles-runtime-state.js +109 -0
- package/dist/senses/bluebubbles-session-cleanup.js +72 -0
- package/dist/senses/bluebubbles.js +1142 -0
- package/dist/senses/cli.js +340 -138
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/debug-activity.js +148 -0
- package/dist/senses/inner-dialog-worker.js +47 -18
- package/dist/senses/inner-dialog.js +330 -84
- package/dist/senses/pipeline.js +256 -0
- package/dist/senses/teams.js +541 -129
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +14 -3
- package/subagents/README.md +46 -33
- package/subagents/work-doer.md +28 -24
- package/subagents/work-merger.md +24 -30
- package/subagents/work-planner.md +44 -27
- package/dist/heart/daemon/specialist-session.js +0 -142
- package/dist/inner-worker-entry.js +0 -4
|
@@ -33,19 +33,112 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.finalAnswerTool = exports.
|
|
36
|
+
exports.finalAnswerTool = exports.tools = exports.baseToolDefinitions = exports.editFileReadTracker = void 0;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
|
+
const fg = __importStar(require("fast-glob"));
|
|
38
39
|
const child_process_1 = require("child_process");
|
|
39
40
|
const path = __importStar(require("path"));
|
|
40
41
|
const skills_1 = require("./skills");
|
|
41
42
|
const config_1 = require("../heart/config");
|
|
42
43
|
const runtime_1 = require("../nerves/runtime");
|
|
43
44
|
const identity_1 = require("../heart/identity");
|
|
44
|
-
const
|
|
45
|
-
const
|
|
45
|
+
const socket_client_1 = require("../heart/daemon/socket-client");
|
|
46
|
+
const thoughts_1 = require("../heart/daemon/thoughts");
|
|
47
|
+
const manager_1 = require("../heart/bridges/manager");
|
|
48
|
+
const session_recall_1 = require("../heart/session-recall");
|
|
46
49
|
const tools_1 = require("./coding/tools");
|
|
47
50
|
const memory_1 = require("../mind/memory");
|
|
48
|
-
const
|
|
51
|
+
const pending_1 = require("../mind/pending");
|
|
52
|
+
const progress_story_1 = require("../heart/progress-story");
|
|
53
|
+
// Tracks which file paths have been read via read_file in this session.
|
|
54
|
+
// edit_file requires a file to be read first (must-read-first guard).
|
|
55
|
+
exports.editFileReadTracker = new Set();
|
|
56
|
+
function buildContextDiff(lines, changeStart, changeEnd, contextSize = 3) {
|
|
57
|
+
const start = Math.max(0, changeStart - contextSize);
|
|
58
|
+
const end = Math.min(lines.length, changeEnd + contextSize);
|
|
59
|
+
const result = [];
|
|
60
|
+
for (let i = start; i < end; i++) {
|
|
61
|
+
const lineNum = i + 1;
|
|
62
|
+
const prefix = (i >= changeStart && i < changeEnd) ? ">" : " ";
|
|
63
|
+
result.push(`${prefix} ${lineNum} | ${lines[i]}`);
|
|
64
|
+
}
|
|
65
|
+
return result.join("\n");
|
|
66
|
+
}
|
|
67
|
+
const NO_SESSION_FOUND_MESSAGE = "no session found for that friend/channel/key combination.";
|
|
68
|
+
const EMPTY_SESSION_MESSAGE = "session exists but has no non-system messages.";
|
|
69
|
+
function findDelegatingBridgeId(ctx) {
|
|
70
|
+
const currentSession = ctx?.currentSession;
|
|
71
|
+
if (!currentSession)
|
|
72
|
+
return undefined;
|
|
73
|
+
return ctx?.activeBridges?.find((bridge) => bridge.lifecycle === "active"
|
|
74
|
+
&& bridge.attachedSessions.some((session) => session.friendId === currentSession.friendId
|
|
75
|
+
&& session.channel === currentSession.channel
|
|
76
|
+
&& session.key === currentSession.key))?.id;
|
|
77
|
+
}
|
|
78
|
+
async function recallSessionSafely(options) {
|
|
79
|
+
try {
|
|
80
|
+
return await (0, session_recall_1.recallSession)(options);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (options.summarize) {
|
|
84
|
+
(0, runtime_1.emitNervesEvent)({
|
|
85
|
+
component: "daemon",
|
|
86
|
+
event: "daemon.session_recall_summary_fallback",
|
|
87
|
+
message: "session recall summarization failed; using raw transcript",
|
|
88
|
+
meta: {
|
|
89
|
+
friendId: options.friendId,
|
|
90
|
+
channel: options.channel,
|
|
91
|
+
key: options.key,
|
|
92
|
+
error: error instanceof Error ? error.message : String(error),
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
try {
|
|
96
|
+
return await (0, session_recall_1.recallSession)({
|
|
97
|
+
...options,
|
|
98
|
+
summarize: undefined,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return { kind: "missing" };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { kind: "missing" };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function normalizeProgressOutcome(text) {
|
|
109
|
+
const trimmed = text.trim();
|
|
110
|
+
if (!trimmed || trimmed === "nothing yet" || trimmed === "nothing recent") {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
if (trimmed.startsWith("\"") && trimmed.endsWith("\"") && trimmed.length >= 2) {
|
|
114
|
+
return trimmed.slice(1, -1);
|
|
115
|
+
}
|
|
116
|
+
return trimmed;
|
|
117
|
+
}
|
|
118
|
+
function renderInnerProgressStatus(status) {
|
|
119
|
+
if (status.processing === "pending") {
|
|
120
|
+
return (0, progress_story_1.renderProgressStory)((0, progress_story_1.buildProgressStory)({
|
|
121
|
+
scope: "inner-delegation",
|
|
122
|
+
phase: "queued",
|
|
123
|
+
objective: status.queue,
|
|
124
|
+
outcomeText: `wake: ${status.wake}`,
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
if (status.processing === "started") {
|
|
128
|
+
return (0, progress_story_1.renderProgressStory)((0, progress_story_1.buildProgressStory)({
|
|
129
|
+
scope: "inner-delegation",
|
|
130
|
+
phase: "processing",
|
|
131
|
+
outcomeText: `wake: ${status.wake}`,
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
const completedOutcome = normalizeProgressOutcome(status.surfaced) ?? status.surfaced;
|
|
135
|
+
return (0, progress_story_1.renderProgressStory)((0, progress_story_1.buildProgressStory)({
|
|
136
|
+
scope: "inner-delegation",
|
|
137
|
+
phase: "completed",
|
|
138
|
+
objective: null,
|
|
139
|
+
outcomeText: completedOutcome,
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
49
142
|
exports.baseToolDefinitions = [
|
|
50
143
|
{
|
|
51
144
|
tool: {
|
|
@@ -55,12 +148,27 @@ exports.baseToolDefinitions = [
|
|
|
55
148
|
description: "read file contents",
|
|
56
149
|
parameters: {
|
|
57
150
|
type: "object",
|
|
58
|
-
properties: {
|
|
151
|
+
properties: {
|
|
152
|
+
path: { type: "string" },
|
|
153
|
+
offset: { type: "number", description: "1-based line number to start reading from" },
|
|
154
|
+
limit: { type: "number", description: "maximum number of lines to return" },
|
|
155
|
+
},
|
|
59
156
|
required: ["path"],
|
|
60
157
|
},
|
|
61
158
|
},
|
|
62
159
|
},
|
|
63
|
-
handler: (a) =>
|
|
160
|
+
handler: (a) => {
|
|
161
|
+
const content = fs.readFileSync(a.path, "utf-8");
|
|
162
|
+
exports.editFileReadTracker.add(a.path);
|
|
163
|
+
const offset = a.offset ? parseInt(a.offset, 10) : undefined;
|
|
164
|
+
const limit = a.limit ? parseInt(a.limit, 10) : undefined;
|
|
165
|
+
if (offset === undefined && limit === undefined)
|
|
166
|
+
return content;
|
|
167
|
+
const lines = content.split("\n");
|
|
168
|
+
const start = offset ? offset - 1 : 0;
|
|
169
|
+
const end = limit !== undefined ? start + limit : lines.length;
|
|
170
|
+
return lines.slice(start, end).join("\n");
|
|
171
|
+
},
|
|
64
172
|
},
|
|
65
173
|
{
|
|
66
174
|
tool: {
|
|
@@ -75,103 +183,213 @@ exports.baseToolDefinitions = [
|
|
|
75
183
|
},
|
|
76
184
|
},
|
|
77
185
|
},
|
|
78
|
-
handler: (a) =>
|
|
186
|
+
handler: (a) => {
|
|
187
|
+
fs.mkdirSync(path.dirname(a.path), { recursive: true });
|
|
188
|
+
fs.writeFileSync(a.path, a.content, "utf-8");
|
|
189
|
+
return "ok";
|
|
190
|
+
},
|
|
79
191
|
},
|
|
80
192
|
{
|
|
81
193
|
tool: {
|
|
82
194
|
type: "function",
|
|
83
195
|
function: {
|
|
84
|
-
name: "
|
|
85
|
-
description: "
|
|
196
|
+
name: "edit_file",
|
|
197
|
+
description: "surgically edit a file by replacing an exact string. the file must have been read via read_file first. old_string must match exactly one location in the file.",
|
|
86
198
|
parameters: {
|
|
87
199
|
type: "object",
|
|
88
|
-
properties: {
|
|
89
|
-
|
|
200
|
+
properties: {
|
|
201
|
+
path: { type: "string" },
|
|
202
|
+
old_string: { type: "string" },
|
|
203
|
+
new_string: { type: "string" },
|
|
204
|
+
},
|
|
205
|
+
required: ["path", "old_string", "new_string"],
|
|
90
206
|
},
|
|
91
207
|
},
|
|
92
208
|
},
|
|
93
|
-
handler: (a) =>
|
|
209
|
+
handler: (a) => {
|
|
210
|
+
if (!exports.editFileReadTracker.has(a.path)) {
|
|
211
|
+
return `error: you must read the file with read_file before editing it. call read_file on ${a.path} first.`;
|
|
212
|
+
}
|
|
213
|
+
let content;
|
|
214
|
+
try {
|
|
215
|
+
content = fs.readFileSync(a.path, "utf-8");
|
|
216
|
+
}
|
|
217
|
+
catch (e) {
|
|
218
|
+
return `error: could not read file: ${e instanceof Error ? e.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(e)}`;
|
|
219
|
+
}
|
|
220
|
+
// Count occurrences
|
|
221
|
+
const occurrences = [];
|
|
222
|
+
let searchFrom = 0;
|
|
223
|
+
while (true) {
|
|
224
|
+
const idx = content.indexOf(a.old_string, searchFrom);
|
|
225
|
+
if (idx === -1)
|
|
226
|
+
break;
|
|
227
|
+
occurrences.push(idx);
|
|
228
|
+
searchFrom = idx + 1;
|
|
229
|
+
}
|
|
230
|
+
if (occurrences.length === 0) {
|
|
231
|
+
return `error: old_string not found in ${a.path}`;
|
|
232
|
+
}
|
|
233
|
+
if (occurrences.length > 1) {
|
|
234
|
+
return `error: old_string is ambiguous -- found ${occurrences.length} matches in ${a.path}. provide more context to make the match unique.`;
|
|
235
|
+
}
|
|
236
|
+
// Single unique match -- replace
|
|
237
|
+
const idx = occurrences[0];
|
|
238
|
+
const updated = content.slice(0, idx) + a.new_string + content.slice(idx + a.old_string.length);
|
|
239
|
+
fs.writeFileSync(a.path, updated, "utf-8");
|
|
240
|
+
// Build contextual diff
|
|
241
|
+
const lines = updated.split("\n");
|
|
242
|
+
const prefixLines = content.slice(0, idx).split("\n");
|
|
243
|
+
const changeStartLine = prefixLines.length - 1;
|
|
244
|
+
const newStringLines = a.new_string.split("\n");
|
|
245
|
+
const changeEndLine = changeStartLine + newStringLines.length;
|
|
246
|
+
return buildContextDiff(lines, changeStartLine, changeEndLine);
|
|
247
|
+
},
|
|
94
248
|
},
|
|
95
249
|
{
|
|
96
250
|
tool: {
|
|
97
251
|
type: "function",
|
|
98
252
|
function: {
|
|
99
|
-
name: "
|
|
100
|
-
description: "
|
|
253
|
+
name: "glob",
|
|
254
|
+
description: "find files matching a glob pattern. returns matching paths sorted alphabetically, one per line.",
|
|
101
255
|
parameters: {
|
|
102
256
|
type: "object",
|
|
103
|
-
properties: {
|
|
104
|
-
|
|
257
|
+
properties: {
|
|
258
|
+
pattern: { type: "string", description: "glob pattern (e.g. **/*.ts)" },
|
|
259
|
+
cwd: { type: "string", description: "directory to search from (defaults to process.cwd())" },
|
|
260
|
+
},
|
|
261
|
+
required: ["pattern"],
|
|
105
262
|
},
|
|
106
263
|
},
|
|
107
264
|
},
|
|
108
|
-
handler: (a) =>
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
.join("\n")
|
|
265
|
+
handler: (a) => {
|
|
266
|
+
const cwd = a.cwd || process.cwd();
|
|
267
|
+
const matches = fg.globSync(a.pattern, { cwd, dot: true });
|
|
268
|
+
return matches.sort().join("\n");
|
|
269
|
+
},
|
|
112
270
|
},
|
|
113
271
|
{
|
|
114
272
|
tool: {
|
|
115
273
|
type: "function",
|
|
116
274
|
function: {
|
|
117
|
-
name: "
|
|
118
|
-
description: "
|
|
275
|
+
name: "grep",
|
|
276
|
+
description: "search file contents for lines matching a regex pattern. searches recursively when given a directory. returns matching lines with file path and line numbers.",
|
|
119
277
|
parameters: {
|
|
120
278
|
type: "object",
|
|
121
279
|
properties: {
|
|
122
|
-
|
|
123
|
-
|
|
280
|
+
pattern: { type: "string", description: "regex pattern to search for" },
|
|
281
|
+
path: { type: "string", description: "file or directory to search" },
|
|
282
|
+
context_lines: { type: "number", description: "number of surrounding context lines (default 0)" },
|
|
283
|
+
include: { type: "string", description: "glob filter to limit searched files (e.g. *.ts)" },
|
|
124
284
|
},
|
|
125
|
-
required: ["
|
|
285
|
+
required: ["pattern", "path"],
|
|
126
286
|
},
|
|
127
287
|
},
|
|
128
288
|
},
|
|
129
289
|
handler: (a) => {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
290
|
+
const targetPath = a.path;
|
|
291
|
+
const regex = new RegExp(a.pattern);
|
|
292
|
+
const contextLines = parseInt(a.context_lines || "0", 10);
|
|
293
|
+
const includeGlob = a.include || undefined;
|
|
294
|
+
function searchFile(filePath) {
|
|
295
|
+
let content;
|
|
296
|
+
try {
|
|
297
|
+
content = fs.readFileSync(filePath, "utf-8");
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
return [];
|
|
133
301
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
302
|
+
const lines = content.split("\n");
|
|
303
|
+
const matchIndices = new Set();
|
|
304
|
+
for (let i = 0; i < lines.length; i++) {
|
|
305
|
+
if (regex.test(lines[i])) {
|
|
306
|
+
matchIndices.add(i);
|
|
137
307
|
}
|
|
138
|
-
(0, child_process_1.execSync)(`git add ${p}`, { encoding: "utf-8" });
|
|
139
308
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
309
|
+
if (matchIndices.size === 0)
|
|
310
|
+
return [];
|
|
311
|
+
const outputIndices = new Set();
|
|
312
|
+
for (const idx of matchIndices) {
|
|
313
|
+
const start = Math.max(0, idx - contextLines);
|
|
314
|
+
const end = Math.min(lines.length - 1, idx + contextLines);
|
|
315
|
+
for (let i = start; i <= end; i++) {
|
|
316
|
+
outputIndices.add(i);
|
|
317
|
+
}
|
|
143
318
|
}
|
|
144
|
-
(
|
|
145
|
-
|
|
319
|
+
const sortedIndices = [...outputIndices].sort((a, b) => a - b);
|
|
320
|
+
const results = [];
|
|
321
|
+
for (const idx of sortedIndices) {
|
|
322
|
+
const lineNum = idx + 1;
|
|
323
|
+
if (matchIndices.has(idx)) {
|
|
324
|
+
results.push(`${filePath}:${lineNum}: ${lines[idx]}`);
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
results.push(`-${filePath}:${lineNum}: ${lines[idx]}`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return results;
|
|
146
331
|
}
|
|
147
|
-
|
|
148
|
-
|
|
332
|
+
function collectFiles(dirPath) {
|
|
333
|
+
const files = [];
|
|
334
|
+
function walk(dir) {
|
|
335
|
+
let entries;
|
|
336
|
+
try {
|
|
337
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
for (const entry of entries) {
|
|
343
|
+
const fullPath = path.join(dir, entry.name);
|
|
344
|
+
if (entry.isDirectory()) {
|
|
345
|
+
walk(fullPath);
|
|
346
|
+
}
|
|
347
|
+
else if (entry.isFile()) {
|
|
348
|
+
files.push(fullPath);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
walk(dirPath);
|
|
353
|
+
return files.sort();
|
|
149
354
|
}
|
|
355
|
+
function matchesGlob(filePath, glob) {
|
|
356
|
+
const escaped = glob
|
|
357
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
358
|
+
.replace(/\*/g, ".*")
|
|
359
|
+
.replace(/\?/g, ".");
|
|
360
|
+
return new RegExp(`(^|/)${escaped}$`).test(filePath);
|
|
361
|
+
}
|
|
362
|
+
const stat = fs.statSync(targetPath, { throwIfNoEntry: false });
|
|
363
|
+
if (!stat)
|
|
364
|
+
return "";
|
|
365
|
+
if (stat.isFile()) {
|
|
366
|
+
return searchFile(targetPath).join("\n");
|
|
367
|
+
}
|
|
368
|
+
let files = collectFiles(targetPath);
|
|
369
|
+
if (includeGlob) {
|
|
370
|
+
files = files.filter((f) => matchesGlob(f, includeGlob));
|
|
371
|
+
}
|
|
372
|
+
const allResults = [];
|
|
373
|
+
for (const file of files) {
|
|
374
|
+
allResults.push(...searchFile(file));
|
|
375
|
+
}
|
|
376
|
+
return allResults.join("\n");
|
|
150
377
|
},
|
|
151
378
|
},
|
|
152
379
|
{
|
|
153
380
|
tool: {
|
|
154
381
|
type: "function",
|
|
155
382
|
function: {
|
|
156
|
-
name: "
|
|
157
|
-
description: "
|
|
383
|
+
name: "shell",
|
|
384
|
+
description: "run shell command",
|
|
158
385
|
parameters: {
|
|
159
386
|
type: "object",
|
|
160
|
-
properties: {
|
|
161
|
-
command: { type: "string" },
|
|
162
|
-
},
|
|
387
|
+
properties: { command: { type: "string" } },
|
|
163
388
|
required: ["command"],
|
|
164
389
|
},
|
|
165
390
|
},
|
|
166
391
|
},
|
|
167
|
-
handler: (a) => {
|
|
168
|
-
try {
|
|
169
|
-
return (0, child_process_1.execSync)(`gh ${a.command}`, { encoding: "utf-8", timeout: 60000 });
|
|
170
|
-
}
|
|
171
|
-
catch (e) {
|
|
172
|
-
return `error: ${e}`;
|
|
173
|
-
}
|
|
174
|
-
},
|
|
392
|
+
handler: (a) => (0, child_process_1.execSync)(a.command, { encoding: "utf-8", timeout: 30000 }),
|
|
175
393
|
},
|
|
176
394
|
{
|
|
177
395
|
tool: {
|
|
@@ -206,20 +424,6 @@ exports.baseToolDefinitions = [
|
|
|
206
424
|
}
|
|
207
425
|
},
|
|
208
426
|
},
|
|
209
|
-
{
|
|
210
|
-
tool: {
|
|
211
|
-
type: "function",
|
|
212
|
-
function: {
|
|
213
|
-
name: "get_current_time",
|
|
214
|
-
description: "get the current date and time in America/Los_Angeles (Pacific Time)",
|
|
215
|
-
parameters: { type: "object", properties: {} },
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
handler: () => new Date().toLocaleString("en-US", {
|
|
219
|
-
timeZone: "America/Los_Angeles",
|
|
220
|
-
hour12: false,
|
|
221
|
-
}),
|
|
222
|
-
},
|
|
223
427
|
{
|
|
224
428
|
tool: {
|
|
225
429
|
type: "function",
|
|
@@ -235,7 +439,7 @@ exports.baseToolDefinitions = [
|
|
|
235
439
|
},
|
|
236
440
|
handler: (a) => {
|
|
237
441
|
try {
|
|
238
|
-
const result = (0, child_process_1.spawnSync)("claude", ["-p", "--dangerously-skip-permissions", "--add-dir", "."], {
|
|
442
|
+
const result = (0, child_process_1.spawnSync)("claude", ["-p", "--no-session-persistence", "--dangerously-skip-permissions", "--add-dir", "."], {
|
|
239
443
|
input: a.prompt,
|
|
240
444
|
encoding: "utf-8",
|
|
241
445
|
timeout: 60000,
|
|
@@ -375,151 +579,6 @@ exports.baseToolDefinitions = [
|
|
|
375
579
|
return JSON.stringify(friend, null, 2);
|
|
376
580
|
},
|
|
377
581
|
},
|
|
378
|
-
{
|
|
379
|
-
tool: {
|
|
380
|
-
type: "function",
|
|
381
|
-
function: {
|
|
382
|
-
name: "task_board",
|
|
383
|
-
description: "show the task board grouped by status",
|
|
384
|
-
parameters: { type: "object", properties: {} },
|
|
385
|
-
},
|
|
386
|
-
},
|
|
387
|
-
handler: () => {
|
|
388
|
-
const board = (0, tasks_1.getTaskModule)().getBoard();
|
|
389
|
-
return board.full || board.compact || "no tasks found";
|
|
390
|
-
},
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
tool: {
|
|
394
|
-
type: "function",
|
|
395
|
-
function: {
|
|
396
|
-
name: "task_create",
|
|
397
|
-
description: "create a new task in the bundle task system",
|
|
398
|
-
parameters: {
|
|
399
|
-
type: "object",
|
|
400
|
-
properties: {
|
|
401
|
-
title: { type: "string" },
|
|
402
|
-
type: { type: "string", enum: ["one-shot", "ongoing", "habit"] },
|
|
403
|
-
category: { type: "string" },
|
|
404
|
-
body: { type: "string" },
|
|
405
|
-
},
|
|
406
|
-
required: ["title", "type", "category", "body"],
|
|
407
|
-
},
|
|
408
|
-
},
|
|
409
|
-
},
|
|
410
|
-
handler: (a) => {
|
|
411
|
-
try {
|
|
412
|
-
const created = (0, tasks_1.getTaskModule)().createTask({
|
|
413
|
-
title: a.title,
|
|
414
|
-
type: a.type,
|
|
415
|
-
category: a.category,
|
|
416
|
-
body: a.body,
|
|
417
|
-
});
|
|
418
|
-
return `created: ${created}`;
|
|
419
|
-
}
|
|
420
|
-
catch (error) {
|
|
421
|
-
return `error: ${error instanceof Error ? error.message : String(error)}`;
|
|
422
|
-
}
|
|
423
|
-
},
|
|
424
|
-
},
|
|
425
|
-
{
|
|
426
|
-
tool: {
|
|
427
|
-
type: "function",
|
|
428
|
-
function: {
|
|
429
|
-
name: "task_update_status",
|
|
430
|
-
description: "update a task status using validated transitions",
|
|
431
|
-
parameters: {
|
|
432
|
-
type: "object",
|
|
433
|
-
properties: {
|
|
434
|
-
name: { type: "string" },
|
|
435
|
-
status: { type: "string" },
|
|
436
|
-
},
|
|
437
|
-
required: ["name", "status"],
|
|
438
|
-
},
|
|
439
|
-
},
|
|
440
|
-
},
|
|
441
|
-
handler: (a) => {
|
|
442
|
-
const result = (0, tasks_1.getTaskModule)().updateStatus(a.name, a.status);
|
|
443
|
-
if (!result.ok) {
|
|
444
|
-
return `error: ${result.reason ?? "status update failed"}`;
|
|
445
|
-
}
|
|
446
|
-
const archivedSuffix = result.archived && result.archived.length > 0
|
|
447
|
-
? ` | archived: ${result.archived.join(", ")}`
|
|
448
|
-
: "";
|
|
449
|
-
return `updated: ${a.name} -> ${result.to}${archivedSuffix}`;
|
|
450
|
-
},
|
|
451
|
-
},
|
|
452
|
-
{
|
|
453
|
-
tool: {
|
|
454
|
-
type: "function",
|
|
455
|
-
function: {
|
|
456
|
-
name: "task_board_status",
|
|
457
|
-
description: "show board detail for a specific status",
|
|
458
|
-
parameters: {
|
|
459
|
-
type: "object",
|
|
460
|
-
properties: {
|
|
461
|
-
status: { type: "string" },
|
|
462
|
-
},
|
|
463
|
-
required: ["status"],
|
|
464
|
-
},
|
|
465
|
-
},
|
|
466
|
-
},
|
|
467
|
-
handler: (a) => {
|
|
468
|
-
const lines = (0, tasks_1.getTaskModule)().boardStatus(a.status);
|
|
469
|
-
return lines.length > 0 ? lines.join("\n") : "no tasks in that status";
|
|
470
|
-
},
|
|
471
|
-
},
|
|
472
|
-
{
|
|
473
|
-
tool: {
|
|
474
|
-
type: "function",
|
|
475
|
-
function: {
|
|
476
|
-
name: "task_board_action",
|
|
477
|
-
description: "show tasks or validation issues that require action",
|
|
478
|
-
parameters: {
|
|
479
|
-
type: "object",
|
|
480
|
-
properties: {
|
|
481
|
-
scope: { type: "string" },
|
|
482
|
-
},
|
|
483
|
-
},
|
|
484
|
-
},
|
|
485
|
-
},
|
|
486
|
-
handler: (a) => {
|
|
487
|
-
const lines = (0, tasks_1.getTaskModule)().boardAction();
|
|
488
|
-
if (!a.scope) {
|
|
489
|
-
return lines.length > 0 ? lines.join("\n") : "no action required";
|
|
490
|
-
}
|
|
491
|
-
const filtered = lines.filter((line) => line.includes(a.scope));
|
|
492
|
-
return filtered.length > 0 ? filtered.join("\n") : "no matching action items";
|
|
493
|
-
},
|
|
494
|
-
},
|
|
495
|
-
{
|
|
496
|
-
tool: {
|
|
497
|
-
type: "function",
|
|
498
|
-
function: {
|
|
499
|
-
name: "task_board_deps",
|
|
500
|
-
description: "show unresolved task dependencies",
|
|
501
|
-
parameters: { type: "object", properties: {} },
|
|
502
|
-
},
|
|
503
|
-
},
|
|
504
|
-
handler: () => {
|
|
505
|
-
const lines = (0, tasks_1.getTaskModule)().boardDeps();
|
|
506
|
-
return lines.length > 0 ? lines.join("\n") : "no unresolved dependencies";
|
|
507
|
-
},
|
|
508
|
-
},
|
|
509
|
-
{
|
|
510
|
-
tool: {
|
|
511
|
-
type: "function",
|
|
512
|
-
function: {
|
|
513
|
-
name: "task_board_sessions",
|
|
514
|
-
description: "show tasks with active coding or sub-agent sessions",
|
|
515
|
-
parameters: { type: "object", properties: {} },
|
|
516
|
-
},
|
|
517
|
-
},
|
|
518
|
-
handler: () => {
|
|
519
|
-
const lines = (0, tasks_1.getTaskModule)().boardSessions();
|
|
520
|
-
return lines.length > 0 ? lines.join("\n") : "no active sessions";
|
|
521
|
-
},
|
|
522
|
-
},
|
|
523
582
|
{
|
|
524
583
|
tool: {
|
|
525
584
|
type: "function",
|
|
@@ -604,6 +663,103 @@ exports.baseToolDefinitions = [
|
|
|
604
663
|
},
|
|
605
664
|
},
|
|
606
665
|
// -- cross-session awareness --
|
|
666
|
+
{
|
|
667
|
+
tool: {
|
|
668
|
+
type: "function",
|
|
669
|
+
function: {
|
|
670
|
+
name: "bridge_manage",
|
|
671
|
+
description: "create and manage shared live-work bridges across already-active sessions.",
|
|
672
|
+
parameters: {
|
|
673
|
+
type: "object",
|
|
674
|
+
properties: {
|
|
675
|
+
action: {
|
|
676
|
+
type: "string",
|
|
677
|
+
enum: ["begin", "attach", "status", "promote_task", "complete", "cancel"],
|
|
678
|
+
},
|
|
679
|
+
bridgeId: { type: "string", description: "bridge id for all actions except begin" },
|
|
680
|
+
objective: { type: "string", description: "objective for begin" },
|
|
681
|
+
summary: { type: "string", description: "optional concise shared-work summary" },
|
|
682
|
+
friendId: { type: "string", description: "target friend id for attach" },
|
|
683
|
+
channel: { type: "string", description: "target channel for attach" },
|
|
684
|
+
key: { type: "string", description: "target session key for attach (defaults to 'session')" },
|
|
685
|
+
title: { type: "string", description: "task title override for promote_task" },
|
|
686
|
+
category: { type: "string", description: "task category override for promote_task" },
|
|
687
|
+
body: { type: "string", description: "task body override for promote_task" },
|
|
688
|
+
},
|
|
689
|
+
required: ["action"],
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
},
|
|
693
|
+
handler: async (args, ctx) => {
|
|
694
|
+
const manager = (0, manager_1.createBridgeManager)();
|
|
695
|
+
const action = (args.action || "").trim();
|
|
696
|
+
if (action === "begin") {
|
|
697
|
+
if (!ctx?.currentSession) {
|
|
698
|
+
return "bridge_manage begin requires an active session context.";
|
|
699
|
+
}
|
|
700
|
+
const objective = (args.objective || "").trim();
|
|
701
|
+
if (!objective)
|
|
702
|
+
return "objective is required for bridge begin.";
|
|
703
|
+
return (0, manager_1.formatBridgeStatus)(manager.beginBridge({
|
|
704
|
+
objective,
|
|
705
|
+
summary: (args.summary || objective).trim(),
|
|
706
|
+
session: ctx.currentSession,
|
|
707
|
+
}));
|
|
708
|
+
}
|
|
709
|
+
const bridgeId = (args.bridgeId || "").trim();
|
|
710
|
+
if (!bridgeId) {
|
|
711
|
+
return "bridgeId is required for this bridge action.";
|
|
712
|
+
}
|
|
713
|
+
if (action === "attach") {
|
|
714
|
+
const friendId = (args.friendId || "").trim();
|
|
715
|
+
const channel = (args.channel || "").trim();
|
|
716
|
+
const key = (args.key || "session").trim();
|
|
717
|
+
if (!friendId || !channel) {
|
|
718
|
+
return "friendId and channel are required for bridge attach.";
|
|
719
|
+
}
|
|
720
|
+
const sessionPath = (0, config_1.resolveSessionPath)(friendId, channel, key);
|
|
721
|
+
const recall = await recallSessionSafely({
|
|
722
|
+
sessionPath,
|
|
723
|
+
friendId,
|
|
724
|
+
channel,
|
|
725
|
+
key,
|
|
726
|
+
messageCount: 20,
|
|
727
|
+
trustLevel: ctx?.context?.friend?.trustLevel,
|
|
728
|
+
summarize: ctx?.summarize,
|
|
729
|
+
});
|
|
730
|
+
if (recall.kind === "missing") {
|
|
731
|
+
return NO_SESSION_FOUND_MESSAGE;
|
|
732
|
+
}
|
|
733
|
+
return (0, manager_1.formatBridgeStatus)(manager.attachSession(bridgeId, {
|
|
734
|
+
friendId,
|
|
735
|
+
channel,
|
|
736
|
+
key,
|
|
737
|
+
sessionPath,
|
|
738
|
+
snapshot: recall.kind === "ok" ? recall.snapshot : EMPTY_SESSION_MESSAGE,
|
|
739
|
+
}));
|
|
740
|
+
}
|
|
741
|
+
if (action === "status") {
|
|
742
|
+
const bridge = manager.getBridge(bridgeId);
|
|
743
|
+
if (!bridge)
|
|
744
|
+
return `bridge not found: ${bridgeId}`;
|
|
745
|
+
return (0, manager_1.formatBridgeStatus)(bridge);
|
|
746
|
+
}
|
|
747
|
+
if (action === "promote_task") {
|
|
748
|
+
return (0, manager_1.formatBridgeStatus)(manager.promoteBridgeToTask(bridgeId, {
|
|
749
|
+
title: args.title,
|
|
750
|
+
category: args.category,
|
|
751
|
+
body: args.body,
|
|
752
|
+
}));
|
|
753
|
+
}
|
|
754
|
+
if (action === "complete") {
|
|
755
|
+
return (0, manager_1.formatBridgeStatus)(manager.completeBridge(bridgeId));
|
|
756
|
+
}
|
|
757
|
+
if (action === "cancel") {
|
|
758
|
+
return (0, manager_1.formatBridgeStatus)(manager.cancelBridge(bridgeId));
|
|
759
|
+
}
|
|
760
|
+
return `unknown bridge action: ${action}`;
|
|
761
|
+
},
|
|
762
|
+
},
|
|
607
763
|
{
|
|
608
764
|
tool: {
|
|
609
765
|
type: "function",
|
|
@@ -617,40 +773,43 @@ exports.baseToolDefinitions = [
|
|
|
617
773
|
channel: { type: "string", description: "the channel: cli, teams, or inner" },
|
|
618
774
|
key: { type: "string", description: "session key (defaults to 'session')" },
|
|
619
775
|
messageCount: { type: "string", description: "how many recent messages to return (default 20)" },
|
|
776
|
+
mode: { type: "string", enum: ["transcript", "status"], description: "transcript (default) or lightweight status for self/inner checks" },
|
|
620
777
|
},
|
|
621
778
|
required: ["friendId", "channel"],
|
|
622
779
|
},
|
|
623
780
|
},
|
|
624
781
|
},
|
|
625
782
|
handler: async (args, ctx) => {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
const messages = (data.messages || [])
|
|
635
|
-
.filter((m) => m.role !== "system");
|
|
636
|
-
const tail = messages.slice(-count);
|
|
637
|
-
if (tail.length === 0)
|
|
638
|
-
return "session exists but has no non-system messages.";
|
|
639
|
-
const transcript = tail.map((m) => `[${m.role}] ${m.content}`).join("\n");
|
|
640
|
-
// LLM summarization when summarize function is available
|
|
641
|
-
if (ctx?.summarize) {
|
|
642
|
-
const trustLevel = ctx.context?.friend?.trustLevel ?? "family";
|
|
643
|
-
const isSelfQuery = friendId === "self";
|
|
644
|
-
const instruction = isSelfQuery
|
|
645
|
-
? "summarize this session transcript fully and transparently. this is my own inner dialog — include all details, decisions, and reasoning."
|
|
646
|
-
: `summarize this session transcript. the person asking has trust level: ${trustLevel}. family=full transparency, friend=share work and general topics but protect other people's identities, acquaintance=very guarded minimal disclosure.`;
|
|
647
|
-
return await ctx.summarize(transcript, instruction);
|
|
783
|
+
const friendId = args.friendId;
|
|
784
|
+
const channel = args.channel;
|
|
785
|
+
const key = args.key || "session";
|
|
786
|
+
const count = parseInt(args.messageCount || "20", 10);
|
|
787
|
+
const mode = args.mode || "transcript";
|
|
788
|
+
if (mode === "status") {
|
|
789
|
+
if (friendId !== "self" || channel !== "inner") {
|
|
790
|
+
return "status mode is only available for self/inner dialog.";
|
|
648
791
|
}
|
|
649
|
-
|
|
792
|
+
const sessionPath = (0, thoughts_1.getInnerDialogSessionPath)((0, identity_1.getAgentRoot)());
|
|
793
|
+
const pendingDir = (0, pending_1.getInnerDialogPendingDir)((0, identity_1.getAgentName)());
|
|
794
|
+
return renderInnerProgressStatus((0, thoughts_1.readInnerDialogStatus)(sessionPath, pendingDir));
|
|
650
795
|
}
|
|
651
|
-
|
|
652
|
-
|
|
796
|
+
const sessFile = (0, config_1.resolveSessionPath)(friendId, channel, key);
|
|
797
|
+
const recall = await recallSessionSafely({
|
|
798
|
+
sessionPath: sessFile,
|
|
799
|
+
friendId,
|
|
800
|
+
channel,
|
|
801
|
+
key,
|
|
802
|
+
messageCount: count,
|
|
803
|
+
trustLevel: ctx?.context?.friend?.trustLevel,
|
|
804
|
+
summarize: ctx?.summarize,
|
|
805
|
+
});
|
|
806
|
+
if (recall.kind === "missing") {
|
|
807
|
+
return NO_SESSION_FOUND_MESSAGE;
|
|
653
808
|
}
|
|
809
|
+
if (recall.kind === "empty") {
|
|
810
|
+
return EMPTY_SESSION_MESSAGE;
|
|
811
|
+
}
|
|
812
|
+
return recall.summary;
|
|
654
813
|
},
|
|
655
814
|
},
|
|
656
815
|
{
|
|
@@ -671,35 +830,90 @@ exports.baseToolDefinitions = [
|
|
|
671
830
|
},
|
|
672
831
|
},
|
|
673
832
|
},
|
|
674
|
-
handler: async (args) => {
|
|
833
|
+
handler: async (args, ctx) => {
|
|
675
834
|
const friendId = args.friendId;
|
|
676
835
|
const channel = args.channel;
|
|
677
836
|
const key = args.key || "session";
|
|
678
837
|
const content = args.content;
|
|
679
838
|
const now = Date.now();
|
|
680
|
-
const
|
|
839
|
+
const agentName = (0, identity_1.getAgentName)();
|
|
840
|
+
// Self-routing: messages to "self" always go to inner dialog pending dir,
|
|
841
|
+
// regardless of the channel or key the agent specified.
|
|
842
|
+
const isSelf = friendId === "self";
|
|
843
|
+
const pendingDir = isSelf
|
|
844
|
+
? (0, pending_1.getInnerDialogPendingDir)(agentName)
|
|
845
|
+
: (0, pending_1.getPendingDir)(agentName, friendId, channel, key);
|
|
681
846
|
fs.mkdirSync(pendingDir, { recursive: true });
|
|
682
847
|
const fileName = `${now}-${Math.random().toString(36).slice(2, 10)}.json`;
|
|
683
848
|
const filePath = path.join(pendingDir, fileName);
|
|
849
|
+
const delegatingBridgeId = findDelegatingBridgeId(ctx);
|
|
850
|
+
const delegatedFrom = isSelf
|
|
851
|
+
&& ctx?.currentSession
|
|
852
|
+
&& !(ctx.currentSession.friendId === "self" && ctx.currentSession.channel === "inner")
|
|
853
|
+
? {
|
|
854
|
+
friendId: ctx.currentSession.friendId,
|
|
855
|
+
channel: ctx.currentSession.channel,
|
|
856
|
+
key: ctx.currentSession.key,
|
|
857
|
+
...(delegatingBridgeId ? { bridgeId: delegatingBridgeId } : {}),
|
|
858
|
+
}
|
|
859
|
+
: undefined;
|
|
684
860
|
const envelope = {
|
|
685
|
-
from:
|
|
861
|
+
from: agentName,
|
|
686
862
|
friendId,
|
|
687
863
|
channel,
|
|
688
864
|
key,
|
|
689
865
|
content,
|
|
690
866
|
timestamp: now,
|
|
867
|
+
...(delegatedFrom ? { delegatedFrom } : {}),
|
|
691
868
|
};
|
|
692
869
|
fs.writeFileSync(filePath, JSON.stringify(envelope, null, 2));
|
|
870
|
+
if (isSelf) {
|
|
871
|
+
let wakeResponse = null;
|
|
872
|
+
try {
|
|
873
|
+
wakeResponse = await (0, socket_client_1.requestInnerWake)(agentName);
|
|
874
|
+
}
|
|
875
|
+
catch {
|
|
876
|
+
wakeResponse = null;
|
|
877
|
+
}
|
|
878
|
+
if (!wakeResponse?.ok) {
|
|
879
|
+
const { runInnerDialogTurn } = await Promise.resolve().then(() => __importStar(require("../senses/inner-dialog")));
|
|
880
|
+
if (ctx?.context?.channel.channel === "inner") {
|
|
881
|
+
queueMicrotask(() => {
|
|
882
|
+
void runInnerDialogTurn({ reason: "instinct" });
|
|
883
|
+
});
|
|
884
|
+
return renderInnerProgressStatus({
|
|
885
|
+
queue: "queued to inner/dialog",
|
|
886
|
+
wake: "inline scheduled",
|
|
887
|
+
processing: "pending",
|
|
888
|
+
surfaced: "nothing yet",
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
const turnResult = await runInnerDialogTurn({ reason: "instinct" });
|
|
893
|
+
const surfacedPreview = normalizeProgressOutcome((0, thoughts_1.formatSurfacedValue)((0, thoughts_1.extractThoughtResponseFromMessages)(turnResult?.messages ?? [])));
|
|
894
|
+
return (0, progress_story_1.renderProgressStory)((0, progress_story_1.buildProgressStory)({
|
|
895
|
+
scope: "inner-delegation",
|
|
896
|
+
phase: "completed",
|
|
897
|
+
objective: "queued to inner/dialog",
|
|
898
|
+
outcomeText: `wake: inline fallback\n${surfacedPreview}`,
|
|
899
|
+
}));
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
return renderInnerProgressStatus({
|
|
903
|
+
queue: "queued to inner/dialog",
|
|
904
|
+
wake: "daemon requested",
|
|
905
|
+
processing: "pending",
|
|
906
|
+
surfaced: "nothing yet",
|
|
907
|
+
});
|
|
908
|
+
}
|
|
693
909
|
const preview = content.length > 80 ? content.slice(0, 80) + "…" : content;
|
|
694
|
-
|
|
910
|
+
const target = `${channel}/${key}`;
|
|
911
|
+
return `message queued for delivery to ${friendId} on ${target}. preview: "${preview}". it will be delivered when their session is next active.`;
|
|
695
912
|
},
|
|
696
913
|
},
|
|
697
914
|
...tools_1.codingToolDefinitions,
|
|
698
915
|
];
|
|
699
|
-
// Backward-compat: extract just the OpenAI tool schemas
|
|
700
916
|
exports.tools = exports.baseToolDefinitions.map((d) => d.tool);
|
|
701
|
-
// Backward-compat: extract just the handlers by name
|
|
702
|
-
exports.baseToolHandlers = Object.fromEntries(exports.baseToolDefinitions.map((d) => [d.tool.function.name, d.handler]));
|
|
703
917
|
exports.finalAnswerTool = {
|
|
704
918
|
type: "function",
|
|
705
919
|
function: {
|
|
@@ -707,7 +921,10 @@ exports.finalAnswerTool = {
|
|
|
707
921
|
description: "respond to the user with your message. call this tool when you are ready to deliver your response.",
|
|
708
922
|
parameters: {
|
|
709
923
|
type: "object",
|
|
710
|
-
properties: {
|
|
924
|
+
properties: {
|
|
925
|
+
answer: { type: "string" },
|
|
926
|
+
intent: { type: "string", enum: ["complete", "blocked", "direct_reply"] },
|
|
927
|
+
},
|
|
711
928
|
required: ["answer"],
|
|
712
929
|
},
|
|
713
930
|
},
|