@ouro.bot/cli 0.1.0-alpha.105 → 0.1.0-alpha.106
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 +160 -31
- package/dist/heart/commitments.js +0 -4
- package/dist/mind/obligation-steering.js +9 -114
- package/dist/mind/prompt.js +12 -0
- package/dist/senses/pipeline.js +0 -24
- 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.106",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Family-scoped status answers now come from the live obligation/session world-state directly instead of a regex-triggered 'status question' mode, so agents can answer naturally while still seeing all material live work across sessions.",
|
|
8
|
+
"Raw inbound text no longer masquerades as a real commitment or next action; current lanes, artifacts, and next steps are now grounded in persistent obligations, live coding state, and concrete session activity."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
4
11
|
{
|
|
5
12
|
"version": "0.1.0-alpha.105",
|
|
6
13
|
"changes": [
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatOtherActiveSessionSummaries = formatOtherActiveSessionSummaries;
|
|
3
4
|
exports.suggestBridgeForActiveWork = suggestBridgeForActiveWork;
|
|
4
5
|
exports.buildActiveWorkFrame = buildActiveWorkFrame;
|
|
5
6
|
exports.formatActiveWorkFrame = formatActiveWorkFrame;
|
|
@@ -7,6 +8,7 @@ const runtime_1 = require("../nerves/runtime");
|
|
|
7
8
|
const state_machine_1 = require("./bridges/state-machine");
|
|
8
9
|
const obligations_1 = require("./obligations");
|
|
9
10
|
const target_resolution_1 = require("./target-resolution");
|
|
11
|
+
const config_1 = require("./config");
|
|
10
12
|
function activityPriority(source) {
|
|
11
13
|
return source === "friend-facing" ? 0 : 1;
|
|
12
14
|
}
|
|
@@ -28,9 +30,9 @@ function isActiveBridge(bridge) {
|
|
|
28
30
|
return bridge.lifecycle === "active";
|
|
29
31
|
}
|
|
30
32
|
function hasSharedObligationPressure(input) {
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
||
|
|
33
|
+
return input.mustResolveBeforeHandoff
|
|
34
|
+
|| summarizeLiveTasks(input.taskBoard).length > 0
|
|
35
|
+
|| activeObligationCount(input.pendingObligations) > 0;
|
|
34
36
|
}
|
|
35
37
|
function formatCodingLaneLabel(session) {
|
|
36
38
|
return `${session.runner} ${session.id}`;
|
|
@@ -86,6 +88,16 @@ function findPrimaryOpenObligation(frame) {
|
|
|
86
88
|
?? (frame.pendingObligations ?? []).find(obligations_1.isOpenObligation)
|
|
87
89
|
?? null;
|
|
88
90
|
}
|
|
91
|
+
function matchesCurrentSession(frame, obligation) {
|
|
92
|
+
return Boolean(frame.currentSession
|
|
93
|
+
&& obligation.origin.friendId === frame.currentSession.friendId
|
|
94
|
+
&& obligation.origin.channel === frame.currentSession.channel
|
|
95
|
+
&& (0, config_1.sanitizeKey)(obligation.origin.key) === (0, config_1.sanitizeKey)(frame.currentSession.key));
|
|
96
|
+
}
|
|
97
|
+
function findCurrentSessionOpenObligation(frame) {
|
|
98
|
+
return (frame.pendingObligations ?? []).find((obligation) => (0, obligations_1.isOpenObligationStatus)(obligation.status) && matchesCurrentSession(frame, obligation))
|
|
99
|
+
?? null;
|
|
100
|
+
}
|
|
89
101
|
function formatActiveLane(frame, obligation) {
|
|
90
102
|
const liveCodingSession = frame.codingSessions?.[0];
|
|
91
103
|
if (liveCodingSession) {
|
|
@@ -94,12 +106,12 @@ function formatActiveLane(frame, obligation) {
|
|
|
94
106
|
if (obligation?.currentSurface?.label) {
|
|
95
107
|
return obligation.currentSurface.label;
|
|
96
108
|
}
|
|
109
|
+
if (obligation && matchesCurrentSession(frame, obligation) && frame.currentSession) {
|
|
110
|
+
return "this same thread";
|
|
111
|
+
}
|
|
97
112
|
if (frame.inner?.job?.status === "running") {
|
|
98
113
|
return "inner dialog";
|
|
99
114
|
}
|
|
100
|
-
if (typeof frame.currentObligation === "string" && frame.currentObligation.trim().length > 0 && frame.currentSession) {
|
|
101
|
-
return "this same thread";
|
|
102
|
-
}
|
|
103
115
|
return null;
|
|
104
116
|
}
|
|
105
117
|
function formatCurrentArtifact(frame, obligation) {
|
|
@@ -112,11 +124,17 @@ function formatCurrentArtifact(frame, obligation) {
|
|
|
112
124
|
if ((frame.codingSessions ?? []).length > 0) {
|
|
113
125
|
return "no PR or merge artifact yet";
|
|
114
126
|
}
|
|
115
|
-
if (
|
|
127
|
+
if (obligation) {
|
|
116
128
|
return "no artifact yet";
|
|
117
129
|
}
|
|
118
130
|
return null;
|
|
119
131
|
}
|
|
132
|
+
function formatObligationContentNextAction(obligation) {
|
|
133
|
+
const content = obligation?.content?.trim();
|
|
134
|
+
if (!content)
|
|
135
|
+
return null;
|
|
136
|
+
return `work on "${content}" and bring back a concrete artifact`;
|
|
137
|
+
}
|
|
120
138
|
function formatNextAction(frame, obligation) {
|
|
121
139
|
if (obligation?.nextAction?.trim()) {
|
|
122
140
|
return obligation.nextAction.trim();
|
|
@@ -138,13 +156,128 @@ function formatNextAction(frame, obligation) {
|
|
|
138
156
|
return "update runtime, verify version/changelog, then re-observe";
|
|
139
157
|
}
|
|
140
158
|
if (obligation) {
|
|
141
|
-
return "continue the active loop and bring the result back here";
|
|
159
|
+
return formatObligationContentNextAction(obligation) || "continue the active loop and bring the result back here";
|
|
142
160
|
}
|
|
143
|
-
if (
|
|
144
|
-
return
|
|
161
|
+
if (frame.mustResolveBeforeHandoff) {
|
|
162
|
+
return "finish what i started here before moving on";
|
|
145
163
|
}
|
|
146
164
|
return null;
|
|
147
165
|
}
|
|
166
|
+
const RECENT_OTHER_LIVE_SESSION_WINDOW_MS = 60 * 60 * 1000;
|
|
167
|
+
function sessionOriginKey(origin) {
|
|
168
|
+
return `${origin.friendId}/${origin.channel}/${(0, config_1.sanitizeKey)(origin.key)}`;
|
|
169
|
+
}
|
|
170
|
+
function codingSessionTimestampMs(session) {
|
|
171
|
+
return Date.parse(session.lastActivityAt ?? session.startedAt);
|
|
172
|
+
}
|
|
173
|
+
function obligationTimestampMs(obligation) {
|
|
174
|
+
return Date.parse(obligation.updatedAt ?? obligation.createdAt);
|
|
175
|
+
}
|
|
176
|
+
function newestObligationFirst(left, right) {
|
|
177
|
+
return obligationTimestampMs(right) - obligationTimestampMs(left);
|
|
178
|
+
}
|
|
179
|
+
function formatOtherSessionArtifact(obligation, codingSession) {
|
|
180
|
+
if (obligation?.currentArtifact?.trim())
|
|
181
|
+
return obligation.currentArtifact.trim();
|
|
182
|
+
if (obligation?.currentSurface?.kind === "merge" && obligation.currentSurface.label.trim()) {
|
|
183
|
+
return obligation.currentSurface.label.trim();
|
|
184
|
+
}
|
|
185
|
+
if (codingSession)
|
|
186
|
+
return "no PR or merge artifact yet";
|
|
187
|
+
return obligation ? "no artifact yet" : "no explicit artifact yet";
|
|
188
|
+
}
|
|
189
|
+
function formatOtherSessionNextAction(obligation, codingSession) {
|
|
190
|
+
if (obligation?.nextAction?.trim())
|
|
191
|
+
return obligation.nextAction.trim();
|
|
192
|
+
if (obligation?.status === "waiting_for_merge") {
|
|
193
|
+
return `wait for checks, merge ${formatMergeArtifact(obligation)}, then update runtime`;
|
|
194
|
+
}
|
|
195
|
+
if (obligation?.status === "updating_runtime") {
|
|
196
|
+
return "update runtime, verify version/changelog, then re-observe";
|
|
197
|
+
}
|
|
198
|
+
if (codingSession?.status === "waiting_input") {
|
|
199
|
+
return `answer ${formatCodingLaneLabel(codingSession)} and continue`;
|
|
200
|
+
}
|
|
201
|
+
if (codingSession?.status === "stalled") {
|
|
202
|
+
return `unstick ${formatCodingLaneLabel(codingSession)} and continue`;
|
|
203
|
+
}
|
|
204
|
+
if (codingSession) {
|
|
205
|
+
return "finish the coding pass and bring the result back there";
|
|
206
|
+
}
|
|
207
|
+
if (obligation) {
|
|
208
|
+
return formatObligationContentNextAction(obligation) || "continue the active loop and bring the result back there";
|
|
209
|
+
}
|
|
210
|
+
return "check this session and bring back the latest concrete state";
|
|
211
|
+
}
|
|
212
|
+
function formatOtherSessionLine(label, status, activeLane, artifact, nextAction) {
|
|
213
|
+
return `- ${label}: [${status}] ${activeLane}; artifact ${artifact}; next ${nextAction}`;
|
|
214
|
+
}
|
|
215
|
+
function formatOtherActiveSessionSummaries(frame, nowMs = Date.now()) {
|
|
216
|
+
const originMap = new Map();
|
|
217
|
+
for (const session of frame.friendActivity?.allOtherLiveSessions ?? []) {
|
|
218
|
+
if (session.friendId === "self" || session.channel === "inner")
|
|
219
|
+
continue;
|
|
220
|
+
originMap.set(sessionOriginKey(session), {
|
|
221
|
+
friendId: session.friendId,
|
|
222
|
+
channel: session.channel,
|
|
223
|
+
key: session.key,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
const orphanCodingSummaries = (frame.otherCodingSessions ?? [])
|
|
227
|
+
.filter((session) => !session.originSession)
|
|
228
|
+
.sort((left, right) => codingSessionTimestampMs(right) - codingSessionTimestampMs(left))
|
|
229
|
+
.map((session) => ({
|
|
230
|
+
timestampMs: codingSessionTimestampMs(session),
|
|
231
|
+
line: formatOtherSessionLine("another session", session.status, formatCodingLaneLabel(session), "no PR or merge artifact yet", formatOtherSessionNextAction(null, session)),
|
|
232
|
+
}));
|
|
233
|
+
for (const session of frame.otherCodingSessions ?? []) {
|
|
234
|
+
if (!session.originSession)
|
|
235
|
+
continue;
|
|
236
|
+
if (frame.currentSession
|
|
237
|
+
&& session.originSession.friendId === frame.currentSession.friendId
|
|
238
|
+
&& session.originSession.channel === frame.currentSession.channel
|
|
239
|
+
&& (0, config_1.sanitizeKey)(session.originSession.key) === (0, config_1.sanitizeKey)(frame.currentSession.key)) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
originMap.set(sessionOriginKey(session.originSession), session.originSession);
|
|
243
|
+
}
|
|
244
|
+
for (const obligation of frame.pendingObligations ?? []) {
|
|
245
|
+
if (obligation.status === "fulfilled" || matchesCurrentSession(frame, obligation))
|
|
246
|
+
continue;
|
|
247
|
+
originMap.set(sessionOriginKey(obligation.origin), obligation.origin);
|
|
248
|
+
}
|
|
249
|
+
const summaries = [...originMap.values()].map((origin) => {
|
|
250
|
+
const originKey = sessionOriginKey(origin);
|
|
251
|
+
const obligation = [...(frame.pendingObligations ?? [])]
|
|
252
|
+
.filter((candidate) => candidate.status !== "fulfilled" && sessionOriginKey(candidate.origin) === originKey)
|
|
253
|
+
.sort(newestObligationFirst)[0] ?? null;
|
|
254
|
+
const codingSession = [...(frame.otherCodingSessions ?? [])]
|
|
255
|
+
.filter((candidate) => candidate.originSession && sessionOriginKey(candidate.originSession) === originKey)
|
|
256
|
+
.sort((left, right) => codingSessionTimestampMs(right) - codingSessionTimestampMs(left))[0] ?? null;
|
|
257
|
+
const liveSession = (frame.friendActivity?.allOtherLiveSessions ?? []).find((candidate) => sessionOriginKey(candidate) === originKey) ?? null;
|
|
258
|
+
const hasFreshSessionActivity = liveSession
|
|
259
|
+
? (nowMs - liveSession.lastActivityMs) <= RECENT_OTHER_LIVE_SESSION_WINDOW_MS
|
|
260
|
+
: false;
|
|
261
|
+
if (!obligation && !codingSession && !hasFreshSessionActivity) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
const timestampMs = Math.max(liveSession?.lastActivityMs ?? 0, codingSession ? codingSessionTimestampMs(codingSession) : 0, obligation ? obligationTimestampMs(obligation) : 0);
|
|
265
|
+
const activeLane = codingSession
|
|
266
|
+
? formatCodingLaneLabel(codingSession)
|
|
267
|
+
: obligation?.currentSurface?.label?.trim() || "this live thread";
|
|
268
|
+
const artifact = formatOtherSessionArtifact(obligation, codingSession);
|
|
269
|
+
const nextAction = formatOtherSessionNextAction(obligation, codingSession);
|
|
270
|
+
const status = obligation?.status ?? codingSession?.status ?? "active";
|
|
271
|
+
const label = liveSession?.friendName ?? origin.friendId;
|
|
272
|
+
return {
|
|
273
|
+
timestampMs,
|
|
274
|
+
line: formatOtherSessionLine(`${label}/${origin.channel}/${origin.key}`, status, activeLane, artifact, nextAction),
|
|
275
|
+
};
|
|
276
|
+
}).filter((entry) => entry !== null)
|
|
277
|
+
.sort((left, right) => right.timestampMs - left.timestampMs);
|
|
278
|
+
const lines = summaries.map((entry) => entry.line);
|
|
279
|
+
return [...lines, ...orphanCodingSummaries.map((entry) => entry.line)];
|
|
280
|
+
}
|
|
148
281
|
function suggestBridgeForActiveWork(input) {
|
|
149
282
|
const targetCandidates = (input.targetCandidates ?? [])
|
|
150
283
|
.filter((candidate) => {
|
|
@@ -164,10 +297,17 @@ function suggestBridgeForActiveWork(input) {
|
|
|
164
297
|
.sort((a, b) => {
|
|
165
298
|
return b.lastActivityMs - a.lastActivityMs;
|
|
166
299
|
});
|
|
167
|
-
if (!hasSharedObligationPressure(
|
|
300
|
+
if (!hasSharedObligationPressure({
|
|
301
|
+
mustResolveBeforeHandoff: input.mustResolveBeforeHandoff,
|
|
302
|
+
taskBoard: input.taskBoard,
|
|
303
|
+
pendingObligations: input.pendingObligations,
|
|
304
|
+
}) || targetCandidates.length === 0) {
|
|
168
305
|
return null;
|
|
169
306
|
}
|
|
170
307
|
const targetSession = targetCandidates[0];
|
|
308
|
+
const objectiveHint = [...(input.pendingObligations ?? [])]
|
|
309
|
+
.find((obligation) => (0, obligations_1.isOpenObligationStatus)(obligation.status))
|
|
310
|
+
?.content?.trim() || "keep this shared work aligned";
|
|
171
311
|
const activeBridge = input.bridges.find(isActiveBridge) ?? null;
|
|
172
312
|
if (activeBridge) {
|
|
173
313
|
const alreadyAttached = activeBridge.attachedSessions.some((session) => session.friendId === targetSession.friendId
|
|
@@ -186,7 +326,7 @@ function suggestBridgeForActiveWork(input) {
|
|
|
186
326
|
return {
|
|
187
327
|
kind: "begin-new",
|
|
188
328
|
targetSession,
|
|
189
|
-
objectiveHint
|
|
329
|
+
objectiveHint,
|
|
190
330
|
reason: "shared-work-candidate",
|
|
191
331
|
};
|
|
192
332
|
}
|
|
@@ -237,6 +377,7 @@ function buildActiveWorkFrame(input) {
|
|
|
237
377
|
currentObligation: input.currentObligation,
|
|
238
378
|
mustResolveBeforeHandoff: input.mustResolveBeforeHandoff,
|
|
239
379
|
bridges: input.bridges,
|
|
380
|
+
pendingObligations: input.pendingObligations,
|
|
240
381
|
taskBoard: input.taskBoard,
|
|
241
382
|
targetCandidates: input.targetCandidates,
|
|
242
383
|
}),
|
|
@@ -263,16 +404,16 @@ function buildActiveWorkFrame(input) {
|
|
|
263
404
|
function formatActiveWorkFrame(frame) {
|
|
264
405
|
const lines = ["## what i'm holding"];
|
|
265
406
|
const primaryObligation = findPrimaryOpenObligation(frame);
|
|
407
|
+
const currentSessionObligation = findCurrentSessionOpenObligation(frame);
|
|
266
408
|
const activeLane = formatActiveLane(frame, primaryObligation);
|
|
267
409
|
const currentArtifact = formatCurrentArtifact(frame, primaryObligation);
|
|
268
410
|
const nextAction = formatNextAction(frame, primaryObligation);
|
|
269
|
-
const
|
|
270
|
-
const otherLiveSessions = frame.friendActivity?.allOtherLiveSessions ?? [];
|
|
411
|
+
const otherActiveSessions = formatOtherActiveSessionSummaries(frame);
|
|
271
412
|
// Session line
|
|
272
413
|
if (frame.currentSession) {
|
|
273
414
|
let sessionLine = `i'm in a conversation on ${formatSessionLabel(frame.currentSession)}.`;
|
|
274
|
-
if (
|
|
275
|
-
sessionLine += ` i
|
|
415
|
+
if (currentSessionObligation?.content?.trim()) {
|
|
416
|
+
sessionLine += ` i still owe them: ${currentSessionObligation.content.trim()}.`;
|
|
276
417
|
}
|
|
277
418
|
else if (frame.mustResolveBeforeHandoff) {
|
|
278
419
|
sessionLine += " i need to finish what i started here before moving on.";
|
|
@@ -340,22 +481,10 @@ function formatActiveWorkFrame(frame) {
|
|
|
340
481
|
lines.push(`- [${session.status}] ${formatCodingLaneLabel(session)}${describeCodingSessionScope(session, frame.currentSession)}`);
|
|
341
482
|
}
|
|
342
483
|
}
|
|
343
|
-
if (
|
|
484
|
+
if (otherActiveSessions.length > 0) {
|
|
344
485
|
lines.push("");
|
|
345
|
-
lines.push("## other
|
|
346
|
-
|
|
347
|
-
const origin = session.originSession
|
|
348
|
-
? `${session.originSession.friendId}/${session.originSession.channel}/${session.originSession.key}`
|
|
349
|
-
: "another session";
|
|
350
|
-
lines.push(`- [${session.status}] ${formatCodingLaneLabel(session)} for ${origin}`);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
if (otherLiveSessions.length > 0) {
|
|
354
|
-
lines.push("");
|
|
355
|
-
lines.push("## other live sessions");
|
|
356
|
-
for (const session of otherLiveSessions) {
|
|
357
|
-
lines.push(`- ${session.friendName}/${session.channel}/${session.key}`);
|
|
358
|
-
}
|
|
486
|
+
lines.push("## other active sessions");
|
|
487
|
+
lines.push(...otherActiveSessions);
|
|
359
488
|
}
|
|
360
489
|
// Task pressure
|
|
361
490
|
if ((frame.taskPressure?.liveTaskNames ?? []).length > 0) {
|
|
@@ -34,10 +34,6 @@ function deriveCommitments(activeWorkFrame, innerJob, pendingObligations) {
|
|
|
34
34
|
completionCriteria.push("close my active obligation loops");
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
// Obligation (from current turn -- kept for backward compat)
|
|
38
|
-
if (typeof activeWorkFrame.currentObligation === "string" && activeWorkFrame.currentObligation.trim().length > 0) {
|
|
39
|
-
committedTo.push(`i told them i'd ${activeWorkFrame.currentObligation.trim()}`);
|
|
40
|
-
}
|
|
41
37
|
// Inner job
|
|
42
38
|
if (innerJob.status === "queued" || innerJob.status === "running") {
|
|
43
39
|
const contentSuffix = innerJob.content ? ` -- ${innerJob.content.slice(0, 60)}` : "";
|
|
@@ -8,8 +8,8 @@ exports.renderLiveThreadStatusShape = renderLiveThreadStatusShape;
|
|
|
8
8
|
exports.buildExactStatusReply = buildExactStatusReply;
|
|
9
9
|
exports.renderExactStatusReplyContract = renderExactStatusReplyContract;
|
|
10
10
|
const config_1 = require("../heart/config");
|
|
11
|
+
const active_work_1 = require("../heart/active-work");
|
|
11
12
|
const runtime_1 = require("../nerves/runtime");
|
|
12
|
-
const RECENT_OTHER_LIVE_SESSION_WINDOW_MS = 60 * 60 * 1000;
|
|
13
13
|
function findActivePersistentObligation(frame) {
|
|
14
14
|
if (!frame)
|
|
15
15
|
return null;
|
|
@@ -30,102 +30,6 @@ function matchesSessionOrigin(frame, origin) {
|
|
|
30
30
|
&& origin.channel === frame.currentSession.channel
|
|
31
31
|
&& (0, config_1.sanitizeKey)(origin.key) === (0, config_1.sanitizeKey)(frame.currentSession.key));
|
|
32
32
|
}
|
|
33
|
-
function sessionOriginKey(origin) {
|
|
34
|
-
return `${origin.friendId}/${origin.channel}/${(0, config_1.sanitizeKey)(origin.key)}`;
|
|
35
|
-
}
|
|
36
|
-
function codingSessionTimestampMs(session) {
|
|
37
|
-
return Date.parse(session.lastActivityAt ?? session.startedAt);
|
|
38
|
-
}
|
|
39
|
-
function formatCodingLaneLabel(session) {
|
|
40
|
-
return `${session.runner} ${session.id}`;
|
|
41
|
-
}
|
|
42
|
-
function formatOtherSessionArtifact(obligation, codingSession) {
|
|
43
|
-
if (obligation?.currentArtifact?.trim())
|
|
44
|
-
return obligation.currentArtifact.trim();
|
|
45
|
-
if (obligation?.currentSurface?.kind === "merge" && obligation.currentSurface.label.trim()) {
|
|
46
|
-
return obligation.currentSurface.label.trim();
|
|
47
|
-
}
|
|
48
|
-
if (codingSession)
|
|
49
|
-
return "no PR or merge artifact yet";
|
|
50
|
-
return "no artifact yet";
|
|
51
|
-
}
|
|
52
|
-
function formatOtherSessionNextAction(obligation, codingSession) {
|
|
53
|
-
if (obligation?.nextAction?.trim())
|
|
54
|
-
return obligation.nextAction.trim();
|
|
55
|
-
if (obligation?.status === "waiting_for_merge") {
|
|
56
|
-
return `wait for checks, merge ${formatMergeArtifact(obligation)}, then update runtime`;
|
|
57
|
-
}
|
|
58
|
-
if (obligation?.status === "updating_runtime") {
|
|
59
|
-
return "update runtime, verify version/changelog, then re-observe";
|
|
60
|
-
}
|
|
61
|
-
if (codingSession?.status === "waiting_input") {
|
|
62
|
-
return `answer ${formatCodingLaneLabel(codingSession)} and continue`;
|
|
63
|
-
}
|
|
64
|
-
if (codingSession?.status === "stalled") {
|
|
65
|
-
return `unstick ${formatCodingLaneLabel(codingSession)} and continue`;
|
|
66
|
-
}
|
|
67
|
-
if (codingSession) {
|
|
68
|
-
return "finish the coding pass and bring the result back there";
|
|
69
|
-
}
|
|
70
|
-
if (obligation) {
|
|
71
|
-
return "continue the active loop and bring the result back there";
|
|
72
|
-
}
|
|
73
|
-
return "check this session and bring back the latest concrete state";
|
|
74
|
-
}
|
|
75
|
-
function findFriendNameForOrigin(frame, origin) {
|
|
76
|
-
return (frame.friendActivity?.allOtherLiveSessions ?? []).find((entry) => sessionOriginKey(entry) === sessionOriginKey(origin))?.friendName ?? origin.friendId;
|
|
77
|
-
}
|
|
78
|
-
function buildOtherActiveSessionLines(frame) {
|
|
79
|
-
const originMap = new Map();
|
|
80
|
-
for (const session of frame.friendActivity?.allOtherLiveSessions ?? []) {
|
|
81
|
-
if (session.friendId === "self" || session.channel === "inner")
|
|
82
|
-
continue;
|
|
83
|
-
originMap.set(sessionOriginKey(session), {
|
|
84
|
-
friendId: session.friendId,
|
|
85
|
-
channel: session.channel,
|
|
86
|
-
key: session.key,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
for (const session of frame.otherCodingSessions ?? []) {
|
|
90
|
-
if (!session.originSession || matchesSessionOrigin(frame, session.originSession))
|
|
91
|
-
continue;
|
|
92
|
-
originMap.set(sessionOriginKey(session.originSession), session.originSession);
|
|
93
|
-
}
|
|
94
|
-
for (const obligation of frame.pendingObligations ?? []) {
|
|
95
|
-
if (obligation.status === "fulfilled" || matchesSessionOrigin(frame, obligation.origin))
|
|
96
|
-
continue;
|
|
97
|
-
originMap.set(sessionOriginKey(obligation.origin), obligation.origin);
|
|
98
|
-
}
|
|
99
|
-
const summaries = [...originMap.values()].map((origin) => {
|
|
100
|
-
const obligation = [...(frame.pendingObligations ?? [])]
|
|
101
|
-
.filter((candidate) => candidate.status !== "fulfilled" && sessionOriginKey(candidate.origin) === sessionOriginKey(origin))
|
|
102
|
-
.sort(newestObligationFirst)[0] ?? null;
|
|
103
|
-
const codingSession = [...(frame.otherCodingSessions ?? [])]
|
|
104
|
-
.filter((candidate) => candidate.originSession && sessionOriginKey(candidate.originSession) === sessionOriginKey(origin))
|
|
105
|
-
.sort((left, right) => codingSessionTimestampMs(right) - codingSessionTimestampMs(left))[0] ?? null;
|
|
106
|
-
const liveSession = (frame.friendActivity?.allOtherLiveSessions ?? []).find((candidate) => sessionOriginKey(candidate) === sessionOriginKey(origin)) ?? null;
|
|
107
|
-
const hasFreshSessionActivity = liveSession
|
|
108
|
-
? (Date.now() - liveSession.lastActivityMs) <= RECENT_OTHER_LIVE_SESSION_WINDOW_MS
|
|
109
|
-
: false;
|
|
110
|
-
if (!obligation && !codingSession && !hasFreshSessionActivity) {
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
const timestampMs = Math.max(liveSession?.lastActivityMs ?? 0, codingSession ? codingSessionTimestampMs(codingSession) : 0, obligation ? obligationTimestampMs(obligation) : 0);
|
|
114
|
-
const activeLane = codingSession
|
|
115
|
-
? formatCodingLaneLabel(codingSession)
|
|
116
|
-
: obligation?.currentSurface?.label?.trim() || "this live thread";
|
|
117
|
-
const artifact = formatOtherSessionArtifact(obligation, codingSession);
|
|
118
|
-
const nextAction = formatOtherSessionNextAction(obligation, codingSession);
|
|
119
|
-
const status = obligation?.status ?? codingSession?.status ?? "active";
|
|
120
|
-
const friendName = findFriendNameForOrigin(frame, origin);
|
|
121
|
-
return {
|
|
122
|
-
timestampMs,
|
|
123
|
-
line: `- ${friendName}/${origin.channel}/${origin.key}: [${status}] ${activeLane}; artifact ${artifact}; next ${nextAction}`,
|
|
124
|
-
};
|
|
125
|
-
}).filter((entry) => entry !== null)
|
|
126
|
-
.sort((left, right) => right.timestampMs - left.timestampMs);
|
|
127
|
-
return summaries.length > 0 ? summaries.map((entry) => entry.line) : ["- none"];
|
|
128
|
-
}
|
|
129
33
|
function findStatusObligation(frame) {
|
|
130
34
|
if (!frame)
|
|
131
35
|
return null;
|
|
@@ -197,30 +101,20 @@ function formatActiveLane(frame, obligation) {
|
|
|
197
101
|
: `${liveCodingSession.runner} ${liveCodingSession.id}`;
|
|
198
102
|
}
|
|
199
103
|
return obligation.currentSurface?.label
|
|
200
|
-
|| (frame
|
|
104
|
+
|| (matchesCurrentSession(frame, obligation) ? "this same thread" : "this live loop");
|
|
201
105
|
}
|
|
202
106
|
function formatCurrentArtifact(frame, obligation) {
|
|
203
107
|
if (obligation?.currentArtifact)
|
|
204
108
|
return obligation.currentArtifact;
|
|
205
109
|
if (obligation?.currentSurface?.kind === "merge")
|
|
206
110
|
return obligation.currentSurface.label;
|
|
207
|
-
if (frame.currentObligation?.trim())
|
|
208
|
-
return "no artifact yet";
|
|
209
111
|
if ((frame.codingSessions ?? []).length > 0)
|
|
210
112
|
return "no PR or merge artifact yet";
|
|
211
|
-
return obligation ? "no
|
|
212
|
-
}
|
|
213
|
-
function isStatusCheckPrompt(text) {
|
|
214
|
-
const trimmed = text?.trim();
|
|
215
|
-
if (!trimmed)
|
|
216
|
-
return false;
|
|
217
|
-
return /^(what are you doing|what(?:'|’)s your status|status|status update|what changed|where are you at|where things stand)\??$/i.test(trimmed);
|
|
113
|
+
return obligation ? "no artifact yet" : "";
|
|
218
114
|
}
|
|
219
115
|
function formatNextAction(frame, obligation) {
|
|
220
116
|
if (obligation?.nextAction)
|
|
221
117
|
return obligation.nextAction;
|
|
222
|
-
const currentObligation = frame.currentObligation?.trim() ?? "";
|
|
223
|
-
const statusCheckPrompt = isStatusCheckPrompt(currentObligation);
|
|
224
118
|
const liveCodingSession = frame.codingSessions?.[0];
|
|
225
119
|
if (liveCodingSession?.status === "waiting_input") {
|
|
226
120
|
return `answer ${liveCodingSession.runner} ${liveCodingSession.id} and continue`;
|
|
@@ -237,13 +131,13 @@ function formatNextAction(frame, obligation) {
|
|
|
237
131
|
if (obligation?.status === "updating_runtime") {
|
|
238
132
|
return "update runtime, verify version/changelog, then re-observe";
|
|
239
133
|
}
|
|
240
|
-
if (
|
|
241
|
-
return `work on "${
|
|
134
|
+
if (obligation?.content?.trim()) {
|
|
135
|
+
return `work on "${obligation.content.trim()}" and bring back a concrete artifact`;
|
|
242
136
|
}
|
|
243
137
|
return obligation ? "continue the active loop and bring the result back here" : "";
|
|
244
138
|
}
|
|
245
139
|
function renderConcreteStatusGuidance(frame, obligation) {
|
|
246
|
-
const activeLane = obligation ? formatActiveLane(frame, obligation) :
|
|
140
|
+
const activeLane = obligation ? formatActiveLane(frame, obligation) : "";
|
|
247
141
|
const currentArtifact = formatCurrentArtifact(frame, obligation);
|
|
248
142
|
const nextAction = formatNextAction(frame, obligation);
|
|
249
143
|
const liveConversation = frame.currentSession
|
|
@@ -258,7 +152,7 @@ the current artifact is ${currentArtifact}.
|
|
|
258
152
|
if i just finished or verified something concrete in this live lane, i name that as the latest checkpoint.
|
|
259
153
|
the next action is ${nextAction}.
|
|
260
154
|
|
|
261
|
-
i
|
|
155
|
+
i answer naturally from those facts instead of forcing a canned status block.`;
|
|
262
156
|
}
|
|
263
157
|
function renderLiveThreadStatusShape(frame) {
|
|
264
158
|
if (!frame.currentSession)
|
|
@@ -297,7 +191,8 @@ function buildExactStatusReply(frame, obligation, latestCheckpoint, statusCheckS
|
|
|
297
191
|
];
|
|
298
192
|
if (statusCheckScope === "all-sessions-family") {
|
|
299
193
|
lines.push("other active sessions:");
|
|
300
|
-
|
|
194
|
+
const summaries = (0, active_work_1.formatOtherActiveSessionSummaries)(frame);
|
|
195
|
+
lines.push(...(summaries.length > 0 ? summaries : ["- none"]));
|
|
301
196
|
}
|
|
302
197
|
return lines.join("\n");
|
|
303
198
|
}
|
package/dist/mind/prompt.js
CHANGED
|
@@ -457,6 +457,17 @@ function activeWorkSection(options) {
|
|
|
457
457
|
return "";
|
|
458
458
|
return (0, active_work_1.formatActiveWorkFrame)(options.activeWorkFrame);
|
|
459
459
|
}
|
|
460
|
+
function familyCrossSessionTruthSection(context, options) {
|
|
461
|
+
if (!options?.activeWorkFrame)
|
|
462
|
+
return "";
|
|
463
|
+
if (context?.friend?.trustLevel !== "family")
|
|
464
|
+
return "";
|
|
465
|
+
return `## cross-session truth
|
|
466
|
+
if a family member asks what i'm up to or how things are going, that includes the material live work i can see across sessions, not just this thread.
|
|
467
|
+
i answer naturally from the live world-state in this prompt.
|
|
468
|
+
i do not rely on canned status-question modes or phrase matching.
|
|
469
|
+
if part of the picture is still fuzzy, i say what i can see and what still needs checking.`;
|
|
470
|
+
}
|
|
460
471
|
function centerOfGravitySteeringSection(channel, options) {
|
|
461
472
|
if (channel === "inner")
|
|
462
473
|
return "";
|
|
@@ -753,6 +764,7 @@ async function buildSystem(channel = "cli", options, context) {
|
|
|
753
764
|
skillsSection(),
|
|
754
765
|
taskBoardSection(),
|
|
755
766
|
activeWorkSection(options),
|
|
767
|
+
familyCrossSessionTruthSection(context, options),
|
|
756
768
|
statusCheckSection(channel, options),
|
|
757
769
|
centerOfGravitySteeringSection(channel, options),
|
|
758
770
|
commitmentsSection(options),
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -38,23 +38,6 @@ function emptyTaskBoard() {
|
|
|
38
38
|
activeBridges: [],
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
const STATUS_CHECK_PATTERNS = [
|
|
42
|
-
/^\s*what are you doing\??\s*$/i,
|
|
43
|
-
/^\s*what'?s your status\??\s*$/i,
|
|
44
|
-
/^\s*status\??\s*$/i,
|
|
45
|
-
/^\s*status update\??\s*$/i,
|
|
46
|
-
/^\s*what changed\??\s*$/i,
|
|
47
|
-
/^\s*where (?:are you at|things stand)\??\s*$/i,
|
|
48
|
-
];
|
|
49
|
-
function isStatusCheckRequested(ingressTexts) {
|
|
50
|
-
const latest = ingressTexts
|
|
51
|
-
?.map((text) => text.trim())
|
|
52
|
-
.filter((text) => text.length > 0)
|
|
53
|
-
.at(-1);
|
|
54
|
-
if (!latest)
|
|
55
|
-
return false;
|
|
56
|
-
return STATUS_CHECK_PATTERNS.some((pattern) => pattern.test(latest));
|
|
57
|
-
}
|
|
58
41
|
function isLiveCodingSessionStatus(status) {
|
|
59
42
|
return status === "spawning"
|
|
60
43
|
|| status === "running"
|
|
@@ -293,10 +276,6 @@ async function handleInboundTurn(input) {
|
|
|
293
276
|
}
|
|
294
277
|
// Step 5: runAgent
|
|
295
278
|
const existingToolContext = input.runAgentOptions?.toolContext;
|
|
296
|
-
const statusCheckRequested = isStatusCheckRequested(input.continuityIngressTexts);
|
|
297
|
-
const statusCheckScope = statusCheckRequested && resolvedContext.friend.trustLevel === "family"
|
|
298
|
-
? "all-sessions-family"
|
|
299
|
-
: undefined;
|
|
300
279
|
const runAgentOptions = {
|
|
301
280
|
...input.runAgentOptions,
|
|
302
281
|
bridgeContext,
|
|
@@ -304,9 +283,6 @@ async function handleInboundTurn(input) {
|
|
|
304
283
|
delegationDecision,
|
|
305
284
|
currentSessionKey: currentSession.key,
|
|
306
285
|
currentObligation,
|
|
307
|
-
statusCheckRequested,
|
|
308
|
-
statusCheckScope,
|
|
309
|
-
toolChoiceRequired: statusCheckRequested ? true : input.runAgentOptions?.toolChoiceRequired,
|
|
310
286
|
mustResolveBeforeHandoff,
|
|
311
287
|
setMustResolveBeforeHandoff: (value) => {
|
|
312
288
|
mustResolveBeforeHandoff = value;
|