@cydm/happy-elves 0.1.0-beta.283 → 0.1.0-beta.285
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/apps/cli/dist/commands/lib/session-output.d.ts +1 -1
- package/apps/cli/dist/commands/lib/session-output.js +10 -0
- package/apps/cli/dist/commands/lib/session-view.js +12 -1
- package/apps/cli/package.json +1 -1
- package/apps/daemon/dist/session/reconcile.js +21 -0
- package/apps/daemon/package.json +1 -1
- package/apps/relay/dist/machine-handlers.js +2 -2
- package/apps/relay/dist/relay-context.js +0 -25
- package/package.json +1 -1
- package/packages/shared/dist/protocol-schemas.d.ts +2 -1
- package/packages/shared/dist/protocol-schemas.js +1 -1
- package/packages/shared/dist/protocol-types.d.ts +1 -1
- package/packages/shared/dist/session-state.d.ts +1 -1
- package/packages/shared/dist/session-state.js +6 -3
|
@@ -29,7 +29,7 @@ export type TurnSummary = {
|
|
|
29
29
|
checkpointId?: string;
|
|
30
30
|
runtimeTurnId?: string;
|
|
31
31
|
turnSeq?: number;
|
|
32
|
-
status: "running" | "completed" | "failed" | "cancelled";
|
|
32
|
+
status: "running" | "completed" | "failed" | "cancelled" | "unknown";
|
|
33
33
|
prompt: string;
|
|
34
34
|
output: string;
|
|
35
35
|
terminalText: string;
|
|
@@ -243,6 +243,13 @@ export function summarizeTurns(events) {
|
|
|
243
243
|
current.checkpointId = payload.currentHead;
|
|
244
244
|
current.runtimeTurnId = payload.lastTurnId;
|
|
245
245
|
}
|
|
246
|
+
else if (payload?.type === "status" && isReconcileUnknownTag(payload.tag)) {
|
|
247
|
+
if (current.status === "running") {
|
|
248
|
+
current.status = "unknown";
|
|
249
|
+
current.completedAt = event.createdAt;
|
|
250
|
+
current.terminalText = payload.text.trim();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
246
253
|
else if (payload?.type === "memory_used") {
|
|
247
254
|
current.usedMemories = dedupeUsedMemories([...current.usedMemories, ...payload.memories]);
|
|
248
255
|
}
|
|
@@ -472,6 +479,9 @@ function turnInProgressError(sessionId, turn, latestCompleted) {
|
|
|
472
479
|
latestCompletedTurnId: latestCompleted?.turnId,
|
|
473
480
|
});
|
|
474
481
|
}
|
|
482
|
+
function isReconcileUnknownTag(tag) {
|
|
483
|
+
return tag === "reconcile:unknown" || tag === "reconcile:not_found" || tag === "reconcile:uninspectable";
|
|
484
|
+
}
|
|
475
485
|
export async function rebuildTurnOutput(client, sessionId, turnId) {
|
|
476
486
|
const events = await client.history(sessionId, 1000);
|
|
477
487
|
const folded = foldAliasedRuntimeEvents(events);
|
|
@@ -34,7 +34,7 @@ function orchestrationStateFromStatus(status) {
|
|
|
34
34
|
return "idle";
|
|
35
35
|
if (status === "completed")
|
|
36
36
|
return "completed";
|
|
37
|
-
if (status === "failed" || status === "offline")
|
|
37
|
+
if (status === "failed" || status === "offline" || status === "unknown")
|
|
38
38
|
return "blocked";
|
|
39
39
|
return "closed";
|
|
40
40
|
}
|
|
@@ -70,6 +70,17 @@ export function deriveOrchestration(session, events = []) {
|
|
|
70
70
|
completed: false,
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
|
+
if (latestTerminalTurn?.status === "unknown") {
|
|
74
|
+
return {
|
|
75
|
+
state: "blocked",
|
|
76
|
+
rawStatus: session.status,
|
|
77
|
+
needsUser: false,
|
|
78
|
+
blocked: true,
|
|
79
|
+
completed: false,
|
|
80
|
+
reason: "execution-unknown",
|
|
81
|
+
lastEventId: latestTerminalTurn.lastEventId,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
73
84
|
const state = orchestrationStateFromStatus(session.status);
|
|
74
85
|
return {
|
|
75
86
|
state,
|
package/apps/cli/package.json
CHANGED
|
@@ -4,6 +4,7 @@ import { getRuntime } from "../runtime.js";
|
|
|
4
4
|
import { sessions, sessionTurns } from "../state.js";
|
|
5
5
|
import { sendCommandResponse } from "../relay/send.js";
|
|
6
6
|
import { settleScheduleTurnTerminal } from "../schedule/runner.js";
|
|
7
|
+
import { emitEvent } from "./events.js";
|
|
7
8
|
import { commandSessionMetadata } from "./metadata.js";
|
|
8
9
|
export async function handleReconcileTurn(ws, config, command) {
|
|
9
10
|
if (command.type !== "machine:reconcileTurn")
|
|
@@ -89,11 +90,31 @@ export async function handleReconcileTurn(ws, config, command) {
|
|
|
89
90
|
result,
|
|
90
91
|
},
|
|
91
92
|
});
|
|
93
|
+
if (isUnconfirmedReconcileResult(result) && result.turnId) {
|
|
94
|
+
await emitEvent(ws, config, command.sessionId, result.turnId, {
|
|
95
|
+
type: "status",
|
|
96
|
+
tag: `reconcile:${result.status}`,
|
|
97
|
+
text: reconcileStatusText(result),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
92
100
|
await sendReconcileResult(ws, config, command, result);
|
|
93
101
|
if (result.status === "terminal" && result.terminalStatus && result.turnId) {
|
|
94
102
|
await settleTerminalSideEffects(config, result);
|
|
95
103
|
}
|
|
96
104
|
}
|
|
105
|
+
function isUnconfirmedReconcileResult(result) {
|
|
106
|
+
return result.status === "unknown" || result.status === "not_found" || result.status === "uninspectable";
|
|
107
|
+
}
|
|
108
|
+
function reconcileStatusText(result) {
|
|
109
|
+
const reason = result.reason ? ` Reason: ${result.reason}` : "";
|
|
110
|
+
if (result.status === "not_found") {
|
|
111
|
+
return `Unable to confirm whether the previous execution finished; provider reported authoritative not found.${reason}`;
|
|
112
|
+
}
|
|
113
|
+
if (result.status === "uninspectable") {
|
|
114
|
+
return `Unable to confirm whether the previous execution finished; this runtime cannot inspect the turn.${reason}`;
|
|
115
|
+
}
|
|
116
|
+
return `Unable to confirm whether the previous execution finished.${reason}`;
|
|
117
|
+
}
|
|
97
118
|
async function sendReconcileResult(ws, config, command, result) {
|
|
98
119
|
await sendCommandResponse(ws, {
|
|
99
120
|
type: "machine:turnReconciled",
|
package/apps/daemon/package.json
CHANGED
|
@@ -246,9 +246,9 @@ export function handleMachineMessage(context, connection, message) {
|
|
|
246
246
|
(!message.result.turnId || message.result.turnId === claim?.turn_id);
|
|
247
247
|
if (claimMatches && turnId) {
|
|
248
248
|
db.prepare(`UPDATE sessions
|
|
249
|
-
SET status = '
|
|
249
|
+
SET status = 'unknown',
|
|
250
250
|
current_head = COALESCE(current_head, ?),
|
|
251
|
-
last_turn_id =
|
|
251
|
+
last_turn_id = COALESCE(last_turn_id, ?),
|
|
252
252
|
updated_at = ?
|
|
253
253
|
WHERE id = ? AND account_id = ? AND machine_id = ? AND status != 'closed'`).run(turnId, turnId, ts, message.result.sessionId, connection.accountId, connection.machineId);
|
|
254
254
|
if (requestId) {
|
|
@@ -230,21 +230,6 @@ export function createRelayContext(options) {
|
|
|
230
230
|
.get(claim.account_id, claim.request_id);
|
|
231
231
|
if (admission && (admission.finished_at !== null || admission.terminal_status !== null))
|
|
232
232
|
return {};
|
|
233
|
-
const session = options.db
|
|
234
|
-
.prepare(`SELECT status, current_head, last_turn_id, updated_at
|
|
235
|
-
FROM sessions
|
|
236
|
-
WHERE account_id = ? AND id = ?`)
|
|
237
|
-
.get(claim.account_id, claim.session_id);
|
|
238
|
-
if (admission?.dispatch === "delivered" &&
|
|
239
|
-
session &&
|
|
240
|
-
isSettledSessionProjectionStatus(session.status) &&
|
|
241
|
-
session.updated_at > claim.created_at &&
|
|
242
|
-
(session.last_turn_id === claim.turn_id || (session.current_head !== claim.turn_id && session.last_turn_id !== claim.turn_id))) {
|
|
243
|
-
return {
|
|
244
|
-
terminalStatus: terminalStatusForSettledSessionStatus(session.status),
|
|
245
|
-
finishedAt: session.updated_at,
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
233
|
const newerTerminal = options.db
|
|
249
234
|
.prepare(`SELECT 1
|
|
250
235
|
FROM relay_admissions
|
|
@@ -259,16 +244,6 @@ export function createRelayContext(options) {
|
|
|
259
244
|
.get(claim.account_id, claim.session_id, claim.request_id, claim.created_at);
|
|
260
245
|
return newerTerminal ? {} : undefined;
|
|
261
246
|
}
|
|
262
|
-
function terminalStatusForSettledSessionStatus(status) {
|
|
263
|
-
if (status === "failed")
|
|
264
|
-
return "failed";
|
|
265
|
-
if (status === "cancelled" || status === "closed")
|
|
266
|
-
return "cancelled";
|
|
267
|
-
return "completed";
|
|
268
|
-
}
|
|
269
|
-
function isSettledSessionProjectionStatus(status) {
|
|
270
|
-
return status === "ready" || status === "completed" || status === "cancelled" || status === "closed";
|
|
271
|
-
}
|
|
272
247
|
function claimSessionTurn(params) {
|
|
273
248
|
const existing = activeSessionClaim(params.accountId, params.sessionId);
|
|
274
249
|
if (existing && existing.request_id !== params.requestId)
|
package/package.json
CHANGED
|
@@ -211,6 +211,7 @@ export declare const sessionSnapshotSchema: z.ZodObject<{
|
|
|
211
211
|
new: "new";
|
|
212
212
|
ready: "ready";
|
|
213
213
|
running: "running";
|
|
214
|
+
unknown: "unknown";
|
|
214
215
|
completed: "completed";
|
|
215
216
|
failed: "failed";
|
|
216
217
|
cancelled: "cancelled";
|
|
@@ -457,9 +458,9 @@ export declare const daemonLifecycleResultSchema: z.ZodObject<{
|
|
|
457
458
|
platform: z.ZodOptional<z.ZodString>;
|
|
458
459
|
arch: z.ZodOptional<z.ZodString>;
|
|
459
460
|
installMode: z.ZodOptional<z.ZodEnum<{
|
|
461
|
+
unknown: "unknown";
|
|
460
462
|
"npm-global": "npm-global";
|
|
461
463
|
"repo-dev": "repo-dev";
|
|
462
|
-
unknown: "unknown";
|
|
463
464
|
}>>;
|
|
464
465
|
updateSupported: z.ZodOptional<z.ZodBoolean>;
|
|
465
466
|
updateUnsupportedReason: z.ZodOptional<z.ZodString>;
|
|
@@ -79,7 +79,7 @@ export const sessionSnapshotSchema = z.object({
|
|
|
79
79
|
agent: z.string().min(1),
|
|
80
80
|
cwd: z.string(),
|
|
81
81
|
name: z.string().min(1),
|
|
82
|
-
status: z.enum(["new", "ready", "running", "completed", "failed", "cancelled", "offline", "closed"]),
|
|
82
|
+
status: z.enum(["new", "ready", "running", "unknown", "completed", "failed", "cancelled", "offline", "closed"]),
|
|
83
83
|
createdAt: z.number(),
|
|
84
84
|
updatedAt: z.number(),
|
|
85
85
|
encryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
@@ -57,7 +57,7 @@ export type SessionSnapshot = {
|
|
|
57
57
|
agent: string;
|
|
58
58
|
cwd: string;
|
|
59
59
|
name: string;
|
|
60
|
-
status: "new" | "ready" | "running" | "completed" | "failed" | "cancelled" | "offline" | "closed";
|
|
60
|
+
status: "new" | "ready" | "running" | "unknown" | "completed" | "failed" | "cancelled" | "offline" | "closed";
|
|
61
61
|
createdAt: number;
|
|
62
62
|
updatedAt: number;
|
|
63
63
|
encryptedMetadata?: EncryptedEnvelope;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const sessionStatuses: readonly ["new", "ready", "running", "completed", "failed", "cancelled", "offline", "closed"];
|
|
1
|
+
export declare const sessionStatuses: readonly ["new", "ready", "running", "unknown", "completed", "failed", "cancelled", "offline", "closed"];
|
|
2
2
|
export type SessionStatus = (typeof sessionStatuses)[number];
|
|
3
3
|
export type ControllerSessionCommand = "prompt" | "cancel" | "resume" | "rewind" | "fork" | "rename" | "close";
|
|
4
4
|
export type SessionCommandDecision = {
|
|
@@ -2,6 +2,7 @@ export const sessionStatuses = [
|
|
|
2
2
|
"new",
|
|
3
3
|
"ready",
|
|
4
4
|
"running",
|
|
5
|
+
"unknown",
|
|
5
6
|
"completed",
|
|
6
7
|
"failed",
|
|
7
8
|
"cancelled",
|
|
@@ -15,7 +16,7 @@ export function isSessionClosed(status) {
|
|
|
15
16
|
return status === "closed";
|
|
16
17
|
}
|
|
17
18
|
export function isSessionBusy(status) {
|
|
18
|
-
return status === "running";
|
|
19
|
+
return status === "running" || status === "unknown";
|
|
19
20
|
}
|
|
20
21
|
export function controllerSessionCommandDecision(status, command) {
|
|
21
22
|
if (command === "close" && status === "closed")
|
|
@@ -27,11 +28,11 @@ export function controllerSessionCommandDecision(status, command) {
|
|
|
27
28
|
message: "Session is closed",
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
|
-
if (command === "prompt" && status
|
|
31
|
+
if (command === "prompt" && isSessionBusy(status)) {
|
|
31
32
|
return {
|
|
32
33
|
allowed: false,
|
|
33
34
|
code: "SESSION_BUSY",
|
|
34
|
-
message: "Session already has a running turn",
|
|
35
|
+
message: status === "unknown" ? "Session has a turn whose execution status is unknown" : "Session already has a running turn",
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
38
|
return { allowed: true };
|
|
@@ -43,6 +44,8 @@ export function statusAfterMachineDisconnect(status) {
|
|
|
43
44
|
return "failed";
|
|
44
45
|
if (status === "running")
|
|
45
46
|
return "offline";
|
|
47
|
+
if (status === "unknown")
|
|
48
|
+
return "unknown";
|
|
46
49
|
return status;
|
|
47
50
|
}
|
|
48
51
|
//# sourceMappingURL=session-state.js.map
|