@ouro.bot/cli 0.1.0-alpha.108 → 0.1.0-alpha.109
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 +7 -0
- package/dist/heart/active-work.js +71 -4
- package/dist/mind/prompt.js +3 -1
- package/dist/senses/pipeline.js +24 -23
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
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.109",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Each inbound turn now carries a fresh live world-state checkpoint, so natural questions like 'what are you up to?' anchor on current sessions, obligations, coding lanes, and next actions instead of stale transcript history.",
|
|
8
|
+
"Active-work now serves as the agent's top-level center of gravity: material obligations are normalized, duplicate-origin noise is collapsed, and inner dialog is treated as one lane inside the live world-state instead of the whole self."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
4
11
|
{
|
|
5
12
|
"version": "0.1.0-alpha.108",
|
|
6
13
|
"changes": [
|
|
@@ -4,11 +4,13 @@ exports.formatOtherActiveSessionSummaries = formatOtherActiveSessionSummaries;
|
|
|
4
4
|
exports.suggestBridgeForActiveWork = suggestBridgeForActiveWork;
|
|
5
5
|
exports.buildActiveWorkFrame = buildActiveWorkFrame;
|
|
6
6
|
exports.formatActiveWorkFrame = formatActiveWorkFrame;
|
|
7
|
+
exports.formatLiveWorldStateCheckpoint = formatLiveWorldStateCheckpoint;
|
|
7
8
|
const runtime_1 = require("../nerves/runtime");
|
|
8
9
|
const state_machine_1 = require("./bridges/state-machine");
|
|
9
10
|
const obligations_1 = require("./obligations");
|
|
10
11
|
const target_resolution_1 = require("./target-resolution");
|
|
11
12
|
const config_1 = require("./config");
|
|
13
|
+
const RECENT_ACTIVE_OBLIGATION_WINDOW_MS = 60 * 60 * 1000;
|
|
12
14
|
function activityPriority(source) {
|
|
13
15
|
return source === "friend-facing" ? 0 : 1;
|
|
14
16
|
}
|
|
@@ -51,6 +53,49 @@ function describeCodingSessionScope(session, currentSession) {
|
|
|
51
53
|
function activeObligationCount(obligations) {
|
|
52
54
|
return (obligations ?? []).filter((ob) => (0, obligations_1.isOpenObligationStatus)(ob.status)).length;
|
|
53
55
|
}
|
|
56
|
+
function obligationOriginKey(obligation) {
|
|
57
|
+
return `${obligation.origin.friendId}/${obligation.origin.channel}/${(0, config_1.sanitizeKey)(obligation.origin.key)}`;
|
|
58
|
+
}
|
|
59
|
+
function buildLiveCodingLabelSet(codingSessions, otherCodingSessions) {
|
|
60
|
+
return new Set([
|
|
61
|
+
...codingSessions.map(formatCodingLaneLabel),
|
|
62
|
+
...otherCodingSessions.map(formatCodingLaneLabel),
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
function isMaterialActiveObligation(obligation, liveCodingLabels, nowMs) {
|
|
66
|
+
if (obligation.currentArtifact?.trim())
|
|
67
|
+
return true;
|
|
68
|
+
if (obligation.status === "waiting_for_merge" || obligation.status === "updating_runtime")
|
|
69
|
+
return true;
|
|
70
|
+
const surface = obligation.currentSurface;
|
|
71
|
+
if (surface?.kind === "merge" || surface?.kind === "runtime")
|
|
72
|
+
return true;
|
|
73
|
+
const recentlyTouched = (nowMs - obligationTimestampMs(obligation)) <= RECENT_ACTIVE_OBLIGATION_WINDOW_MS;
|
|
74
|
+
if (surface?.kind === "coding") {
|
|
75
|
+
const liveLabel = surface.label.trim();
|
|
76
|
+
return (liveLabel.length > 0 && liveCodingLabels.has(liveLabel)) || recentlyTouched;
|
|
77
|
+
}
|
|
78
|
+
return recentlyTouched;
|
|
79
|
+
}
|
|
80
|
+
function normalizePendingObligations(obligations, codingSessions, otherCodingSessions) {
|
|
81
|
+
const openObligations = (obligations ?? []).filter((obligation) => (0, obligations_1.isOpenObligationStatus)(obligation.status));
|
|
82
|
+
if (openObligations.length === 0)
|
|
83
|
+
return [];
|
|
84
|
+
const liveCodingLabels = buildLiveCodingLabelSet(codingSessions, otherCodingSessions);
|
|
85
|
+
const nowMs = Date.now();
|
|
86
|
+
const normalized = [];
|
|
87
|
+
const seenOrigins = new Set();
|
|
88
|
+
for (const obligation of [...openObligations].sort(newestObligationFirst)) {
|
|
89
|
+
if (!isMaterialActiveObligation(obligation, liveCodingLabels, nowMs))
|
|
90
|
+
continue;
|
|
91
|
+
const originKey = obligationOriginKey(obligation);
|
|
92
|
+
if (seenOrigins.has(originKey))
|
|
93
|
+
continue;
|
|
94
|
+
seenOrigins.add(originKey);
|
|
95
|
+
normalized.push(obligation);
|
|
96
|
+
}
|
|
97
|
+
return normalized;
|
|
98
|
+
}
|
|
54
99
|
function formatObligationSurface(obligation) {
|
|
55
100
|
if (!obligation.currentSurface?.label)
|
|
56
101
|
return "";
|
|
@@ -175,7 +220,8 @@ function codingSessionTimestampMs(session) {
|
|
|
175
220
|
return Date.parse(session.lastActivityAt ?? session.startedAt);
|
|
176
221
|
}
|
|
177
222
|
function obligationTimestampMs(obligation) {
|
|
178
|
-
|
|
223
|
+
const value = Date.parse(obligation.updatedAt ?? obligation.createdAt);
|
|
224
|
+
return Number.isFinite(value) ? value : 0;
|
|
179
225
|
}
|
|
180
226
|
function newestObligationFirst(left, right) {
|
|
181
227
|
return obligationTimestampMs(right) - obligationTimestampMs(left);
|
|
@@ -348,11 +394,11 @@ function buildActiveWorkFrame(input) {
|
|
|
348
394
|
: [];
|
|
349
395
|
const liveTaskNames = summarizeLiveTasks(input.taskBoard);
|
|
350
396
|
const activeBridgePresent = input.bridges.some(isActiveBridge);
|
|
351
|
-
const openObligations = activeObligationCount(input.pendingObligations);
|
|
352
397
|
const liveCodingSessions = input.codingSessions ?? [];
|
|
353
398
|
const allOtherLiveSessions = [...input.friendActivity].sort(compareActivity);
|
|
354
399
|
const otherCodingSessions = input.otherCodingSessions ?? [];
|
|
355
|
-
const pendingObligations = input.pendingObligations
|
|
400
|
+
const pendingObligations = normalizePendingObligations(input.pendingObligations, liveCodingSessions, otherCodingSessions);
|
|
401
|
+
const openObligations = activeObligationCount(pendingObligations);
|
|
356
402
|
const centerOfGravity = activeBridgePresent
|
|
357
403
|
? "shared-work"
|
|
358
404
|
: (input.inner.status === "running" || input.inner.hasPending || input.mustResolveBeforeHandoff || openObligations > 0 || liveCodingSessions.length > 0)
|
|
@@ -384,7 +430,7 @@ function buildActiveWorkFrame(input) {
|
|
|
384
430
|
currentObligation: input.currentObligation,
|
|
385
431
|
mustResolveBeforeHandoff: input.mustResolveBeforeHandoff,
|
|
386
432
|
bridges: input.bridges,
|
|
387
|
-
pendingObligations
|
|
433
|
+
pendingObligations,
|
|
388
434
|
taskBoard: input.taskBoard,
|
|
389
435
|
targetCandidates: input.targetCandidates,
|
|
390
436
|
}),
|
|
@@ -411,6 +457,7 @@ function buildActiveWorkFrame(input) {
|
|
|
411
457
|
function formatActiveWorkFrame(frame) {
|
|
412
458
|
const lines = ["## what i'm holding"];
|
|
413
459
|
lines.push("this is my top-level live world-state right now. inner work, coding lanes, other sessions, and return obligations all belong inside this picture.");
|
|
460
|
+
lines.push("if older checkpoints elsewhere in the transcript disagree with this picture, this picture wins.");
|
|
414
461
|
const primaryObligation = findPrimaryOpenObligation(frame);
|
|
415
462
|
const currentSessionObligation = findCurrentSessionOpenObligation(frame);
|
|
416
463
|
const activeLane = formatActiveLane(frame, primaryObligation);
|
|
@@ -538,3 +585,23 @@ function formatActiveWorkFrame(frame) {
|
|
|
538
585
|
}
|
|
539
586
|
return lines.join("\n");
|
|
540
587
|
}
|
|
588
|
+
function formatLiveWorldStateCheckpoint(frame) {
|
|
589
|
+
const primaryObligation = findPrimaryOpenObligation(frame);
|
|
590
|
+
const activeLane = formatActiveLane(frame, primaryObligation) ?? "no explicit live lane";
|
|
591
|
+
const currentArtifact = formatCurrentArtifact(frame, primaryObligation) ?? "no artifact yet";
|
|
592
|
+
const nextAction = formatNextAction(frame, primaryObligation) ?? "continue from the live world-state";
|
|
593
|
+
const otherActiveSessions = formatOtherActiveSessionSummaries(frame);
|
|
594
|
+
const lines = [
|
|
595
|
+
"## live world-state checkpoint",
|
|
596
|
+
"this is the freshest reality for this turn. if older transcript history disagrees, treat it as stale.",
|
|
597
|
+
`- live conversation: ${frame.currentSession ? formatSessionLabel(frame.currentSession) : "not in a live conversation"}`,
|
|
598
|
+
`- active lane: ${activeLane}`,
|
|
599
|
+
`- current artifact: ${currentArtifact}`,
|
|
600
|
+
`- next action: ${nextAction}`,
|
|
601
|
+
];
|
|
602
|
+
if (otherActiveSessions.length > 0) {
|
|
603
|
+
lines.push("other active sessions:");
|
|
604
|
+
lines.push(...otherActiveSessions);
|
|
605
|
+
}
|
|
606
|
+
return lines.join("\n");
|
|
607
|
+
}
|
package/dist/mind/prompt.js
CHANGED
|
@@ -467,6 +467,8 @@ if a family member asks what i'm up to or how things are going, that includes th
|
|
|
467
467
|
i answer naturally from the live world-state in this prompt.
|
|
468
468
|
i treat the active-work section above as my reliable top-level surface for this.
|
|
469
469
|
i do not claim i lack a top-level view when that surface is already present.
|
|
470
|
+
i treat older checkpoints elsewhere in this transcript as stale history when they conflict with the active-work surface above.
|
|
471
|
+
i do not repeat an old coding lane or old checkpoint as current just because it appeared earlier in the thread.
|
|
470
472
|
i only reach for query_active_work when i want a fresh read of that same surface.
|
|
471
473
|
i do not rebuild whole-self status from scratch with query_session and coding_status unless i need to verify a specific gap.
|
|
472
474
|
i do not rely on canned status-question modes or phrase matching.
|
|
@@ -490,7 +492,7 @@ function centerOfGravitySteeringSection(channel, options, context) {
|
|
|
490
492
|
const statusObligation = (0, obligation_steering_1.findStatusObligation)(frame);
|
|
491
493
|
const genericConcreteStatus = (0, obligation_steering_1.renderConcreteStatusGuidance)(frame, statusObligation);
|
|
492
494
|
const liveWorldClause = context?.friend?.trustLevel === "family"
|
|
493
|
-
? "\nmy center of gravity lives in the active-work world-state above. inner work is one lane inside it, not the whole picture."
|
|
495
|
+
? "\nmy center of gravity lives in the active-work world-state above. inner work is one lane inside it, not the whole picture.\nwhen that world-state conflicts with older transcript history, the world-state wins."
|
|
494
496
|
: "";
|
|
495
497
|
if (cog === "local-turn") {
|
|
496
498
|
return genericConcreteStatus || (0, obligation_steering_1.renderLiveThreadStatusShape)(frame);
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -44,6 +44,24 @@ function isLiveCodingSessionStatus(status) {
|
|
|
44
44
|
|| status === "waiting_input"
|
|
45
45
|
|| status === "stalled";
|
|
46
46
|
}
|
|
47
|
+
function prependTurnSections(message, sections) {
|
|
48
|
+
if (message.role !== "user" || sections.length === 0)
|
|
49
|
+
return message;
|
|
50
|
+
const prefix = sections.join("\n\n");
|
|
51
|
+
if (typeof message.content === "string") {
|
|
52
|
+
return {
|
|
53
|
+
...message,
|
|
54
|
+
content: `${prefix}\n\n${message.content}`,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
...message,
|
|
59
|
+
content: [
|
|
60
|
+
{ type: "text", text: `${prefix}\n\n` },
|
|
61
|
+
...message.content,
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
47
65
|
function readInnerWorkState() {
|
|
48
66
|
const defaultJob = {
|
|
49
67
|
status: "idle",
|
|
@@ -242,33 +260,16 @@ async function handleInboundTurn(input) {
|
|
|
242
260
|
: (input.drainDeferredReturns?.(resolvedContext.friend.id) ?? []);
|
|
243
261
|
const sessionPending = input.drainPending(input.pendingDir);
|
|
244
262
|
const pending = [...deferredReturns, ...sessionPending];
|
|
245
|
-
// Assemble messages: session messages +
|
|
263
|
+
// Assemble messages: session messages + live world-state checkpoint + pending + inbound user messages
|
|
264
|
+
const prefixSections = [(0, active_work_1.formatLiveWorldStateCheckpoint)(activeWorkFrame)];
|
|
246
265
|
if (pending.length > 0) {
|
|
247
|
-
// Format pending messages and prepend to the user content
|
|
248
266
|
const pendingSection = pending
|
|
249
267
|
.map((msg) => `[pending from ${msg.from}]: ${msg.content}`)
|
|
250
268
|
.join("\n");
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
if (typeof firstMsg.content === "string") {
|
|
256
|
-
input.messages[0] = {
|
|
257
|
-
...firstMsg,
|
|
258
|
-
content: `## pending messages\n${pendingSection}\n\n${firstMsg.content}`,
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
input.messages[0] = {
|
|
263
|
-
...firstMsg,
|
|
264
|
-
content: [
|
|
265
|
-
{ type: "text", text: `## pending messages\n${pendingSection}\n\n` },
|
|
266
|
-
...firstMsg.content,
|
|
267
|
-
],
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
269
|
+
prefixSections.push(`## pending messages\n${pendingSection}`);
|
|
270
|
+
}
|
|
271
|
+
if (input.messages.length > 0) {
|
|
272
|
+
input.messages[0] = prependTurnSections(input.messages[0], prefixSections);
|
|
272
273
|
}
|
|
273
274
|
// Append user messages from the inbound turn
|
|
274
275
|
for (const msg of input.messages) {
|