@cjhyy/code-shell-pet 0.9.8 → 0.9.10
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/dist/long-task.d.ts +36 -4
- package/dist/long-task.js +97 -4
- package/dist/projection-extension.js +2 -0
- package/dist/session-index.js +56 -3
- package/dist/types.d.ts +6 -0
- package/package.json +2 -2
package/dist/long-task.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export interface PetLongTaskCompletionTarget {
|
|
|
30
30
|
replyAttachmentKinds?: PetReplyAttachmentKind[];
|
|
31
31
|
}
|
|
32
32
|
export type PetReplyAttachmentKind = "image" | "file" | "audio" | "video";
|
|
33
|
-
export type PetLongTaskEventKind = "created" | "started" | "progress" | "waiting" | "paused" | "resumed" | "retrying" | "artifact" | "checkpoint" | "verification-changed" | "completion-target-set" | "interrupted" | "completed" | "failed" | "cancelled" | "closure-decided" | "continuation-started" | "closure-recorded" | "work-memory-recorded";
|
|
33
|
+
export type PetLongTaskEventKind = "created" | "started" | "run-bound" | "run-prepared" | "result-updated" | "progress" | "waiting" | "paused" | "resumed" | "retrying" | "artifact" | "checkpoint" | "verification-changed" | "completion-target-set" | "interrupted" | "completed" | "failed" | "cancelled" | "closure-decided" | "continuation-started" | "closure-recorded" | "work-memory-recorded";
|
|
34
34
|
export interface PetLongTaskEvent {
|
|
35
35
|
id: string;
|
|
36
36
|
sequence: number;
|
|
@@ -41,6 +41,9 @@ export interface PetLongTaskEvent {
|
|
|
41
41
|
waitingFor?: string;
|
|
42
42
|
nextAction?: string;
|
|
43
43
|
artifacts?: PetLongTaskArtifact[];
|
|
44
|
+
attempt?: number;
|
|
45
|
+
runId?: string;
|
|
46
|
+
clientMessageId?: string;
|
|
44
47
|
}
|
|
45
48
|
export interface PetLongTask {
|
|
46
49
|
schemaVersion: typeof PET_LONG_TASK_SCHEMA_VERSION;
|
|
@@ -59,6 +62,10 @@ export interface PetLongTask {
|
|
|
59
62
|
status: PetLongTaskStatus;
|
|
60
63
|
phase: PetLongTaskPhase;
|
|
61
64
|
attempt: number;
|
|
65
|
+
/** Current run's transcript user-message id; absent in historical rows. */
|
|
66
|
+
runId?: string;
|
|
67
|
+
/** Expected launch client id before binding, current run client id afterwards. */
|
|
68
|
+
clientMessageId?: string;
|
|
62
69
|
revision: number;
|
|
63
70
|
createdAt: number;
|
|
64
71
|
updatedAt: number;
|
|
@@ -127,6 +134,8 @@ export interface CreatePetLongTaskInput {
|
|
|
127
134
|
objective: string;
|
|
128
135
|
workspacePath: string | null;
|
|
129
136
|
sessionId: string;
|
|
137
|
+
runId?: string;
|
|
138
|
+
clientMessageId?: string;
|
|
130
139
|
executionBackend?: PetWorkExecutionBackend;
|
|
131
140
|
verificationMode?: PetLongTaskVerificationMode;
|
|
132
141
|
completionTarget?: PetLongTaskCompletionTarget;
|
|
@@ -134,6 +143,28 @@ export interface CreatePetLongTaskInput {
|
|
|
134
143
|
at: number;
|
|
135
144
|
}
|
|
136
145
|
export type PetLongTaskTransition = {
|
|
146
|
+
/** Optimistic fence for observations queued before retry/resume. */
|
|
147
|
+
attempt?: number;
|
|
148
|
+
runId?: string;
|
|
149
|
+
clientMessageId?: string;
|
|
150
|
+
} & PetLongTaskTransitionInput;
|
|
151
|
+
type PetLongTaskTransitionInput = {
|
|
152
|
+
kind: "run-prepared";
|
|
153
|
+
at: number;
|
|
154
|
+
clientMessageId?: string;
|
|
155
|
+
} | {
|
|
156
|
+
kind: "run-bound";
|
|
157
|
+
at: number;
|
|
158
|
+
runId: string;
|
|
159
|
+
previousRunId?: string;
|
|
160
|
+
} | {
|
|
161
|
+
kind: "result-updated";
|
|
162
|
+
at: number;
|
|
163
|
+
attempt: number;
|
|
164
|
+
runId: string;
|
|
165
|
+
summary?: string;
|
|
166
|
+
terminalStatus?: "completed" | "failed";
|
|
167
|
+
} | {
|
|
137
168
|
kind: "started";
|
|
138
169
|
at: number;
|
|
139
170
|
message?: string;
|
|
@@ -233,9 +264,9 @@ export type PetLongTaskTransition = {
|
|
|
233
264
|
export declare function createPetLongTask(input: CreatePetLongTaskInput): PetLongTask;
|
|
234
265
|
/**
|
|
235
266
|
* Apply one durable transition. Terminal tasks only accept retry/cancel or a
|
|
236
|
-
* closure-delivery acknowledgement
|
|
237
|
-
*
|
|
238
|
-
* action such as pause or
|
|
267
|
+
* closure-delivery acknowledgement. A completed task can also record an explicit
|
|
268
|
+
* result update fenced to its current run and attempt. Late worker events cannot
|
|
269
|
+
* undo an explicit user action such as pause, cancel, or retry.
|
|
239
270
|
*/
|
|
240
271
|
export declare function transitionPetLongTask(current: PetLongTask, transition: PetLongTaskTransition): PetLongTask;
|
|
241
272
|
/** Defensive parser used by durable hosts. Invalid rows are dropped independently. */
|
|
@@ -269,3 +300,4 @@ export interface PetLongTaskContext {
|
|
|
269
300
|
/** Bounded task continuity injected into each Mimi manager turn. */
|
|
270
301
|
export declare function buildPetLongTaskContext(tasks: readonly PetLongTask[]): PetLongTaskContext;
|
|
271
302
|
export declare function petLongTaskResumePrompt(task: PetLongTask): string;
|
|
303
|
+
export {};
|
package/dist/long-task.js
CHANGED
|
@@ -159,6 +159,8 @@ export function createPetLongTask(input) {
|
|
|
159
159
|
status: "queued",
|
|
160
160
|
phase: "planning",
|
|
161
161
|
attempt: 1,
|
|
162
|
+
runId: input.runId,
|
|
163
|
+
clientMessageId: input.clientMessageId,
|
|
162
164
|
revision: 1,
|
|
163
165
|
createdAt: input.at,
|
|
164
166
|
updatedAt: input.at,
|
|
@@ -169,11 +171,26 @@ export function createPetLongTask(input) {
|
|
|
169
171
|
}
|
|
170
172
|
/**
|
|
171
173
|
* Apply one durable transition. Terminal tasks only accept retry/cancel or a
|
|
172
|
-
* closure-delivery acknowledgement
|
|
173
|
-
*
|
|
174
|
-
* action such as pause or
|
|
174
|
+
* closure-delivery acknowledgement. A completed task can also record an explicit
|
|
175
|
+
* result update fenced to its current run and attempt. Late worker events cannot
|
|
176
|
+
* undo an explicit user action such as pause, cancel, or retry.
|
|
175
177
|
*/
|
|
176
178
|
export function transitionPetLongTask(current, transition) {
|
|
179
|
+
if (transition.attempt !== undefined && transition.attempt !== current.attempt)
|
|
180
|
+
return current;
|
|
181
|
+
if (current.status === "paused" && transition.runId !== undefined)
|
|
182
|
+
return current;
|
|
183
|
+
if (transition.kind !== "run-bound" &&
|
|
184
|
+
transition.kind !== "run-prepared" &&
|
|
185
|
+
transition.kind !== "retrying" &&
|
|
186
|
+
((transition.runId !== undefined &&
|
|
187
|
+
(transition.runId !== current.runId ||
|
|
188
|
+
transition.clientMessageId !== current.clientMessageId)) ||
|
|
189
|
+
(transition.clientMessageId !== undefined &&
|
|
190
|
+
transition.clientMessageId !== current.clientMessageId)))
|
|
191
|
+
return current;
|
|
192
|
+
if (transition.kind === "result-updated" && (current.status !== "completed" || !current.runId))
|
|
193
|
+
return current;
|
|
177
194
|
if (transition.kind === "closure-decided" && current.closureDecision?.key === transition.key) {
|
|
178
195
|
return current;
|
|
179
196
|
}
|
|
@@ -202,6 +219,7 @@ export function transitionPetLongTask(current, transition) {
|
|
|
202
219
|
transition.kind !== "retrying" &&
|
|
203
220
|
transition.kind !== "cancelled" &&
|
|
204
221
|
transition.kind !== "background-wait-recovered" &&
|
|
222
|
+
transition.kind !== "result-updated" &&
|
|
205
223
|
transition.kind !== "closure-decided" &&
|
|
206
224
|
transition.kind !== "continuation-started" &&
|
|
207
225
|
transition.kind !== "closure-recorded" &&
|
|
@@ -231,6 +249,50 @@ export function transitionPetLongTask(current, transition) {
|
|
|
231
249
|
};
|
|
232
250
|
let event;
|
|
233
251
|
switch (transition.kind) {
|
|
252
|
+
case "run-prepared":
|
|
253
|
+
Object.assign(next, { runId: undefined, clientMessageId: transition.clientMessageId });
|
|
254
|
+
event = { kind: transition.kind, at: transition.at, message: "Preparing to continue work" };
|
|
255
|
+
break;
|
|
256
|
+
case "run-bound":
|
|
257
|
+
if (current.runId !== transition.previousRunId)
|
|
258
|
+
return current;
|
|
259
|
+
// A resume can prepare a different launch before a queued start is applied.
|
|
260
|
+
// Unbound launches share undefined previousRunId; the submit id is their CAS.
|
|
261
|
+
if (!current.runId &&
|
|
262
|
+
current.clientMessageId !== undefined &&
|
|
263
|
+
current.clientMessageId !== transition.clientMessageId)
|
|
264
|
+
return current;
|
|
265
|
+
if (current.runId === transition.runId)
|
|
266
|
+
return current;
|
|
267
|
+
Object.assign(next, {
|
|
268
|
+
runId: transition.runId,
|
|
269
|
+
clientMessageId: transition.clientMessageId,
|
|
270
|
+
status: "running",
|
|
271
|
+
phase: "executing",
|
|
272
|
+
resultSummary: undefined,
|
|
273
|
+
waitingFor: undefined,
|
|
274
|
+
});
|
|
275
|
+
event = { kind: transition.kind, at: transition.at, message: "Work session started" };
|
|
276
|
+
break;
|
|
277
|
+
case "result-updated": {
|
|
278
|
+
const summary = bounded(transition.summary, MAX_PET_LONG_TASK_SUMMARY_LENGTH);
|
|
279
|
+
const message = summary ?? current.resultSummary ?? "Work session result confirmed";
|
|
280
|
+
if (current.events.some((item) => item.kind === "result-updated" &&
|
|
281
|
+
item.runId === transition.runId &&
|
|
282
|
+
item.attempt === current.attempt) &&
|
|
283
|
+
(!summary || summary === current.resultSummary) &&
|
|
284
|
+
(!transition.terminalStatus || transition.terminalStatus === current.status))
|
|
285
|
+
return current;
|
|
286
|
+
Object.assign(next, {
|
|
287
|
+
status: transition.terminalStatus ?? current.status,
|
|
288
|
+
...(summary ? { resultSummary: summary, summary } : {}),
|
|
289
|
+
...(transition.terminalStatus === "failed"
|
|
290
|
+
? { lastError: summary, completedAt: transition.at }
|
|
291
|
+
: {}),
|
|
292
|
+
});
|
|
293
|
+
event = { kind: transition.kind, at: transition.at, phase: "finalizing", message };
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
234
296
|
case "started":
|
|
235
297
|
Object.assign(next, {
|
|
236
298
|
status: "running",
|
|
@@ -334,6 +396,8 @@ export function transitionPetLongTask(current, transition) {
|
|
|
334
396
|
status: "queued",
|
|
335
397
|
phase: "planning",
|
|
336
398
|
attempt: current.attempt + 1,
|
|
399
|
+
runId: undefined,
|
|
400
|
+
clientMessageId: transition.clientMessageId,
|
|
337
401
|
// A retry is a new attempt in the same durable Session. Keeping the
|
|
338
402
|
// previous attempt's start time would let an old projection terminal
|
|
339
403
|
// pass the new attempt's time fence.
|
|
@@ -593,7 +657,12 @@ export function transitionPetLongTask(current, transition) {
|
|
|
593
657
|
};
|
|
594
658
|
break;
|
|
595
659
|
}
|
|
596
|
-
next.events = appendEvent(current,
|
|
660
|
+
next.events = appendEvent(current, {
|
|
661
|
+
...event,
|
|
662
|
+
attempt: next.attempt,
|
|
663
|
+
runId: next.runId,
|
|
664
|
+
clientMessageId: next.clientMessageId,
|
|
665
|
+
});
|
|
597
666
|
return next;
|
|
598
667
|
}
|
|
599
668
|
function isStatus(value) {
|
|
@@ -618,6 +687,9 @@ function isEventKind(value) {
|
|
|
618
687
|
[
|
|
619
688
|
"created",
|
|
620
689
|
"started",
|
|
690
|
+
"run-bound",
|
|
691
|
+
"run-prepared",
|
|
692
|
+
"result-updated",
|
|
621
693
|
"progress",
|
|
622
694
|
"waiting",
|
|
623
695
|
"paused",
|
|
@@ -657,6 +729,19 @@ function parseEvent(value) {
|
|
|
657
729
|
sequence: event.sequence,
|
|
658
730
|
kind: event.kind,
|
|
659
731
|
at: event.at,
|
|
732
|
+
...(typeof event.attempt === "number" &&
|
|
733
|
+
Number.isSafeInteger(event.attempt) &&
|
|
734
|
+
event.attempt > 0
|
|
735
|
+
? { attempt: event.attempt }
|
|
736
|
+
: {}),
|
|
737
|
+
...(typeof event.runId === "string" && event.runId.length > 0 && event.runId.length <= 256
|
|
738
|
+
? { runId: event.runId }
|
|
739
|
+
: {}),
|
|
740
|
+
...(typeof event.clientMessageId === "string" &&
|
|
741
|
+
event.clientMessageId.length > 0 &&
|
|
742
|
+
event.clientMessageId.length <= 256
|
|
743
|
+
? { clientMessageId: event.clientMessageId }
|
|
744
|
+
: {}),
|
|
660
745
|
...(typeof event.message === "string" ? { message: bounded(event.message, 2_000) } : {}),
|
|
661
746
|
...(isPhase(event.phase) ? { phase: event.phase } : {}),
|
|
662
747
|
...(typeof event.waitingFor === "string" ? { waitingFor: bounded(event.waitingFor, 500) } : {}),
|
|
@@ -794,6 +879,14 @@ export function parsePetLongTask(value) {
|
|
|
794
879
|
status: record.status,
|
|
795
880
|
phase: record.phase,
|
|
796
881
|
attempt: record.attempt,
|
|
882
|
+
...(typeof record.runId === "string" && record.runId.length > 0 && record.runId.length <= 256
|
|
883
|
+
? { runId: record.runId }
|
|
884
|
+
: {}),
|
|
885
|
+
...(typeof record.clientMessageId === "string" &&
|
|
886
|
+
record.clientMessageId.length > 0 &&
|
|
887
|
+
record.clientMessageId.length <= 256
|
|
888
|
+
? { clientMessageId: record.clientMessageId }
|
|
889
|
+
: {}),
|
|
797
890
|
revision: record.revision,
|
|
798
891
|
createdAt: record.createdAt,
|
|
799
892
|
updatedAt: record.updatedAt,
|
|
@@ -75,6 +75,8 @@ export function createPetProjectionObserver(host) {
|
|
|
75
75
|
queueDepth: live.queueDepth,
|
|
76
76
|
lastActivityAt: Math.max(live.lastActivityAt, indexed?.lastActivityAt ?? 0),
|
|
77
77
|
pendingDecisionCount,
|
|
78
|
+
runId: indexed?.runId,
|
|
79
|
+
clientMessageId: indexed?.clientMessageId,
|
|
78
80
|
completionKind: liveRunState === "idle" ? indexed?.completionKind : undefined,
|
|
79
81
|
terminal,
|
|
80
82
|
freshness: { source: "live-snapshot", observedAt, workerState: "active" },
|
package/dist/session-index.js
CHANGED
|
@@ -54,6 +54,8 @@ function baseProjection(catalog, observedAt, workerState) {
|
|
|
54
54
|
owner: LOCAL_PET_OWNER,
|
|
55
55
|
agentSessionId: catalog.sessionId,
|
|
56
56
|
coreSessionId: catalog.sessionId,
|
|
57
|
+
runId: catalog.runId,
|
|
58
|
+
clientMessageId: catalog.clientMessageId,
|
|
57
59
|
title: catalog.title,
|
|
58
60
|
workspaceDisplayName: catalog.workspaceDisplayName,
|
|
59
61
|
runState: status ? "terminal" : "dormant",
|
|
@@ -68,7 +70,14 @@ function baseProjection(catalog, observedAt, workerState) {
|
|
|
68
70
|
: completionKind === "limit_stop"
|
|
69
71
|
? "已到运行限制"
|
|
70
72
|
: undefined,
|
|
71
|
-
terminal: status
|
|
73
|
+
terminal: status
|
|
74
|
+
? {
|
|
75
|
+
status,
|
|
76
|
+
at: catalog.updatedAt,
|
|
77
|
+
runId: catalog.runId,
|
|
78
|
+
clientMessageId: catalog.clientMessageId,
|
|
79
|
+
}
|
|
80
|
+
: undefined,
|
|
72
81
|
freshness: { source: "disk", observedAt, workerState },
|
|
73
82
|
};
|
|
74
83
|
}
|
|
@@ -261,12 +270,44 @@ export class SessionIndex {
|
|
|
261
270
|
return true;
|
|
262
271
|
}
|
|
263
272
|
reduceEvent(current, event, observedAt) {
|
|
273
|
+
if ("agentId" in event && event.agentId !== undefined) {
|
|
274
|
+
// Child activity is useful progress, but cannot change the parent's lifecycle.
|
|
275
|
+
if (event.type === "turn_complete" || event.type === "error")
|
|
276
|
+
return current;
|
|
277
|
+
return {
|
|
278
|
+
...current,
|
|
279
|
+
lastActivityAt: observedAt,
|
|
280
|
+
summary: event.type === "tool_use_start"
|
|
281
|
+
? `正在运行 ${safeToolName(event.toolCall.toolName)}`.slice(0, 64)
|
|
282
|
+
: current.summary,
|
|
283
|
+
freshness: { source: "live-event", observedAt, workerState: "active" },
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
if (event.type !== "session_started" &&
|
|
287
|
+
current.runId &&
|
|
288
|
+
(event.runId !== current.runId || event.clientMessageId !== current.clientMessageId)) {
|
|
289
|
+
return current;
|
|
290
|
+
}
|
|
264
291
|
const next = {
|
|
265
292
|
...current,
|
|
266
293
|
lastActivityAt: observedAt,
|
|
267
294
|
freshness: { source: "live-event", observedAt, workerState: "active" },
|
|
268
295
|
};
|
|
269
296
|
switch (event.type) {
|
|
297
|
+
case "session_started":
|
|
298
|
+
if (current.runId &&
|
|
299
|
+
(event.runId === current.runId || event.previousRunId !== current.runId))
|
|
300
|
+
return current;
|
|
301
|
+
return {
|
|
302
|
+
...next,
|
|
303
|
+
runId: event.runId,
|
|
304
|
+
clientMessageId: event.clientMessageId,
|
|
305
|
+
runState: "running",
|
|
306
|
+
phase: "model",
|
|
307
|
+
summary: "模型处理中",
|
|
308
|
+
completionKind: undefined,
|
|
309
|
+
terminal: undefined,
|
|
310
|
+
};
|
|
270
311
|
case "stream_request_start":
|
|
271
312
|
return {
|
|
272
313
|
...next,
|
|
@@ -322,7 +363,14 @@ export class SessionIndex {
|
|
|
322
363
|
? "本轮已完成"
|
|
323
364
|
: "运行已结束",
|
|
324
365
|
completionKind: undefined,
|
|
325
|
-
terminal: current.queueDepth > 0
|
|
366
|
+
terminal: current.queueDepth > 0
|
|
367
|
+
? undefined
|
|
368
|
+
: {
|
|
369
|
+
status,
|
|
370
|
+
at: observedAt,
|
|
371
|
+
runId: current.runId,
|
|
372
|
+
clientMessageId: current.clientMessageId,
|
|
373
|
+
},
|
|
326
374
|
};
|
|
327
375
|
}
|
|
328
376
|
case "error":
|
|
@@ -332,7 +380,12 @@ export class SessionIndex {
|
|
|
332
380
|
phase: "finalizing",
|
|
333
381
|
summary: "运行失败",
|
|
334
382
|
completionKind: undefined,
|
|
335
|
-
terminal: {
|
|
383
|
+
terminal: {
|
|
384
|
+
status: "failed",
|
|
385
|
+
at: observedAt,
|
|
386
|
+
runId: current.runId,
|
|
387
|
+
clientMessageId: current.clientMessageId,
|
|
388
|
+
},
|
|
336
389
|
};
|
|
337
390
|
default:
|
|
338
391
|
return next;
|
package/dist/types.d.ts
CHANGED
|
@@ -27,16 +27,22 @@ export interface PetSessionProjection {
|
|
|
27
27
|
queueDepth: number;
|
|
28
28
|
lastActivityAt: number;
|
|
29
29
|
pendingDecisionCount: number;
|
|
30
|
+
runId?: string;
|
|
31
|
+
clientMessageId?: string;
|
|
30
32
|
/** Exceptional completed-run boundary that is waiting for recovery/continuation. */
|
|
31
33
|
completionKind?: TurnCompletionKind;
|
|
32
34
|
terminal?: {
|
|
33
35
|
status: PetTerminalStatus;
|
|
34
36
|
at: number;
|
|
37
|
+
runId?: string;
|
|
38
|
+
clientMessageId?: string;
|
|
35
39
|
};
|
|
36
40
|
freshness: PetProjectionFreshness;
|
|
37
41
|
}
|
|
38
42
|
export interface PetCatalogSession {
|
|
39
43
|
sessionId: string;
|
|
44
|
+
runId?: string;
|
|
45
|
+
clientMessageId?: string;
|
|
40
46
|
title?: string;
|
|
41
47
|
workspaceDisplayName?: string;
|
|
42
48
|
updatedAt: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cjhyy/code-shell-pet",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.10",
|
|
4
4
|
"description": "Pet (top-level personal assistant) capability for CodeShell — projection state machine, DelegateWork contract, Mimi behavior profile.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@cjhyy/code-shell-core": "0.9.
|
|
39
|
+
"@cjhyy/code-shell-core": "0.9.10"
|
|
40
40
|
},
|
|
41
41
|
"engines": {
|
|
42
42
|
"node": ">=20.10"
|