@bridge4dev/runner 0.60.0 → 0.61.0
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/adapters/claude.js +72 -13
- package/dist/adapters/codex.js +22 -2
- package/dist/adapters/questions.js +1 -0
- package/dist/adapters/types.d.ts +42 -1
- package/dist/journal.d.ts +40 -0
- package/dist/journal.js +82 -0
- package/dist/protocol.d.ts +52 -0
- package/dist/protocol.js +14 -0
- package/dist/supervisor.d.ts +87 -2
- package/dist/supervisor.js +493 -88
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/adapters/claude.js
CHANGED
|
@@ -2180,6 +2180,65 @@ class ClaudeSession {
|
|
|
2180
2180
|
conversationAnchor() {
|
|
2181
2181
|
return this.lastMessageUuid;
|
|
2182
2182
|
}
|
|
2183
|
+
/** A compaction the CLI has announced and not yet ended (#348). */
|
|
2184
|
+
compacting = false;
|
|
2185
|
+
/**
|
|
2186
|
+
* `system:status` — the CLI's own word on what it is doing (#348).
|
|
2187
|
+
*
|
|
2188
|
+
* Read the way the CLI's own remote client reads it (`noteInbound`):
|
|
2189
|
+
* «compacting» opens a compaction, `requesting` says nothing about one (the
|
|
2190
|
+
* summary itself is a model request, and this status arrives DURING a
|
|
2191
|
+
* compaction), and any other status closes it — with `compact_result` when
|
|
2192
|
+
* the CLI says how it went, and as «skipped» when it does not: a PreCompact
|
|
2193
|
+
* hook that said no, or a reactive compaction that found nothing to fold,
|
|
2194
|
+
* both end on a bare `status: null`. Left unclosed, that start line would
|
|
2195
|
+
* keep the dashboard saying «compacting» until the turn ended, minutes later.
|
|
2196
|
+
*
|
|
2197
|
+
* De-duplicated here as well as in the supervisor: the CLI re-says
|
|
2198
|
+
* «compacting» every thirty seconds while it waits on a precomputed summary.
|
|
2199
|
+
*
|
|
2200
|
+
* No `standalone` on this agent: `/compact` is a turn, and its `result`
|
|
2201
|
+
* settles the status the ordinary way.
|
|
2202
|
+
*/
|
|
2203
|
+
noteStatus(msg) {
|
|
2204
|
+
const status = msg.status;
|
|
2205
|
+
if (status === 'requesting')
|
|
2206
|
+
return;
|
|
2207
|
+
if (status === 'compacting') {
|
|
2208
|
+
if (this.compacting)
|
|
2209
|
+
return;
|
|
2210
|
+
this.compacting = true;
|
|
2211
|
+
this.emit({ type: 'compaction', phase: 'started' });
|
|
2212
|
+
return;
|
|
2213
|
+
}
|
|
2214
|
+
// An end is only an end of something that began: without a start on
|
|
2215
|
+
// record there is nothing to close, and the second of two endings (a
|
|
2216
|
+
// `compact_result` after a `compact_boundary`) must not open a second
|
|
2217
|
+
// pair. A mode change also travels on this message — `{status: null,
|
|
2218
|
+
// permissionMode}` on every `setPermissionMode` in CLI 2.1.271 — and says
|
|
2219
|
+
// nothing about a compaction at all.
|
|
2220
|
+
if (!this.compacting)
|
|
2221
|
+
return;
|
|
2222
|
+
const compactResult = msg.compact_result;
|
|
2223
|
+
if (compactResult === undefined && msg.permissionMode !== undefined)
|
|
2224
|
+
return;
|
|
2225
|
+
this.compacting = false;
|
|
2226
|
+
if (compactResult === 'failed') {
|
|
2227
|
+
this.emit({
|
|
2228
|
+
type: 'compaction',
|
|
2229
|
+
phase: 'finished',
|
|
2230
|
+
ok: false,
|
|
2231
|
+
error: maskString(String(msg.compact_error ?? 'unknown')).slice(0, 300),
|
|
2232
|
+
});
|
|
2233
|
+
return;
|
|
2234
|
+
}
|
|
2235
|
+
this.emit({
|
|
2236
|
+
type: 'compaction',
|
|
2237
|
+
phase: 'finished',
|
|
2238
|
+
ok: true,
|
|
2239
|
+
...(compactResult === 'success' ? {} : { skipped: true }),
|
|
2240
|
+
});
|
|
2241
|
+
}
|
|
2183
2242
|
/**
|
|
2184
2243
|
* `/compact` — the CLI's own command, delivered as ordinary user input.
|
|
2185
2244
|
*
|
|
@@ -2296,19 +2355,15 @@ class ClaudeSession {
|
|
|
2296
2355
|
this.refreshUsage();
|
|
2297
2356
|
}
|
|
2298
2357
|
else if (msg.subtype === 'status') {
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
text: compactResult === 'failed'
|
|
2309
|
-
? `Compaction failed: ${maskString(String(msg.compact_error ?? 'unknown')).slice(0, 300)}`
|
|
2310
|
-
: 'Conversation compacted',
|
|
2311
|
-
});
|
|
2358
|
+
this.noteStatus(msg);
|
|
2359
|
+
}
|
|
2360
|
+
else if (msg.subtype === 'compact_boundary') {
|
|
2361
|
+
// The summary is in place: this marker is the end of a
|
|
2362
|
+
// compaction whether or not a status said so first (#348) — the
|
|
2363
|
+
// CLI's own remote client reads it the same way.
|
|
2364
|
+
if (this.compacting) {
|
|
2365
|
+
this.compacting = false;
|
|
2366
|
+
this.emit({ type: 'compaction', phase: 'finished', ok: true });
|
|
2312
2367
|
}
|
|
2313
2368
|
}
|
|
2314
2369
|
else if (msg.subtype === 'api_retry') {
|
|
@@ -2440,6 +2495,10 @@ class ClaudeSession {
|
|
|
2440
2495
|
break;
|
|
2441
2496
|
}
|
|
2442
2497
|
case 'result': {
|
|
2498
|
+
// A turn's end is the end of any compaction it carried (#348):
|
|
2499
|
+
// the supervisor closes the pair on `turn_end`, and the flag here
|
|
2500
|
+
// has to agree, or the next «compacting» would be read as a repeat.
|
|
2501
|
+
this.compacting = false;
|
|
2443
2502
|
this.emit({
|
|
2444
2503
|
type: 'cost',
|
|
2445
2504
|
costUsd: msg.total_cost_usd,
|
package/dist/adapters/codex.js
CHANGED
|
@@ -876,6 +876,7 @@ class CodexSession {
|
|
|
876
876
|
return false;
|
|
877
877
|
try {
|
|
878
878
|
await this.client.request('thread/compact/start', { threadId: this.threadId });
|
|
879
|
+
this.requestedCompaction = true;
|
|
879
880
|
return true;
|
|
880
881
|
}
|
|
881
882
|
catch (error) {
|
|
@@ -883,6 +884,14 @@ class CodexSession {
|
|
|
883
884
|
return false;
|
|
884
885
|
}
|
|
885
886
|
}
|
|
887
|
+
/**
|
|
888
|
+
* A compaction THIS adapter asked for with `thread/compact/start` (#348) —
|
|
889
|
+
* the one kind that runs outside any turn and therefore has nothing to
|
|
890
|
+
* settle the session status behind it. The agent's own compaction inside a
|
|
891
|
+
* turn is not it, even when its item happens to complete before the
|
|
892
|
+
* `turn/started` that announces the turn.
|
|
893
|
+
*/
|
|
894
|
+
requestedCompaction = false;
|
|
886
895
|
stop(reason = 'session_stopped') {
|
|
887
896
|
if (this.stopped)
|
|
888
897
|
return;
|
|
@@ -1472,8 +1481,19 @@ class CodexSession {
|
|
|
1472
1481
|
return;
|
|
1473
1482
|
}
|
|
1474
1483
|
case 'contextCompaction': {
|
|
1475
|
-
|
|
1476
|
-
|
|
1484
|
+
// #348: an event, not a notice — see `AgentEvent['compaction']`. A
|
|
1485
|
+
// compaction started from the dashboard runs outside any turn on this
|
|
1486
|
+
// agent (`thread/compact/start` creates none), so nothing will settle
|
|
1487
|
+
// the status behind it; `standalone` tells the supervisor to.
|
|
1488
|
+
if (method === 'item/started') {
|
|
1489
|
+
this.emit({ type: 'compaction', phase: 'started' });
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1492
|
+
if (done) {
|
|
1493
|
+
const standalone = this.requestedCompaction && this.activeTurnId === null;
|
|
1494
|
+
this.requestedCompaction = false;
|
|
1495
|
+
this.emit({ type: 'compaction', phase: 'finished', ok: true, standalone });
|
|
1496
|
+
}
|
|
1477
1497
|
return;
|
|
1478
1498
|
}
|
|
1479
1499
|
case 'webSearch':
|
|
@@ -110,6 +110,7 @@ const INVALIDATION_PHRASES = {
|
|
|
110
110
|
turn_aborted: 'the turn was interrupted',
|
|
111
111
|
agent_cancelled: 'the agent withdrew it',
|
|
112
112
|
budget_spent: 'the session ran out of its allowed working time',
|
|
113
|
+
not_held: 'the agent no longer holds this question',
|
|
113
114
|
};
|
|
114
115
|
/** The question was taken away from the user — say why, never fake an answer. */
|
|
115
116
|
export function invalidationMessage(reason) {
|
package/dist/adapters/types.d.ts
CHANGED
|
@@ -366,7 +366,16 @@ export interface AgentQuestionAnswer {
|
|
|
366
366
|
notes?: string;
|
|
367
367
|
}
|
|
368
368
|
/** Why a question was taken away from the user without them answering it. */
|
|
369
|
-
export type QuestionInvalidationReason = 'session_stopped' | 'session_parked' | 'runner_restarted' | 'turn_aborted' | 'agent_cancelled' | 'budget_spent'
|
|
369
|
+
export type QuestionInvalidationReason = 'session_stopped' | 'session_parked' | 'runner_restarted' | 'turn_aborted' | 'agent_cancelled' | 'budget_spent'
|
|
370
|
+
/**
|
|
371
|
+
* An answer arrived for a card no live process holds (#392): the card
|
|
372
|
+
* outlived the process that asked, or the ask was withdrawn before the
|
|
373
|
+
* answer got here. The runner does not know which, and says only what it
|
|
374
|
+
* does know. Never handed to an agent — there is no agent holding the ask
|
|
375
|
+
* to hand it to — so its phrase in `INVALIDATION_PHRASES` is for the type
|
|
376
|
+
* checker; the words a person reads are the dashboard's.
|
|
377
|
+
*/
|
|
378
|
+
| 'not_held';
|
|
370
379
|
/** The dashboard's answer to one open ask. */
|
|
371
380
|
export interface QuestionReply {
|
|
372
381
|
askId: string;
|
|
@@ -502,6 +511,38 @@ export type AgentEvent = {
|
|
|
502
511
|
type: 'notice';
|
|
503
512
|
level: 'info' | 'warn';
|
|
504
513
|
text: string;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* The conversation is being folded into a summary, or just was (#348).
|
|
517
|
+
*
|
|
518
|
+
* Its own event and not a `notice` on purpose: adapter notices are
|
|
519
|
+
* de-duplicated per session on their text (gotcha §148), so «Conversation
|
|
520
|
+
* compacted» reached the feed once and every later compaction was silence.
|
|
521
|
+
* A compaction is a fact the feed has to hear every time — the dashboard's
|
|
522
|
+
* «compacting…» indicator is read off the feed, and a second compaction
|
|
523
|
+
* with no lines is a second compaction the person cannot see end.
|
|
524
|
+
*
|
|
525
|
+
* `standalone` on the ending: `true` when NO turn is going to close behind
|
|
526
|
+
* this compaction, so the supervisor has to settle the session status
|
|
527
|
+
* itself. Codex runs a compaction started from the dashboard outside any
|
|
528
|
+
* turn (`thread/compact/start`); Claude delivers `/compact` as a turn, and
|
|
529
|
+
* that turn's own ending settles the status the ordinary way.
|
|
530
|
+
*/
|
|
531
|
+
| {
|
|
532
|
+
type: 'compaction';
|
|
533
|
+
phase: 'started';
|
|
534
|
+
} | {
|
|
535
|
+
type: 'compaction';
|
|
536
|
+
phase: 'finished';
|
|
537
|
+
ok: boolean;
|
|
538
|
+
error?: string;
|
|
539
|
+
standalone?: boolean;
|
|
540
|
+
/**
|
|
541
|
+
* It ended without a summary: the CLI decided not to compact after all
|
|
542
|
+
* (a PreCompact hook said no, or it found nothing worth folding). Not a
|
|
543
|
+
* failure — nothing broke — and not a compaction either.
|
|
544
|
+
*/
|
|
545
|
+
skipped?: boolean;
|
|
505
546
|
} | {
|
|
506
547
|
type: 'cost';
|
|
507
548
|
costUsd: number;
|
package/dist/journal.d.ts
CHANGED
|
@@ -58,6 +58,23 @@ export declare class SessionJournal {
|
|
|
58
58
|
anchor: string;
|
|
59
59
|
providerSessionId: string;
|
|
60
60
|
} | null;
|
|
61
|
+
/**
|
|
62
|
+
* Every card this journal has published, and whether it is still open —
|
|
63
|
+
* in the order they were asked (#392).
|
|
64
|
+
*
|
|
65
|
+
* The persistent twin of the supervisor's `running.openQuestions`: that set
|
|
66
|
+
* dies with the process, and a process that dies ungracefully never gets to
|
|
67
|
+
* `shutdown()`, which is the only place it withdraws them. This one is
|
|
68
|
+
* rebuilt from the file, so the next process can close what the last one
|
|
69
|
+
* left open — the card in the browser does not know the runner restarted.
|
|
70
|
+
*
|
|
71
|
+
* Closed cards are remembered too, not only dropped: «this card was closed
|
|
72
|
+
* by somebody» is the fact that stops a SECOND tombstone. A queued answer
|
|
73
|
+
* that reaches the next process after a restore has already closed the card
|
|
74
|
+
* must rescue the words and say nothing more about the card — and the only
|
|
75
|
+
* witness that the card was closed is this file.
|
|
76
|
+
*/
|
|
77
|
+
private readonly asks;
|
|
61
78
|
constructor(sessionId: string, dir?: string);
|
|
62
79
|
private replay;
|
|
63
80
|
private write;
|
|
@@ -86,6 +103,29 @@ export declare class SessionJournal {
|
|
|
86
103
|
recordStatus(status: string, extra?: Record<string, unknown>, epoch?: number): void;
|
|
87
104
|
/** Assign the next seq and persist the event before it is sent. */
|
|
88
105
|
append(eventType: string, payload: Record<string, unknown>): JournalEvent;
|
|
106
|
+
/**
|
|
107
|
+
* Keep `openAsks` in step with the cards going out through `append` (#392).
|
|
108
|
+
*
|
|
109
|
+
* Here and not in the supervisor, because `append` is the one door every
|
|
110
|
+
* event takes: a card that was published was published through it, and so
|
|
111
|
+
* was every resolution — the adapter's own, `withdrawOpenQuestions`, the
|
|
112
|
+
* `not_open` miss. A set kept beside the callers would need every one of
|
|
113
|
+
* them to remember it, which is exactly how the in-memory set came to be
|
|
114
|
+
* empty at the moment it was needed.
|
|
115
|
+
*
|
|
116
|
+
* A resolution for a card this journal never published writes nothing:
|
|
117
|
+
* there is nothing to close, and remembering strangers would only grow the
|
|
118
|
+
* file.
|
|
119
|
+
*/
|
|
120
|
+
private trackAsk;
|
|
121
|
+
/** The cards still waiting on a person, oldest first (#392). */
|
|
122
|
+
openAskIds(): string[];
|
|
123
|
+
/**
|
|
124
|
+
* What this journal knows about one card (#392): `open`, `closed`, or
|
|
125
|
+
* nothing at all — a card asked by a runner from before these lines existed,
|
|
126
|
+
* or one this state directory never saw.
|
|
127
|
+
*/
|
|
128
|
+
askState(askId: string): 'open' | 'closed' | undefined;
|
|
89
129
|
/**
|
|
90
130
|
* Never reuse a seq the API already stored: after a runner state-dir wipe the
|
|
91
131
|
* local counter restarts at 1 and every replayed event would collide with an
|
package/dist/journal.js
CHANGED
|
@@ -21,6 +21,23 @@ export class SessionJournal {
|
|
|
21
21
|
lastStatus = null;
|
|
22
22
|
/** The agent's conversation tip, and the provider session it lives in. */
|
|
23
23
|
lastAnchor = null;
|
|
24
|
+
/**
|
|
25
|
+
* Every card this journal has published, and whether it is still open —
|
|
26
|
+
* in the order they were asked (#392).
|
|
27
|
+
*
|
|
28
|
+
* The persistent twin of the supervisor's `running.openQuestions`: that set
|
|
29
|
+
* dies with the process, and a process that dies ungracefully never gets to
|
|
30
|
+
* `shutdown()`, which is the only place it withdraws them. This one is
|
|
31
|
+
* rebuilt from the file, so the next process can close what the last one
|
|
32
|
+
* left open — the card in the browser does not know the runner restarted.
|
|
33
|
+
*
|
|
34
|
+
* Closed cards are remembered too, not only dropped: «this card was closed
|
|
35
|
+
* by somebody» is the fact that stops a SECOND tombstone. A queued answer
|
|
36
|
+
* that reaches the next process after a restore has already closed the card
|
|
37
|
+
* must rescue the words and say nothing more about the card — and the only
|
|
38
|
+
* witness that the card was closed is this file.
|
|
39
|
+
*/
|
|
40
|
+
asks = new Map();
|
|
24
41
|
constructor(sessionId, dir = journalDir()) {
|
|
25
42
|
this.sessionId = sessionId;
|
|
26
43
|
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
@@ -50,6 +67,16 @@ export class SessionJournal {
|
|
|
50
67
|
});
|
|
51
68
|
if (parsed.seq >= this.nextSeq)
|
|
52
69
|
this.nextSeq = parsed.seq + 1;
|
|
70
|
+
// The event lines carry the same fact as `ask_open`/`ask_closed`, and
|
|
71
|
+
// replaying both is harmless: the set is a set.
|
|
72
|
+
this.trackAsk(parsed.eventType, parsed.payload, false);
|
|
73
|
+
}
|
|
74
|
+
else if (parsed.kind === 'ask_open') {
|
|
75
|
+
if (this.asks.get(parsed.askId) !== 'closed')
|
|
76
|
+
this.asks.set(parsed.askId, 'open');
|
|
77
|
+
}
|
|
78
|
+
else if (parsed.kind === 'ask_closed') {
|
|
79
|
+
this.asks.set(parsed.askId, 'closed');
|
|
53
80
|
}
|
|
54
81
|
else if (parsed.kind === 'ack') {
|
|
55
82
|
this.unackedBySeq.delete(parsed.seq);
|
|
@@ -107,6 +134,11 @@ export class SessionJournal {
|
|
|
107
134
|
if (this.lastAnchor) {
|
|
108
135
|
lines.push({ kind: 'anchor', ...this.lastAnchor });
|
|
109
136
|
}
|
|
137
|
+
// AFTER the event lines: an unacked `question` re-written above would
|
|
138
|
+
// otherwise reopen, on the next replay, a card these lines say is closed.
|
|
139
|
+
for (const [askId, state] of this.asks) {
|
|
140
|
+
lines.push({ kind: state === 'open' ? 'ask_open' : 'ask_closed', askId });
|
|
141
|
+
}
|
|
110
142
|
if (this.lastStatus) {
|
|
111
143
|
lines.push({
|
|
112
144
|
kind: 'status',
|
|
@@ -182,8 +214,58 @@ export class SessionJournal {
|
|
|
182
214
|
const event = { seq: this.nextSeq++, eventType, payload };
|
|
183
215
|
this.write({ kind: 'event', ...event, ts: new Date().toISOString() });
|
|
184
216
|
this.unackedBySeq.set(event.seq, event);
|
|
217
|
+
this.trackAsk(eventType, payload, true);
|
|
185
218
|
return event;
|
|
186
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Keep `openAsks` in step with the cards going out through `append` (#392).
|
|
222
|
+
*
|
|
223
|
+
* Here and not in the supervisor, because `append` is the one door every
|
|
224
|
+
* event takes: a card that was published was published through it, and so
|
|
225
|
+
* was every resolution — the adapter's own, `withdrawOpenQuestions`, the
|
|
226
|
+
* `not_open` miss. A set kept beside the callers would need every one of
|
|
227
|
+
* them to remember it, which is exactly how the in-memory set came to be
|
|
228
|
+
* empty at the moment it was needed.
|
|
229
|
+
*
|
|
230
|
+
* A resolution for a card this journal never published writes nothing:
|
|
231
|
+
* there is nothing to close, and remembering strangers would only grow the
|
|
232
|
+
* file.
|
|
233
|
+
*/
|
|
234
|
+
trackAsk(eventType, payload, persist) {
|
|
235
|
+
if (eventType !== 'question' && eventType !== 'question_resolved')
|
|
236
|
+
return;
|
|
237
|
+
const askId = payload['askId'];
|
|
238
|
+
if (typeof askId !== 'string' || !askId)
|
|
239
|
+
return;
|
|
240
|
+
const state = this.asks.get(askId);
|
|
241
|
+
if (eventType === 'question') {
|
|
242
|
+
// A card is asked once; a replayed event line for one already closed
|
|
243
|
+
// (compaction keeps unacked events) must not reopen it.
|
|
244
|
+
if (state !== undefined)
|
|
245
|
+
return;
|
|
246
|
+
this.asks.set(askId, 'open');
|
|
247
|
+
if (persist)
|
|
248
|
+
this.write({ kind: 'ask_open', askId });
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (state !== 'open')
|
|
252
|
+
return;
|
|
253
|
+
this.asks.set(askId, 'closed');
|
|
254
|
+
if (persist)
|
|
255
|
+
this.write({ kind: 'ask_closed', askId });
|
|
256
|
+
}
|
|
257
|
+
/** The cards still waiting on a person, oldest first (#392). */
|
|
258
|
+
openAskIds() {
|
|
259
|
+
return [...this.asks].filter(([, state]) => state === 'open').map(([askId]) => askId);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* What this journal knows about one card (#392): `open`, `closed`, or
|
|
263
|
+
* nothing at all — a card asked by a runner from before these lines existed,
|
|
264
|
+
* or one this state directory never saw.
|
|
265
|
+
*/
|
|
266
|
+
askState(askId) {
|
|
267
|
+
return this.asks.get(askId);
|
|
268
|
+
}
|
|
187
269
|
/**
|
|
188
270
|
* Never reuse a seq the API already stored: after a runner state-dir wipe the
|
|
189
271
|
* local counter restarts at 1 and every replayed event would collide with an
|
package/dist/protocol.d.ts
CHANGED
|
@@ -32,6 +32,20 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
|
|
|
32
32
|
* behaviour every runner had before this release.
|
|
33
33
|
*/
|
|
34
34
|
pausedUntil: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
35
|
+
/**
|
|
36
|
+
* Subagents the API still believes to be alive in this session (#393).
|
|
37
|
+
*
|
|
38
|
+
* The number is the dead process's last word, kept by the API: a runner
|
|
39
|
+
* restart takes every subagent with it, and the new process seeds its own
|
|
40
|
+
* count at zero — so the descriptor is the only place the number survives
|
|
41
|
+
* long enough to be written down. The API sends it only while it still
|
|
42
|
+
* believes it (its own trust window on the count's age); absent or zero
|
|
43
|
+
* means «nothing to say», and a restore says nothing.
|
|
44
|
+
*
|
|
45
|
+
* `.catch(undefined)` like its neighbours: one malformed value must cost
|
|
46
|
+
* its own session a line at most, never the frame (QA-100 MAJOR-1).
|
|
47
|
+
*/
|
|
48
|
+
backgroundTasks: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
|
|
35
49
|
/**
|
|
36
50
|
* The newest published version of THIS session's agent — Р13, §4.8.
|
|
37
51
|
*
|
|
@@ -246,6 +260,7 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
|
|
|
246
260
|
} | undefined;
|
|
247
261
|
workMode?: "DIRECT" | "BRANCH" | undefined;
|
|
248
262
|
pausedUntil?: string | null | undefined;
|
|
263
|
+
backgroundTasks?: number | undefined;
|
|
249
264
|
agentLatestVersion?: string | undefined;
|
|
250
265
|
skipAgentPrompt?: boolean | undefined;
|
|
251
266
|
branchHint?: string | undefined;
|
|
@@ -295,6 +310,7 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
|
|
|
295
310
|
activeMsBase?: number | undefined;
|
|
296
311
|
extraBudgetMinutes?: number | null | undefined;
|
|
297
312
|
pausedUntil?: unknown;
|
|
313
|
+
backgroundTasks?: unknown;
|
|
298
314
|
agentLatestVersion?: unknown;
|
|
299
315
|
skipAgentPrompt?: unknown;
|
|
300
316
|
branchHint?: unknown;
|
|
@@ -450,6 +466,20 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
450
466
|
* behaviour every runner had before this release.
|
|
451
467
|
*/
|
|
452
468
|
pausedUntil: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
469
|
+
/**
|
|
470
|
+
* Subagents the API still believes to be alive in this session (#393).
|
|
471
|
+
*
|
|
472
|
+
* The number is the dead process's last word, kept by the API: a runner
|
|
473
|
+
* restart takes every subagent with it, and the new process seeds its own
|
|
474
|
+
* count at zero — so the descriptor is the only place the number survives
|
|
475
|
+
* long enough to be written down. The API sends it only while it still
|
|
476
|
+
* believes it (its own trust window on the count's age); absent or zero
|
|
477
|
+
* means «nothing to say», and a restore says nothing.
|
|
478
|
+
*
|
|
479
|
+
* `.catch(undefined)` like its neighbours: one malformed value must cost
|
|
480
|
+
* its own session a line at most, never the frame (QA-100 MAJOR-1).
|
|
481
|
+
*/
|
|
482
|
+
backgroundTasks: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
|
|
453
483
|
/**
|
|
454
484
|
* The newest published version of THIS session's agent — Р13, §4.8.
|
|
455
485
|
*
|
|
@@ -664,6 +694,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
664
694
|
} | undefined;
|
|
665
695
|
workMode?: "DIRECT" | "BRANCH" | undefined;
|
|
666
696
|
pausedUntil?: string | null | undefined;
|
|
697
|
+
backgroundTasks?: number | undefined;
|
|
667
698
|
agentLatestVersion?: string | undefined;
|
|
668
699
|
skipAgentPrompt?: boolean | undefined;
|
|
669
700
|
branchHint?: string | undefined;
|
|
@@ -713,6 +744,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
713
744
|
activeMsBase?: number | undefined;
|
|
714
745
|
extraBudgetMinutes?: number | null | undefined;
|
|
715
746
|
pausedUntil?: unknown;
|
|
747
|
+
backgroundTasks?: unknown;
|
|
716
748
|
agentLatestVersion?: unknown;
|
|
717
749
|
skipAgentPrompt?: unknown;
|
|
718
750
|
branchHint?: unknown;
|
|
@@ -759,6 +791,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
759
791
|
} | undefined;
|
|
760
792
|
workMode?: "DIRECT" | "BRANCH" | undefined;
|
|
761
793
|
pausedUntil?: string | null | undefined;
|
|
794
|
+
backgroundTasks?: number | undefined;
|
|
762
795
|
agentLatestVersion?: string | undefined;
|
|
763
796
|
skipAgentPrompt?: boolean | undefined;
|
|
764
797
|
branchHint?: string | undefined;
|
|
@@ -814,6 +847,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
814
847
|
activeMsBase?: number | undefined;
|
|
815
848
|
extraBudgetMinutes?: number | null | undefined;
|
|
816
849
|
pausedUntil?: unknown;
|
|
850
|
+
backgroundTasks?: unknown;
|
|
817
851
|
agentLatestVersion?: unknown;
|
|
818
852
|
skipAgentPrompt?: unknown;
|
|
819
853
|
branchHint?: unknown;
|
|
@@ -883,6 +917,20 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
883
917
|
* behaviour every runner had before this release.
|
|
884
918
|
*/
|
|
885
919
|
pausedUntil: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
920
|
+
/**
|
|
921
|
+
* Subagents the API still believes to be alive in this session (#393).
|
|
922
|
+
*
|
|
923
|
+
* The number is the dead process's last word, kept by the API: a runner
|
|
924
|
+
* restart takes every subagent with it, and the new process seeds its own
|
|
925
|
+
* count at zero — so the descriptor is the only place the number survives
|
|
926
|
+
* long enough to be written down. The API sends it only while it still
|
|
927
|
+
* believes it (its own trust window on the count's age); absent or zero
|
|
928
|
+
* means «nothing to say», and a restore says nothing.
|
|
929
|
+
*
|
|
930
|
+
* `.catch(undefined)` like its neighbours: one malformed value must cost
|
|
931
|
+
* its own session a line at most, never the frame (QA-100 MAJOR-1).
|
|
932
|
+
*/
|
|
933
|
+
backgroundTasks: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
|
|
886
934
|
/**
|
|
887
935
|
* The newest published version of THIS session's agent — Р13, §4.8.
|
|
888
936
|
*
|
|
@@ -1097,6 +1145,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1097
1145
|
} | undefined;
|
|
1098
1146
|
workMode?: "DIRECT" | "BRANCH" | undefined;
|
|
1099
1147
|
pausedUntil?: string | null | undefined;
|
|
1148
|
+
backgroundTasks?: number | undefined;
|
|
1100
1149
|
agentLatestVersion?: string | undefined;
|
|
1101
1150
|
skipAgentPrompt?: boolean | undefined;
|
|
1102
1151
|
branchHint?: string | undefined;
|
|
@@ -1146,6 +1195,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1146
1195
|
activeMsBase?: number | undefined;
|
|
1147
1196
|
extraBudgetMinutes?: number | null | undefined;
|
|
1148
1197
|
pausedUntil?: unknown;
|
|
1198
|
+
backgroundTasks?: unknown;
|
|
1149
1199
|
agentLatestVersion?: unknown;
|
|
1150
1200
|
skipAgentPrompt?: unknown;
|
|
1151
1201
|
branchHint?: unknown;
|
|
@@ -1192,6 +1242,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1192
1242
|
} | undefined;
|
|
1193
1243
|
workMode?: "DIRECT" | "BRANCH" | undefined;
|
|
1194
1244
|
pausedUntil?: string | null | undefined;
|
|
1245
|
+
backgroundTasks?: number | undefined;
|
|
1195
1246
|
agentLatestVersion?: string | undefined;
|
|
1196
1247
|
skipAgentPrompt?: boolean | undefined;
|
|
1197
1248
|
branchHint?: string | undefined;
|
|
@@ -1244,6 +1295,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1244
1295
|
activeMsBase?: number | undefined;
|
|
1245
1296
|
extraBudgetMinutes?: number | null | undefined;
|
|
1246
1297
|
pausedUntil?: unknown;
|
|
1298
|
+
backgroundTasks?: unknown;
|
|
1247
1299
|
agentLatestVersion?: unknown;
|
|
1248
1300
|
skipAgentPrompt?: unknown;
|
|
1249
1301
|
branchHint?: unknown;
|
package/dist/protocol.js
CHANGED
|
@@ -59,6 +59,20 @@ export const SessionDescriptorSchema = z.object({
|
|
|
59
59
|
* behaviour every runner had before this release.
|
|
60
60
|
*/
|
|
61
61
|
pausedUntil: z.string().max(40).nullable().optional().catch(undefined),
|
|
62
|
+
/**
|
|
63
|
+
* Subagents the API still believes to be alive in this session (#393).
|
|
64
|
+
*
|
|
65
|
+
* The number is the dead process's last word, kept by the API: a runner
|
|
66
|
+
* restart takes every subagent with it, and the new process seeds its own
|
|
67
|
+
* count at zero — so the descriptor is the only place the number survives
|
|
68
|
+
* long enough to be written down. The API sends it only while it still
|
|
69
|
+
* believes it (its own trust window on the count's age); absent or zero
|
|
70
|
+
* means «nothing to say», and a restore says nothing.
|
|
71
|
+
*
|
|
72
|
+
* `.catch(undefined)` like its neighbours: one malformed value must cost
|
|
73
|
+
* its own session a line at most, never the frame (QA-100 MAJOR-1).
|
|
74
|
+
*/
|
|
75
|
+
backgroundTasks: z.number().int().min(0).optional().catch(undefined),
|
|
62
76
|
/**
|
|
63
77
|
* The newest published version of THIS session's agent — Р13, §4.8.
|
|
64
78
|
*
|