@ouro.bot/cli 0.1.0-alpha.103 → 0.1.0-alpha.105
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 +14 -0
- package/dist/heart/active-work.js +27 -1
- package/dist/heart/core.js +18 -10
- package/dist/mind/obligation-steering.js +139 -11
- package/dist/mind/prompt.js +1 -1
- package/dist/senses/pipeline.js +21 -12
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
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.105",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Family-wide status answers now dedupe normalized session keys, drop inner/self noise, and ignore stale non-obligation lanes so 'what are you doing?' stays focused on real active work across all live sessions.",
|
|
8
|
+
"BlueBubbles and CLI lanes that refer to the same live thread now collapse into one clean status line, preventing duplicate session bullets when family asks for the full cross-session picture."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"version": "0.1.0-alpha.104",
|
|
13
|
+
"changes": [
|
|
14
|
+
"Family-scoped status checks now keep the five-line header anchored on the current live conversation while appending an `other active sessions:` block for every other live lane the agent is actively working.",
|
|
15
|
+
"The inbound pipeline, active-work frame, prompt steering, and status retry logic now preserve non-current live coding lanes and obligations so family status answers stop hiding parallel work in other sessions."
|
|
16
|
+
]
|
|
17
|
+
},
|
|
4
18
|
{
|
|
5
19
|
"version": "0.1.0-alpha.103",
|
|
6
20
|
"changes": [
|
|
@@ -203,6 +203,9 @@ function buildActiveWorkFrame(input) {
|
|
|
203
203
|
const activeBridgePresent = input.bridges.some(isActiveBridge);
|
|
204
204
|
const openObligations = activeObligationCount(input.pendingObligations);
|
|
205
205
|
const liveCodingSessions = input.codingSessions ?? [];
|
|
206
|
+
const allOtherLiveSessions = [...input.friendActivity].sort(compareActivity);
|
|
207
|
+
const otherCodingSessions = input.otherCodingSessions ?? [];
|
|
208
|
+
const pendingObligations = input.pendingObligations ?? [];
|
|
206
209
|
const centerOfGravity = activeBridgePresent
|
|
207
210
|
? "shared-work"
|
|
208
211
|
: (input.inner.status === "running" || input.inner.hasPending || input.mustResolveBeforeHandoff || openObligations > 0 || liveCodingSessions.length > 0)
|
|
@@ -223,9 +226,11 @@ function buildActiveWorkFrame(input) {
|
|
|
223
226
|
friendActivity: {
|
|
224
227
|
freshestForCurrentFriend: friendSessions[0] ?? null,
|
|
225
228
|
otherLiveSessionsForCurrentFriend: friendSessions,
|
|
229
|
+
allOtherLiveSessions,
|
|
226
230
|
},
|
|
227
231
|
codingSessions: liveCodingSessions,
|
|
228
|
-
|
|
232
|
+
otherCodingSessions,
|
|
233
|
+
pendingObligations,
|
|
229
234
|
targetCandidates: input.targetCandidates ?? [],
|
|
230
235
|
bridgeSuggestion: suggestBridgeForActiveWork({
|
|
231
236
|
currentSession: input.currentSession,
|
|
@@ -247,6 +252,8 @@ function buildActiveWorkFrame(input) {
|
|
|
247
252
|
liveTasks: frame.taskPressure.liveTaskNames.length,
|
|
248
253
|
liveSessions: frame.friendActivity.otherLiveSessionsForCurrentFriend.length,
|
|
249
254
|
codingSessions: frame.codingSessions.length,
|
|
255
|
+
otherLiveSessions: allOtherLiveSessions.length,
|
|
256
|
+
otherCodingSessions: otherCodingSessions.length,
|
|
250
257
|
pendingObligations: openObligations,
|
|
251
258
|
hasBridgeSuggestion: frame.bridgeSuggestion !== null,
|
|
252
259
|
},
|
|
@@ -259,6 +266,8 @@ function formatActiveWorkFrame(frame) {
|
|
|
259
266
|
const activeLane = formatActiveLane(frame, primaryObligation);
|
|
260
267
|
const currentArtifact = formatCurrentArtifact(frame, primaryObligation);
|
|
261
268
|
const nextAction = formatNextAction(frame, primaryObligation);
|
|
269
|
+
const otherCodingSessions = frame.otherCodingSessions ?? [];
|
|
270
|
+
const otherLiveSessions = frame.friendActivity?.allOtherLiveSessions ?? [];
|
|
262
271
|
// Session line
|
|
263
272
|
if (frame.currentSession) {
|
|
264
273
|
let sessionLine = `i'm in a conversation on ${formatSessionLabel(frame.currentSession)}.`;
|
|
@@ -331,6 +340,23 @@ function formatActiveWorkFrame(frame) {
|
|
|
331
340
|
lines.push(`- [${session.status}] ${formatCodingLaneLabel(session)}${describeCodingSessionScope(session, frame.currentSession)}`);
|
|
332
341
|
}
|
|
333
342
|
}
|
|
343
|
+
if (otherCodingSessions.length > 0) {
|
|
344
|
+
lines.push("");
|
|
345
|
+
lines.push("## other live coding work");
|
|
346
|
+
for (const session of otherCodingSessions) {
|
|
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
|
+
}
|
|
359
|
+
}
|
|
334
360
|
// Task pressure
|
|
335
361
|
if ((frame.taskPressure?.liveTaskNames ?? []).length > 0) {
|
|
336
362
|
lines.push("");
|
package/dist/heart/core.js
CHANGED
|
@@ -273,24 +273,32 @@ function getFinalAnswerRetryError(mustResolveBeforeHandoff, intent, sawSteeringF
|
|
|
273
273
|
}
|
|
274
274
|
return null;
|
|
275
275
|
}
|
|
276
|
-
function hasExactStatusReplyShape(answer) {
|
|
276
|
+
function hasExactStatusReplyShape(answer, statusCheckScope) {
|
|
277
277
|
const lines = answer.trimEnd().split(/\r?\n/);
|
|
278
|
-
|
|
279
|
-
return false;
|
|
280
|
-
return (/^live conversation:\s+\S.+$/i.test(lines[0])
|
|
278
|
+
const hasFiveLineHeader = (/^live conversation:\s+\S.+$/i.test(lines[0])
|
|
281
279
|
&& /^active lane:\s+\S.+$/i.test(lines[1])
|
|
282
280
|
&& /^current artifact:\s+\S.+$/i.test(lines[2])
|
|
283
281
|
&& /^latest checkpoint:\s+\S.+$/i.test(lines[3])
|
|
284
282
|
&& /^next action:\s+\S.+$/i.test(lines[4]));
|
|
283
|
+
if (!hasFiveLineHeader)
|
|
284
|
+
return false;
|
|
285
|
+
if (statusCheckScope !== "all-sessions-family") {
|
|
286
|
+
return lines.length === 5;
|
|
287
|
+
}
|
|
288
|
+
if (lines.length < 7)
|
|
289
|
+
return false;
|
|
290
|
+
if (!/^other active sessions:\s*$/i.test(lines[5]))
|
|
291
|
+
return false;
|
|
292
|
+
return lines.slice(6).every((line) => /^-\s+\S.+$/i.test(line));
|
|
285
293
|
}
|
|
286
294
|
function extractLatestCheckpoint(answer) {
|
|
287
295
|
const latestLine = answer.trimEnd().split(/\r?\n/)[3];
|
|
288
296
|
return latestLine.replace(/^latest checkpoint:\s*/i, "").trim();
|
|
289
297
|
}
|
|
290
|
-
function getStatusReplyRetryError(answer, statusCheckRequested, activeWorkFrame) {
|
|
298
|
+
function getStatusReplyRetryError(answer, statusCheckRequested, activeWorkFrame, statusCheckScope) {
|
|
291
299
|
if (!statusCheckRequested || answer == null)
|
|
292
300
|
return null;
|
|
293
|
-
if (hasExactStatusReplyShape(answer))
|
|
301
|
+
if (hasExactStatusReplyShape(answer, statusCheckScope))
|
|
294
302
|
return null;
|
|
295
303
|
if (!activeWorkFrame) {
|
|
296
304
|
return `the user asked for current status. call final_answer again using exactly these five non-empty lines and nothing else:
|
|
@@ -301,8 +309,8 @@ latest checkpoint: ...
|
|
|
301
309
|
next action: ...`;
|
|
302
310
|
}
|
|
303
311
|
return `the user asked for current status right now.
|
|
304
|
-
${(0, obligation_steering_1.renderExactStatusReplyContract)(activeWorkFrame, (0, obligation_steering_1.findStatusObligation)(activeWorkFrame))}
|
|
305
|
-
call final_answer again using that exact
|
|
312
|
+
${(0, obligation_steering_1.renderExactStatusReplyContract)(activeWorkFrame, (0, obligation_steering_1.findStatusObligation)(activeWorkFrame), statusCheckScope)}
|
|
313
|
+
call final_answer again using that exact status shape and nothing else.`;
|
|
306
314
|
}
|
|
307
315
|
// Re-export kick utilities for backward compat
|
|
308
316
|
var kicks_1 = require("./kicks");
|
|
@@ -632,10 +640,10 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
632
640
|
// Supports: {"answer":"text","intent":"..."} or "text" (JSON string).
|
|
633
641
|
const { answer, intent } = parseFinalAnswerPayload(result.toolCalls[0].arguments);
|
|
634
642
|
const retryError = getFinalAnswerRetryError(mustResolveBeforeHandoffActive, intent, sawSteeringFollowUp, options?.delegationDecision, sawSendMessageSelf, sawGoInward, sawQuerySession, options?.currentObligation ?? null, options?.activeWorkFrame?.inner?.job, sawExternalStateQuery);
|
|
635
|
-
const statusReplyRetryError = getStatusReplyRetryError(answer, options?.statusCheckRequested, options?.activeWorkFrame);
|
|
643
|
+
const statusReplyRetryError = getStatusReplyRetryError(answer, options?.statusCheckRequested, options?.activeWorkFrame, options?.statusCheckScope);
|
|
636
644
|
const exactStatusReplyAccepted = Boolean(options?.statusCheckRequested) && !statusReplyRetryError && answer != null;
|
|
637
645
|
const deliveredAnswer = exactStatusReplyAccepted && options?.activeWorkFrame
|
|
638
|
-
? (0, obligation_steering_1.buildExactStatusReply)(options.activeWorkFrame, (0, obligation_steering_1.findStatusObligation)(options.activeWorkFrame), extractLatestCheckpoint(answer))
|
|
646
|
+
? (0, obligation_steering_1.buildExactStatusReply)(options.activeWorkFrame, (0, obligation_steering_1.findStatusObligation)(options.activeWorkFrame), extractLatestCheckpoint(answer), options?.statusCheckScope)
|
|
639
647
|
: answer;
|
|
640
648
|
const validDirectReply = mustResolveBeforeHandoffActive && intent === "direct_reply" && sawSteeringFollowUp;
|
|
641
649
|
const validTerminalIntent = intent === "complete" || intent === "blocked";
|
|
@@ -7,7 +7,9 @@ exports.renderConcreteStatusGuidance = renderConcreteStatusGuidance;
|
|
|
7
7
|
exports.renderLiveThreadStatusShape = renderLiveThreadStatusShape;
|
|
8
8
|
exports.buildExactStatusReply = buildExactStatusReply;
|
|
9
9
|
exports.renderExactStatusReplyContract = renderExactStatusReplyContract;
|
|
10
|
+
const config_1 = require("../heart/config");
|
|
10
11
|
const runtime_1 = require("../nerves/runtime");
|
|
12
|
+
const RECENT_OTHER_LIVE_SESSION_WINDOW_MS = 60 * 60 * 1000;
|
|
11
13
|
function findActivePersistentObligation(frame) {
|
|
12
14
|
if (!frame)
|
|
13
15
|
return null;
|
|
@@ -20,10 +22,109 @@ function newestObligationFirst(left, right) {
|
|
|
20
22
|
return obligationTimestampMs(right) - obligationTimestampMs(left);
|
|
21
23
|
}
|
|
22
24
|
function matchesCurrentSession(frame, obligation) {
|
|
25
|
+
return matchesSessionOrigin(frame, obligation.origin);
|
|
26
|
+
}
|
|
27
|
+
function matchesSessionOrigin(frame, origin) {
|
|
23
28
|
return Boolean(frame.currentSession
|
|
24
|
-
&&
|
|
25
|
-
&&
|
|
26
|
-
&&
|
|
29
|
+
&& origin.friendId === frame.currentSession.friendId
|
|
30
|
+
&& origin.channel === frame.currentSession.channel
|
|
31
|
+
&& (0, config_1.sanitizeKey)(origin.key) === (0, config_1.sanitizeKey)(frame.currentSession.key));
|
|
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"];
|
|
27
128
|
}
|
|
28
129
|
function findStatusObligation(frame) {
|
|
29
130
|
if (!frame)
|
|
@@ -36,6 +137,12 @@ function findStatusObligation(frame) {
|
|
|
36
137
|
return sameSession;
|
|
37
138
|
return openObligations[0] ?? null;
|
|
38
139
|
}
|
|
140
|
+
function findCurrentSessionStatusObligation(frame) {
|
|
141
|
+
const openObligations = [...(frame.pendingObligations ?? [])]
|
|
142
|
+
.filter((obligation) => obligation.status !== "fulfilled")
|
|
143
|
+
.sort(newestObligationFirst);
|
|
144
|
+
return openObligations.find((obligation) => matchesCurrentSession(frame, obligation)) ?? null;
|
|
145
|
+
}
|
|
39
146
|
function renderActiveObligationSteering(obligation) {
|
|
40
147
|
(0, runtime_1.emitNervesEvent)({
|
|
41
148
|
component: "mind",
|
|
@@ -168,25 +275,46 @@ no option list.
|
|
|
168
275
|
present tense only.
|
|
169
276
|
if a finished step matters, i label it "just finished" instead of presenting it as current work.`;
|
|
170
277
|
}
|
|
171
|
-
function buildExactStatusReply(frame, obligation, latestCheckpoint) {
|
|
278
|
+
function buildExactStatusReply(frame, obligation, latestCheckpoint, statusCheckScope) {
|
|
279
|
+
const headerObligation = statusCheckScope === "all-sessions-family"
|
|
280
|
+
? findCurrentSessionStatusObligation(frame)
|
|
281
|
+
: obligation;
|
|
172
282
|
const liveConversation = frame.currentSession
|
|
173
283
|
? `${frame.currentSession.channel}/${frame.currentSession.key}`
|
|
174
284
|
: "not in a live conversation";
|
|
175
|
-
const activeLane =
|
|
176
|
-
? formatActiveLane(frame,
|
|
285
|
+
const activeLane = headerObligation
|
|
286
|
+
? formatActiveLane(frame, headerObligation)
|
|
177
287
|
: (frame.currentSession ? "this same thread" : "this live loop");
|
|
178
|
-
const currentArtifact = formatCurrentArtifact(frame,
|
|
179
|
-
const nextAction = formatNextAction(frame,
|
|
288
|
+
const currentArtifact = formatCurrentArtifact(frame, headerObligation) || "no artifact yet";
|
|
289
|
+
const nextAction = formatNextAction(frame, headerObligation) || "continue the active loop and bring the result back here";
|
|
180
290
|
const latest = latestCheckpoint.trim() || "<freshest concrete thing i just finished or verified>";
|
|
181
|
-
|
|
291
|
+
const lines = [
|
|
182
292
|
`live conversation: ${liveConversation}`,
|
|
183
293
|
`active lane: ${activeLane}`,
|
|
184
294
|
`current artifact: ${currentArtifact}`,
|
|
185
295
|
`latest checkpoint: ${latest}`,
|
|
186
296
|
`next action: ${nextAction}`,
|
|
187
|
-
]
|
|
297
|
+
];
|
|
298
|
+
if (statusCheckScope === "all-sessions-family") {
|
|
299
|
+
lines.push("other active sessions:");
|
|
300
|
+
lines.push(...buildOtherActiveSessionLines(frame));
|
|
301
|
+
}
|
|
302
|
+
return lines.join("\n");
|
|
188
303
|
}
|
|
189
|
-
function renderExactStatusReplyContract(frame, obligation) {
|
|
304
|
+
function renderExactStatusReplyContract(frame, obligation, statusCheckScope) {
|
|
305
|
+
const headerObligation = statusCheckScope === "all-sessions-family"
|
|
306
|
+
? findCurrentSessionStatusObligation(frame)
|
|
307
|
+
: obligation;
|
|
308
|
+
if (statusCheckScope === "all-sessions-family") {
|
|
309
|
+
return `reply using exactly this status shape and nothing else:
|
|
310
|
+
live conversation: ${frame.currentSession ? `${frame.currentSession.channel}/${frame.currentSession.key}` : "not in a live conversation"}
|
|
311
|
+
active lane: ${headerObligation ? formatActiveLane(frame, headerObligation) : (frame.currentSession ? "this same thread" : "this live loop")}
|
|
312
|
+
current artifact: ${formatCurrentArtifact(frame, headerObligation) || "no artifact yet"}
|
|
313
|
+
latest checkpoint: <freshest concrete thing i just finished or verified>
|
|
314
|
+
next action: ${formatNextAction(frame, headerObligation) || "continue the active loop and bring the result back here"}
|
|
315
|
+
other active sessions:
|
|
316
|
+
- <session label>: <what i'm doing there right now>`;
|
|
317
|
+
}
|
|
190
318
|
return `reply using exactly these five lines and nothing else:
|
|
191
319
|
${buildExactStatusReply(frame, obligation, "<freshest concrete thing i just finished or verified>")}
|
|
192
320
|
`;
|
package/dist/mind/prompt.js
CHANGED
|
@@ -544,7 +544,7 @@ function statusCheckSection(channel, options) {
|
|
|
544
544
|
const activeObligation = (0, obligation_steering_1.findStatusObligation)(frame);
|
|
545
545
|
return `## status question on this turn
|
|
546
546
|
the user is asking for current status right now.
|
|
547
|
-
${(0, obligation_steering_1.renderExactStatusReplyContract)(frame, activeObligation)}`;
|
|
547
|
+
${(0, obligation_steering_1.renderExactStatusReplyContract)(frame, activeObligation, options.statusCheckScope)}`;
|
|
548
548
|
}
|
|
549
549
|
function commitmentsSection(options) {
|
|
550
550
|
if (!options?.activeWorkFrame)
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -55,6 +55,12 @@ function isStatusCheckRequested(ingressTexts) {
|
|
|
55
55
|
return false;
|
|
56
56
|
return STATUS_CHECK_PATTERNS.some((pattern) => pattern.test(latest));
|
|
57
57
|
}
|
|
58
|
+
function isLiveCodingSessionStatus(status) {
|
|
59
|
+
return status === "spawning"
|
|
60
|
+
|| status === "running"
|
|
61
|
+
|| status === "waiting_input"
|
|
62
|
+
|| status === "stalled";
|
|
63
|
+
}
|
|
58
64
|
function readInnerWorkState() {
|
|
59
65
|
const defaultJob = {
|
|
60
66
|
status: "idle",
|
|
@@ -205,23 +211,21 @@ async function handleInboundTurn(input) {
|
|
|
205
211
|
pendingObligations = [];
|
|
206
212
|
}
|
|
207
213
|
let codingSessions = [];
|
|
214
|
+
let otherCodingSessions = [];
|
|
208
215
|
try {
|
|
209
|
-
|
|
216
|
+
const liveCodingSessions = (0, coding_1.getCodingSessionManager)()
|
|
210
217
|
.listSessions()
|
|
211
|
-
.filter((session) =>
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return session.originSession.friendId === currentSession.friendId
|
|
219
|
-
&& session.originSession.channel === currentSession.channel
|
|
220
|
-
&& session.originSession.key === currentSession.key;
|
|
221
|
-
});
|
|
218
|
+
.filter((session) => isLiveCodingSessionStatus(session.status) && Boolean(session.originSession));
|
|
219
|
+
codingSessions = liveCodingSessions.filter((session) => session.originSession?.friendId === currentSession.friendId
|
|
220
|
+
&& session.originSession.channel === currentSession.channel
|
|
221
|
+
&& session.originSession.key === currentSession.key);
|
|
222
|
+
otherCodingSessions = liveCodingSessions.filter((session) => !(session.originSession?.friendId === currentSession.friendId
|
|
223
|
+
&& session.originSession.channel === currentSession.channel
|
|
224
|
+
&& session.originSession.key === currentSession.key));
|
|
222
225
|
}
|
|
223
226
|
catch {
|
|
224
227
|
codingSessions = [];
|
|
228
|
+
otherCodingSessions = [];
|
|
225
229
|
}
|
|
226
230
|
const activeWorkFrame = (0, active_work_1.buildActiveWorkFrame)({
|
|
227
231
|
currentSession,
|
|
@@ -230,6 +234,7 @@ async function handleInboundTurn(input) {
|
|
|
230
234
|
inner: readInnerWorkState(),
|
|
231
235
|
bridges: activeBridges,
|
|
232
236
|
codingSessions,
|
|
237
|
+
otherCodingSessions,
|
|
233
238
|
pendingObligations,
|
|
234
239
|
taskBoard: (() => {
|
|
235
240
|
try {
|
|
@@ -289,6 +294,9 @@ async function handleInboundTurn(input) {
|
|
|
289
294
|
// Step 5: runAgent
|
|
290
295
|
const existingToolContext = input.runAgentOptions?.toolContext;
|
|
291
296
|
const statusCheckRequested = isStatusCheckRequested(input.continuityIngressTexts);
|
|
297
|
+
const statusCheckScope = statusCheckRequested && resolvedContext.friend.trustLevel === "family"
|
|
298
|
+
? "all-sessions-family"
|
|
299
|
+
: undefined;
|
|
292
300
|
const runAgentOptions = {
|
|
293
301
|
...input.runAgentOptions,
|
|
294
302
|
bridgeContext,
|
|
@@ -297,6 +305,7 @@ async function handleInboundTurn(input) {
|
|
|
297
305
|
currentSessionKey: currentSession.key,
|
|
298
306
|
currentObligation,
|
|
299
307
|
statusCheckRequested,
|
|
308
|
+
statusCheckScope,
|
|
300
309
|
toolChoiceRequired: statusCheckRequested ? true : input.runAgentOptions?.toolChoiceRequired,
|
|
301
310
|
mustResolveBeforeHandoff,
|
|
302
311
|
setMustResolveBeforeHandoff: (value) => {
|