@ouro.bot/cli 0.1.0-alpha.203 → 0.1.0-alpha.205
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/changelog.json +12 -0
- package/dist/heart/agent-entry.js +37 -2
- package/dist/heart/attention-types.js +8 -0
- package/dist/heart/core.js +7 -7
- package/dist/heart/daemon/daemon.js +31 -0
- package/dist/heart/daemon/mcp-server.js +33 -16
- package/dist/heart/daemon/sense-manager.js +23 -2
- package/dist/heart/turn-context.js +358 -0
- package/dist/mind/prompt.js +20 -15
- package/dist/repertoire/tools.js +28 -2
- package/dist/senses/pipeline.js +20 -157
- package/dist/senses/surface-tool.js +0 -27
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.205",
|
|
6
|
+
"changes": [
|
|
7
|
+
"refactor: enforce subsystem boundaries — eliminate all heart/ and nerves/ static imports from senses/, move AttentionItem type to heart/, surfaceToolDef to repertoire/, SteeringFollowUpEffect to heart/turn-coordinator, inline BlueBubbles runtime state reader in daemon"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"version": "0.1.0-alpha.204",
|
|
12
|
+
"changes": [
|
|
13
|
+
"refactor: introduce TurnContext snapshot — centralize state assembly from pipeline.ts into buildTurnContext(), thread pre-read state through prompt assembly to eliminate ad-hoc filesystem reads"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
4
16
|
{
|
|
5
17
|
"version": "0.1.0-alpha.203",
|
|
6
18
|
"changes": [
|
|
@@ -1,4 +1,37 @@
|
|
|
1
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
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
// Unified agent runtime entrypoint.
|
|
4
37
|
// Requires --agent before importing runtime modules that rely on identity.
|
|
@@ -7,10 +40,12 @@ if (!process.argv.includes("--agent")) {
|
|
|
7
40
|
console.error("Missing required --agent <name> argument.\nUsage: node dist/heart/agent-entry.js --agent ouroboros");
|
|
8
41
|
process.exit(1);
|
|
9
42
|
}
|
|
10
|
-
const inner_dialog_worker_1 = require("../senses/inner-dialog-worker");
|
|
11
43
|
const cli_logging_1 = require("../nerves/cli-logging");
|
|
12
44
|
(0, cli_logging_1.configureCliRuntimeLogger)("self");
|
|
13
|
-
|
|
45
|
+
// Dynamic import: agent-entry is boot-time wiring that starts a sense process.
|
|
46
|
+
// Using dynamic import avoids a static heart/ -> senses/ dependency.
|
|
47
|
+
Promise.resolve().then(() => __importStar(require("../senses/inner-dialog-worker"))).then(({ startInnerDialogWorker }) => startInnerDialogWorker())
|
|
48
|
+
.catch((error) => {
|
|
14
49
|
// eslint-disable-next-line no-console -- fatal startup guard for worker process
|
|
15
50
|
console.error(error instanceof Error ? error.message : String(error));
|
|
16
51
|
process.exit(1);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared attention queue types.
|
|
4
|
+
*
|
|
5
|
+
* Canonical home for the AttentionItem interface — consumed by heart/, repertoire/, nerves/, and senses/.
|
|
6
|
+
* Placed in heart/ because attention is a turn-coordination concern.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/dist/heart/core.js
CHANGED
|
@@ -18,7 +18,7 @@ const config_1 = require("./config");
|
|
|
18
18
|
const identity_1 = require("./identity");
|
|
19
19
|
const tools_1 = require("../repertoire/tools");
|
|
20
20
|
const channel_1 = require("../mind/friends/channel");
|
|
21
|
-
const
|
|
21
|
+
const tools_2 = require("../repertoire/tools");
|
|
22
22
|
const runtime_1 = require("../nerves/runtime");
|
|
23
23
|
const context_1 = require("../mind/context");
|
|
24
24
|
const prompt_1 = require("../mind/prompt");
|
|
@@ -148,11 +148,11 @@ function getProviderDisplayLabel(facing = "human") {
|
|
|
148
148
|
return providerLabelBuilders[provider]();
|
|
149
149
|
}
|
|
150
150
|
// Re-export tools, execTool, summarizeArgs from ./tools for backward compat
|
|
151
|
-
var
|
|
152
|
-
Object.defineProperty(exports, "tools", { enumerable: true, get: function () { return
|
|
153
|
-
Object.defineProperty(exports, "execTool", { enumerable: true, get: function () { return
|
|
154
|
-
Object.defineProperty(exports, "summarizeArgs", { enumerable: true, get: function () { return
|
|
155
|
-
Object.defineProperty(exports, "getToolsForChannel", { enumerable: true, get: function () { return
|
|
151
|
+
var tools_3 = require("../repertoire/tools");
|
|
152
|
+
Object.defineProperty(exports, "tools", { enumerable: true, get: function () { return tools_3.tools; } });
|
|
153
|
+
Object.defineProperty(exports, "execTool", { enumerable: true, get: function () { return tools_3.execTool; } });
|
|
154
|
+
Object.defineProperty(exports, "summarizeArgs", { enumerable: true, get: function () { return tools_3.summarizeArgs; } });
|
|
155
|
+
Object.defineProperty(exports, "getToolsForChannel", { enumerable: true, get: function () { return tools_3.getToolsForChannel; } });
|
|
156
156
|
// Re-export streaming functions for backward compat
|
|
157
157
|
var streaming_1 = require("./streaming");
|
|
158
158
|
Object.defineProperty(exports, "streamChatCompletion", { enumerable: true, get: function () { return streaming_1.streamChatCompletion; } });
|
|
@@ -530,7 +530,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
530
530
|
const activeTools = [
|
|
531
531
|
...filteredBaseTools,
|
|
532
532
|
tools_1.ponderTool,
|
|
533
|
-
...(isInnerDialog ? [
|
|
533
|
+
...(isInnerDialog ? [tools_2.surfaceToolDef, tools_1.restTool] : []),
|
|
534
534
|
...((currentContext?.isGroupChat || options?.isReactionSignal) && !isInnerDialog ? [tools_1.observeTool] : []),
|
|
535
535
|
...(!isInnerDialog ? [tools_1.settleTool] : []),
|
|
536
536
|
];
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.OuroDaemon = void 0;
|
|
37
37
|
exports.killOrphanProcesses = killOrphanProcesses;
|
|
38
38
|
exports.writePidfile = writePidfile;
|
|
39
|
+
exports.handleAgentSenseTurn = handleAgentSenseTurn;
|
|
39
40
|
const fs = __importStar(require("fs"));
|
|
40
41
|
const net = __importStar(require("net"));
|
|
41
42
|
const os = __importStar(require("os"));
|
|
@@ -177,6 +178,33 @@ function parseIncomingCommand(raw) {
|
|
|
177
178
|
}
|
|
178
179
|
return parsed;
|
|
179
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Handle agent.senseTurn command: runs a full agent turn via the daemon process.
|
|
183
|
+
* Dynamic import lazy-loads shared-turn. Hot-reload works because ouro dev
|
|
184
|
+
* restarts the daemon process (fresh module cache).
|
|
185
|
+
*/
|
|
186
|
+
async function handleAgentSenseTurn(command) {
|
|
187
|
+
try {
|
|
188
|
+
const { runSenseTurn } = await Promise.resolve().then(() => __importStar(require("../../senses/shared-turn")));
|
|
189
|
+
const result = await runSenseTurn({
|
|
190
|
+
agentName: command.agent,
|
|
191
|
+
channel: command.channel,
|
|
192
|
+
sessionKey: command.sessionKey,
|
|
193
|
+
friendId: command.friendId,
|
|
194
|
+
userMessage: command.message,
|
|
195
|
+
});
|
|
196
|
+
return {
|
|
197
|
+
ok: true,
|
|
198
|
+
message: result.response,
|
|
199
|
+
data: { ponderDeferred: result.ponderDeferred },
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
/* v8 ignore next -- branch: String(error) fallback only for non-Error throws @preserve */
|
|
204
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
205
|
+
return { ok: false, error: `sense turn failed: ${errorMessage}` };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
180
208
|
class OuroDaemon {
|
|
181
209
|
socketPath;
|
|
182
210
|
processManager;
|
|
@@ -683,6 +711,9 @@ class OuroDaemon {
|
|
|
683
711
|
return (0, agent_service_1.handleAgentReportBlocker)(command);
|
|
684
712
|
case "agent.reportComplete":
|
|
685
713
|
return (0, agent_service_1.handleAgentReportComplete)(command);
|
|
714
|
+
case "agent.senseTurn":
|
|
715
|
+
return handleAgentSenseTurn(command);
|
|
716
|
+
/* v8 ignore stop */
|
|
686
717
|
case "cron.list": {
|
|
687
718
|
const jobs = this.scheduler.listJobs();
|
|
688
719
|
const summary = jobs.length === 0
|
|
@@ -38,7 +38,6 @@ exports.getToolSchemas = getToolSchemas;
|
|
|
38
38
|
const socket_client_1 = require("./socket-client");
|
|
39
39
|
const agentService = __importStar(require("./agent-service"));
|
|
40
40
|
const runtime_1 = require("../../nerves/runtime");
|
|
41
|
-
const shared_turn_1 = require("../../senses/shared-turn");
|
|
42
41
|
const session_id_resolver_1 = require("./session-id-resolver");
|
|
43
42
|
const pending_1 = require("../../mind/pending");
|
|
44
43
|
/**
|
|
@@ -249,19 +248,22 @@ function createMcpServer(options) {
|
|
|
249
248
|
const message = toolArgs.message ?? "";
|
|
250
249
|
/* v8 ignore stop */
|
|
251
250
|
try {
|
|
252
|
-
const
|
|
253
|
-
|
|
251
|
+
const response = await (0, socket_client_1.sendDaemonCommand)(socketPath, {
|
|
252
|
+
kind: "agent.senseTurn",
|
|
253
|
+
agent,
|
|
254
|
+
friendId,
|
|
254
255
|
channel: "mcp",
|
|
255
256
|
sessionKey: sessionId,
|
|
256
|
-
|
|
257
|
-
userMessage: message,
|
|
257
|
+
message,
|
|
258
258
|
});
|
|
259
|
+
/* v8 ignore next -- branch: ?? fallback for empty daemon response @preserve */
|
|
260
|
+
const text = response.message ?? "(empty response)";
|
|
259
261
|
writeResponse({
|
|
260
262
|
jsonrpc: "2.0",
|
|
261
263
|
id: request.id,
|
|
262
264
|
result: {
|
|
263
|
-
content: [{ type: "text", text
|
|
264
|
-
isError:
|
|
265
|
+
content: [{ type: "text", text }],
|
|
266
|
+
isError: !response.ok,
|
|
265
267
|
},
|
|
266
268
|
});
|
|
267
269
|
}
|
|
@@ -269,11 +271,17 @@ function createMcpServer(options) {
|
|
|
269
271
|
/* v8 ignore start — instanceof guard defensive; thrown errors are always Error */
|
|
270
272
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
271
273
|
/* v8 ignore stop */
|
|
274
|
+
/* v8 ignore start -- daemon-down detection: only triggers with real socket I/O @preserve */
|
|
275
|
+
const isDaemonDown = errorMessage.includes("ECONNREFUSED") || errorMessage.includes("ENOENT");
|
|
276
|
+
const userMessage = isDaemonDown
|
|
277
|
+
? "The daemon is not running. Start it with `ouro up` (production) or `ouro dev` (development), then retry."
|
|
278
|
+
: `Error: ${errorMessage}`;
|
|
279
|
+
/* v8 ignore stop */
|
|
272
280
|
writeResponse({
|
|
273
281
|
jsonrpc: "2.0",
|
|
274
282
|
id: request.id,
|
|
275
283
|
result: {
|
|
276
|
-
content: [{ type: "text", text:
|
|
284
|
+
content: [{ type: "text", text: userMessage }],
|
|
277
285
|
isError: true,
|
|
278
286
|
},
|
|
279
287
|
});
|
|
@@ -306,7 +314,7 @@ function createMcpServer(options) {
|
|
|
306
314
|
}
|
|
307
315
|
return;
|
|
308
316
|
}
|
|
309
|
-
// ── delegate: full conversation turn via
|
|
317
|
+
// ── delegate: full conversation turn via daemon ──
|
|
310
318
|
if (toolName === "delegate") {
|
|
311
319
|
/* v8 ignore start — ?? fallback defensive; MCP clients always send task */
|
|
312
320
|
const task = toolArgs.task ?? "";
|
|
@@ -314,19 +322,22 @@ function createMcpServer(options) {
|
|
|
314
322
|
const context = toolArgs.context;
|
|
315
323
|
const delegateMessage = context ? `[delegate] ${task}\n\ncontext: ${context}` : `[delegate] ${task}`;
|
|
316
324
|
try {
|
|
317
|
-
const
|
|
318
|
-
|
|
325
|
+
const response = await (0, socket_client_1.sendDaemonCommand)(socketPath, {
|
|
326
|
+
kind: "agent.senseTurn",
|
|
327
|
+
agent,
|
|
328
|
+
friendId,
|
|
319
329
|
channel: "mcp",
|
|
320
330
|
sessionKey: sessionId,
|
|
321
|
-
|
|
322
|
-
userMessage: delegateMessage,
|
|
331
|
+
message: delegateMessage,
|
|
323
332
|
});
|
|
333
|
+
/* v8 ignore next -- branch: ?? fallback for empty daemon response @preserve */
|
|
334
|
+
const text = response.message ?? "(empty response)";
|
|
324
335
|
writeResponse({
|
|
325
336
|
jsonrpc: "2.0",
|
|
326
337
|
id: request.id,
|
|
327
338
|
result: {
|
|
328
|
-
content: [{ type: "text", text
|
|
329
|
-
isError:
|
|
339
|
+
content: [{ type: "text", text }],
|
|
340
|
+
isError: !response.ok,
|
|
330
341
|
},
|
|
331
342
|
});
|
|
332
343
|
}
|
|
@@ -334,11 +345,17 @@ function createMcpServer(options) {
|
|
|
334
345
|
/* v8 ignore start — instanceof guard defensive; thrown errors are always Error */
|
|
335
346
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
336
347
|
/* v8 ignore stop */
|
|
348
|
+
/* v8 ignore start -- daemon-down detection: only triggers with real socket I/O @preserve */
|
|
349
|
+
const isDaemonDown = errorMessage.includes("ECONNREFUSED") || errorMessage.includes("ENOENT");
|
|
350
|
+
const userMessage = isDaemonDown
|
|
351
|
+
? "The daemon is not running. Start it with `ouro up` (production) or `ouro dev` (development), then retry."
|
|
352
|
+
: `Error: ${errorMessage}`;
|
|
353
|
+
/* v8 ignore stop */
|
|
337
354
|
writeResponse({
|
|
338
355
|
jsonrpc: "2.0",
|
|
339
356
|
id: request.id,
|
|
340
357
|
result: {
|
|
341
|
-
content: [{ type: "text", text:
|
|
358
|
+
content: [{ type: "text", text: userMessage }],
|
|
342
359
|
isError: true,
|
|
343
360
|
},
|
|
344
361
|
});
|
|
@@ -38,7 +38,6 @@ const fs = __importStar(require("fs"));
|
|
|
38
38
|
const os = __importStar(require("os"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const runtime_1 = require("../../nerves/runtime");
|
|
41
|
-
const bluebubbles_runtime_state_1 = require("../../senses/bluebubbles-runtime-state");
|
|
42
41
|
const identity_1 = require("../identity");
|
|
43
42
|
const sense_truth_1 = require("../sense-truth");
|
|
44
43
|
const process_manager_1 = require("./process-manager");
|
|
@@ -187,13 +186,35 @@ function blueBubblesRuntimeStateIsFresh(lastCheckedAt, now = Date.now()) {
|
|
|
187
186
|
}
|
|
188
187
|
return checkedAt >= now - BLUEBUBBLES_RUNTIME_FRESHNESS_WINDOW_MS;
|
|
189
188
|
}
|
|
189
|
+
function readBlueBubblesRuntimeJson(runtimePath) {
|
|
190
|
+
try {
|
|
191
|
+
const raw = fs.readFileSync(runtimePath, "utf-8");
|
|
192
|
+
const parsed = JSON.parse(raw);
|
|
193
|
+
/* v8 ignore start -- branches: ternary fallbacks for missing/malformed BB runtime fields @preserve */
|
|
194
|
+
return {
|
|
195
|
+
upstreamStatus: parsed.upstreamStatus === "ok" || parsed.upstreamStatus === "error"
|
|
196
|
+
? parsed.upstreamStatus
|
|
197
|
+
: "unknown",
|
|
198
|
+
detail: typeof parsed.detail === "string" && parsed.detail.trim()
|
|
199
|
+
? parsed.detail
|
|
200
|
+
: "startup health probe pending",
|
|
201
|
+
lastCheckedAt: typeof parsed.lastCheckedAt === "string" ? parsed.lastCheckedAt : undefined,
|
|
202
|
+
};
|
|
203
|
+
/* v8 ignore stop */
|
|
204
|
+
/* v8 ignore start -- defensive: catch for missing/corrupt BB runtime state file @preserve */
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
return { upstreamStatus: "unknown", detail: "startup health probe pending" };
|
|
208
|
+
}
|
|
209
|
+
/* v8 ignore stop */
|
|
210
|
+
}
|
|
190
211
|
function readBlueBubblesRuntimeFacts(agent, bundlesRoot, snapshot) {
|
|
191
212
|
const agentRoot = path.join(bundlesRoot, `${agent}.ouro`);
|
|
192
213
|
const runtimePath = path.join(agentRoot, "state", "senses", "bluebubbles", "runtime.json");
|
|
193
214
|
if (!fs.existsSync(runtimePath)) {
|
|
194
215
|
return { runtime: snapshot?.runtime };
|
|
195
216
|
}
|
|
196
|
-
const state = (
|
|
217
|
+
const state = readBlueBubblesRuntimeJson(runtimePath);
|
|
197
218
|
if (!blueBubblesRuntimeStateIsFresh(state.lastCheckedAt)) {
|
|
198
219
|
return { runtime: snapshot?.runtime };
|
|
199
220
|
}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TurnContext: a single pre-read snapshot of all state sources needed
|
|
4
|
+
* by the inbound-turn pipeline and prompt assembly.
|
|
5
|
+
*
|
|
6
|
+
* Before this module existed, pipeline.ts read ~10 state sources inline
|
|
7
|
+
* and prompt.ts did several ad-hoc filesystem reads. This centralizes
|
|
8
|
+
* all reads into one place so the rest of the turn is pure derivation.
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.buildTurnContext = buildTurnContext;
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const runtime_1 = require("../nerves/runtime");
|
|
48
|
+
const manager_1 = require("./bridges/manager");
|
|
49
|
+
const identity_1 = require("./identity");
|
|
50
|
+
const tasks_1 = require("../repertoire/tasks");
|
|
51
|
+
const coding_1 = require("../repertoire/coding");
|
|
52
|
+
const session_activity_1 = require("./session-activity");
|
|
53
|
+
const thoughts_1 = require("./daemon/thoughts");
|
|
54
|
+
const pending_1 = require("../mind/pending");
|
|
55
|
+
const obligations_1 = require("./obligations");
|
|
56
|
+
const target_resolution_1 = require("./target-resolution");
|
|
57
|
+
const episodes_1 = require("../mind/episodes");
|
|
58
|
+
const cares_1 = require("./cares");
|
|
59
|
+
const config_1 = require("./config");
|
|
60
|
+
const daemon_health_1 = require("./daemon/daemon-health");
|
|
61
|
+
const prompt_1 = require("../mind/prompt");
|
|
62
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
63
|
+
const DAEMON_SOCKET_PATH = "/tmp/ouroboros-daemon.sock";
|
|
64
|
+
function isLiveCodingSessionStatus(status) {
|
|
65
|
+
return status === "spawning"
|
|
66
|
+
|| status === "running"
|
|
67
|
+
|| status === "waiting_input"
|
|
68
|
+
|| status === "stalled";
|
|
69
|
+
}
|
|
70
|
+
function emptyTaskBoard() {
|
|
71
|
+
return {
|
|
72
|
+
compact: "",
|
|
73
|
+
full: "",
|
|
74
|
+
byStatus: {
|
|
75
|
+
drafting: [],
|
|
76
|
+
processing: [],
|
|
77
|
+
validating: [],
|
|
78
|
+
collaborating: [],
|
|
79
|
+
paused: [],
|
|
80
|
+
blocked: [],
|
|
81
|
+
done: [],
|
|
82
|
+
cancelled: [],
|
|
83
|
+
},
|
|
84
|
+
issues: [],
|
|
85
|
+
actionRequired: [],
|
|
86
|
+
unresolvedDependencies: [],
|
|
87
|
+
activeSessions: [],
|
|
88
|
+
activeBridges: [],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function readInnerWorkState() {
|
|
92
|
+
const defaultJob = {
|
|
93
|
+
status: "idle",
|
|
94
|
+
content: null,
|
|
95
|
+
origin: null,
|
|
96
|
+
mode: "reflect",
|
|
97
|
+
obligationStatus: null,
|
|
98
|
+
surfacedResult: null,
|
|
99
|
+
queuedAt: null,
|
|
100
|
+
startedAt: null,
|
|
101
|
+
surfacedAt: null,
|
|
102
|
+
};
|
|
103
|
+
try {
|
|
104
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
105
|
+
const pendingDir = (0, pending_1.getInnerDialogPendingDir)((0, identity_1.getAgentName)());
|
|
106
|
+
const sessionPath = (0, thoughts_1.getInnerDialogSessionPath)(agentRoot);
|
|
107
|
+
const { pendingMessages, turns, runtimeState } = (0, thoughts_1.readInnerDialogRawData)(sessionPath, pendingDir);
|
|
108
|
+
const dialogStatus = (0, thoughts_1.deriveInnerDialogStatus)(pendingMessages, turns, runtimeState);
|
|
109
|
+
const job = (0, thoughts_1.deriveInnerJob)(pendingMessages, turns, runtimeState);
|
|
110
|
+
const storeObligationPending = (0, obligations_1.readPendingObligations)(agentRoot).length > 0;
|
|
111
|
+
return {
|
|
112
|
+
status: dialogStatus.processing === "started" ? "running" : "idle",
|
|
113
|
+
hasPending: dialogStatus.queue !== "clear",
|
|
114
|
+
origin: dialogStatus.origin,
|
|
115
|
+
contentSnippet: dialogStatus.contentSnippet,
|
|
116
|
+
obligationPending: dialogStatus.obligationPending || storeObligationPending,
|
|
117
|
+
job,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
121
|
+
return {
|
|
122
|
+
status: "idle",
|
|
123
|
+
hasPending: false,
|
|
124
|
+
job: defaultJob,
|
|
125
|
+
/* v8 ignore stop */
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function checkDaemonRunning() {
|
|
130
|
+
try {
|
|
131
|
+
return fs.existsSync(DAEMON_SOCKET_PATH);
|
|
132
|
+
}
|
|
133
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
134
|
+
return false;
|
|
135
|
+
/* v8 ignore stop */
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function hasTextField(record, key) {
|
|
139
|
+
return typeof record?.[key] === "string" && record[key].trim().length > 0;
|
|
140
|
+
}
|
|
141
|
+
function readSenseStatusLines() {
|
|
142
|
+
const config = (0, identity_1.loadAgentConfig)();
|
|
143
|
+
const senses = config.senses ?? {
|
|
144
|
+
cli: { enabled: true },
|
|
145
|
+
teams: { enabled: false },
|
|
146
|
+
bluebubbles: { enabled: false },
|
|
147
|
+
};
|
|
148
|
+
let payload = {};
|
|
149
|
+
try {
|
|
150
|
+
const raw = fs.readFileSync((0, identity_1.getAgentSecretsPath)(), "utf-8");
|
|
151
|
+
const parsed = JSON.parse(raw);
|
|
152
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
153
|
+
payload = parsed;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
157
|
+
payload = {};
|
|
158
|
+
/* v8 ignore stop */
|
|
159
|
+
}
|
|
160
|
+
const teams = payload.teams;
|
|
161
|
+
const bluebubbles = payload.bluebubbles;
|
|
162
|
+
const configured = {
|
|
163
|
+
cli: true,
|
|
164
|
+
teams: hasTextField(teams, "clientId") && hasTextField(teams, "clientSecret") && hasTextField(teams, "tenantId"),
|
|
165
|
+
bluebubbles: hasTextField(bluebubbles, "serverUrl") && hasTextField(bluebubbles, "password"),
|
|
166
|
+
};
|
|
167
|
+
const rows = [
|
|
168
|
+
{ label: "CLI", status: "interactive" },
|
|
169
|
+
{
|
|
170
|
+
label: "Teams",
|
|
171
|
+
status: !senses.teams.enabled ? "disabled" : configured.teams ? "ready" : "needs_config",
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
label: "BlueBubbles",
|
|
175
|
+
status: !senses.bluebubbles.enabled ? "disabled" : configured.bluebubbles ? "ready" : "needs_config",
|
|
176
|
+
},
|
|
177
|
+
];
|
|
178
|
+
return rows.map((row) => `- ${row.label}: ${row.status}`);
|
|
179
|
+
}
|
|
180
|
+
function readBundleMetaFile() {
|
|
181
|
+
try {
|
|
182
|
+
const metaPath = path.join((0, identity_1.getAgentRoot)(), "bundle-meta.json");
|
|
183
|
+
const raw = fs.readFileSync(metaPath, "utf-8");
|
|
184
|
+
return JSON.parse(raw);
|
|
185
|
+
}
|
|
186
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
187
|
+
return null;
|
|
188
|
+
/* v8 ignore stop */
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// ── Builder ─────────────────────────────────────────────────────────
|
|
192
|
+
async function buildTurnContext(input) {
|
|
193
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
194
|
+
const agentName = (0, identity_1.getAgentName)();
|
|
195
|
+
// Sync config
|
|
196
|
+
let syncConfig = { enabled: false, remote: "origin" };
|
|
197
|
+
try {
|
|
198
|
+
syncConfig = (0, config_1.getSyncConfig)();
|
|
199
|
+
}
|
|
200
|
+
catch { /* v8 ignore next -- defensive @preserve */ /* config not available */ }
|
|
201
|
+
// Bridges
|
|
202
|
+
const activeBridges = (0, manager_1.createBridgeManager)().findBridgesForSession({
|
|
203
|
+
friendId: input.currentSession.friendId,
|
|
204
|
+
channel: input.currentSession.channel,
|
|
205
|
+
key: input.currentSession.key,
|
|
206
|
+
});
|
|
207
|
+
// Session activity
|
|
208
|
+
let sessionActivity = [];
|
|
209
|
+
try {
|
|
210
|
+
sessionActivity = (0, session_activity_1.listSessionActivity)({
|
|
211
|
+
sessionsDir: `${agentRoot}/state/sessions`,
|
|
212
|
+
friendsDir: `${agentRoot}/friends`,
|
|
213
|
+
agentName,
|
|
214
|
+
currentSession: {
|
|
215
|
+
friendId: input.currentSession.friendId,
|
|
216
|
+
channel: input.currentSession.channel,
|
|
217
|
+
key: input.currentSession.key,
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
222
|
+
sessionActivity = [];
|
|
223
|
+
/* v8 ignore stop */
|
|
224
|
+
}
|
|
225
|
+
// Target candidates
|
|
226
|
+
let targetCandidates = [];
|
|
227
|
+
try {
|
|
228
|
+
if (input.channel !== "inner") {
|
|
229
|
+
targetCandidates = await (0, target_resolution_1.listTargetSessionCandidates)({
|
|
230
|
+
sessionsDir: `${agentRoot}/state/sessions`,
|
|
231
|
+
friendsDir: `${agentRoot}/friends`,
|
|
232
|
+
agentName,
|
|
233
|
+
currentSession: {
|
|
234
|
+
friendId: input.currentSession.friendId,
|
|
235
|
+
channel: input.currentSession.channel,
|
|
236
|
+
key: input.currentSession.key,
|
|
237
|
+
},
|
|
238
|
+
friendStore: input.friendStore,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
243
|
+
targetCandidates = [];
|
|
244
|
+
/* v8 ignore stop */
|
|
245
|
+
}
|
|
246
|
+
// Pending obligations
|
|
247
|
+
let pendingObligations = [];
|
|
248
|
+
try {
|
|
249
|
+
pendingObligations = (0, obligations_1.readPendingObligations)(agentRoot);
|
|
250
|
+
}
|
|
251
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
252
|
+
pendingObligations = [];
|
|
253
|
+
/* v8 ignore stop */
|
|
254
|
+
}
|
|
255
|
+
// Coding sessions
|
|
256
|
+
let codingSessions = [];
|
|
257
|
+
let otherCodingSessions = [];
|
|
258
|
+
try {
|
|
259
|
+
const liveCodingSessions = (0, coding_1.getCodingSessionManager)()
|
|
260
|
+
.listSessions()
|
|
261
|
+
.filter((session) => isLiveCodingSessionStatus(session.status) && Boolean(session.originSession));
|
|
262
|
+
codingSessions = liveCodingSessions.filter((session) => session.originSession?.friendId === input.currentSession.friendId
|
|
263
|
+
&& session.originSession.channel === input.currentSession.channel
|
|
264
|
+
&& session.originSession.key === input.currentSession.key);
|
|
265
|
+
otherCodingSessions = liveCodingSessions.filter((session) => !(session.originSession?.friendId === input.currentSession.friendId
|
|
266
|
+
&& session.originSession.channel === input.currentSession.channel
|
|
267
|
+
&& session.originSession.key === input.currentSession.key));
|
|
268
|
+
}
|
|
269
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
270
|
+
codingSessions = [];
|
|
271
|
+
otherCodingSessions = [];
|
|
272
|
+
/* v8 ignore stop */
|
|
273
|
+
}
|
|
274
|
+
// Inner work state
|
|
275
|
+
const innerWorkState = readInnerWorkState();
|
|
276
|
+
// Task board
|
|
277
|
+
let taskBoard;
|
|
278
|
+
try {
|
|
279
|
+
taskBoard = (0, tasks_1.getTaskModule)().getBoard();
|
|
280
|
+
}
|
|
281
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
282
|
+
taskBoard = emptyTaskBoard();
|
|
283
|
+
/* v8 ignore stop */
|
|
284
|
+
}
|
|
285
|
+
// Return obligations
|
|
286
|
+
let returnObligations = [];
|
|
287
|
+
try {
|
|
288
|
+
returnObligations = (0, obligations_1.listActiveReturnObligations)(agentName);
|
|
289
|
+
}
|
|
290
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
291
|
+
returnObligations = [];
|
|
292
|
+
/* v8 ignore stop */
|
|
293
|
+
}
|
|
294
|
+
// Recent episodes
|
|
295
|
+
const recentEpisodes = (0, episodes_1.readRecentEpisodes)(agentRoot, { limit: 20 });
|
|
296
|
+
// Active cares
|
|
297
|
+
const activeCares = (0, cares_1.readActiveCares)(agentRoot);
|
|
298
|
+
// ── Prompt-assembly pre-reads ──────────────────────────────────────
|
|
299
|
+
const daemonRunning = checkDaemonRunning();
|
|
300
|
+
let senseStatusLines = [];
|
|
301
|
+
try {
|
|
302
|
+
senseStatusLines = readSenseStatusLines();
|
|
303
|
+
}
|
|
304
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
305
|
+
senseStatusLines = [];
|
|
306
|
+
/* v8 ignore stop */
|
|
307
|
+
}
|
|
308
|
+
const bundleMeta = readBundleMetaFile();
|
|
309
|
+
let daemonHealth = null;
|
|
310
|
+
try {
|
|
311
|
+
daemonHealth = (0, daemon_health_1.readHealth)((0, daemon_health_1.getDefaultHealthPath)());
|
|
312
|
+
}
|
|
313
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
314
|
+
daemonHealth = null;
|
|
315
|
+
/* v8 ignore stop */
|
|
316
|
+
}
|
|
317
|
+
let journalFiles = [];
|
|
318
|
+
try {
|
|
319
|
+
const journalDir = path.join(agentRoot, "journal");
|
|
320
|
+
journalFiles = (0, prompt_1.readJournalFiles)(journalDir);
|
|
321
|
+
}
|
|
322
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
323
|
+
journalFiles = [];
|
|
324
|
+
/* v8 ignore stop */
|
|
325
|
+
}
|
|
326
|
+
(0, runtime_1.emitNervesEvent)({
|
|
327
|
+
component: "senses",
|
|
328
|
+
event: "senses.turn_context_built",
|
|
329
|
+
message: "turn context snapshot assembled",
|
|
330
|
+
meta: {
|
|
331
|
+
channel: input.channel,
|
|
332
|
+
obligationCount: pendingObligations.length,
|
|
333
|
+
bridgeCount: activeBridges.length,
|
|
334
|
+
codingSessionCount: codingSessions.length,
|
|
335
|
+
episodeCount: recentEpisodes.length,
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
return {
|
|
339
|
+
activeBridges,
|
|
340
|
+
sessionActivity,
|
|
341
|
+
targetCandidates,
|
|
342
|
+
pendingObligations,
|
|
343
|
+
codingSessions,
|
|
344
|
+
otherCodingSessions,
|
|
345
|
+
innerWorkState,
|
|
346
|
+
taskBoard,
|
|
347
|
+
returnObligations,
|
|
348
|
+
recentEpisodes,
|
|
349
|
+
activeCares,
|
|
350
|
+
syncConfig,
|
|
351
|
+
syncFailure: undefined, // Set by pipeline after preTurnPull
|
|
352
|
+
daemonRunning,
|
|
353
|
+
senseStatusLines,
|
|
354
|
+
bundleMeta,
|
|
355
|
+
daemonHealth,
|
|
356
|
+
journalFiles,
|
|
357
|
+
};
|
|
358
|
+
}
|
package/dist/mind/prompt.js
CHANGED
|
@@ -257,7 +257,11 @@ function processTypeLabel(channel) {
|
|
|
257
257
|
return PROCESS_TYPE_LABELS[channel];
|
|
258
258
|
}
|
|
259
259
|
const DAEMON_SOCKET_PATH = "/tmp/ouroboros-daemon.sock";
|
|
260
|
-
function daemonStatus() {
|
|
260
|
+
function daemonStatus(preRead) {
|
|
261
|
+
/* v8 ignore next 2 -- pre-read branch: exercised via pipeline TurnContext path, not unit-testable in isolation @preserve */
|
|
262
|
+
if (preRead !== undefined) {
|
|
263
|
+
return preRead ? "running" : "not running";
|
|
264
|
+
}
|
|
261
265
|
try {
|
|
262
266
|
return fs.existsSync(DAEMON_SOCKET_PATH) ? "running" : "not running";
|
|
263
267
|
}
|
|
@@ -265,14 +269,15 @@ function daemonStatus() {
|
|
|
265
269
|
return "unknown";
|
|
266
270
|
}
|
|
267
271
|
}
|
|
268
|
-
function runtimeInfoSection(channel) {
|
|
272
|
+
function runtimeInfoSection(channel, options) {
|
|
269
273
|
const lines = [];
|
|
270
274
|
const agentName = (0, identity_1.getAgentName)();
|
|
271
275
|
const currentVersion = (0, bundle_manifest_1.getPackageVersion)();
|
|
272
276
|
lines.push(`## runtime`);
|
|
273
277
|
lines.push(`agent: ${agentName}`);
|
|
274
278
|
lines.push(`runtime version: ${currentVersion}`);
|
|
275
|
-
|
|
279
|
+
/* v8 ignore next -- branch: pre-read path exercised via pipeline TurnContext, not unit-testable in isolation @preserve */
|
|
280
|
+
const bundleMeta = options?.bundleMeta !== undefined ? options.bundleMeta : readBundleMeta();
|
|
276
281
|
if (bundleMeta?.previousRuntimeVersion && bundleMeta.previousRuntimeVersion !== currentVersion) {
|
|
277
282
|
lines.push(`previously: ${bundleMeta.previousRuntimeVersion}`);
|
|
278
283
|
const changelogCommand = (0, ouro_version_manager_1.buildChangelogCommand)(bundleMeta.previousRuntimeVersion, currentVersion);
|
|
@@ -289,7 +294,7 @@ function runtimeInfoSection(channel) {
|
|
|
289
294
|
lines.push(`channel: ${channel}`);
|
|
290
295
|
lines.push(`current sense: ${channel}`);
|
|
291
296
|
lines.push(`process type: ${processTypeLabel(channel)}`);
|
|
292
|
-
lines.push(`daemon: ${daemonStatus()}`);
|
|
297
|
+
lines.push(`daemon: ${daemonStatus(options?.daemonRunning)}`);
|
|
293
298
|
lines.push(`mcp serve: i can expose my tools to dev tools via \`ouro mcp-serve\`. see the configure-dev-tools skill for setup.`);
|
|
294
299
|
if (channel === "cli") {
|
|
295
300
|
lines.push("i introduce myself on boot with a fun random greeting.");
|
|
@@ -308,7 +313,7 @@ function runtimeInfoSection(channel) {
|
|
|
308
313
|
lines.push("i am responding in Microsoft Teams. i keep responses concise. i use markdown formatting. i do not introduce myself on boot.");
|
|
309
314
|
}
|
|
310
315
|
lines.push("");
|
|
311
|
-
lines.push(...senseRuntimeGuidance(channel));
|
|
316
|
+
lines.push(...senseRuntimeGuidance(channel, options?.senseStatusLines));
|
|
312
317
|
return lines.join("\n");
|
|
313
318
|
}
|
|
314
319
|
function hasTextField(record, key) {
|
|
@@ -356,9 +361,9 @@ function localSenseStatusLines() {
|
|
|
356
361
|
_senseStatusLinesCache = rows.map((row) => `- ${row.label}: ${row.status}`);
|
|
357
362
|
return [..._senseStatusLinesCache];
|
|
358
363
|
}
|
|
359
|
-
function senseRuntimeGuidance(channel) {
|
|
364
|
+
function senseRuntimeGuidance(channel, preReadStatusLines) {
|
|
360
365
|
const lines = ["available senses:"];
|
|
361
|
-
lines.push(...localSenseStatusLines());
|
|
366
|
+
lines.push(...(preReadStatusLines ?? localSenseStatusLines()));
|
|
362
367
|
lines.push("sense states:");
|
|
363
368
|
lines.push("- interactive = available when opened by the user instead of kept running by the daemon");
|
|
364
369
|
lines.push("- disabled = turned off in agent.json");
|
|
@@ -876,9 +881,8 @@ function formatRelativeTime(nowMs, mtimeMs) {
|
|
|
876
881
|
const days = Math.floor(hours / 24);
|
|
877
882
|
return `${days} day${days === 1 ? "" : "s"} ago`;
|
|
878
883
|
}
|
|
879
|
-
function journalSection(agentRoot, now) {
|
|
880
|
-
const
|
|
881
|
-
const files = readJournalFiles(journalDir);
|
|
884
|
+
function journalSection(agentRoot, now, preReadFiles) {
|
|
885
|
+
const files = preReadFiles ?? readJournalFiles(path.join(agentRoot, "journal"));
|
|
882
886
|
if (files.length === 0)
|
|
883
887
|
return "";
|
|
884
888
|
const nowMs = (now ?? new Date()).getTime();
|
|
@@ -977,9 +981,10 @@ function formatElapsedBrief(ms) {
|
|
|
977
981
|
const hours = Math.floor(minutes / 60);
|
|
978
982
|
return `${hours}h ago`;
|
|
979
983
|
}
|
|
980
|
-
function rhythmStatusSection() {
|
|
984
|
+
function rhythmStatusSection(preReadHealth) {
|
|
981
985
|
try {
|
|
982
|
-
|
|
986
|
+
/* v8 ignore next -- branch: pre-read path exercised via pipeline TurnContext @preserve */
|
|
987
|
+
const health = preReadHealth !== undefined ? preReadHealth : (0, daemon_health_1.readHealth)((0, daemon_health_1.getDefaultHealthPath)());
|
|
983
988
|
if (!health)
|
|
984
989
|
return "";
|
|
985
990
|
const habitNames = Object.keys(health.habits);
|
|
@@ -1032,8 +1037,8 @@ async function buildSystem(channel = "cli", options, context) {
|
|
|
1032
1037
|
// Group 2: my body & environment
|
|
1033
1038
|
"# my body & environment",
|
|
1034
1039
|
bodyMapSection((0, identity_1.getAgentName)()),
|
|
1035
|
-
runtimeInfoSection(channel),
|
|
1036
|
-
rhythmStatusSection(),
|
|
1040
|
+
runtimeInfoSection(channel, options),
|
|
1041
|
+
rhythmStatusSection(options?.daemonHealth),
|
|
1037
1042
|
channelNatureSection((0, channel_1.getChannelCapabilities)(channel)),
|
|
1038
1043
|
providerSection(channel),
|
|
1039
1044
|
dateSection(),
|
|
@@ -1055,7 +1060,7 @@ async function buildSystem(channel = "cli", options, context) {
|
|
|
1055
1060
|
...(channel === "inner" ? [
|
|
1056
1061
|
"# my inner life",
|
|
1057
1062
|
metacognitiveFramingSection(channel),
|
|
1058
|
-
journalSection((0, identity_1.getAgentRoot)()),
|
|
1063
|
+
journalSection((0, identity_1.getAgentRoot)(), undefined, options?.journalFiles),
|
|
1059
1064
|
] : []),
|
|
1060
1065
|
// Group 6: social context (non-local, non-inner channels)
|
|
1061
1066
|
// Individual sections self-gate on isRemoteChannel/channel checks.
|
package/dist/repertoire/tools.js
CHANGED
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.restTool = exports.ponderTool = exports.observeTool = exports.settleTool = exports.tools = void 0;
|
|
36
|
+
exports.surfaceToolDef = exports.restTool = exports.ponderTool = exports.observeTool = exports.settleTool = exports.tools = void 0;
|
|
37
37
|
exports.getToolsForChannel = getToolsForChannel;
|
|
38
38
|
exports.isConfirmationRequired = isConfirmationRequired;
|
|
39
39
|
exports.execTool = execTool;
|
|
@@ -66,10 +66,36 @@ Object.defineProperty(exports, "settleTool", { enumerable: true, get: function (
|
|
|
66
66
|
Object.defineProperty(exports, "observeTool", { enumerable: true, get: function () { return tools_base_2.observeTool; } });
|
|
67
67
|
Object.defineProperty(exports, "ponderTool", { enumerable: true, get: function () { return tools_base_2.ponderTool; } });
|
|
68
68
|
Object.defineProperty(exports, "restTool", { enumerable: true, get: function () { return tools_base_2.restTool; } });
|
|
69
|
+
// Surface tool schema — canonical home. Handler lives in senses/surface-tool.ts.
|
|
70
|
+
exports.surfaceToolDef = {
|
|
71
|
+
type: "function",
|
|
72
|
+
function: {
|
|
73
|
+
name: "surface",
|
|
74
|
+
description: "share a thought outward — deliver an answer, ask a follow-up, or surface progress to whoever needs to hear it. pass delegationId to address a held thought (see your attention queue above), or friendId for spontaneous outreach. does not end your turn.",
|
|
75
|
+
parameters: {
|
|
76
|
+
type: "object",
|
|
77
|
+
properties: {
|
|
78
|
+
content: {
|
|
79
|
+
type: "string",
|
|
80
|
+
description: "the message to deliver",
|
|
81
|
+
},
|
|
82
|
+
delegationId: {
|
|
83
|
+
type: "string",
|
|
84
|
+
description: "ID from your attention queue — addresses a specific held thought",
|
|
85
|
+
},
|
|
86
|
+
friendId: {
|
|
87
|
+
type: "string",
|
|
88
|
+
description: "friend to reach out to spontaneously (when not addressing a held thought)",
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
required: ["content"],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
69
95
|
// Surface tool handler: routes content to friend's freshest session
|
|
70
96
|
/* v8 ignore start -- surface handler wiring: core logic tested via surface-tool.test.ts; this wires identity/routing deps @preserve */
|
|
71
97
|
const surfaceToolDefinition = {
|
|
72
|
-
tool:
|
|
98
|
+
tool: exports.surfaceToolDef,
|
|
73
99
|
handler: async (args, ctx) => {
|
|
74
100
|
const queue = ctx?.delegatedOrigins ?? [];
|
|
75
101
|
const agentName = (() => { try {
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -47,15 +47,9 @@ const commands_1 = require("./commands");
|
|
|
47
47
|
const continuity_1 = require("./continuity");
|
|
48
48
|
const manager_1 = require("../heart/bridges/manager");
|
|
49
49
|
const identity_1 = require("../heart/identity");
|
|
50
|
-
const tasks_1 = require("../repertoire/tasks");
|
|
51
|
-
const coding_1 = require("../repertoire/coding");
|
|
52
|
-
const session_activity_1 = require("../heart/session-activity");
|
|
53
50
|
const socket_client_1 = require("../heart/daemon/socket-client");
|
|
54
51
|
const active_work_1 = require("../heart/active-work");
|
|
55
52
|
const delegation_1 = require("../heart/delegation");
|
|
56
|
-
const target_resolution_1 = require("../heart/target-resolution");
|
|
57
|
-
const thoughts_1 = require("../heart/daemon/thoughts");
|
|
58
|
-
const pending_1 = require("../mind/pending");
|
|
59
53
|
const obligations_1 = require("../heart/obligations");
|
|
60
54
|
const provider_failover_1 = require("../heart/provider-failover");
|
|
61
55
|
const provider_ping_1 = require("../heart/provider-ping");
|
|
@@ -67,7 +61,7 @@ const sync_1 = require("../heart/sync");
|
|
|
67
61
|
const config_1 = require("../heart/config");
|
|
68
62
|
const presence_1 = require("../heart/presence");
|
|
69
63
|
const episodes_1 = require("../mind/episodes");
|
|
70
|
-
const
|
|
64
|
+
const turn_context_1 = require("../heart/turn-context");
|
|
71
65
|
/**
|
|
72
66
|
* Emit episodes for obligation state transitions detected during a turn.
|
|
73
67
|
* Exported for direct testability (avoids v8 coverage merge issues in multi-file test suites).
|
|
@@ -88,33 +82,6 @@ function emitObligationTransitionEpisodes(agentRoot, preTurnObligationIds, postT
|
|
|
88
82
|
}
|
|
89
83
|
}
|
|
90
84
|
}
|
|
91
|
-
function emptyTaskBoard() {
|
|
92
|
-
return {
|
|
93
|
-
compact: "",
|
|
94
|
-
full: "",
|
|
95
|
-
byStatus: {
|
|
96
|
-
drafting: [],
|
|
97
|
-
processing: [],
|
|
98
|
-
validating: [],
|
|
99
|
-
collaborating: [],
|
|
100
|
-
paused: [],
|
|
101
|
-
blocked: [],
|
|
102
|
-
done: [],
|
|
103
|
-
cancelled: [],
|
|
104
|
-
},
|
|
105
|
-
issues: [],
|
|
106
|
-
actionRequired: [],
|
|
107
|
-
unresolvedDependencies: [],
|
|
108
|
-
activeSessions: [],
|
|
109
|
-
activeBridges: [],
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
function isLiveCodingSessionStatus(status) {
|
|
113
|
-
return status === "spawning"
|
|
114
|
-
|| status === "running"
|
|
115
|
-
|| status === "waiting_input"
|
|
116
|
-
|| status === "stalled";
|
|
117
|
-
}
|
|
118
85
|
function prependTurnSections(message, sections) {
|
|
119
86
|
/* v8 ignore next -- defensive: only user messages with non-empty sections reach here @preserve */
|
|
120
87
|
if (message.role !== "user" || sections.length === 0)
|
|
@@ -136,44 +103,6 @@ function prependTurnSections(message, sections) {
|
|
|
136
103
|
};
|
|
137
104
|
/* v8 ignore stop */
|
|
138
105
|
}
|
|
139
|
-
function readInnerWorkState() {
|
|
140
|
-
const defaultJob = {
|
|
141
|
-
status: "idle",
|
|
142
|
-
content: null,
|
|
143
|
-
origin: null,
|
|
144
|
-
mode: "reflect",
|
|
145
|
-
obligationStatus: null,
|
|
146
|
-
surfacedResult: null,
|
|
147
|
-
queuedAt: null,
|
|
148
|
-
startedAt: null,
|
|
149
|
-
surfacedAt: null,
|
|
150
|
-
};
|
|
151
|
-
try {
|
|
152
|
-
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
153
|
-
const pendingDir = (0, pending_1.getInnerDialogPendingDir)((0, identity_1.getAgentName)());
|
|
154
|
-
const sessionPath = (0, thoughts_1.getInnerDialogSessionPath)(agentRoot);
|
|
155
|
-
const { pendingMessages, turns, runtimeState } = (0, thoughts_1.readInnerDialogRawData)(sessionPath, pendingDir);
|
|
156
|
-
const dialogStatus = (0, thoughts_1.deriveInnerDialogStatus)(pendingMessages, turns, runtimeState);
|
|
157
|
-
const job = (0, thoughts_1.deriveInnerJob)(pendingMessages, turns, runtimeState);
|
|
158
|
-
// Derive obligationPending from both the pending message field and the obligation store
|
|
159
|
-
const storeObligationPending = (0, obligations_1.readPendingObligations)(agentRoot).length > 0;
|
|
160
|
-
return {
|
|
161
|
-
status: dialogStatus.processing === "started" ? "running" : "idle",
|
|
162
|
-
hasPending: dialogStatus.queue !== "clear",
|
|
163
|
-
origin: dialogStatus.origin,
|
|
164
|
-
contentSnippet: dialogStatus.contentSnippet,
|
|
165
|
-
obligationPending: dialogStatus.obligationPending || storeObligationPending,
|
|
166
|
-
job,
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
catch {
|
|
170
|
-
return {
|
|
171
|
-
status: "idle",
|
|
172
|
-
hasPending: false,
|
|
173
|
-
job: defaultJob,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
106
|
// ── Pipeline ──────────────────────────────────────────────────────
|
|
178
107
|
let _lastSessionKey = null;
|
|
179
108
|
async function handleInboundTurn(input) {
|
|
@@ -377,100 +306,29 @@ async function handleInboundTurn(input) {
|
|
|
377
306
|
}
|
|
378
307
|
}
|
|
379
308
|
/* v8 ignore stop */
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
309
|
+
// Build the turn context snapshot — centralizes all state reads
|
|
310
|
+
const ctx = await (0, turn_context_1.buildTurnContext)({
|
|
311
|
+
currentSession,
|
|
312
|
+
channel: input.channel,
|
|
313
|
+
friendStore: input.friendStore,
|
|
384
314
|
});
|
|
315
|
+
// Propagate sync failure from pre-turn pull
|
|
316
|
+
ctx.syncFailure = syncFailure;
|
|
317
|
+
const { activeBridges, sessionActivity, pendingObligations, codingSessions, otherCodingSessions } = ctx;
|
|
385
318
|
const bridgeContext = (0, manager_1.formatBridgeContext)(activeBridges) || undefined;
|
|
386
|
-
let sessionActivity = [];
|
|
387
|
-
try {
|
|
388
|
-
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
389
|
-
sessionActivity = (0, session_activity_1.listSessionActivity)({
|
|
390
|
-
sessionsDir: `${agentRoot}/state/sessions`,
|
|
391
|
-
friendsDir: `${agentRoot}/friends`,
|
|
392
|
-
agentName: (0, identity_1.getAgentName)(),
|
|
393
|
-
currentSession: {
|
|
394
|
-
friendId: currentSession.friendId,
|
|
395
|
-
channel: currentSession.channel,
|
|
396
|
-
key: currentSession.key,
|
|
397
|
-
},
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
catch {
|
|
401
|
-
sessionActivity = [];
|
|
402
|
-
}
|
|
403
|
-
let targetCandidates = [];
|
|
404
|
-
try {
|
|
405
|
-
if (input.channel !== "inner") {
|
|
406
|
-
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
407
|
-
targetCandidates = await (0, target_resolution_1.listTargetSessionCandidates)({
|
|
408
|
-
sessionsDir: `${agentRoot}/state/sessions`,
|
|
409
|
-
friendsDir: `${agentRoot}/friends`,
|
|
410
|
-
agentName: (0, identity_1.getAgentName)(),
|
|
411
|
-
currentSession: {
|
|
412
|
-
friendId: currentSession.friendId,
|
|
413
|
-
channel: currentSession.channel,
|
|
414
|
-
key: currentSession.key,
|
|
415
|
-
},
|
|
416
|
-
friendStore: input.friendStore,
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
catch {
|
|
421
|
-
targetCandidates = [];
|
|
422
|
-
}
|
|
423
|
-
let pendingObligations = [];
|
|
424
|
-
try {
|
|
425
|
-
pendingObligations = (0, obligations_1.readPendingObligations)((0, identity_1.getAgentRoot)());
|
|
426
|
-
}
|
|
427
|
-
catch {
|
|
428
|
-
pendingObligations = [];
|
|
429
|
-
}
|
|
430
|
-
let codingSessions = [];
|
|
431
|
-
let otherCodingSessions = [];
|
|
432
|
-
try {
|
|
433
|
-
const liveCodingSessions = (0, coding_1.getCodingSessionManager)()
|
|
434
|
-
.listSessions()
|
|
435
|
-
.filter((session) => isLiveCodingSessionStatus(session.status) && Boolean(session.originSession));
|
|
436
|
-
codingSessions = liveCodingSessions.filter((session) => session.originSession?.friendId === currentSession.friendId
|
|
437
|
-
&& session.originSession.channel === currentSession.channel
|
|
438
|
-
&& session.originSession.key === currentSession.key);
|
|
439
|
-
otherCodingSessions = liveCodingSessions.filter((session) => !(session.originSession?.friendId === currentSession.friendId
|
|
440
|
-
&& session.originSession.channel === currentSession.channel
|
|
441
|
-
&& session.originSession.key === currentSession.key));
|
|
442
|
-
}
|
|
443
|
-
catch {
|
|
444
|
-
codingSessions = [];
|
|
445
|
-
otherCodingSessions = [];
|
|
446
|
-
}
|
|
447
319
|
const activeWorkFrame = (0, active_work_1.buildActiveWorkFrame)({
|
|
448
320
|
currentSession,
|
|
449
321
|
currentObligation,
|
|
450
322
|
mustResolveBeforeHandoff,
|
|
451
|
-
inner:
|
|
323
|
+
inner: ctx.innerWorkState,
|
|
452
324
|
bridges: activeBridges,
|
|
453
325
|
codingSessions,
|
|
454
326
|
otherCodingSessions,
|
|
455
327
|
pendingObligations,
|
|
456
|
-
taskBoard:
|
|
457
|
-
try {
|
|
458
|
-
return (0, tasks_1.getTaskModule)().getBoard();
|
|
459
|
-
}
|
|
460
|
-
catch {
|
|
461
|
-
return emptyTaskBoard();
|
|
462
|
-
}
|
|
463
|
-
})(),
|
|
328
|
+
taskBoard: ctx.taskBoard,
|
|
464
329
|
friendActivity: sessionActivity,
|
|
465
|
-
targetCandidates,
|
|
466
|
-
innerReturnObligations:
|
|
467
|
-
try {
|
|
468
|
-
return (0, obligations_1.listActiveReturnObligations)((0, identity_1.getAgentName)());
|
|
469
|
-
}
|
|
470
|
-
catch {
|
|
471
|
-
return [];
|
|
472
|
-
}
|
|
473
|
-
})(),
|
|
330
|
+
targetCandidates: ctx.targetCandidates,
|
|
331
|
+
innerReturnObligations: ctx.returnObligations,
|
|
474
332
|
});
|
|
475
333
|
const delegationDecision = (0, delegation_1.decideDelegation)({
|
|
476
334
|
channel: input.channel,
|
|
@@ -501,8 +359,7 @@ async function handleInboundTurn(input) {
|
|
|
501
359
|
try {
|
|
502
360
|
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
503
361
|
const agentName = (0, identity_1.getAgentName)();
|
|
504
|
-
const recentEpisodes
|
|
505
|
-
const activeCares = (0, cares_1.readActiveCares)(agentRoot);
|
|
362
|
+
const { recentEpisodes, activeCares } = ctx;
|
|
506
363
|
const tempoState = (0, tempo_1.deriveTempo)({
|
|
507
364
|
activeSessions: sessionActivity.length + 1,
|
|
508
365
|
openObligations: pendingObligations.length,
|
|
@@ -570,6 +427,12 @@ async function handleInboundTurn(input) {
|
|
|
570
427
|
setMustResolveBeforeHandoff: (value) => {
|
|
571
428
|
mustResolveBeforeHandoff = value;
|
|
572
429
|
},
|
|
430
|
+
// Pre-read state from TurnContext for prompt assembly
|
|
431
|
+
daemonRunning: ctx.daemonRunning,
|
|
432
|
+
senseStatusLines: ctx.senseStatusLines,
|
|
433
|
+
bundleMeta: ctx.bundleMeta,
|
|
434
|
+
daemonHealth: ctx.daemonHealth,
|
|
435
|
+
journalFiles: ctx.journalFiles,
|
|
573
436
|
toolContext: {
|
|
574
437
|
/* v8 ignore next -- default no-op signin satisfies interface; real signin injected by sense adapter @preserve */
|
|
575
438
|
signin: async () => undefined,
|
|
@@ -1,35 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.surfaceToolDef = void 0;
|
|
4
3
|
exports.handleSurface = handleSurface;
|
|
5
4
|
const attention_queue_1 = require("./attention-queue");
|
|
6
5
|
const runtime_1 = require("../nerves/runtime");
|
|
7
|
-
// ── Tool definition ──────────────────────────────────────────────
|
|
8
|
-
exports.surfaceToolDef = {
|
|
9
|
-
type: "function",
|
|
10
|
-
function: {
|
|
11
|
-
name: "surface",
|
|
12
|
-
description: "share a thought outward — deliver an answer, ask a follow-up, or surface progress to whoever needs to hear it. pass delegationId to address a held thought (see your attention queue above), or friendId for spontaneous outreach. does not end your turn.",
|
|
13
|
-
parameters: {
|
|
14
|
-
type: "object",
|
|
15
|
-
properties: {
|
|
16
|
-
content: {
|
|
17
|
-
type: "string",
|
|
18
|
-
description: "the message to deliver",
|
|
19
|
-
},
|
|
20
|
-
delegationId: {
|
|
21
|
-
type: "string",
|
|
22
|
-
description: "ID from your attention queue — addresses a specific held thought",
|
|
23
|
-
},
|
|
24
|
-
friendId: {
|
|
25
|
-
type: "string",
|
|
26
|
-
description: "friend to reach out to spontaneously (when not addressing a held thought)",
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
required: ["content"],
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
6
|
async function handleSurface(input) {
|
|
34
7
|
const { content, delegationId, friendId, queue, routeToFriend, advanceObligation, fulfillHeartObligation } = input;
|
|
35
8
|
// Resolve target friend
|