@agentproto/runtime 2.2.0 → 2.4.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/README.md +1 -0
- package/dist/catalog-models.mjs +2 -1
- package/dist/catalog-models.mjs.map +1 -1
- package/dist/config.d.ts +20 -0
- package/dist/config.mjs.map +1 -1
- package/dist/index.d.ts +261 -5
- package/dist/index.mjs +581 -38
- package/dist/index.mjs.map +1 -1
- package/dist/resume-strategies.mjs.map +1 -1
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -1659,7 +1659,7 @@ declare function createTaskLedger(opts: {
|
|
|
1659
1659
|
* and session_monitor MCP tool (long-poll multiplexed).
|
|
1660
1660
|
*/
|
|
1661
1661
|
|
|
1662
|
-
type SessionEventType = "session:turn-end" | "session:awaiting-input" | "session:permission-request" | "session:permission-resolved" | "session:exited" | "session:reaped" | "session:resumed" | "session:spawned" | "session:command-done" | "session:model-changed" | "session:config-changed" | "session:renamed" | "policy:passed" | "policy:failed" | "policy:commit-ready" | "policy:committed" | "cron:fired" | "cron:succeeded" | "cron:failed" | "activity:changed" | "task:changed";
|
|
1662
|
+
type SessionEventType = "session:turn-end" | "session:awaiting-input" | "session:permission-request" | "session:permission-resolved" | "session:exited" | "session:reaped" | "session:stalled" | "session:stall-cleared" | "session:resumed" | "session:spawned" | "session:command-done" | "session:model-changed" | "session:config-changed" | "session:renamed" | "policy:passed" | "policy:failed" | "policy:commit-ready" | "policy:committed" | "cron:fired" | "cron:succeeded" | "cron:failed" | "activity:changed" | "task:changed";
|
|
1663
1663
|
/**
|
|
1664
1664
|
* Fixed severity vocabulary for a judge-gate finding (WP-D). Deliberately
|
|
1665
1665
|
* small and fixed so `policy_status` output is comparable across different
|
|
@@ -1806,6 +1806,47 @@ interface SessionReapedEvent {
|
|
|
1806
1806
|
label?: string;
|
|
1807
1807
|
ts: string;
|
|
1808
1808
|
}
|
|
1809
|
+
/**
|
|
1810
|
+
* Emitted by the turn-liveness watchdog (`runStallWatchdogPass`) when a
|
|
1811
|
+
* mid-turn agent-cli session's adapter stream has gone silent past the
|
|
1812
|
+
* configured threshold: `busy:true`, not legitimately `blockedOn` a
|
|
1813
|
+
* subagent/command, and no `lastActivityAt` traffic since. The target
|
|
1814
|
+
* failure mode is a DEAD adapter stream — zero frames mid-turn, e.g. a
|
|
1815
|
+
* network drop — that otherwise leaves the row `status:"running"`,
|
|
1816
|
+
* `lastError:null`, indistinguishable from healthy long work except by
|
|
1817
|
+
* manually comparing `lastActivityAt` to the clock. Detection + signal
|
|
1818
|
+
* ONLY: nothing here kills or restarts the session (unlike `session:reaped`
|
|
1819
|
+
* / crash-detect's `session:exited`). `stalledSinceMs` is the epoch ms of
|
|
1820
|
+
* the last real activity that was observed before the trip — a consumer
|
|
1821
|
+
* computes "silent for" as `Date.now() - stalledSinceMs`. Same bus
|
|
1822
|
+
* distribution as every other lifecycle event (`session_events_poll`, the
|
|
1823
|
+
* webhook notifier, the routine engine, `session_monitor`). Paired with
|
|
1824
|
+
* `session:stall-cleared` when the flag is later cleared.
|
|
1825
|
+
*/
|
|
1826
|
+
interface SessionStalledEvent {
|
|
1827
|
+
type: "session:stalled";
|
|
1828
|
+
sessionId: string;
|
|
1829
|
+
stalledSinceMs: number;
|
|
1830
|
+
label?: string;
|
|
1831
|
+
ts: string;
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Emitted when a session's `stalledSinceMs` flag (see {@link
|
|
1835
|
+
* SessionStalledEvent}) is cleared — by new adapter activity
|
|
1836
|
+
* (`pulseActivity`), the next turn starting, or the turn's own `finally`
|
|
1837
|
+
* (busy flips false, so "mid-turn and silent" no longer holds either way).
|
|
1838
|
+
* Does NOT imply the earlier trip was a false alarm — recovery from a
|
|
1839
|
+
* genuinely dead stream normally happens via the turn eventually erroring
|
|
1840
|
+
* out or being killed, not via a resumed stream; a clear immediately
|
|
1841
|
+
* followed by fresh `lastActivityAt` traffic is the "it wasn't actually
|
|
1842
|
+
* dead" case. Same bus distribution as every other lifecycle event.
|
|
1843
|
+
*/
|
|
1844
|
+
interface SessionStallClearedEvent {
|
|
1845
|
+
type: "session:stall-cleared";
|
|
1846
|
+
sessionId: string;
|
|
1847
|
+
label?: string;
|
|
1848
|
+
ts: string;
|
|
1849
|
+
}
|
|
1809
1850
|
/**
|
|
1810
1851
|
* Emitted when a dead agent-cli row is brought back IN PLACE — same session
|
|
1811
1852
|
* id, same descriptor — by the lazy resume-on-prompt path (`maybeResumeAgent`)
|
|
@@ -2056,7 +2097,7 @@ interface TaskChangedEvent {
|
|
|
2056
2097
|
sessionId?: string;
|
|
2057
2098
|
ts: string;
|
|
2058
2099
|
}
|
|
2059
|
-
type SessionEvent = SessionTurnEndEvent | SessionAwaitingInputEvent | SessionPermissionRequestEvent | SessionPermissionResolvedEvent | SessionExitedEvent | SessionReapedEvent | SessionResumedEvent | SessionSpawnedEvent | SessionCommandDoneEvent | SessionModelChangedEvent | SessionConfigChangedEvent | SessionRenamedEvent | PolicyPassedEvent | PolicyFailedEvent | PolicyCommitReadyEvent | PolicyCommittedEvent | CronFiredEvent | CronSucceededEvent | CronFailedEvent | ActivityChangedEvent | TaskChangedEvent;
|
|
2100
|
+
type SessionEvent = SessionTurnEndEvent | SessionAwaitingInputEvent | SessionPermissionRequestEvent | SessionPermissionResolvedEvent | SessionExitedEvent | SessionReapedEvent | SessionStalledEvent | SessionStallClearedEvent | SessionResumedEvent | SessionSpawnedEvent | SessionCommandDoneEvent | SessionModelChangedEvent | SessionConfigChangedEvent | SessionRenamedEvent | PolicyPassedEvent | PolicyFailedEvent | PolicyCommitReadyEvent | PolicyCommittedEvent | CronFiredEvent | CronSucceededEvent | CronFailedEvent | ActivityChangedEvent | TaskChangedEvent;
|
|
2060
2101
|
interface SessionEventBus {
|
|
2061
2102
|
emit(ev: SessionEvent): void;
|
|
2062
2103
|
/** Subscribe to a specific event type. Returns an unsubscribe fn. */
|
|
@@ -3753,8 +3794,14 @@ interface AuthOptions {
|
|
|
3753
3794
|
*/
|
|
3754
3795
|
|
|
3755
3796
|
interface SessionObserver {
|
|
3756
|
-
/** Record the outgoing message that opens a new turn.
|
|
3757
|
-
|
|
3797
|
+
/** Record the outgoing message that opens a new turn. `opts.source`, when
|
|
3798
|
+
* set, is the prompt's provenance — `agent:<sessionId>` for a prompt
|
|
3799
|
+
* injected by another session (`agent_prompt` from a supervisor), absent
|
|
3800
|
+
* for a human operator — so a transcript view can attribute the turn to
|
|
3801
|
+
* its real author instead of "you". */
|
|
3802
|
+
recordPrompt(sessionId: string, message: unknown, opts?: {
|
|
3803
|
+
source?: string;
|
|
3804
|
+
}): void;
|
|
3758
3805
|
/** Record one structured stream event (text-delta, tool-call, usage_update, …). */
|
|
3759
3806
|
recordEvent(sessionId: string, evt: AgentStreamEvent): void;
|
|
3760
3807
|
/** Record the durable turn-boundary / exit usage snapshot. */
|
|
@@ -3995,6 +4042,16 @@ interface AgentStreamEvent {
|
|
|
3995
4042
|
* but no `cost`). */
|
|
3996
4043
|
tokensIn?: number;
|
|
3997
4044
|
tokensOut?: number;
|
|
4045
|
+
/** "permission-resolved" outcome for the "agent-prompt" it answers (same
|
|
4046
|
+
* `toolCallId`) — mirrors `session:permission-resolved`'s `decision` so
|
|
4047
|
+
* the durable transcript can tell an answered ask from a still-pending
|
|
4048
|
+
* one. Not an ACP `StreamEvent` kind (synthesized by the registry, same
|
|
4049
|
+
* as "notice"/"turn-end" synthetics) — see registerPendingPermission's
|
|
4050
|
+
* docblock for the "agent-prompt" ask this resolves. */
|
|
4051
|
+
decision?: "approve" | "deny" | "cancelled";
|
|
4052
|
+
/** "permission-resolved" chosen option id, when the driver's offered
|
|
4053
|
+
* options included one (e.g. ACP's `allow_always`). */
|
|
4054
|
+
optionId?: string;
|
|
3998
4055
|
}
|
|
3999
4056
|
/**
|
|
4000
4057
|
* Env vars the registry injects into every process it spawns on a session's
|
|
@@ -4019,6 +4076,14 @@ interface AgentStreamEvent {
|
|
|
4019
4076
|
* assign-last rule is what makes that true by construction rather than by
|
|
4020
4077
|
* accident, and is what guarantees a child spawned from inside a session
|
|
4021
4078
|
* gets its OWN id rather than inheriting its parent's.
|
|
4079
|
+
*
|
|
4080
|
+
* `PARENT_SESSION_ID_ENV` is the third var, injected by `session-spawn.ts`
|
|
4081
|
+
* only (agent spawns, and only when the spawn resolved a parent): the
|
|
4082
|
+
* recorded `parentSessionId` lineage, so a child agent can know WHO spawned
|
|
4083
|
+
* it without a registry round-trip — the discovery half of the child→parent
|
|
4084
|
+
* report-back channel (`message_parent` is the delivery half). Same
|
|
4085
|
+
* assign-last/no-forgery rule as the other two: it mirrors the descriptor's
|
|
4086
|
+
* own `parentSessionId` field, never anything caller- or env-inherited.
|
|
4022
4087
|
*/
|
|
4023
4088
|
declare const SESSION_ID_ENV = "AGENTPROTO_SESSION_ID";
|
|
4024
4089
|
declare const WORKSPACE_SLUG_ENV = "AGENTPROTO_WORKSPACE_SLUG";
|
|
@@ -4126,6 +4191,22 @@ interface SessionDescriptor {
|
|
|
4126
4191
|
* every read since it's a live OS query, stale the instant it's
|
|
4127
4192
|
* written to disk. */
|
|
4128
4193
|
processAlive?: boolean;
|
|
4194
|
+
/** Count of live supervisors currently blocked waiting on this session —
|
|
4195
|
+
* HTTP `GET /sessions/:id/wait` long-polls and `session_monitor`
|
|
4196
|
+
* subscriptions, both via `monitorSessionWait` (#session-visibility).
|
|
4197
|
+
* Ephemeral, in-memory, stamped at read time (list()/get()) from the
|
|
4198
|
+
* registry's waiter counter — NEVER persisted (a waiter can't survive a
|
|
4199
|
+
* daemon restart). 0/absent ⇒ nothing is watching. Lets a UI mark a
|
|
4200
|
+
* session "supervised — notify on turn-end". */
|
|
4201
|
+
watchers?: number;
|
|
4202
|
+
/** Count of DESCENDANT sessions (children, grandchildren, …) currently
|
|
4203
|
+
* mid-turn, derived at read time from the `parentSessionId` lineage
|
|
4204
|
+
* (#session-visibility, subtree rollup). Lets a UI show an idle parent that
|
|
4205
|
+
* is really "delegating" — waiting on its own busy subtree — distinctly
|
|
4206
|
+
* from a genuinely quiet session. Ephemeral, never persisted; 0/absent ⇒ no
|
|
4207
|
+
* busy descendants. NOTE: in-process subagents a harness runs itself are
|
|
4208
|
+
* invisible to the daemon between turns, so they don't count here. */
|
|
4209
|
+
childrenBusy?: number;
|
|
4129
4210
|
/** Short human-readable string describing the most recent automatic
|
|
4130
4211
|
* failure — currently only stamped by `markCrashed` (e.g. "adapter
|
|
4131
4212
|
* process gone (pid 1234) — session crashed"). Not a stack trace or raw
|
|
@@ -4134,6 +4215,25 @@ interface SessionDescriptor {
|
|
|
4134
4215
|
/** ISO 8601 timestamp of the crash-detect sweep that flipped this row to
|
|
4135
4216
|
* `endedReason:"crashed"`. Absent for every other terminal path. */
|
|
4136
4217
|
crashedAt?: string;
|
|
4218
|
+
/** Epoch ms of the last known-good `lastActivityAt` reading at the moment
|
|
4219
|
+
* the turn-liveness watchdog (`runStallWatchdogPass`) decided this row's
|
|
4220
|
+
* in-flight turn had gone silent for too long: `busy:true`,
|
|
4221
|
+
* `blockedOn` undefined (not legitimately waiting on a subagent/command),
|
|
4222
|
+
* and no adapter traffic since. Distinct from a slow tool call — the
|
|
4223
|
+
* target failure mode is a dead adapter stream that will never emit
|
|
4224
|
+
* another frame (a network drop, a hung child), the case where `status`
|
|
4225
|
+
* stays `"running"`, `lastError` stays null, and nothing else
|
|
4226
|
+
* distinguishes it from healthy long work.
|
|
4227
|
+
*
|
|
4228
|
+
* Stamped by `markStalled` (never by `list()`/read time — this is a
|
|
4229
|
+
* discrete trip, not a recomputed projection), and CLEARED by
|
|
4230
|
+
* `clearStalled` the moment ANY new activity is observed — the next
|
|
4231
|
+
* `pulseActivity`, the next turn start, or the turn's own `finally`
|
|
4232
|
+
* (busy flips false, so the mid-turn claim no longer holds). Absent
|
|
4233
|
+
* (never a stale value) whenever the session isn't currently flagged
|
|
4234
|
+
* stalled. Detection + signal only — nothing here kills or restarts the
|
|
4235
|
+
* session. */
|
|
4236
|
+
stalledSinceMs?: number;
|
|
4137
4237
|
/** DERIVED, read-time only (never persisted — stripped by `snapshotRows`,
|
|
4138
4238
|
* stamped by `stampInterrupted` in list()/get()/findByIdOrName). True when
|
|
4139
4239
|
* this session died with a turn in flight under a daemon restart —
|
|
@@ -4643,6 +4743,12 @@ interface SessionSummary {
|
|
|
4643
4743
|
lastOutputAt?: string;
|
|
4644
4744
|
lastActivityAt?: string;
|
|
4645
4745
|
processAlive?: boolean;
|
|
4746
|
+
/** Live supervisor waiter count (#session-visibility) — see
|
|
4747
|
+
* `SessionDescriptor.watchers`. Ephemeral, stamped at read time. */
|
|
4748
|
+
watchers?: number;
|
|
4749
|
+
/** Busy-descendant count (#session-visibility, subtree rollup) — see
|
|
4750
|
+
* `SessionDescriptor.childrenBusy`. Drives the "delegating" row state. */
|
|
4751
|
+
childrenBusy?: number;
|
|
4646
4752
|
label?: string;
|
|
4647
4753
|
title?: string;
|
|
4648
4754
|
renamedByUser?: boolean;
|
|
@@ -4670,6 +4776,7 @@ interface SessionSummary {
|
|
|
4670
4776
|
turnsCompleted?: number;
|
|
4671
4777
|
busy?: boolean;
|
|
4672
4778
|
blockedOn?: "subagent" | "command";
|
|
4779
|
+
stalledSinceMs?: number;
|
|
4673
4780
|
origin?: string;
|
|
4674
4781
|
parentSessionId?: string;
|
|
4675
4782
|
depth?: number;
|
|
@@ -4943,6 +5050,7 @@ interface SessionsRegistry {
|
|
|
4943
5050
|
* the previous mid-turn rejection byte-for-byte. */
|
|
4944
5051
|
sendPrompt(id: string, message: unknown, opts?: {
|
|
4945
5052
|
interrupt?: boolean;
|
|
5053
|
+
source?: string;
|
|
4946
5054
|
}): Promise<void>;
|
|
4947
5055
|
/** Fire-and-forget variant of `sendPrompt` for the TURN ITSELF only.
|
|
4948
5056
|
* Admission (resume attempt + the missing/wrong-kind/dead/busy
|
|
@@ -4962,8 +5070,12 @@ interface SessionsRegistry {
|
|
|
4962
5070
|
* prompt is admitted + fired on the SAME live session. Ignored
|
|
4963
5071
|
* (identical to the default) when the session is idle. Omitted or
|
|
4964
5072
|
* `false` reproduces today's mid-turn rejection byte-for-byte. */
|
|
5073
|
+
/** `opts.source` on either prompt verb is the turn's provenance
|
|
5074
|
+
* (`agent:<sessionId>` when another session injected it — see
|
|
5075
|
+
* `SessionObserver.recordPrompt`); recording-only, never behavioral. */
|
|
4965
5076
|
enqueuePrompt(id: string, message: unknown, opts?: {
|
|
4966
5077
|
interrupt?: boolean;
|
|
5078
|
+
source?: string;
|
|
4967
5079
|
}): Promise<void>;
|
|
4968
5080
|
/** Eagerly resume ONE dead-but-resumable agent-cli session IN PLACE,
|
|
4969
5081
|
* WITHOUT a prompt — the boot-time counterpart to the lazy resume that
|
|
@@ -5104,6 +5216,15 @@ interface SessionsRegistry {
|
|
|
5104
5216
|
total: number;
|
|
5105
5217
|
};
|
|
5106
5218
|
get(id: string): SessionDescriptor | undefined;
|
|
5219
|
+
/** Register a live waiter on a session (#session-visibility) — bumps the
|
|
5220
|
+
* ephemeral `watchers` counter surfaced on the descriptor at read time.
|
|
5221
|
+
* Called by `monitorSessionWait` when a `/sessions/:id/wait` long-poll or
|
|
5222
|
+
* `session_monitor` subscription actually blocks. A no-op for an unknown id
|
|
5223
|
+
* is fine (the wait may outlive the row). */
|
|
5224
|
+
incWatchers(id: string): void;
|
|
5225
|
+
/** Balance an {@link incWatchers} when the waiter resolves or times out.
|
|
5226
|
+
* Clamps at 0 and drops the map entry at zero so the counter can't leak. */
|
|
5227
|
+
decWatchers(id: string): void;
|
|
5107
5228
|
/** Archive a TERMINAL-status session (exited/killed/error) — sets
|
|
5108
5229
|
* `archived: true` and persists. Pure housekeeping: hides the row from
|
|
5109
5230
|
* `list()`'s default view, nothing else. Refuses (throws) a still-alive
|
|
@@ -5236,6 +5357,33 @@ interface SessionsRegistry {
|
|
|
5236
5357
|
* an already-terminal or non-agent-cli row. Returns true iff a row was
|
|
5237
5358
|
* actually marked crashed. */
|
|
5238
5359
|
markCrashed(id: string): boolean;
|
|
5360
|
+
/** Flip a LIVE, mid-turn agent-cli row to `stalledSinceMs:<ts>` — the
|
|
5361
|
+
* primitive the turn-liveness watchdog (`runStallWatchdogPass`) drives on
|
|
5362
|
+
* a periodic sweep when a turn's adapter stream has gone silent past the
|
|
5363
|
+
* threshold. Unlike `markCrashed`/`reapIdle`, this NEVER changes `status`,
|
|
5364
|
+
* kills anything, or clears the live binding — it's a pure signal
|
|
5365
|
+
* (detection + surfacing only), so the session stays exactly as running
|
|
5366
|
+
* as it was. Emits `session:stalled`.
|
|
5367
|
+
*
|
|
5368
|
+
* Purely mechanical: the caller (the sweep) owns the silence/threshold
|
|
5369
|
+
* policy. This method only guards the invariants a stall-mark must never
|
|
5370
|
+
* violate — it refuses (returns false, no-op) a row that isn't a live
|
|
5371
|
+
* (`running`) agent-cli session, isn't currently `busy` (mid-turn), is
|
|
5372
|
+
* legitimately `blockedOn` a subagent/command, or is already flagged
|
|
5373
|
+
* stalled (idempotent — the sweep's own candidate filter already excludes
|
|
5374
|
+
* these, this is the second line of defense for any other caller).
|
|
5375
|
+
* Returns true iff the row was actually flagged. */
|
|
5376
|
+
markStalled(id: string, stalledSinceMs: number): boolean;
|
|
5377
|
+
/** Clear a row's `stalledSinceMs` flag — called the instant ANY activity
|
|
5378
|
+
* disproves the stall claim: `pulseActivity` (new adapter traffic), the
|
|
5379
|
+
* next turn's start, and the turn's own `finally` (busy flips false, so
|
|
5380
|
+
* "mid-turn and silent" no longer holds either way). Emits
|
|
5381
|
+
* `session:stall-cleared` — but ONLY when the row was actually flagged;
|
|
5382
|
+
* a session that was never stalled clearing on every turn boundary would
|
|
5383
|
+
* spam the bus with a no-op event on every single turn. Returns true iff
|
|
5384
|
+
* a flag was actually cleared; false (no-op, no event) for an unknown id
|
|
5385
|
+
* or a row that wasn't flagged. */
|
|
5386
|
+
clearStalled(id: string): boolean;
|
|
5239
5387
|
/** Whether an in-place resume is currently IN FLIGHT for this session
|
|
5240
5388
|
* (`rt.resumePromise` set) — the restart-scheduler's periodic sweep
|
|
5241
5389
|
* (`runRestartSweepPass`, PR-2) consults this to skip a row a concurrent
|
|
@@ -6386,6 +6534,103 @@ declare function runCrashDetectPass(opts: {
|
|
|
6386
6534
|
isServed?: (desc: SessionDescriptor) => boolean;
|
|
6387
6535
|
}): CrashDetectSummary;
|
|
6388
6536
|
|
|
6537
|
+
/**
|
|
6538
|
+
* Turn-liveness watchdog (turn-liveness-watchdog chantier).
|
|
6539
|
+
*
|
|
6540
|
+
* Agent-cli sessions report `status:"running"` for the entire life of a
|
|
6541
|
+
* turn, and nothing else observes the adapter's event stream directly. When
|
|
6542
|
+
* that stream dies mid-turn — a network drop, a hung child, zero frames
|
|
6543
|
+
* ever again — nothing throws: there's no RPC failure to catch, just
|
|
6544
|
+
* silence. The descriptor keeps lying `status:"running"`, `lastError:null`,
|
|
6545
|
+
* `blockedOn:undefined` — identical to a session doing genuine, healthy
|
|
6546
|
+
* long work. A supervisor only catches it by manually comparing
|
|
6547
|
+
* `lastActivityAt` to the clock (the live incident this chantier exists
|
|
6548
|
+
* for: `sess_0b94542f`, `lastActivityAt` frozen 36 minutes into a turn with
|
|
6549
|
+
* no other signal).
|
|
6550
|
+
*
|
|
6551
|
+
* This pass sweeps the registry, finds agent-cli sessions that are BUSY
|
|
6552
|
+
* (mid-turn), NOT legitimately `blockedOn` a subagent/command (a real
|
|
6553
|
+
* long-running tool call is expected to go quiet — that's not the failure
|
|
6554
|
+
* mode this catches), and silent past a threshold, and FLAGS them
|
|
6555
|
+
* (`registry.markStalled`): stamps `stalledSinceMs` and emits
|
|
6556
|
+
* `session:stalled` — same shape discipline as `crash-reaper.ts` /
|
|
6557
|
+
* `idle-reaper.ts`, except conservative by design: a `blockedOn` row is
|
|
6558
|
+
* NEVER a candidate, no matter how long it's been silent, because a slow
|
|
6559
|
+
* build and a dead stream are indistinguishable from `lastActivityAt`
|
|
6560
|
+
* alone once a tool call is legitimately in flight. The predicate is
|
|
6561
|
+
* deliberately biased toward missing a genuinely-dead-but-blocked stream
|
|
6562
|
+
* over false-positiving a healthy long tool call.
|
|
6563
|
+
*
|
|
6564
|
+
* DETECTION AND SURFACING ONLY. No auto-kill, no auto-restart — those are
|
|
6565
|
+
* later work, if ever; see AGENTS.md's "definition of done" for why this
|
|
6566
|
+
* pass stops at a signal.
|
|
6567
|
+
*
|
|
6568
|
+
* The trip/clear ACTIONS and their invariants (agent-cli-only, running-only,
|
|
6569
|
+
* busy-only, unblocked-only, idempotent, emit `session:stalled` /
|
|
6570
|
+
* `session:stall-cleared`) live behind `registry.markStalled` /
|
|
6571
|
+
* `registry.clearStalled`. This module owns only the POLICY: which rows have
|
|
6572
|
+
* gone silent long enough mid-turn to be worth flagging. Clearing on
|
|
6573
|
+
* recovery is event-driven (pulseActivity / turn start / turn finally in
|
|
6574
|
+
* sessions.ts), NOT this sweep's job — the sweep only ever adds the flag,
|
|
6575
|
+
* it never removes one, so a row already flagged is simply excluded from
|
|
6576
|
+
* the next sweep's candidate set until something clears it.
|
|
6577
|
+
*
|
|
6578
|
+
* OFF by default in the sense that a non-positive / undefined
|
|
6579
|
+
* `turnStallAfterMs` disables the pass entirely (it returns `enabled:false`
|
|
6580
|
+
* and never touches a row) — same opt-in shape as crash-detect and
|
|
6581
|
+
* idle-reap. Like crash-detect, the gateway wires a sane default threshold
|
|
6582
|
+
* so this is DEFAULT-ON in practice (see index.ts): detection is
|
|
6583
|
+
* non-destructive observability, so the bar for shipping it enabled is
|
|
6584
|
+
* lower than for anything that touches a live process.
|
|
6585
|
+
*/
|
|
6586
|
+
|
|
6587
|
+
/** Tally of one stall-watchdog sweep, for the periodic log line + tests. */
|
|
6588
|
+
interface StallWatchdogSummary {
|
|
6589
|
+
/** Whether the pass actually ran. False when `turnStallAfterMs` is
|
|
6590
|
+
* non-positive/undefined (the knob is off) — the pass short-circuits and
|
|
6591
|
+
* every count is 0. Distinguishes "ran, found nothing stalled" from
|
|
6592
|
+
* "disabled". */
|
|
6593
|
+
enabled: boolean;
|
|
6594
|
+
/** Rows that matched the stall policy — the sweep's candidate set. */
|
|
6595
|
+
candidates: number;
|
|
6596
|
+
/** Rows actually flagged stalled (`markStalled` returned true). */
|
|
6597
|
+
stalled: number;
|
|
6598
|
+
/** The flagged ids, for the sweep's summary log line. */
|
|
6599
|
+
ids: string[];
|
|
6600
|
+
}
|
|
6601
|
+
/** The slice of the sessions registry the watchdog needs: enumerate every
|
|
6602
|
+
* row (including archived, for parity with idle-reaper's / crash-detect's
|
|
6603
|
+
* scan shape; archived rows are never `running` anyway so the predicate
|
|
6604
|
+
* excludes them regardless) and flag one stalled by id. Structural so the
|
|
6605
|
+
* pass is a pure, unit-testable function decoupled from the full registry
|
|
6606
|
+
* surface. */
|
|
6607
|
+
interface StallWatchdogRegistry {
|
|
6608
|
+
list(opts?: {
|
|
6609
|
+
includeArchived?: boolean;
|
|
6610
|
+
}): readonly SessionDescriptor[];
|
|
6611
|
+
markStalled(id: string, stalledSinceMs: number): boolean;
|
|
6612
|
+
}
|
|
6613
|
+
/**
|
|
6614
|
+
* Run one stall-watchdog sweep. Pure over the injected `now` (ms epoch), so
|
|
6615
|
+
* a test pins a fake clock and asserts deterministically. Returns the
|
|
6616
|
+
* tally; the caller (the gateway's periodic ticker) turns it into a
|
|
6617
|
+
* one-line log per sweep.
|
|
6618
|
+
*/
|
|
6619
|
+
declare function runStallWatchdogPass(opts: {
|
|
6620
|
+
registry: StallWatchdogRegistry;
|
|
6621
|
+
/** Flag agent-cli sessions mid-turn and silent longer than this many ms.
|
|
6622
|
+
* Non-positive / undefined ⇒ the pass is DISABLED. (The gateway wires a
|
|
6623
|
+
* sane default so this is default-on in practice — see index.ts.) */
|
|
6624
|
+
turnStallAfterMs: number | undefined;
|
|
6625
|
+
/** Injected clock (ms since epoch). Defaults to `Date.now`. */
|
|
6626
|
+
now?: () => number;
|
|
6627
|
+
/** Cross-process gate (mirrors idle-reaper's / crash-detect's §5): with
|
|
6628
|
+
* two daemons sharing the workspace buckets, each sweeps only rows for
|
|
6629
|
+
* the workspace IT serves. Return false to exclude a row. Omitted ⇒
|
|
6630
|
+
* every row is served. */
|
|
6631
|
+
isServed?: (desc: SessionDescriptor) => boolean;
|
|
6632
|
+
}): StallWatchdogSummary;
|
|
6633
|
+
|
|
6389
6634
|
/**
|
|
6390
6635
|
* Turns a raw tool-call name + args (and its eventual result) into a short,
|
|
6391
6636
|
* human-readable line for ring-buffer / CLI / transcript rendering. Without
|
|
@@ -7495,6 +7740,17 @@ interface CreateGatewayOptions {
|
|
|
7495
7740
|
* the sweep never runs, so a scheduled `nextRestartAt` sits inert.
|
|
7496
7741
|
* Surfaced in `daemon_health` / `GET /health`. */
|
|
7497
7742
|
restartSweepIntervalMs?: number;
|
|
7743
|
+
/** Turn-liveness watchdog threshold in ms (turn-liveness-watchdog
|
|
7744
|
+
* chantier). Mirrors the `daemon.turnStallAfterMs` config knob; the CLI
|
|
7745
|
+
* resolves it (env > config > a sane default — DEFAULT ON, same shape as
|
|
7746
|
+
* `crashDetectIntervalMs`) and passes it here. The gateway starts a
|
|
7747
|
+
* periodic sweep that flags a BUSY agent-cli session mid-turn, not
|
|
7748
|
+
* legitimately `blockedOn` a subagent/command, and silent past this
|
|
7749
|
+
* threshold: stamps `stalledSinceMs` and emits `session:stalled`
|
|
7750
|
+
* (`registry.markStalled`, driven by `runStallWatchdogPass`). Non-positive
|
|
7751
|
+
* ⇒ the sweep never runs. Detects only; never kills or restarts. Surfaced
|
|
7752
|
+
* in `daemon_health` / `GET /health`. */
|
|
7753
|
+
turnStallAfterMs?: number;
|
|
7498
7754
|
/**
|
|
7499
7755
|
* Resolves a heartbeat-runnable agent from its workspace id.
|
|
7500
7756
|
* Required for HEARTBEAT.md to do anything; without it ticks emit
|
|
@@ -7729,4 +7985,4 @@ interface GatewayHandle {
|
|
|
7729
7985
|
*/
|
|
7730
7986
|
declare function createGateway(opts: CreateGatewayOptions): Promise<GatewayHandle>;
|
|
7731
7987
|
|
|
7732
|
-
export { type ActivityKind, type ActivityListFilter, type ActivityPolicyLister, type ActivityProjector, type ActivityProjectorRegistry, type ActivityProjectorSession, type ActivityRecord, type ActivitySource, type ActivityState, type ActivityWaitingOn, type ActivityWorkflowLister, AdapterAuthDescriptor, type AdapterCapabilitiesLister, type AdapterInstallResult, type AdapterListEntry, type AgentAdapterInstaller, type AgentAdapterLister, type AgentAdapterResolver, type AgentSessionLike, type AgentStreamEvent, type AnthropicReaderConfig, AnthropicRemainingQuotaReader, type AttachPolicyInput, type AttachSandboxOpts, type AttachSandboxResult, AuthMethod, BUCKETS_ROOT, type BrowserAdapterHandle, type BrowserAdapterInfo, type BrowserAdapterLister, type BrowserAdapterResolver, BuildHeartbeatAgent, CanonicalPosture, type CatalogModelsLister, CatalogModelsQuery, CatalogModelsResponse, type CatalogProviderModel, type CatalogProviderModelsQuery, type CatalogProviderModelsResponse, type CatalogProviderPricing, type ClaudeNativeRef, type CommitSpec, type CompletionPolicySupervisor, ContextProfile, type ConversationIndexRecord, type ConversationNativeRef, type CostBudgetDecision, type CrashDetectSummary, type CrashReaperRegistry, type CreateGatewayOptions, type CreateOfferInput, type CreatedOffer, DEFAULT_BUCKET, DEFAULT_ORCHESTRATOR_TOOLS, DEFAULT_WORKTREE_ISOLATION, DeclaredAdapterOption, type DeclaredAdapterPreset, type EagerResumeFailReason, type EagerResumeOutcome, type EagerResumeSkipReason, type EagerResumeSummary, EffortLevel, type GateSpec, type GatewayHandle, type HermesNativeRef, INBOUND_PROVIDERS, type IdleReapSummary, type IdleReaperRegistry, type InboundEndpoint, type InboundEndpointStore, type InboundEndpointStoreOptions, type InboundEnqueuePrompt, type InboundIsSessionAlive, type InboundMessage, type InboundProvider, type InboundRestartSession, type InboundRouteMode, type InboundRouterDeps, type InboundRouterLog, type InboundSpawnForContact, type InboundWatcher, type JudgeGateSpec, LEGACY_SESSIONS_FILE, type LocatedConversation, type LocatedConversationByPath, type McpCredentialDeps, type MigrationMarker, type NormalizeInboundResult, type OnFailSpec, type OpenPrResolver, type OrchestratorGatewayDeps, type OrchestratorInjection, type OrchestratorInjector, type OrchestratorInjectorDeps, type OrchestratorMcpServerFactory, type OrchestratorScope, type OrphanReaperRegistry, PAIRINGS_VERSION, POSTURE_NATIVE_ALIASES, POSTURE_PREAMBLES, type PairingChannelContext, type PairingChannelHandle, type PairingChannelMode, type PairingRecord, type PairingRegistry, type PairingRegistryDeps, type PendingPermission, type PermissionRespondInput, type PermissionRespondResult, type PolicyRunState, type PolicyRunStatus, Posture, type PostureResolution, type PrResolvedState, type PrStateResolver, type PresetInfo, type PricingResolver, type QuotaReadableProfile, type QuotaStoreFile, type QuotaStoreOptions, type ReconnectLogGate, type RegisterBrowserInput, type RegisterPairingToolsOptions, type RegisterSessionInput, type RemainingQuota, type RemainingQuotaReader, type ResolveNativeLinkInput, ResolvedAuthSpec, ResumeDisabledError, type RouteAwareLaunchConfig, type RouteAwareLaunchConfigInput, RouteSpec, type RuntimeMeta, SESSION_ID_ENV, type SandboxAdapterInfo, type SandboxConnectionDescriptor, type SandboxProviderCapabilities, type SandboxProviderHandle, type SandboxProviderLister, type SandboxProviderResolver, type ScopeTokenRegistry, SessionConfig, type SessionDescriptor, type SessionKind, type SessionObserver, type SessionSnapshots, type SessionStatus, type SessionUsage, type SessionWaitEvent, type SessionWaitResult, type SessionsRegistry, type ShellGateSpec, type SpawnAgentInput, type SpawnSessionInput, type StoredProfileQuota, TASK_STATUSES, type TaskCaller, type TaskChangedEvent, type TaskClaimInput, type TaskCreateInput, type TaskGateOutcome, type TaskGateRunner, type TaskLedger, type TaskLedgerRegistry, type TaskLedgerSessionSlice, type TaskListFilter, type TaskRecord, type TaskStatus, type TaskUpdateInput, type TaskVerification, type TaskVerifySupervisor, type TaskWriteResult, type TokenPricing, type TransmitterBinding, type TransmitterBindingStore, type TunnelDescriptor, type TunnelProvider, type TunnelStatus, type UsageBucket, type UsageComputeInput, type UsageRollup, type UsageSnapshotRecord, type UsageSource, WORKSPACE_SLUG_ENV, WORKTREE_ISOLATION_ENV, type WatcherDescriptor, type WatcherStartInput, WorkspaceFs, type WorktreeDecision, type WorktreeField, type WorktreeGcClass, type WorktreeGcOutcomeView, type WorktreeGcPlanEntryView, type WorktreeGcReclaimReason, type WorktreeGcResult, type WorktreeGcRunInput, type WorktreeGcRunner, WorktreeIsolationMode, type WorktreeProvisionOutcome, type WorktreeProvisionRequest, type WorktreeProvisioner, type WorktreeRequest, type WorktreeStatusLister, type WorktreeStatusView, activityCounts, appendConversationRecord, attachSandbox, bucketDir, bucketSessionsFile, bucketTranscriptDir, buildCatalogProviderModels, buildMcpConfigSnippet, buildRouteAwareLaunchConfig, canonicalForModeId, claudeProjectSlug, composeSessionObservers, conversationIndexPath, createActivityProjector, createFileStepCache, createGateway, createInboundEndpointStore, createOrchestratorInjector, createOrchestratorMcpServerFactory, createPairingRegistry, createPrProvenanceReconciler, createReconnectLogGate, createScopeTokenRegistry, createSupervisorTaskGateRunner, createTaskLedger, daemonRegistryDir, decideWorktreeIsolation, declaredPresetToProviderPreset, deriveSessionUsage, enrichRollupWithProviderQuota, enrichWithRemainingQuota, evaluateCostBudget, filterActivities, findConversationRecord, findNativeMode, formatToolCall, formatToolResult, getMcpCredentialDeps, isAgentCliAuthConfigured, isClosedTaskStatus, isSafeBucketSlug, isTerminalActivityState, listBuckets, listPresets, loadQuotaStore, loadWorktreeIsolation, locateConversationByNativePath, locateConversationBySessionId, makeBrowserAdapterLister, migrateLegacySessionsFile, migrationMarkerPath, monitorPolicyWait, monitorSessionWait, narrowOrchestratorTools, normalizeInbound, normalizeModeId, normalizeWorktreeField, parseAnthropicRateLimitHeaders, parseTaskStatus, parseWindow, parseWorktreeIsolationMode, policyToActivities, policyWatchesSession, prToActivities, projectSessionUsage, readConversationIndex, readDaemonRegistry, readProfileQuota, readRegisteredSlugs, readRuntimeMeta, readUsageSnapshots, reapOrphanedDescendants, recordProfileQuota, registerBuiltinRoutes, registerPairingTools, registerSandboxAttachTool, resolveBucketSlug, resolveNativeLink, resolvePosture, rollupUsage, runCrashDetectPass, runEagerResumePass, runIdleReapPass, setMcpCredentialDeps, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, toWorktreeStatusView, turnToActivities, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, verifyInboundSignature, workflowToActivities, writeDaemonRegistryEntry };
|
|
7988
|
+
export { type ActivityKind, type ActivityListFilter, type ActivityPolicyLister, type ActivityProjector, type ActivityProjectorRegistry, type ActivityProjectorSession, type ActivityRecord, type ActivitySource, type ActivityState, type ActivityWaitingOn, type ActivityWorkflowLister, AdapterAuthDescriptor, type AdapterCapabilitiesLister, type AdapterInstallResult, type AdapterListEntry, type AgentAdapterInstaller, type AgentAdapterLister, type AgentAdapterResolver, type AgentSessionLike, type AgentStreamEvent, type AnthropicReaderConfig, AnthropicRemainingQuotaReader, type AttachPolicyInput, type AttachSandboxOpts, type AttachSandboxResult, AuthMethod, BUCKETS_ROOT, type BrowserAdapterHandle, type BrowserAdapterInfo, type BrowserAdapterLister, type BrowserAdapterResolver, BuildHeartbeatAgent, CanonicalPosture, type CatalogModelsLister, CatalogModelsQuery, CatalogModelsResponse, type CatalogProviderModel, type CatalogProviderModelsQuery, type CatalogProviderModelsResponse, type CatalogProviderPricing, type ClaudeNativeRef, type CommitSpec, type CompletionPolicySupervisor, ContextProfile, type ConversationIndexRecord, type ConversationNativeRef, type CostBudgetDecision, type CrashDetectSummary, type CrashReaperRegistry, type CreateGatewayOptions, type CreateOfferInput, type CreatedOffer, DEFAULT_BUCKET, DEFAULT_ORCHESTRATOR_TOOLS, DEFAULT_WORKTREE_ISOLATION, DeclaredAdapterOption, type DeclaredAdapterPreset, type EagerResumeFailReason, type EagerResumeOutcome, type EagerResumeSkipReason, type EagerResumeSummary, EffortLevel, type GateSpec, type GatewayHandle, type HermesNativeRef, INBOUND_PROVIDERS, type IdleReapSummary, type IdleReaperRegistry, type InboundEndpoint, type InboundEndpointStore, type InboundEndpointStoreOptions, type InboundEnqueuePrompt, type InboundIsSessionAlive, type InboundMessage, type InboundProvider, type InboundRestartSession, type InboundRouteMode, type InboundRouterDeps, type InboundRouterLog, type InboundSpawnForContact, type InboundWatcher, type JudgeGateSpec, LEGACY_SESSIONS_FILE, type LocatedConversation, type LocatedConversationByPath, type McpCredentialDeps, type MigrationMarker, type NormalizeInboundResult, type OnFailSpec, type OpenPrResolver, type OrchestratorGatewayDeps, type OrchestratorInjection, type OrchestratorInjector, type OrchestratorInjectorDeps, type OrchestratorMcpServerFactory, type OrchestratorScope, type OrphanReaperRegistry, PAIRINGS_VERSION, POSTURE_NATIVE_ALIASES, POSTURE_PREAMBLES, type PairingChannelContext, type PairingChannelHandle, type PairingChannelMode, type PairingRecord, type PairingRegistry, type PairingRegistryDeps, type PendingPermission, type PermissionRespondInput, type PermissionRespondResult, type PolicyRunState, type PolicyRunStatus, Posture, type PostureResolution, type PrResolvedState, type PrStateResolver, type PresetInfo, type PricingResolver, type QuotaReadableProfile, type QuotaStoreFile, type QuotaStoreOptions, type ReconnectLogGate, type RegisterBrowserInput, type RegisterPairingToolsOptions, type RegisterSessionInput, type RemainingQuota, type RemainingQuotaReader, type ResolveNativeLinkInput, ResolvedAuthSpec, ResumeDisabledError, type RouteAwareLaunchConfig, type RouteAwareLaunchConfigInput, RouteSpec, type RuntimeMeta, SESSION_ID_ENV, type SandboxAdapterInfo, type SandboxConnectionDescriptor, type SandboxProviderCapabilities, type SandboxProviderHandle, type SandboxProviderLister, type SandboxProviderResolver, type ScopeTokenRegistry, SessionConfig, type SessionDescriptor, type SessionKind, type SessionObserver, type SessionSnapshots, type SessionStatus, type SessionUsage, type SessionWaitEvent, type SessionWaitResult, type SessionsRegistry, type ShellGateSpec, type SpawnAgentInput, type SpawnSessionInput, type StallWatchdogRegistry, type StallWatchdogSummary, type StoredProfileQuota, TASK_STATUSES, type TaskCaller, type TaskChangedEvent, type TaskClaimInput, type TaskCreateInput, type TaskGateOutcome, type TaskGateRunner, type TaskLedger, type TaskLedgerRegistry, type TaskLedgerSessionSlice, type TaskListFilter, type TaskRecord, type TaskStatus, type TaskUpdateInput, type TaskVerification, type TaskVerifySupervisor, type TaskWriteResult, type TokenPricing, type TransmitterBinding, type TransmitterBindingStore, type TunnelDescriptor, type TunnelProvider, type TunnelStatus, type UsageBucket, type UsageComputeInput, type UsageRollup, type UsageSnapshotRecord, type UsageSource, WORKSPACE_SLUG_ENV, WORKTREE_ISOLATION_ENV, type WatcherDescriptor, type WatcherStartInput, WorkspaceFs, type WorktreeDecision, type WorktreeField, type WorktreeGcClass, type WorktreeGcOutcomeView, type WorktreeGcPlanEntryView, type WorktreeGcReclaimReason, type WorktreeGcResult, type WorktreeGcRunInput, type WorktreeGcRunner, WorktreeIsolationMode, type WorktreeProvisionOutcome, type WorktreeProvisionRequest, type WorktreeProvisioner, type WorktreeRequest, type WorktreeStatusLister, type WorktreeStatusView, activityCounts, appendConversationRecord, attachSandbox, bucketDir, bucketSessionsFile, bucketTranscriptDir, buildCatalogProviderModels, buildMcpConfigSnippet, buildRouteAwareLaunchConfig, canonicalForModeId, claudeProjectSlug, composeSessionObservers, conversationIndexPath, createActivityProjector, createFileStepCache, createGateway, createInboundEndpointStore, createOrchestratorInjector, createOrchestratorMcpServerFactory, createPairingRegistry, createPrProvenanceReconciler, createReconnectLogGate, createScopeTokenRegistry, createSupervisorTaskGateRunner, createTaskLedger, daemonRegistryDir, decideWorktreeIsolation, declaredPresetToProviderPreset, deriveSessionUsage, enrichRollupWithProviderQuota, enrichWithRemainingQuota, evaluateCostBudget, filterActivities, findConversationRecord, findNativeMode, formatToolCall, formatToolResult, getMcpCredentialDeps, isAgentCliAuthConfigured, isClosedTaskStatus, isSafeBucketSlug, isTerminalActivityState, listBuckets, listPresets, loadQuotaStore, loadWorktreeIsolation, locateConversationByNativePath, locateConversationBySessionId, makeBrowserAdapterLister, migrateLegacySessionsFile, migrationMarkerPath, monitorPolicyWait, monitorSessionWait, narrowOrchestratorTools, normalizeInbound, normalizeModeId, normalizeWorktreeField, parseAnthropicRateLimitHeaders, parseTaskStatus, parseWindow, parseWorktreeIsolationMode, policyToActivities, policyWatchesSession, prToActivities, projectSessionUsage, readConversationIndex, readDaemonRegistry, readProfileQuota, readRegisteredSlugs, readRuntimeMeta, readUsageSnapshots, reapOrphanedDescendants, recordProfileQuota, registerBuiltinRoutes, registerPairingTools, registerSandboxAttachTool, resolveBucketSlug, resolveNativeLink, resolvePosture, rollupUsage, runCrashDetectPass, runEagerResumePass, runIdleReapPass, runStallWatchdogPass, setMcpCredentialDeps, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, toWorktreeStatusView, turnToActivities, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, verifyInboundSignature, workflowToActivities, writeDaemonRegistryEntry };
|