@ouro.bot/cli 0.1.0-alpha.184 → 0.1.0-alpha.185
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 -3
- package/dist/heart/active-work.js +19 -10
- package/dist/heart/agent-relationships.js +161 -0
- package/dist/heart/cares.js +174 -0
- package/dist/heart/daemon/outlook-read.js +40 -0
- package/dist/heart/intentions.js +168 -0
- package/dist/heart/obligations.js +23 -0
- package/dist/heart/presence.js +185 -0
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/wake-packet.js +226 -0
- package/dist/mind/episodes.js +116 -0
- package/dist/mind/prompt.js +10 -1
- package/dist/repertoire/coding/context-pack.js +25 -2
- package/dist/repertoire/tools-base.js +240 -0
- package/dist/senses/pipeline.js +88 -0
- package/package.json +1 -1
package/dist/mind/prompt.js
CHANGED
|
@@ -39,6 +39,7 @@ exports.bodyMapSection = bodyMapSection;
|
|
|
39
39
|
exports.mcpToolsSection = mcpToolsSection;
|
|
40
40
|
exports.runtimeInfoSection = runtimeInfoSection;
|
|
41
41
|
exports.toolRestrictionSection = toolRestrictionSection;
|
|
42
|
+
exports.wakePacketSection = wakePacketSection;
|
|
42
43
|
exports.centerOfGravitySteeringSection = centerOfGravitySteeringSection;
|
|
43
44
|
exports.commitmentsSection = commitmentsSection;
|
|
44
45
|
exports.delegationHintSection = delegationHintSection;
|
|
@@ -481,10 +482,13 @@ function bridgeContextSection(options) {
|
|
|
481
482
|
return "";
|
|
482
483
|
return bridgeContext.startsWith("## ") ? bridgeContext : `## active bridge work\n${bridgeContext}`;
|
|
483
484
|
}
|
|
485
|
+
function wakePacketSection(options) {
|
|
486
|
+
return options?.wakePacket ?? "";
|
|
487
|
+
}
|
|
484
488
|
function activeWorkSection(options) {
|
|
485
489
|
if (!options?.activeWorkFrame)
|
|
486
490
|
return "";
|
|
487
|
-
return (0, active_work_1.formatActiveWorkFrame)(options.activeWorkFrame);
|
|
491
|
+
return (0, active_work_1.formatActiveWorkFrame)(options.activeWorkFrame, { hasWakePacket: !!options?.wakePacket });
|
|
488
492
|
}
|
|
489
493
|
function liveWorldStateSection(options) {
|
|
490
494
|
if (!options?.activeWorkFrame)
|
|
@@ -506,6 +510,10 @@ function familyCrossSessionTruthSection(context, options) {
|
|
|
506
510
|
return "";
|
|
507
511
|
if (context?.friend?.trustLevel !== "family")
|
|
508
512
|
return "";
|
|
513
|
+
// When wake packet is present, compress to one line
|
|
514
|
+
if (options?.wakePacket) {
|
|
515
|
+
return "When family asks whole-self status, answer from the cross-session picture above.";
|
|
516
|
+
}
|
|
509
517
|
return `## cross-session truth
|
|
510
518
|
When family asks what I'm up to or how things are going, I answer from the live world-state across visible sessions and lanes, not just the current thread.
|
|
511
519
|
When live state conflicts with older transcript history, live state wins.
|
|
@@ -1010,6 +1018,7 @@ async function buildSystem(channel = "cli", options, context) {
|
|
|
1010
1018
|
] : []),
|
|
1011
1019
|
// Group 7: dynamic state for this turn
|
|
1012
1020
|
"# dynamic state for this turn",
|
|
1021
|
+
wakePacketSection(options),
|
|
1013
1022
|
liveWorldStateSection(options),
|
|
1014
1023
|
pendingMessagesSection(options),
|
|
1015
1024
|
activeWorkSection(options),
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.prepareCodingContextPack = prepareCodingContextPack;
|
|
37
|
+
exports.emitCodingEpisode = emitCodingEpisode;
|
|
37
38
|
const crypto = __importStar(require("crypto"));
|
|
38
39
|
const fs = __importStar(require("fs"));
|
|
39
40
|
const path = __importStar(require("path"));
|
|
@@ -41,6 +42,7 @@ const child_process_1 = require("child_process");
|
|
|
41
42
|
const active_work_1 = require("../../heart/active-work");
|
|
42
43
|
const identity_1 = require("../../heart/identity");
|
|
43
44
|
const runtime_1 = require("../../nerves/runtime");
|
|
45
|
+
const episodes_1 = require("../../mind/episodes");
|
|
44
46
|
const skills_1 = require("../skills");
|
|
45
47
|
const CONTEXT_FILENAMES = ["AGENTS.md", "CLAUDE.md"];
|
|
46
48
|
function defaultRunCommand(command, args, cwd) {
|
|
@@ -173,7 +175,7 @@ function buildScopeContent(request, contextFiles, skills, agentName) {
|
|
|
173
175
|
formatSkills(skills),
|
|
174
176
|
].join("\n");
|
|
175
177
|
}
|
|
176
|
-
function buildStateContent(request, contextKey, generatedAt, snapshot, existingSessions, agentName, activeWorkFrame) {
|
|
178
|
+
function buildStateContent(request, contextKey, generatedAt, snapshot, existingSessions, agentName, activeWorkFrame, wakePacket) {
|
|
177
179
|
const gitSection = snapshot.available
|
|
178
180
|
? [
|
|
179
181
|
`repoRoot: ${snapshot.repoRoot ?? "unknown"}`,
|
|
@@ -190,6 +192,7 @@ function buildStateContent(request, contextKey, generatedAt, snapshot, existingS
|
|
|
190
192
|
`agent: ${request.parentAgent ?? agentName}`,
|
|
191
193
|
formatOrigin(request),
|
|
192
194
|
`obligationId: ${request.obligationId ?? "none"}`,
|
|
195
|
+
...(wakePacket ? ["", "## Continuity", wakePacket] : []),
|
|
193
196
|
"",
|
|
194
197
|
"## Workspace Snapshot",
|
|
195
198
|
gitSection,
|
|
@@ -226,7 +229,7 @@ function prepareCodingContextPack(input, deps = {}) {
|
|
|
226
229
|
const snapshot = captureRepoSnapshot(input.request.workdir, runCommand);
|
|
227
230
|
const generatedAt = nowIso();
|
|
228
231
|
const scopeContent = buildScopeContent(input.request, contextFiles, skills, agentName);
|
|
229
|
-
const stateContent = buildStateContent(input.request, contextKey, generatedAt, snapshot, existingSessions, agentName, input.activeWorkFrame);
|
|
232
|
+
const stateContent = buildStateContent(input.request, contextKey, generatedAt, snapshot, existingSessions, agentName, input.activeWorkFrame, input.wakePacket || undefined);
|
|
230
233
|
mkdirSync(contextDir, { recursive: true });
|
|
231
234
|
writeFileSync(scopeFile, `${scopeContent}\n`, "utf-8");
|
|
232
235
|
writeFileSync(stateFile, `${stateContent}\n`, "utf-8");
|
|
@@ -252,3 +255,23 @@ function prepareCodingContextPack(input, deps = {}) {
|
|
|
252
255
|
stateContent,
|
|
253
256
|
};
|
|
254
257
|
}
|
|
258
|
+
/**
|
|
259
|
+
* Emit a coding milestone episode when a session completes or blocks.
|
|
260
|
+
* This is the outbound leg of the coding round-trip: compact wake packet goes IN,
|
|
261
|
+
* episodes come BACK OUT.
|
|
262
|
+
*/
|
|
263
|
+
function emitCodingEpisode(agentRoot, session, outcome) {
|
|
264
|
+
(0, episodes_1.emitEpisode)(agentRoot, {
|
|
265
|
+
kind: "coding_milestone",
|
|
266
|
+
summary: `coding session ${session.id} (${session.runner}): ${outcome}`,
|
|
267
|
+
whyItMattered: `coding lane ${session.status}`,
|
|
268
|
+
relatedEntities: [`coding:${session.id}`],
|
|
269
|
+
salience: session.status === "failed" ? "high" : "medium",
|
|
270
|
+
});
|
|
271
|
+
(0, runtime_1.emitNervesEvent)({
|
|
272
|
+
component: "repertoire",
|
|
273
|
+
event: "repertoire.coding_episode_emitted",
|
|
274
|
+
message: `coding episode emitted for ${session.id}`,
|
|
275
|
+
meta: { sessionId: session.id, outcome, status: session.status },
|
|
276
|
+
});
|
|
277
|
+
}
|
|
@@ -62,6 +62,11 @@ const obligations_1 = require("../mind/obligations");
|
|
|
62
62
|
const progress_story_1 = require("../heart/progress-story");
|
|
63
63
|
const cross_chat_delivery_1 = require("../heart/cross-chat-delivery");
|
|
64
64
|
const obligations_2 = require("../heart/obligations");
|
|
65
|
+
const episodes_1 = require("../mind/episodes");
|
|
66
|
+
const cares_1 = require("../heart/cares");
|
|
67
|
+
const agent_relationships_1 = require("../heart/agent-relationships");
|
|
68
|
+
const presence_1 = require("../heart/presence");
|
|
69
|
+
const intentions_1 = require("../heart/intentions");
|
|
65
70
|
// Tracks which file paths have been read via read_file in this session.
|
|
66
71
|
// edit_file requires a file to be read first (must-read-first guard).
|
|
67
72
|
exports.editFileReadTracker = new Set();
|
|
@@ -1498,6 +1503,241 @@ exports.baseToolDefinitions = [
|
|
|
1498
1503
|
requiredCapability: "reasoning-effort",
|
|
1499
1504
|
summaryKeys: ["level"],
|
|
1500
1505
|
},
|
|
1506
|
+
// ── Continuity tools ──────────────────────────────────────────────
|
|
1507
|
+
{
|
|
1508
|
+
tool: {
|
|
1509
|
+
type: "function",
|
|
1510
|
+
function: {
|
|
1511
|
+
name: "query_episodes",
|
|
1512
|
+
description: "Query recent episodes from my continuity memory. Returns timestamped records of significant events (obligation shifts, coding milestones, bridge events, care events, turning points).",
|
|
1513
|
+
parameters: {
|
|
1514
|
+
type: "object",
|
|
1515
|
+
properties: {
|
|
1516
|
+
limit: { type: "number", description: "Maximum episodes to return (default 20)" },
|
|
1517
|
+
kind: { type: "string", description: "Filter by episode kind: obligation_shift, coding_milestone, bridge_event, care_event, tempo_shift, turning_point" },
|
|
1518
|
+
since: { type: "string", description: "ISO timestamp — only return episodes after this time" },
|
|
1519
|
+
},
|
|
1520
|
+
},
|
|
1521
|
+
},
|
|
1522
|
+
},
|
|
1523
|
+
handler: (a) => {
|
|
1524
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
1525
|
+
const options = {};
|
|
1526
|
+
if (a.limit)
|
|
1527
|
+
options.limit = parseInt(a.limit, 10);
|
|
1528
|
+
if (a.kind)
|
|
1529
|
+
options.kinds = [a.kind];
|
|
1530
|
+
if (a.since)
|
|
1531
|
+
options.since = a.since;
|
|
1532
|
+
const episodes = (0, episodes_1.readRecentEpisodes)(agentRoot, options);
|
|
1533
|
+
(0, runtime_1.emitNervesEvent)({ component: "repertoire", event: "repertoire.query_episodes", message: `queried ${episodes.length} episodes`, meta: { count: episodes.length } });
|
|
1534
|
+
return JSON.stringify(episodes, null, 2);
|
|
1535
|
+
},
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
tool: {
|
|
1539
|
+
type: "function",
|
|
1540
|
+
function: {
|
|
1541
|
+
name: "capture_episode",
|
|
1542
|
+
description: "Record a turning point or significant moment. This is my tool for saying 'that was important — keep it.' Nearly frictionless: only summary and whyItMattered required.",
|
|
1543
|
+
parameters: {
|
|
1544
|
+
type: "object",
|
|
1545
|
+
properties: {
|
|
1546
|
+
summary: { type: "string", description: "What happened" },
|
|
1547
|
+
whyItMattered: { type: "string", description: "Why this was significant" },
|
|
1548
|
+
kind: { type: "string", description: "Episode kind (default: turning_point)" },
|
|
1549
|
+
salience: { type: "string", description: "low, medium, high, or critical (default: medium)" },
|
|
1550
|
+
},
|
|
1551
|
+
required: ["summary", "whyItMattered"],
|
|
1552
|
+
},
|
|
1553
|
+
},
|
|
1554
|
+
},
|
|
1555
|
+
handler: (a) => {
|
|
1556
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
1557
|
+
const episode = (0, episodes_1.emitEpisode)(agentRoot, {
|
|
1558
|
+
kind: a.kind ?? "turning_point",
|
|
1559
|
+
summary: a.summary,
|
|
1560
|
+
whyItMattered: a.whyItMattered,
|
|
1561
|
+
relatedEntities: [],
|
|
1562
|
+
salience: a.salience ?? "medium",
|
|
1563
|
+
});
|
|
1564
|
+
(0, runtime_1.emitNervesEvent)({ component: "repertoire", event: "repertoire.capture_episode", message: `captured episode ${episode.id}`, meta: { id: episode.id } });
|
|
1565
|
+
return JSON.stringify(episode, null, 2);
|
|
1566
|
+
},
|
|
1567
|
+
},
|
|
1568
|
+
{
|
|
1569
|
+
tool: {
|
|
1570
|
+
type: "function",
|
|
1571
|
+
function: {
|
|
1572
|
+
name: "query_presence",
|
|
1573
|
+
description: "Check who's around — my own availability/lane and known peer agents.",
|
|
1574
|
+
parameters: { type: "object", properties: {} },
|
|
1575
|
+
},
|
|
1576
|
+
},
|
|
1577
|
+
handler: () => {
|
|
1578
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
1579
|
+
const agentName = (0, identity_1.getAgentName)();
|
|
1580
|
+
const self = (0, presence_1.readPresence)(agentRoot, agentName);
|
|
1581
|
+
const peers = (0, presence_1.readPeerPresence)(agentRoot);
|
|
1582
|
+
(0, runtime_1.emitNervesEvent)({ component: "repertoire", event: "repertoire.query_presence", message: `presence: self + ${peers.length} peers`, meta: { peerCount: peers.length } });
|
|
1583
|
+
return JSON.stringify({ self, peers }, null, 2);
|
|
1584
|
+
},
|
|
1585
|
+
},
|
|
1586
|
+
{
|
|
1587
|
+
tool: {
|
|
1588
|
+
type: "function",
|
|
1589
|
+
function: {
|
|
1590
|
+
name: "query_cares",
|
|
1591
|
+
description: "Query things I care about — ongoing concerns, watched situations, projects, people.",
|
|
1592
|
+
parameters: {
|
|
1593
|
+
type: "object",
|
|
1594
|
+
properties: {
|
|
1595
|
+
status: { type: "string", description: "Filter by status: 'active', 'watching', 'resolved', 'dormant', or 'all' (default: active cares only)" },
|
|
1596
|
+
},
|
|
1597
|
+
},
|
|
1598
|
+
},
|
|
1599
|
+
},
|
|
1600
|
+
handler: (a) => {
|
|
1601
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
1602
|
+
const cares = a.status === "all" ? (0, cares_1.readCares)(agentRoot) : (0, cares_1.readActiveCares)(agentRoot);
|
|
1603
|
+
(0, runtime_1.emitNervesEvent)({ component: "repertoire", event: "repertoire.query_cares", message: `queried ${cares.length} cares`, meta: { count: cares.length } });
|
|
1604
|
+
return JSON.stringify(cares, null, 2);
|
|
1605
|
+
},
|
|
1606
|
+
},
|
|
1607
|
+
{
|
|
1608
|
+
tool: {
|
|
1609
|
+
type: "function",
|
|
1610
|
+
function: {
|
|
1611
|
+
name: "care_manage",
|
|
1612
|
+
description: "Create, update, or resolve a care. Cares are things I watch over — people, projects, missions, system health.",
|
|
1613
|
+
parameters: {
|
|
1614
|
+
type: "object",
|
|
1615
|
+
properties: {
|
|
1616
|
+
action: { type: "string", enum: ["create", "update", "resolve"], description: "What to do" },
|
|
1617
|
+
id: { type: "string", description: "Care ID (required for update/resolve)" },
|
|
1618
|
+
label: { type: "string", description: "Short label for the care" },
|
|
1619
|
+
why: { type: "string", description: "Why this matters" },
|
|
1620
|
+
salience: { type: "string", description: "low, medium, high, or critical" },
|
|
1621
|
+
kind: { type: "string", description: "person, agent, project, mission, or system" },
|
|
1622
|
+
stewardship: { type: "string", description: "mine, shared, or delegated" },
|
|
1623
|
+
},
|
|
1624
|
+
required: ["action"],
|
|
1625
|
+
},
|
|
1626
|
+
},
|
|
1627
|
+
},
|
|
1628
|
+
handler: (a) => {
|
|
1629
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
1630
|
+
let result;
|
|
1631
|
+
if (a.action === "create") {
|
|
1632
|
+
result = (0, cares_1.createCare)(agentRoot, {
|
|
1633
|
+
label: a.label ?? "untitled",
|
|
1634
|
+
why: a.why ?? "",
|
|
1635
|
+
kind: a.kind ?? "project",
|
|
1636
|
+
status: "active",
|
|
1637
|
+
salience: a.salience ?? "medium",
|
|
1638
|
+
steward: a.stewardship ?? "mine",
|
|
1639
|
+
relatedFriendIds: [],
|
|
1640
|
+
relatedAgentIds: [],
|
|
1641
|
+
relatedObligationIds: [],
|
|
1642
|
+
relatedEpisodeIds: [],
|
|
1643
|
+
currentRisk: null,
|
|
1644
|
+
nextCheckAt: null,
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
else if (a.action === "update") {
|
|
1648
|
+
const updates = {};
|
|
1649
|
+
if (a.label)
|
|
1650
|
+
updates.label = a.label;
|
|
1651
|
+
if (a.why)
|
|
1652
|
+
updates.why = a.why;
|
|
1653
|
+
if (a.salience)
|
|
1654
|
+
updates.salience = a.salience;
|
|
1655
|
+
result = (0, cares_1.updateCare)(agentRoot, a.id, updates);
|
|
1656
|
+
}
|
|
1657
|
+
else if (a.action === "resolve") {
|
|
1658
|
+
result = (0, cares_1.resolveCare)(agentRoot, a.id);
|
|
1659
|
+
}
|
|
1660
|
+
(0, runtime_1.emitNervesEvent)({ component: "repertoire", event: "repertoire.care_manage", message: `care ${a.action}`, meta: { action: a.action, id: a.id } });
|
|
1661
|
+
return JSON.stringify(result, null, 2);
|
|
1662
|
+
},
|
|
1663
|
+
},
|
|
1664
|
+
{
|
|
1665
|
+
tool: {
|
|
1666
|
+
type: "function",
|
|
1667
|
+
function: {
|
|
1668
|
+
name: "query_relationships",
|
|
1669
|
+
description: "Query known agent relationships — familiarity, trust, shared missions, interaction history.",
|
|
1670
|
+
parameters: {
|
|
1671
|
+
type: "object",
|
|
1672
|
+
properties: {
|
|
1673
|
+
agentName: { type: "string", description: "Specific agent name to query (omit for all)" },
|
|
1674
|
+
},
|
|
1675
|
+
},
|
|
1676
|
+
},
|
|
1677
|
+
},
|
|
1678
|
+
handler: (a) => {
|
|
1679
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
1680
|
+
const result = a.agentName
|
|
1681
|
+
? (0, agent_relationships_1.readRelationship)(agentRoot, a.agentName)
|
|
1682
|
+
: (0, agent_relationships_1.readRelationships)(agentRoot);
|
|
1683
|
+
(0, runtime_1.emitNervesEvent)({ component: "repertoire", event: "repertoire.query_relationships", message: `queried relationships`, meta: { agentName: a.agentName ?? "all" } });
|
|
1684
|
+
return JSON.stringify(result, null, 2);
|
|
1685
|
+
},
|
|
1686
|
+
},
|
|
1687
|
+
{
|
|
1688
|
+
tool: {
|
|
1689
|
+
type: "function",
|
|
1690
|
+
function: {
|
|
1691
|
+
name: "intention_capture",
|
|
1692
|
+
description: "File a lightweight mental note — something I want to do or check later, below the ceremony threshold of tasks or cares. Cheap to create, easy to close.",
|
|
1693
|
+
parameters: {
|
|
1694
|
+
type: "object",
|
|
1695
|
+
properties: {
|
|
1696
|
+
content: { type: "string", description: "What I want to remember to do" },
|
|
1697
|
+
salience: { type: "string", description: "low, medium, or high (default: low)" },
|
|
1698
|
+
nudgeAfter: { type: "string", description: "ISO timestamp — nudge me after this time" },
|
|
1699
|
+
},
|
|
1700
|
+
required: ["content"],
|
|
1701
|
+
},
|
|
1702
|
+
},
|
|
1703
|
+
},
|
|
1704
|
+
handler: (a) => {
|
|
1705
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
1706
|
+
const intention = (0, intentions_1.captureIntention)(agentRoot, {
|
|
1707
|
+
content: a.content,
|
|
1708
|
+
salience: a.salience ?? "low",
|
|
1709
|
+
source: "tool",
|
|
1710
|
+
...(a.nudgeAfter ? { nudgeAfter: a.nudgeAfter } : {}),
|
|
1711
|
+
});
|
|
1712
|
+
(0, runtime_1.emitNervesEvent)({ component: "repertoire", event: "repertoire.intention_capture", message: `captured intention ${intention.id}`, meta: { id: intention.id } });
|
|
1713
|
+
return JSON.stringify(intention, null, 2);
|
|
1714
|
+
},
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
tool: {
|
|
1718
|
+
type: "function",
|
|
1719
|
+
function: {
|
|
1720
|
+
name: "intention_manage",
|
|
1721
|
+
description: "Resolve or dismiss an intention. Resolve = done. Dismiss = no longer relevant. Both remove it from active list.",
|
|
1722
|
+
parameters: {
|
|
1723
|
+
type: "object",
|
|
1724
|
+
properties: {
|
|
1725
|
+
action: { type: "string", enum: ["resolve", "dismiss"], description: "What to do" },
|
|
1726
|
+
id: { type: "string", description: "Intention ID" },
|
|
1727
|
+
},
|
|
1728
|
+
required: ["action", "id"],
|
|
1729
|
+
},
|
|
1730
|
+
},
|
|
1731
|
+
},
|
|
1732
|
+
handler: (a) => {
|
|
1733
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
1734
|
+
const result = a.action === "resolve"
|
|
1735
|
+
? (0, intentions_1.resolveIntention)(agentRoot, a.id)
|
|
1736
|
+
: (0, intentions_1.dismissIntention)(agentRoot, a.id);
|
|
1737
|
+
(0, runtime_1.emitNervesEvent)({ component: "repertoire", event: "repertoire.intention_manage", message: `intention ${a.action}: ${a.id}`, meta: { action: a.action, id: a.id } });
|
|
1738
|
+
return JSON.stringify(result, null, 2);
|
|
1739
|
+
},
|
|
1740
|
+
},
|
|
1501
1741
|
...tools_1.codingToolDefinitions,
|
|
1502
1742
|
];
|
|
1503
1743
|
exports.tools = exports.baseToolDefinitions.map((d) => d.tool);
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -38,6 +38,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
};
|
|
39
39
|
})();
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.emitObligationTransitionEpisodes = emitObligationTransitionEpisodes;
|
|
41
42
|
exports.handleInboundTurn = handleInboundTurn;
|
|
42
43
|
const runtime_1 = require("../nerves/runtime");
|
|
43
44
|
const commands_1 = require("./commands");
|
|
@@ -58,6 +59,32 @@ const obligations_2 = require("../mind/obligations");
|
|
|
58
59
|
const provider_failover_1 = require("../heart/provider-failover");
|
|
59
60
|
const provider_ping_1 = require("../heart/provider-ping");
|
|
60
61
|
const auth_flow_1 = require("../heart/daemon/auth-flow");
|
|
62
|
+
const tempo_1 = require("../heart/tempo");
|
|
63
|
+
const temporal_view_1 = require("../heart/temporal-view");
|
|
64
|
+
const wake_packet_1 = require("../heart/wake-packet");
|
|
65
|
+
const presence_1 = require("../heart/presence");
|
|
66
|
+
const episodes_1 = require("../mind/episodes");
|
|
67
|
+
const cares_1 = require("../heart/cares");
|
|
68
|
+
/**
|
|
69
|
+
* Emit episodes for obligation state transitions detected during a turn.
|
|
70
|
+
* Exported for direct testability (avoids v8 coverage merge issues in multi-file test suites).
|
|
71
|
+
*/
|
|
72
|
+
function emitObligationTransitionEpisodes(agentRoot, preTurnObligationIds, postTurnObligations, preTurnObligations) {
|
|
73
|
+
const postTurnObligationIds = new Set(postTurnObligations.map((ob) => `${ob.id}:${ob.status}`));
|
|
74
|
+
for (const key of preTurnObligationIds) {
|
|
75
|
+
if (!postTurnObligationIds.has(key)) {
|
|
76
|
+
const [obId] = key.split(":");
|
|
77
|
+
const matchedOb = postTurnObligations.find((ob) => ob.id === obId) ?? preTurnObligations.find((ob) => ob.id === obId);
|
|
78
|
+
(0, episodes_1.emitEpisode)(agentRoot, {
|
|
79
|
+
kind: "obligation_shift",
|
|
80
|
+
summary: `obligation "${matchedOb?.content ?? obId}" status changed`,
|
|
81
|
+
whyItMattered: "obligation state transition detected during turn",
|
|
82
|
+
relatedEntities: [`obligation:${obId}`],
|
|
83
|
+
salience: "medium",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
61
88
|
function emptyTaskBoard() {
|
|
62
89
|
return {
|
|
63
90
|
compact: "",
|
|
@@ -430,6 +457,57 @@ async function handleInboundTurn(input) {
|
|
|
430
457
|
for (const msg of input.messages) {
|
|
431
458
|
sessionMessages.push(msg);
|
|
432
459
|
}
|
|
460
|
+
// Step 4b: Continuity pipeline — derive tempo, build wake packet, snapshot obligations
|
|
461
|
+
let renderedWakePacket;
|
|
462
|
+
const preTurnObligationIds = new Set(pendingObligations.map((ob) => `${ob.id}:${ob.status}`));
|
|
463
|
+
try {
|
|
464
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
465
|
+
const agentName = (0, identity_1.getAgentName)();
|
|
466
|
+
const recentEpisodes = (0, episodes_1.readRecentEpisodes)(agentRoot, { limit: 20 });
|
|
467
|
+
const activeCares = (0, cares_1.readActiveCares)(agentRoot);
|
|
468
|
+
const tempoState = (0, tempo_1.deriveTempo)({
|
|
469
|
+
activeSessions: sessionActivity.length + 1,
|
|
470
|
+
openObligations: pendingObligations.length,
|
|
471
|
+
recentEpisodeCount: recentEpisodes.length,
|
|
472
|
+
lastActivityAgeMs: sessionActivity.length > 0
|
|
473
|
+
? Date.now() - new Date(sessionActivity[0].lastActivityAt).getTime()
|
|
474
|
+
: 0,
|
|
475
|
+
hasBlockers: false, // obligations use specific statuses, not "blocked"
|
|
476
|
+
highSalienceEpisodes: recentEpisodes.filter((ep) => ep.salience === "high" || ep.salience === "critical").length,
|
|
477
|
+
activeCareCount: activeCares.length,
|
|
478
|
+
atRiskCareCount: activeCares.filter((c) => c.currentRisk != null).length,
|
|
479
|
+
});
|
|
480
|
+
const temporalView = (0, temporal_view_1.buildTemporalView)(agentRoot, {
|
|
481
|
+
tempo: tempoState.mode,
|
|
482
|
+
preloaded: {
|
|
483
|
+
recentEpisodes,
|
|
484
|
+
activeObligations: pendingObligations,
|
|
485
|
+
activeCares,
|
|
486
|
+
},
|
|
487
|
+
});
|
|
488
|
+
const wakePacket = (0, wake_packet_1.buildWakePacket)(temporalView);
|
|
489
|
+
renderedWakePacket = (0, wake_packet_1.renderWakePacket)(wakePacket);
|
|
490
|
+
if (!renderedWakePacket)
|
|
491
|
+
renderedWakePacket = undefined;
|
|
492
|
+
// Update self-presence
|
|
493
|
+
const presence = (0, presence_1.derivePresence)(agentRoot, agentName, {
|
|
494
|
+
activeSessions: sessionActivity.length + 1,
|
|
495
|
+
openObligations: pendingObligations.length,
|
|
496
|
+
activeBridges: activeBridges.length,
|
|
497
|
+
codingLanes: codingSessions.length,
|
|
498
|
+
currentTempo: tempoState.mode,
|
|
499
|
+
});
|
|
500
|
+
(0, presence_1.writePresence)(agentRoot, agentName, presence);
|
|
501
|
+
}
|
|
502
|
+
catch (continuityError) {
|
|
503
|
+
(0, runtime_1.emitNervesEvent)({
|
|
504
|
+
level: "warn",
|
|
505
|
+
component: "senses",
|
|
506
|
+
event: "senses.continuity_error",
|
|
507
|
+
message: "continuity pipeline failed, continuing without wake packet",
|
|
508
|
+
meta: { error: continuityError instanceof Error ? continuityError.message : String(continuityError) },
|
|
509
|
+
});
|
|
510
|
+
}
|
|
433
511
|
// Step 5: runAgent
|
|
434
512
|
const existingToolContext = input.runAgentOptions?.toolContext;
|
|
435
513
|
const runAgentOptions = {
|
|
@@ -437,6 +515,7 @@ async function handleInboundTurn(input) {
|
|
|
437
515
|
bridgeContext,
|
|
438
516
|
activeWorkFrame,
|
|
439
517
|
delegationDecision,
|
|
518
|
+
wakePacket: renderedWakePacket,
|
|
440
519
|
pendingMessages: pending.length > 0 ? pending.map((msg) => ({ from: msg.from, content: msg.content })) : undefined,
|
|
441
520
|
currentSessionKey: currentSession.key,
|
|
442
521
|
currentObligation,
|
|
@@ -501,6 +580,15 @@ async function handleInboundTurn(input) {
|
|
|
501
580
|
}
|
|
502
581
|
/* v8 ignore stop */
|
|
503
582
|
}
|
|
583
|
+
// Step 5c: Emit episodes for obligation state transitions
|
|
584
|
+
try {
|
|
585
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
586
|
+
const postTurnObligations = (0, obligations_1.readPendingObligations)(agentRoot);
|
|
587
|
+
emitObligationTransitionEpisodes(agentRoot, preTurnObligationIds, postTurnObligations, pendingObligations);
|
|
588
|
+
}
|
|
589
|
+
catch {
|
|
590
|
+
// Episode emission is non-fatal
|
|
591
|
+
}
|
|
504
592
|
// Step 6: postTurn
|
|
505
593
|
const continuingState = {
|
|
506
594
|
...(mustResolveBeforeHandoff ? { mustResolveBeforeHandoff: true } : {}),
|