@loomcycle/client 1.112.0 → 1.114.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/types.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  * `client.ts` for the input shapes (RunOptions, CreateSnapshotOptions,
8
8
  * etc.) — those are translated to snake_case in the request body.
9
9
  */
10
- export type EventType = "started" | "text" | "tool_call" | "tool_result" | "usage" | "done" | "error" | "retry" | "host_widened" | "session" | "agent" | "awaiting_input" | "awaiting_review" | "subagent_hold" | "awaiting_children" | "children_note" | "steer" | "context_compaction" | "capability_inert" | "hook_decision" | "limit" | "override" | "context_recap" | "context_state" | "context_distill_declined" | "context_exhausted" | "thinking" | "team_decision" | "turn_cancelled" | "provider_fallback" | "fallback_suppressed" | "model_downgraded" | "cache_invalidated" | "reasoning_invalidated" | "channel_publish" | "channel_delivery" | "interruption_pending" | "spawn_child_started" | "spawn_child_result" | "spawn_child_read" | "prompt_snapshot" | "_meta";
10
+ export type EventType = "started" | "text" | "tool_call" | "tool_result" | "usage" | "done" | "error" | "retry" | "host_widened" | "session" | "agent" | "awaiting_input" | "awaiting_review" | "subagent_hold" | "awaiting_children" | "children_note" | "steer" | "context_compaction" | "capability_inert" | "hook_decision" | "limit" | "override" | "context_recap" | "context_state" | "context_distill_declined" | "context_exhausted" | "thinking" | "team_decision" | "turn_cancelled" | "provider_fallback" | "fallback_suppressed" | "model_downgraded" | "cache_invalidated" | "reasoning_invalidated" | "channel_publish" | "channel_delivery" | "interruption_pending" | "spawn_child_started" | "spawn_child_result" | "spawn_child_read" | "prompt_snapshot" | "queued" | "admitted" | "call_queued" | "call_admitted" | "_meta";
11
11
  export interface ToolUse {
12
12
  id: string;
13
13
  name: string;
@@ -223,6 +223,53 @@ export interface InertContextSetting {
223
223
  * leaves the operator hunting for the live knob. */
224
224
  fix?: string;
225
225
  }
226
+ /** Why a per-run override is refused, in {@link OverridableField.reason}:
227
+ * - `token_locked` — the caller's token carries an overrides policy that
228
+ * leaves the field out
229
+ * - `agent_locked` — the agent's definition says `allow_overrides: false`
230
+ *
231
+ * When both apply the token is named, because a run setting the field is
232
+ * refused for that reason first. */
233
+ export type OverrideLockReason = "token_locked" | "agent_locked";
234
+ /** One per-run override in {@link AgentOverridableResponse.fields}. */
235
+ export interface OverridableField {
236
+ /** Whether a run of the agent, started by this caller, may set it. */
237
+ overridable: boolean;
238
+ /** Present when `overridable` is false. */
239
+ reason?: OverrideLockReason;
240
+ /** The run may only make it smaller than the definition allows
241
+ * (`max_concurrent_children`, `interruption`). */
242
+ narrow_only?: boolean;
243
+ /** The largest value accepted (`max_concurrent_children`: the fan-out
244
+ * ceiling, the definition's or the runtime default). */
245
+ max?: number;
246
+ /** The values accepted, when the run path checks against a closed set this
247
+ * agent has: `effort`, the configured `tier`s, and the `provider` and
248
+ * `model` sets the definition declares. Absent means no closed set here —
249
+ * any value the deployment accepts (see `listModels()` / `getRouting()`),
250
+ * not anything at all. Each describes the field set on its own. */
251
+ values?: string[];
252
+ }
253
+ /** The reply from `GET /v1/_agentdef/{name}/overridable` — for every per-run
254
+ * override, whether a run of this agent started by THIS caller may set it.
255
+ *
256
+ * Folds the definition's `allow_overrides` with the caller's token overrides
257
+ * policy, through the same checks the run path refuses with. The answer is
258
+ * the caller's: do not reuse it for another token. Keys of `fields` are wire
259
+ * names (`max_tokens`, not `maxTokens`), one per run option a token's
260
+ * overrides policy can name. */
261
+ export interface AgentOverridableResponse {
262
+ agent: string;
263
+ /** The AgentDef version answered for; absent for a yaml or registered agent,
264
+ * which have no versions. Always the active version: a run cannot pin one. */
265
+ def_id?: string;
266
+ /** The definition's `allow_overrides`; unset reads as true. */
267
+ allow_overrides: boolean;
268
+ /** True when the caller's token carries an overrides policy, so `fields`
269
+ * reflects this caller and not only the agent. */
270
+ restricted_by_token: boolean;
271
+ fields: Record<string, OverridableField>;
272
+ }
226
273
  /** The reply from `retuneRun` — the run's MERGED configuration, not an echo of
227
274
  * the request.
228
275
  *
@@ -375,6 +422,28 @@ export interface CapabilityInertInfo {
375
422
  /** A line naming the tool, the gate, and what to set. */
376
423
  message?: string;
377
424
  }
425
+ /** AdmissionInfo accompanies `event: queued` and `event: admitted` frames.
426
+ * Mirrors providers.AdmissionInfo. */
427
+ export interface AdmissionInfo {
428
+ /** On `queued`: why the run waits — `"user_cap"` (its user already has its
429
+ * cap of runs active) or `"global_cap"` (every run slot is taken). On
430
+ * `call_queued`: why the call waits — `"lane"` (every slot of its call lane
431
+ * is taken) or `"models_in_flight"` (the provider has its cap of models in
432
+ * flight and this call's model is not among them). */
433
+ reason?: "user_cap" | "global_cap" | "lane" | "models_in_flight";
434
+ /** On `queued`: the run's place when it was queued, 1 being the next to
435
+ * start. For `user_cap` it counts only the same user's waiting runs. It
436
+ * moves as other runs start and end; `getRun` reports the current place
437
+ * (`Agent.queue_position`). */
438
+ position?: number;
439
+ /** On `admitted`: how long the run waited for its slot, in milliseconds. On
440
+ * `call_admitted`: how long the call waited. */
441
+ wait_ms?: number;
442
+ /** On `call_queued` / `call_admitted`: the provider id as configured. */
443
+ provider?: string;
444
+ /** On `call_queued` / `call_admitted`: the call lane's model kind (`"chat"`). */
445
+ kind?: string;
446
+ }
378
447
  export interface LimitInfo {
379
448
  /** Which axis tripped: "operator" | "tenant" | "user". */
380
449
  scope: string;
@@ -615,6 +684,11 @@ export interface AgentEvent {
615
684
  /** Payload on `event: limit` (RFC AW) — a per-scope token-budget crossing.
616
685
  * Nil on all other event types. */
617
686
  limit?: LimitInfo;
687
+ /** Payload on `event: queued` (why the run waits, and its place) and
688
+ * `event: admitted` (how long it waited), and on `event: call_queued` /
689
+ * `event: call_admitted` (the same for one model call, with its provider
690
+ * and lane kind). Nil on all other event types. */
691
+ admission?: AdmissionInfo;
618
692
  /** Set on `capability_inert` events: a tool the agent holds and cannot use. */
619
693
  capability_inert?: CapabilityInertInfo;
620
694
  /** Payload on `event: hook_decision`. */
@@ -780,6 +854,15 @@ export interface RunOverrideOptions {
780
854
  * agent's own whole. On a retune it replaces the run's own and takes
781
855
  * effect from the run's next turn; a retune cannot remove it. */
782
856
  outputFormat?: OutputFormatOptions;
857
+ /** The run's own `routing:` block: how the agent's tier candidates are
858
+ * walked — at the run's start, and when the run, having lost its lane
859
+ * slot, would wait too long for its next call. REPLACES the agent's block
860
+ * whole — `{}` turns queue-aware routing off. It chooses only among the
861
+ * candidates the definition declares. `queue_aware` on an agent (or a run)
862
+ * pinned to a provider or model is refused (400). On a retune it replaces
863
+ * the run's own and is read at the run's next call boundary. A sub-agent
864
+ * of the same definition inherits it. */
865
+ routing?: AgentRouting;
783
866
  }
784
867
  export interface RunOptions extends RunOverrideOptions {
785
868
  agent: string;
@@ -859,6 +942,11 @@ export interface RunOptions extends RunOverrideOptions {
859
942
  * is the time bound for a `mode: "detach"` batch child, where `timeoutMs`
860
943
  * is refused. Any agent, model-driven or code-js. */
861
944
  maxWallSeconds?: number;
945
+ /** What the run does when it cannot start at once: `"wait"` (the default)
946
+ * accepts it with status `queued` — the stream yields a `queued` event,
947
+ * then `admitted` when it gets a slot — and `"reject"` refuses it at once
948
+ * (`per_user_quota_exhausted` or `backpressure`). A fresh run only. */
949
+ admission?: "wait" | "reject";
862
950
  /** `"none"` makes this a no-trace run: what it says is delivered on this
863
951
  * stream and stored nowhere — the server keeps a marker for each event
864
952
  * (its type and size) and a class for an error, never the text. Omit (or
@@ -1217,7 +1305,8 @@ export interface ClientOptions {
1217
1305
  }
1218
1306
  /** `configured` is a run created but not yet started (RFC DI). */
1219
1307
  /** `rejected` is a run a reviewer turned down without feedback (RFC DJ). */
1220
- export type AgentStatus = "configured" | "running" | "completed" | "failed" | "cancelled" | "rejected";
1308
+ /** `queued` is a run accepted but waiting for a run slot. */
1309
+ export type AgentStatus = "configured" | "queued" | "running" | "completed" | "failed" | "cancelled" | "rejected";
1221
1310
  /** What a running run is blocked on: an open Channel subscribe, an open
1222
1311
  * Interruption ask, a hold for an operator's review verdict, an
1223
1312
  * interactive run parked for the operator's next turn (`input`), or a run
@@ -1267,6 +1356,14 @@ export interface Agent {
1267
1356
  * (`awaited_state: "review"`) or the child run ids, comma-separated and
1268
1357
  * bounded (`awaited_state: "children"`) the run waits on. */
1269
1358
  awaited_on?: string;
1359
+ /** Where a `queued` run stands now: 1 is the next to start. For
1360
+ * `queue_reason: "user_cap"` it counts only the same user's waiting runs.
1361
+ * {@link LoomcycleClient.getAgent} / getRun only, from the replica that
1362
+ * holds the run's wait; absent on every other run. */
1363
+ queue_position?: number;
1364
+ /** Why a `queued` run waits: its user already has its cap of runs active
1365
+ * (`user_cap`), or every run slot is taken (`global_cap`). */
1366
+ queue_reason?: "user_cap" | "global_cap";
1270
1367
  /** The replica owning the run's live cancel handle. Absent in a
1271
1368
  * single-replica deployment. */
1272
1369
  replica_id?: string;
@@ -1328,9 +1425,16 @@ export interface RunSpec {
1328
1425
  * `maxWallSeconds`: past it the run ends `cancelled` with
1329
1426
  * `stop_reason: "wall_limit"`. Absent when the run has no such limit. */
1330
1427
  max_wall_seconds?: number;
1428
+ /** The run started with its tree's ephemeral volumes read-only: its own
1429
+ * definition, or an ancestor's, says `ephemeral_volumes: "ro"`. A resume
1430
+ * restores it whatever the definition says by then. */
1431
+ ephemeral_read_only?: boolean;
1331
1432
  review_ttl_seconds?: number;
1332
1433
  /** Which model serves the run: model / provider / tier / effort. */
1333
1434
  routing?: Record<string, unknown>;
1435
+ /** The run's own `routing:` block ({@link RunOptions.routing}), when it
1436
+ * set one. Its own key because `routing` above names the model choice. */
1437
+ queue_routing?: AgentRouting;
1334
1438
  /** The run's budget: max_tokens / max_iterations / … */
1335
1439
  resources?: Record<string, unknown>;
1336
1440
  tuning?: Record<string, unknown>;
@@ -1517,7 +1621,33 @@ export interface RunResult {
1517
1621
  }
1518
1622
  export interface ListAgentsResponse {
1519
1623
  agents: Agent[];
1624
+ /** True when an `awaited_state` listing stopped before reading every
1625
+ * running run (it reads at most 1,000), so a matching run may be missing.
1626
+ * Absent otherwise. */
1627
+ truncated?: boolean;
1628
+ }
1629
+ /** {@link LoomcycleClient.listUserAgents}'s filters. */
1630
+ export interface ListUserAgentsOptions {
1631
+ /** One status or several (a run in any of them is listed). Omitted → only
1632
+ * running runs; `"all"` → every status. An unknown status is a 400. */
1633
+ status?: AgentStatus | "all" | AgentStatus[];
1634
+ /** List only running runs blocked on one of these waits. Implies running:
1635
+ * a `status` other than `"running"` with it is a 400. */
1636
+ awaitedState?: AwaitedState | AwaitedState[];
1637
+ /** Narrows the result CLIENT-SIDE to runs whose `parent_agent_id`
1638
+ * matches. */
1639
+ parentAgentId?: string;
1640
+ /** Super-admin tenant-focus (?tenant=, RFC L v0.17.0). Ignored
1641
+ * server-side for a tenant principal — its own tenant is forced. */
1642
+ tenant?: string;
1643
+ signal?: AbortSignal;
1520
1644
  }
1645
+ /** {@link LoomcycleClient.listUserAgents}'s answer: the runs, still an array,
1646
+ * carrying `truncated: true` when an `awaitedState` listing stopped before
1647
+ * reading every running run. */
1648
+ export type AgentList = Agent[] & {
1649
+ truncated?: boolean;
1650
+ };
1521
1651
  /** One page of a team walk's runs ({@link LoomcycleClient.listWalkRuns}),
1522
1652
  * ordered by started_at then run id. `next_cursor` is "" on the last page. */
1523
1653
  export interface WalkRunsPage {
@@ -2308,6 +2438,9 @@ export interface PreHookCall {
2308
2438
  phase: "pre";
2309
2439
  owner: string;
2310
2440
  hook_name: string;
2441
+ /** Present on a signed call only: this delivery's id, inside the signed body.
2442
+ * Dedupe on it, never on the unsigned X-Loomcycle-Delivery header copy. */
2443
+ delivery_id?: string;
2311
2444
  agent: string;
2312
2445
  user_id?: string;
2313
2446
  agent_id?: string;
@@ -2334,6 +2467,9 @@ export interface PostHookCall {
2334
2467
  phase: "post";
2335
2468
  owner: string;
2336
2469
  hook_name: string;
2470
+ /** Present on a signed call only: this delivery's id, inside the signed body.
2471
+ * Dedupe on it, never on the unsigned X-Loomcycle-Delivery header copy. */
2472
+ delivery_id?: string;
2337
2473
  agent: string;
2338
2474
  user_id?: string;
2339
2475
  agent_id?: string;
@@ -2347,6 +2483,9 @@ export interface ChannelHookCall {
2347
2483
  /** `"channel:<name>"`. */
2348
2484
  owner: string;
2349
2485
  hook_name: string;
2486
+ /** Present on a signed call only: this delivery's id, inside the signed body.
2487
+ * Dedupe on it, never on the unsigned X-Loomcycle-Delivery header copy. */
2488
+ delivery_id?: string;
2350
2489
  channel: string;
2351
2490
  scope: string;
2352
2491
  scope_id?: string;
@@ -2378,7 +2517,7 @@ export interface ChannelHookResult {
2378
2517
  * the adapter doesn't re-validate. Use the optional `extra` index
2379
2518
  * signature for forward-compat fields. */
2380
2519
  export type SubstrateToolInput = {
2381
- op: "create" | "fork" | "get" | "list" | "promote" | "retire" | "rediscover" | "verify" | "delete" | "purge";
2520
+ op: "create" | "fork" | "get" | "list" | "promote" | "retire" | "rediscover" | "verify" | "delete" | "purge" | "set_mode";
2382
2521
  name?: string;
2383
2522
  def_id?: string;
2384
2523
  parent_def_id?: string;
@@ -2387,6 +2526,27 @@ export type SubstrateToolInput = {
2387
2526
  promote?: boolean;
2388
2527
  retired?: boolean;
2389
2528
  mode?: VolumeMode;
2529
+ source?: {
2530
+ git: {
2531
+ /** https URL of the repository, on a host the operator allows. */
2532
+ url: string;
2533
+ /** The full 40-digit sha-1 of the commit. */
2534
+ commit: string;
2535
+ /** Where to find the commit when the server serves none by sha. */
2536
+ ref?: string;
2537
+ /** `$cred:<name>` or `$ghapp:<name>`; must be restricted to this URL. */
2538
+ credential?: string;
2539
+ /** May only lower the operator's limit. */
2540
+ max_bytes?: number;
2541
+ /** Also write a diff from this commit: "merge-base:default" or a sha. */
2542
+ diff_base?: string;
2543
+ /** Names for the diff's files, each a plain name under `_meta/`. */
2544
+ outputs?: {
2545
+ diff?: string;
2546
+ numstat?: string;
2547
+ };
2548
+ };
2549
+ };
2390
2550
  [extra: string]: unknown;
2391
2551
  };
2392
2552
  /** Response shape for {@link LoomcycleClient.agentDef} and
@@ -2648,12 +2808,20 @@ export interface TeamRunResult {
2648
2808
  capped_state?: string;
2649
2809
  max_iterations?: number;
2650
2810
  iteration_count?: number;
2651
- /** The per-state trace. Absent when `deduplicated` is set. */
2652
- steps: TeamRunStep[];
2811
+ /** The per-state trace. Absent when `deduplicated` is set: the trace is
2812
+ * built by the request that walks and is not stored on the run, so a retry
2813
+ * answered from the key has none to return. */
2814
+ steps?: TeamRunStep[];
2653
2815
  /** Set (true) when the request's `idempotencyKey` was already held: nothing
2654
2816
  * was started, and this is the walk that holds it, as it is now — `status`
2655
2817
  * may be "running", and there are no `steps`. */
2656
2818
  deduplicated?: boolean;
2819
+ /** On a `deduplicated` answer for a walk that has ended: the stop reason
2820
+ * recorded on its run. Absent while it runs, and when none was recorded. */
2821
+ stop_reason?: string;
2822
+ /** On a `deduplicated` answer for a walk that has ended: why it failed, as
2823
+ * recorded on its run. Absent when it did not fail. */
2824
+ error?: string;
2657
2825
  [extra: string]: unknown;
2658
2826
  }
2659
2827
  /** What team {@link LoomcycleClient.runTeam} walks, and how. */
@@ -2720,6 +2888,11 @@ export interface TeamRunTarget {
2720
2888
  * it has no `steps`: read the walk's member runs for those. Refused with
2721
2889
  * `boardChunkId`, which already resumes a stored position. */
2722
2890
  idempotencyKey?: string;
2891
+ /** When a state hits its iteration cap, ask a human (an interruption)
2892
+ * whether to continue, `reroute:<state>` or abort, instead of ending with
2893
+ * the `iteration_cap` outcome. An ask nobody answers, that times out or is
2894
+ * declined aborts the walk. Default false. */
2895
+ interruptOnCap?: boolean;
2723
2896
  }
2724
2897
  /** What {@link LoomcycleClient.runTeam} returns for `mode: "detach"` — the
2725
2898
  * handle, immediately, with the walk still running behind it.
@@ -2973,6 +3146,114 @@ export type HistoryToolInput = {
2973
3146
  * returns the chat metadata + transcript (or Markdown), `recap` a summary,
2974
3147
  * `resume` a continuation handle. Callers narrow as needed. */
2975
3148
  export type HistoryToolResponse = unknown;
3149
+ /** Who recorded an evaluation, relative to the run it scores. The server
3150
+ * derives it from the caller and the target run; it is never sent. A call
3151
+ * outside a run (this client) records `external` or `unrelated`. */
3152
+ export type EvaluationEmitterRole = "self" | "sibling" | "parent" | "external" | "unrelated";
3153
+ /** `evaluation({op:"submit"})`: record a score against a run. Scores are
3154
+ * additive — submitting again records another evaluation. */
3155
+ export interface EvaluationSubmitInput {
3156
+ op: "submit";
3157
+ run_id: string;
3158
+ /** Required. Convention [-1,1] or [0,1]; the operator chooses. */
3159
+ score: number;
3160
+ /** Named axes to numeric values, e.g. `{correctness: 0.8}`. */
3161
+ dimensions?: Record<string, number>;
3162
+ /** Free-form structured payload. */
3163
+ judgement?: unknown;
3164
+ /** Natural-language reasoning. */
3165
+ rationale?: string;
3166
+ }
3167
+ /** `evaluation({op:"get"})`: one evaluation by id. */
3168
+ export interface EvaluationGetInput {
3169
+ op: "get";
3170
+ eval_id: string;
3171
+ }
3172
+ /** `evaluation({op:"list_for_run"})`: every evaluation of one run. */
3173
+ export interface EvaluationListForRunInput {
3174
+ op: "list_for_run";
3175
+ run_id: string;
3176
+ /** Max rows (default 100). */
3177
+ limit?: number;
3178
+ }
3179
+ /** `evaluation({op:"list_for_def"})`: every evaluation of runs of one
3180
+ * definition version, in the caller's tenant. */
3181
+ export interface EvaluationListForDefInput {
3182
+ op: "list_for_def";
3183
+ def_id: string;
3184
+ /** Max rows (default 100). */
3185
+ limit?: number;
3186
+ }
3187
+ /** `evaluation({op:"aggregate"})`: the scores of a definition rolled up. */
3188
+ export interface EvaluationAggregateInput {
3189
+ op: "aggregate";
3190
+ def_id: string;
3191
+ /** Walk parent_def_id and include the ancestors' evaluations. */
3192
+ include_lineage?: boolean;
3193
+ }
3194
+ /** Input for {@link LoomcycleClient.evaluation}, discriminated by `op`. */
3195
+ export type EvaluationInput = EvaluationSubmitInput | EvaluationGetInput | EvaluationListForRunInput | EvaluationListForDefInput | EvaluationAggregateInput;
3196
+ /** What `submit` returns: the stored row's identity and the derived role. */
3197
+ export interface EvaluationSubmitResult {
3198
+ eval_id: string;
3199
+ run_id: string;
3200
+ /** The definition version the run was running, denormalised at submit
3201
+ * time; `""` for a run that resolved through static config only. */
3202
+ def_id: string;
3203
+ emitter_role: EvaluationEmitterRole;
3204
+ score: number;
3205
+ /** RFC 3339 UTC. */
3206
+ created_at: string;
3207
+ }
3208
+ /** One stored evaluation, as `get` and the `list_for_*` ops return it. */
3209
+ export interface EvaluationRecord {
3210
+ eval_id: string;
3211
+ run_id: string;
3212
+ def_id: string;
3213
+ score: number;
3214
+ /** `null` when the submit carried none. */
3215
+ dimensions: Record<string, number> | null;
3216
+ /** `null` when the submit carried none. */
3217
+ judgement: unknown;
3218
+ rationale: string;
3219
+ emitter_role: EvaluationEmitterRole;
3220
+ emitter_agent_id: string;
3221
+ emitter_run_id: string;
3222
+ /** RFC 3339 UTC. */
3223
+ created_at: string;
3224
+ }
3225
+ /** What `list_for_run` returns. An unknown run, or one the caller may not
3226
+ * read, lists nothing rather than refusing. */
3227
+ export interface EvaluationListForRunResult {
3228
+ run_id: string;
3229
+ evaluations: EvaluationRecord[];
3230
+ }
3231
+ /** What `list_for_def` returns. An unknown definition, or one the caller may
3232
+ * not read, lists nothing rather than refusing. */
3233
+ export interface EvaluationListForDefResult {
3234
+ def_id: string;
3235
+ evaluations: EvaluationRecord[];
3236
+ }
3237
+ /** Summary statistics over a set of scores. */
3238
+ export interface EvaluationScoreStats {
3239
+ mean: number;
3240
+ median: number;
3241
+ min: number;
3242
+ max: number;
3243
+ latest: number;
3244
+ count: number;
3245
+ }
3246
+ /** What `aggregate` returns. `count: 0` for an unknown definition. */
3247
+ export interface EvaluationAggregate {
3248
+ def_id: string;
3249
+ count: number;
3250
+ score: EvaluationScoreStats;
3251
+ /** Keyed by dimension name; only dimensions some row supplied. */
3252
+ dimensions?: Record<string, EvaluationScoreStats>;
3253
+ /** Keyed by emitter role. */
3254
+ by_emitter_role?: Record<string, EvaluationScoreStats>;
3255
+ lineage_included: boolean;
3256
+ }
2976
3257
  /** Volume access mode — read-only or read-write (RFC AH). */
2977
3258
  export type VolumeMode = "ro" | "rw";
2978
3259
  /** One row of {@link LoomcycleClient.listVolumes} (`GET /v1/_volumes`). */
@@ -3467,7 +3748,7 @@ export interface StreamUserRunStatesOptions {
3467
3748
  * `parent_context.walk_id`).
3468
3749
  *
3469
3750
  * A team walk's own run_id IS its walk id, so a caller that started a team
3470
- * with `detach: true` passes back exactly the handle it already holds —
3751
+ * with `mode: "detach"` passes back exactly the handle it already holds —
3471
3752
  * there is no second identifier and nothing to map. That is what makes a
3472
3753
  * live view of one running workflow's agents a filter rather than a
3473
3754
  * feature.
@@ -3635,17 +3916,6 @@ export interface EnsureMcpServerResult {
3635
3916
  /** Populated when `rediscover` ran: the number of tools discovered. */
3636
3917
  discoveredToolCount?: number;
3637
3918
  }
3638
- /** Typed `overlay` for an {@link LoomcycleClient.agentDef} create/fork —
3639
- * the mutable subset of an agent definition. All fields optional (a fork
3640
- * overlays only what changes). The `[extra]` tail keeps it forward-compatible
3641
- * with fields the in-process tool may accept that the adapter doesn't model
3642
- * yet — the tool owns the authoritative schema; the adapter doesn't re-validate.
3643
- *
3644
- * `code_body` is the inline code-js orchestrator source (RFC J): set it (with
3645
- * `provider: "code-js"`) to ingest a code agent through the substrate with NO
3646
- * host filesystem bind — the symmetry that makes code agents work in
3647
- * containers / pure-cloud. Requires `LOOMCYCLE_CODE_AGENTS_ENABLED=1` on the
3648
- * sidecar; create/fork refuses a non-empty `code_body` otherwise. */
3649
3919
  /** Per-agent Channel tool ACL (mirrors the sidecar `channels:` agent yaml).
3650
3920
  * The Channel tool default-denies until publish/subscribe patterns are granted. */
3651
3921
  export interface AgentChannelACL {
@@ -3706,6 +3976,91 @@ export interface AgentDecision {
3706
3976
  /** The models a Decision call may name. Empty = every model the server lists. */
3707
3977
  models?: string[];
3708
3978
  }
3979
+ /** The `sampling` block of an {@link AgentDefOverlay}: {@link SamplingOptions}
3980
+ * in its wire spelling. The overlay is sent verbatim, so its nested blocks are
3981
+ * snake_case — the camelCase run-option types are converted by the client and
3982
+ * would be ignored here. A fork merges it per field; an explicit
3983
+ * `temperature: 0` is deterministic, not unset. */
3984
+ export interface AgentSampling {
3985
+ temperature?: number;
3986
+ top_p?: number;
3987
+ top_k?: number;
3988
+ frequency_penalty?: number;
3989
+ presence_penalty?: number;
3990
+ seed?: number;
3991
+ stop?: string[];
3992
+ }
3993
+ /** The `compaction` block of an {@link AgentDefOverlay}: {@link CompactionOptions}
3994
+ * in its wire spelling, plus `memory_flush`, which only an agent definition
3995
+ * may set. A fork merges it per field. */
3996
+ export interface AgentCompaction {
3997
+ enabled?: boolean;
3998
+ target_percentage?: number;
3999
+ keep_last_n?: number;
4000
+ keep_first?: boolean;
4001
+ autocompact_at_pct?: number;
4002
+ model?: string;
4003
+ /** Bank the span a compaction discards for the memory consolidator.
4004
+ * Per-agent only: a run cannot set it, because it makes the agent persist
4005
+ * memory its definition must authorize. */
4006
+ memory_flush?: boolean;
4007
+ }
4008
+ /** The `context` block of an {@link AgentDefOverlay}: {@link ContextOptions}
4009
+ * in its wire spelling — see there for what each field does. A fork merges it
4010
+ * per field, and the spawn tree inherits it. */
4011
+ export interface AgentContext {
4012
+ mode?: ContextOptions["mode"];
4013
+ keep_last_n?: number;
4014
+ reasoning?: ContextOptions["reasoning"];
4015
+ recap_max_chars?: number;
4016
+ model?: string;
4017
+ autorecap_at_pct?: number;
4018
+ state_schema?: Record<string, unknown>;
4019
+ on_invalid_patch?: ContextOptions["onInvalidPatch"];
4020
+ max_patch_retries?: number;
4021
+ recall?: boolean;
4022
+ harvest_to_memory?: boolean;
4023
+ }
4024
+ /** One entry of a per-tier candidate list (`models` on an
4025
+ * {@link AgentDefOverlay}). */
4026
+ export interface TierCandidate {
4027
+ provider: string;
4028
+ model: string;
4029
+ }
4030
+ /** A core memory block an agent carries (`core_blocks`). Its value is the
4031
+ * Memory entry `core/<label>` in the block's scope, rendered into the system
4032
+ * prompt. */
4033
+ export interface CoreBlock {
4034
+ /** One path segment: no `/`, no whitespace. */
4035
+ label: string;
4036
+ /** Where the value lives. An `agent` block never crosses a spawn boundary. */
4037
+ scope?: "agent" | "user" | "tenant";
4038
+ /** Caps an agent write to the block, in bytes of the JSON value. 0 = only the
4039
+ * scope's `memory_quota_bytes`. */
4040
+ limit_bytes?: number;
4041
+ /** Operator-authored: the agent's writes to it are refused. */
4042
+ read_only?: boolean;
4043
+ }
4044
+ /** Typed `overlay` for an {@link LoomcycleClient.agentDef} create/fork —
4045
+ * the mutable subset of an agent definition. All fields optional (a fork
4046
+ * overlays only what changes). The `[extra]` tail keeps it forward-compatible
4047
+ * with fields the in-process tool may accept that the adapter doesn't model
4048
+ * yet — the tool owns the authoritative schema; the adapter doesn't re-validate.
4049
+ *
4050
+ * `code_body` is the inline code-js orchestrator source (RFC J): set it (with
4051
+ * `provider: "code-js"`) to ingest a code agent through the substrate with NO
4052
+ * host filesystem bind — the symmetry that makes code agents work in
4053
+ * containers / pure-cloud. Requires `LOOMCYCLE_CODE_AGENTS_ENABLED=1` on the
4054
+ * sidecar; create/fork refuses a non-empty `code_body` otherwise. */
4055
+ /** An agent's `routing:` block (RFC EI P4). */
4056
+ export interface AgentRouting {
4057
+ /** Pass over a cascade candidate whose provider is busy enough that the
4058
+ * run's first call would wait longer than `switch_after_ms`, for the next
4059
+ * available one. */
4060
+ queue_aware?: boolean;
4061
+ /** The estimated wait that passes a candidate over. Default 20000. */
4062
+ switch_after_ms?: number;
4063
+ }
3709
4064
  export interface AgentDefOverlay {
3710
4065
  provider?: string;
3711
4066
  model?: string;
@@ -3715,6 +4070,9 @@ export interface AgentDefOverlay {
3715
4070
  code_body?: string;
3716
4071
  tier?: string;
3717
4072
  effort?: string;
4073
+ /** How the provider and model are chosen when a run starts (RFC EI P4).
4074
+ * Tier-routed agents only. Replaced whole by a fork that sets it. */
4075
+ routing?: AgentRouting;
3718
4076
  /** Whether and which tool the model must call (RFC DI). */
3719
4077
  tool_choice?: ToolChoiceOptions;
3720
4078
  /** The JSON schema the answer must follow (RFC DI). */
@@ -3774,6 +4132,10 @@ export interface AgentDefOverlay {
3774
4132
  * refused with `override_not_allowed`. Unset or `true` leaves them to the
3775
4133
  * caller. A fork that does not send it keeps its parent's. */
3776
4134
  allow_overrides?: boolean;
4135
+ /** `"ro"` gives the agent every ephemeral volume of its run read-only,
4136
+ * whatever mode the volume was created with, and the same to every agent
4137
+ * it spawns. The only value; a fork cannot clear it. */
4138
+ ephemeral_volumes?: "ro";
3777
4139
  /** `"none"` makes every run of the agent a no-trace run: its content is
3778
4140
  * delivered to the caller and stored nowhere. A fork that does not send it
3779
4141
  * keeps its parent's, and `"default"` on a no-trace parent is refused. */
@@ -3788,6 +4150,88 @@ export interface AgentDefOverlay {
3788
4150
  channels?: AgentChannelACL;
3789
4151
  /** Interruption tool gate — `enabled: true` REQUIRED for the tool to work. */
3790
4152
  interruption?: AgentInterruptionACL;
4153
+ /** The agent's own description — what an agent file's frontmatter
4154
+ * carries — and part of its content hash. Not the request's top-level
4155
+ * `description`, which is the rationale for this create/fork. */
4156
+ description?: string;
4157
+ /** Tier-routing override: the providers this agent's tier resolution tries,
4158
+ * in order, replacing the server's priority list. No effect on a
4159
+ * provider+model pin. */
4160
+ providers?: string[];
4161
+ /** Per-tier candidate lists, keyed by tier name. A tier set here replaces
4162
+ * the server's definition of that tier for this agent. */
4163
+ models?: Record<string, TierCandidate[]>;
4164
+ /** The web-search providers the WebSearch tool tries, in order. Empty uses
4165
+ * the server's default order. */
4166
+ search_providers?: string[];
4167
+ /** The context window this agent uses, in tokens — distinct from
4168
+ * `max_tokens`, the output cap. Sizes the window on a local model; on a
4169
+ * hosted one it can only lower the effective window. */
4170
+ max_context_tokens?: number;
4171
+ /** Lift the `max_iterations` cap for an LLM agent (cancel is the stop). A
4172
+ * fork can set it but cannot clear it. */
4173
+ unbounded_iterations?: boolean;
4174
+ /** Wall-clock budget, in seconds, for a code-js agent; 0 = the server's
4175
+ * default. Ignored by LLM agents. */
4176
+ run_timeout_seconds?: number;
4177
+ /** The system prompt before skill bodies are baked in. Defaults to
4178
+ * `system_prompt`; set it only to rebuild a prompt from a different base. */
4179
+ system_prompt_base?: string;
4180
+ /** Per-agent LLM sampling, merged per field over the parent's. */
4181
+ sampling?: AgentSampling;
4182
+ /** Context compaction in `append` mode, merged per field. */
4183
+ compaction?: AgentCompaction;
4184
+ /** How history is distilled, merged per field. */
4185
+ context?: AgentContext;
4186
+ /** Volumes the file and exec tools may resolve paths against. None declared
4187
+ * means `default`; declaring any confines the agent to exactly those. */
4188
+ volumes?: string[];
4189
+ /** SQL Memory scopes: `agent` | `user` | `run`. Unset means `["user"]`;
4190
+ * `["-*"]` grants none. */
4191
+ sql_scopes?: string[];
4192
+ /** Per-scope SQL database byte cap; 0 = the server's default. */
4193
+ sql_quota_bytes?: number;
4194
+ /** Whose past chats the History tool may read: `self` | `user` | `tenant` |
4195
+ * `global` (honored only for an admin). Unset means `["user"]`; `["-*"]`
4196
+ * grants none. */
4197
+ history_scope?: string[];
4198
+ /** Core memory blocks rendered into the system prompt. */
4199
+ core_blocks?: CoreBlock[];
4200
+ /** A sub-agent also receives its parent run's user- and tenant-scope core
4201
+ * blocks. */
4202
+ inherit_core_blocks?: boolean;
4203
+ /** Cap on all memory-injected prompt content, in tokens (estimated); 0 = the
4204
+ * server's default. */
4205
+ memory_inject_max_tokens?: number;
4206
+ /** Opt into the memory-usage protocol note. */
4207
+ memory_protocol?: boolean;
4208
+ /** Soft size cap, in bytes, the memory protocol asks the agent to keep its
4209
+ * index document under; 0 = the server's default. */
4210
+ memory_index_max_bytes?: number;
4211
+ /** Grant the Memory tool's consolidation control ops. Default-deny. */
4212
+ memory_consolidation?: boolean;
4213
+ /** Provisioning of the user-root memory document: `lazy` (default),
4214
+ * `force` or `suppress`. */
4215
+ memory_roots?: "lazy" | "force" | "suppress";
4216
+ /** Append the runtime's capability and tool-guide text to the system prompt
4217
+ * — for small models that under-read tool schemas. */
4218
+ inject_tool_guide?: boolean;
4219
+ /** Mark the agent as maintenance plumbing: its chats are excluded from
4220
+ * memory consolidation and hidden from History by default. A fork can set
4221
+ * it and cannot clear it. */
4222
+ internal?: boolean;
4223
+ /** Which AgentDef names this agent may fork / promote / retire: `self`,
4224
+ * `descendants`, `named:<name>` or `any`. Default-deny. */
4225
+ agent_def_scopes?: string[];
4226
+ /** Same closed set as `agent_def_scopes`, for ScheduleDef. Default-deny. */
4227
+ schedule_def_scopes?: string[];
4228
+ /** Same closed set as `agent_def_scopes`, for A2AServerCardDef. Default-deny. */
4229
+ a2a_server_card_def_scopes?: string[];
4230
+ /** Same closed set as `agent_def_scopes`, for A2AAgentDef. Default-deny. */
4231
+ a2a_agent_def_scopes?: string[];
4232
+ /** Which volumes this agent may create / delete / purge: `named:<volume>`
4233
+ * or `any`. Default-deny. */
4234
+ volume_def_scopes?: string[];
3791
4235
  [extra: string]: unknown;
3792
4236
  }
3793
4237
  /** Options for {@link LoomcycleClient.ensureCodeAgent}. */
@@ -3832,6 +4276,507 @@ export interface MCPServerDefVerifyResult {
3832
4276
  /** True if an active row exists for this name. */
3833
4277
  deployed: boolean;
3834
4278
  }
4279
+ /** A HookDef's body: a code-js script the server runs in-process, or a webhook
4280
+ * it calls. The server refuses a code-js body carrying a url or headers, and
4281
+ * an http body carrying code. */
4282
+ export type HookDefBody = {
4283
+ kind: "code-js";
4284
+ /** A script defining `function hook(ev)` that returns the decision. */
4285
+ code: string;
4286
+ } | {
4287
+ kind: "http";
4288
+ /** http:// or https://. */
4289
+ url: string;
4290
+ /** Sent with each call. A value may name a credential as
4291
+ * `$cred:<name>`, resolved for the run when the hook is called — keep
4292
+ * secrets there, not in the URL or a literal value. */
4293
+ headers?: Record<string, string>;
4294
+ /** Signs every delivery: the credential, as `"$cred:<name>"` and nothing
4295
+ * else, whose value keys the `X-Loomcycle-Signature` HMAC. It must be
4296
+ * usable for this `url` (unrestricted, or its `allowed_urls` covering
4297
+ * it). A secret that cannot be resolved fails the call; it is never
4298
+ * sent unsigned. Verify with `verifyLoomcycleDelivery`. */
4299
+ signing_secret?: string;
4300
+ };
4301
+ /** Narrows a tool-event hook (`pre` / `post` / `post_failure`) within what it
4302
+ * is attached to. The server refuses it on any other event. */
4303
+ export type HookDefMatch = {
4304
+ /** Exact tool names or trailing-`*` globs; empty = every tool. */
4305
+ tools?: string[];
4306
+ };
4307
+ /** A HookDef's definition — the `overlay` of a `hookDef` create.
4308
+ *
4309
+ * CLOSED on purpose (no index signature): the server decodes the overlay
4310
+ * strictly and refuses any key it does not know, so an unknown key here is a
4311
+ * compile error rather than a runtime refusal. A type alias rather than an
4312
+ * interface so it stays assignable to the loose `SubstrateToolInput.overlay`. */
4313
+ export type HookDefOverlay = {
4314
+ /** Shown to whoever the hook denies, holds or rewrites — including a tenant
4315
+ * that did not write it. The body is never shown. At most 4 KiB. */
4316
+ description?: string;
4317
+ /** What the hook answers. Wherever it is attached, it is attached under this
4318
+ * event; `channel_publish` is a channel's own. */
4319
+ event: HookEvent;
4320
+ match?: HookDefMatch;
4321
+ body: HookDefBody;
4322
+ /** `"open"` (default): a failing hook lets the call through. `"closed"`: it
4323
+ * stops it. */
4324
+ fail_mode?: HookFailMode;
4325
+ /** Webhook: the whole call (default 5 s, max 60 s). code-js: each run of the
4326
+ * script (default 50 ms, max 1 s). */
4327
+ timeout_ms?: number;
4328
+ };
4329
+ /** The `overlay` of a `hookDef` fork: each top-level field given replaces the
4330
+ * parent's, and `null` clears one (it decodes to the field's zero value). */
4331
+ export type HookDefForkOverlay = {
4332
+ [K in keyof HookDefOverlay]?: HookDefOverlay[K] | null;
4333
+ };
4334
+ /** Typed input for {@link LoomcycleClient.hookDef}, one shape per op. */
4335
+ export type HookDefInput = {
4336
+ op: "create";
4337
+ name: string;
4338
+ overlay: HookDefOverlay;
4339
+ /** Free-text rationale (distinct from `overlay.description`). */
4340
+ description?: string;
4341
+ /** Default true. */
4342
+ promote?: boolean;
4343
+ } | {
4344
+ op: "fork";
4345
+ name: string;
4346
+ /** Default: the active version of `name` in your tenant. */
4347
+ parent_def_id?: string;
4348
+ overlay?: HookDefForkOverlay;
4349
+ description?: string;
4350
+ /** Default false. */
4351
+ promote?: boolean;
4352
+ }
4353
+ /** By `def_id`, or the active version of `name`. */
4354
+ | {
4355
+ op: "get";
4356
+ name?: string;
4357
+ def_id?: string;
4358
+ } | {
4359
+ op: "list";
4360
+ name: string;
4361
+ } | {
4362
+ op: "promote";
4363
+ def_id: string;
4364
+ } | {
4365
+ op: "retire";
4366
+ def_id: string;
4367
+ retired: boolean;
4368
+ } | {
4369
+ op: "verify";
4370
+ name: string;
4371
+ content_sha256?: string;
4372
+ } | {
4373
+ op: "delete";
4374
+ name: string;
4375
+ };
4376
+ /** One HookDef version, as create / fork / get return it (`list` returns
4377
+ * `{name, versions: HookDefRowResponse[]}`). */
4378
+ export interface HookDefRowResponse {
4379
+ def_id: string;
4380
+ name: string;
4381
+ version: number;
4382
+ parent_def_id?: string;
4383
+ description?: string;
4384
+ created_at: string;
4385
+ created_by_agent_id?: string;
4386
+ retired: boolean;
4387
+ /** "sha256:" + 64 hex chars, over the name and the normalized definition. */
4388
+ content_sha256: string;
4389
+ tenant_id?: string;
4390
+ /** The stored definition, normalized: `fail_mode` filled in, empty fields
4391
+ * left out. */
4392
+ definition: HookDefOverlay;
4393
+ /** On create / fork: whether the new version was made active. */
4394
+ promoted?: boolean;
4395
+ }
4396
+ /** Response shape for `HookDef verify`; same semantics as
4397
+ * {@link MCPServerDefVerifyResult}. Asking without `content_sha256` is how to
4398
+ * learn whether `name` is deployed at all: `deployed: false`, never an error. */
4399
+ export interface HookDefVerifyResult {
4400
+ matches: boolean;
4401
+ current_sha256: string;
4402
+ current_def_id: string;
4403
+ version: number;
4404
+ name: string;
4405
+ deployed: boolean;
4406
+ }
4407
+ /** Options for the strictly-typed create methods
4408
+ * ({@link LoomcycleClient.createHookDef},
4409
+ * {@link LoomcycleClient.createScheduleDef},
4410
+ * {@link LoomcycleClient.createWebhookDef}). */
4411
+ export interface CreateDefOptions {
4412
+ /** Free-text rationale stored on the version (not part of the definition). */
4413
+ description?: string;
4414
+ /** Make the new version active. Server default: true. */
4415
+ promote?: boolean;
4416
+ signal?: AbortSignal;
4417
+ }
4418
+ /** Options for the strictly-typed fork methods. */
4419
+ export interface ForkDefOptions extends CreateDefOptions {
4420
+ /** The version to fork. Default: the active version of the name in your
4421
+ * tenant (ScheduleDef / WebhookDef fall back to the yaml template of that
4422
+ * name). Server default for `promote` on a fork: false for HookDef, true
4423
+ * for ScheduleDef and WebhookDef. */
4424
+ parentDefId?: string;
4425
+ }
4426
+ /** Options for {@link LoomcycleClient.ensureHookDef}. */
4427
+ export interface EnsureHookDefOptions {
4428
+ /** Free-text rationale stored on a NEW version. Not part of the definition,
4429
+ * so changing only this does not mint one. */
4430
+ description?: string;
4431
+ signal?: AbortSignal;
4432
+ }
4433
+ /** Result of {@link LoomcycleClient.ensureHookDef}. */
4434
+ export interface EnsureHookDefResult {
4435
+ name: string;
4436
+ defId: string;
4437
+ version: number;
4438
+ /** True when this call created a version; false when the active version
4439
+ * already carried the same definition. */
4440
+ changed: boolean;
4441
+ }
4442
+ /** One `on_complete` entry of a ScheduleDef or WebhookDef: what the server
4443
+ * does after the triggered run finishes. Mirrors config.ScheduledRunHook. */
4444
+ export type ScheduledRunHook = {
4445
+ kind: "channel.publish";
4446
+ channel: string;
4447
+ payload?: Record<string, unknown>;
4448
+ } | {
4449
+ kind: "mcp.call";
4450
+ server: string;
4451
+ tool: string;
4452
+ args?: Record<string, unknown>;
4453
+ } | {
4454
+ kind: "memory.set";
4455
+ scope: string;
4456
+ key: string;
4457
+ /** The value written. */
4458
+ payload?: Record<string, unknown>;
4459
+ };
4460
+ /** One block of a scheduled run's prompt. Only text survives into the run, so
4461
+ * there is no image form here. */
4462
+ export interface ScheduledRunPromptContent {
4463
+ /** Default `"trusted-text"`. `"untrusted-block"` wraps the text as external
4464
+ * input. */
4465
+ type?: "trusted-text" | "untrusted-block";
4466
+ text: string;
4467
+ }
4468
+ /** One segment of a scheduled run's prompt. */
4469
+ export interface ScheduledRunPromptSegment {
4470
+ role: "system" | "user";
4471
+ content: ScheduledRunPromptContent[];
4472
+ }
4473
+ /** The `overlay` of a `scheduleDef` create / fork. On fork, a field the
4474
+ * overlay leaves out keeps the parent's; the credential maps merge key by key.
4475
+ *
4476
+ * The `[extra]` tail stays because the server decodes the overlay loosely and
4477
+ * ignores keys it does not know — including the fields it stamps itself
4478
+ * (`operator_key_restricted`, `isolated`, `capture_disabled`,
4479
+ * `operator_layer`), which an overlay can neither set nor clear. */
4480
+ export interface ScheduleDefOverlay {
4481
+ /** `"run"` (default) invokes `agent`; `"channel"` publishes a tick to
4482
+ * `channel` and starts no run; `"team"` starts a detached walk of `team`. */
4483
+ delivery?: "run" | "channel" | "team";
4484
+ channel?: string;
4485
+ agent?: string;
4486
+ prompt?: ScheduledRunPromptSegment[];
4487
+ /** A 5-field cron expression. Setting it clears `user_tier_schedules`. */
4488
+ schedule?: string;
4489
+ /** Cron per user tier, for a template a fork picks from with `user_tier`.
4490
+ * Setting it clears `schedule`. */
4491
+ user_tier_schedules?: Record<string, string>;
4492
+ required_credentials?: string[];
4493
+ /** IANA zone the cron is read in, e.g. `"Europe/Berlin"`. Default UTC. */
4494
+ timezone?: string;
4495
+ enabled?: boolean;
4496
+ /** 0–1000: run the newest N slots missed during an outage, in slot order.
4497
+ * 0 (default) collapses them into one fire. */
4498
+ catch_up_max?: number;
4499
+ /** N > 0 retires the def after its Nth fire; 0 = unbounded (a fork sends 0
4500
+ * to lift a parent's cap). */
4501
+ max_fires?: number;
4502
+ user_id?: string;
4503
+ /** What a slot does while the previous run is still going. Default
4504
+ * `"forbid"`; refused on `delivery: "channel"`. */
4505
+ concurrency_policy?: "forbid" | "allow" | "replace";
4506
+ user_tier?: string;
4507
+ /** Credential key → value, handed to the fired run. */
4508
+ user_credentials?: Record<string, string>;
4509
+ /** Credential key → env-var NAME the scheduler reads it from (the variable
4510
+ * must be on LOOMCYCLE_SCHEDULER_ENV_ALLOWLIST). */
4511
+ user_credentials_from_env?: Record<string, string>;
4512
+ /** The fired run's bearer — what `${run.user_bearer}` in an MCP server's
4513
+ * headers becomes. Only a stored credential, `"$cred:<name>"`: resolved
4514
+ * for each MCP request, for that server's URL, as a tenant-level
4515
+ * credential of the run's tenant (never a user's or an agent's), so a
4516
+ * credential restricted by `allowed_urls` works. Refused on delivery
4517
+ * `channel` or `team`. */
4518
+ user_bearer?: string;
4519
+ on_complete?: ScheduledRunHook[];
4520
+ /** Non-secret metadata the agent receives as trusted. */
4521
+ metadata?: Record<string, unknown>;
4522
+ /** The tenant fired runs execute in. Your own unless you are an admin;
4523
+ * omit it to use yours. */
4524
+ tenant_id?: string;
4525
+ /** `delivery: "team"` only: the team, its variables as literals, and the
4526
+ * walk's optional input. */
4527
+ team?: string;
4528
+ vars?: Record<string, string>;
4529
+ input?: string;
4530
+ [extra: string]: unknown;
4531
+ }
4532
+ /** Typed input for {@link LoomcycleClient.scheduleDef}, one shape per op. */
4533
+ export type ScheduleDefInput = {
4534
+ op: "create" | "fork";
4535
+ name: string;
4536
+ /** fork only. Default: the active version of `name`, or its yaml
4537
+ * template. */
4538
+ parent_def_id?: string;
4539
+ overlay?: ScheduleDefOverlay;
4540
+ description?: string;
4541
+ /** Default true on both create and fork. */
4542
+ promote?: boolean;
4543
+ } | {
4544
+ op: "get";
4545
+ def_id: string;
4546
+ } | {
4547
+ op: "list";
4548
+ name: string;
4549
+ } | {
4550
+ op: "retire";
4551
+ def_id: string;
4552
+ retired: boolean;
4553
+ }
4554
+ /** Fork `def_id` with `hook` appended to its `on_complete`. */
4555
+ | {
4556
+ op: "add_hook";
4557
+ def_id: string;
4558
+ hook: ScheduledRunHook;
4559
+ }
4560
+ /** Fork `def_id` without its `on_complete[hook_index]` (0-based). */
4561
+ | {
4562
+ op: "remove_hook";
4563
+ def_id: string;
4564
+ hook_index: number;
4565
+ };
4566
+ /** One ScheduleDef version, as create / fork return it. */
4567
+ export interface ScheduleDefRowResponse {
4568
+ def_id: string;
4569
+ name: string;
4570
+ version: number;
4571
+ parent_def_id?: string;
4572
+ description?: string;
4573
+ created_at: string;
4574
+ created_by_agent_id?: string;
4575
+ retired: boolean;
4576
+ bootstrapped_from_static: boolean;
4577
+ /** The stored definition, including the fields the server stamps. */
4578
+ definition: ScheduleDefOverlay;
4579
+ /** Whether the new version was made active. */
4580
+ promoted?: boolean;
4581
+ /** Credential keys a snapshot stripped that this write did not re-supply;
4582
+ * the def stays disabled until they are. */
4583
+ disabled_until_credentials_supplied?: string[];
4584
+ /** Why a key you did name did not count, one line per key. */
4585
+ unusable_credentials?: string[];
4586
+ }
4587
+ /** How a WebhookDef authenticates an inbound request. */
4588
+ export interface WebhookDefAuth {
4589
+ /** `"hmac"` (default) verifies a body signature; `"bearer"` a token;
4590
+ * `"none"` neither. */
4591
+ kind?: "hmac" | "bearer" | "none";
4592
+ /** hmac only; the only one implemented. */
4593
+ algorithm?: "sha256";
4594
+ /** The header carrying the signature. */
4595
+ header?: string;
4596
+ /** Env-var NAME holding the hmac secret — never the secret itself. */
4597
+ signing_secret_env?: string;
4598
+ /** The header naming each delivery, for dedup; without it a body hash is
4599
+ * the delivery's identity. */
4600
+ delivery_id_header?: string;
4601
+ /** Env-var NAME holding the bearer token — never the token itself. */
4602
+ bearer_token_env?: string;
4603
+ /** The verification secret as a stored credential, `"$cred:<name>"` — a
4604
+ * tenant credential of the definition's own tenant, resolved on each
4605
+ * delivery so a rotation needs no restart. Takes the place of
4606
+ * `signing_secret_env` / `bearer_token_env`: set one form, not both. A
4607
+ * literal is refused. */
4608
+ secret?: string;
4609
+ /** The previous secret during a rotation, also `"$cred:<name>"`: a delivery
4610
+ * verified by either is accepted. */
4611
+ previous_secret?: string;
4612
+ }
4613
+ /** One condition a webhook delivery's signed body must meet. Comparison is
4614
+ * typed (a string never equals a number), and a path that is missing, null,
4615
+ * or of another type than the value misses for every `op`, `ne` included. */
4616
+ export interface WebhookDefFilter {
4617
+ /** A JSONPath into the body: `$`, `.key` and `[N]` only. */
4618
+ path: string;
4619
+ /** `glob` takes a string pattern (`*` any run of characters, `?` one);
4620
+ * `in` takes a list of values. */
4621
+ op: "eq" | "ne" | "glob" | "in";
4622
+ /** A literal; set this or `value_from`. */
4623
+ value?: string | number | boolean | Array<string | number | boolean>;
4624
+ /** `"metadata.<key>"`: the definition's own metadata entry of that key. */
4625
+ value_from?: string;
4626
+ }
4627
+ /** Inbound request rate bound for one webhook. */
4628
+ export interface WebhookDefRateLimit {
4629
+ requests_per_minute?: number;
4630
+ burst?: number;
4631
+ }
4632
+ /** Hold the inbound request open until the run finishes (or the timeout). */
4633
+ export interface WebhookDefSyncResponse {
4634
+ enabled?: boolean;
4635
+ timeout_ms?: number;
4636
+ }
4637
+ /** The `overlay` of a `webhookDef` create / fork. On fork, a field the overlay
4638
+ * leaves out keeps the parent's; naming exactly one of `agent` / `channel` /
4639
+ * `team` clears the other two.
4640
+ *
4641
+ * The `[extra]` tail stays for now: the server decodes the overlay loosely
4642
+ * and ignores keys it does not know — including the fields it stamps itself
4643
+ * (`operator_key_restricted`, `isolated`, `capture_disabled`). */
4644
+ export interface WebhookDefOverlay {
4645
+ /** An overlay can only turn a webhook on; to turn one off, restate it. */
4646
+ enabled?: boolean;
4647
+ /** `"spawn"` (default) starts a run of `agent`; `"channel"` publishes the
4648
+ * body to `channel`; `"team"` starts a detached walk of `team` with the body
4649
+ * as its input. */
4650
+ delivery?: "spawn" | "channel" | "team";
4651
+ agent?: string;
4652
+ channel?: string;
4653
+ auth?: WebhookDefAuth;
4654
+ rate_limit?: WebhookDefRateLimit;
4655
+ body_size_limit_bytes?: number;
4656
+ /** Credential key → env-var NAME the receiver reads it from. */
4657
+ user_credentials_from_env?: Record<string, string>;
4658
+ /** Credential key → value, handed to the run. */
4659
+ user_credentials?: Record<string, string>;
4660
+ /** The started run's bearer — what `${run.user_bearer}` in an MCP server's
4661
+ * headers becomes. Only a stored credential, `"$cred:<name>"`: resolved
4662
+ * for each MCP request, for that server's URL, as a tenant-level
4663
+ * credential of the run's tenant (never a user's or an agent's), so a
4664
+ * credential restricted by `allowed_urls` works. Refused on delivery
4665
+ * `channel` or `team`. */
4666
+ user_bearer?: string;
4667
+ /** Pins the started run's user tier; a delivery never chooses it. Must be
4668
+ * one of the server's user tiers. */
4669
+ user_tier?: string;
4670
+ /** A forge preset — `"github"`, `"gitea"` or `"gitlab"` — supplying
4671
+ * defaults for the auth kind and headers, the event header, the ping and
4672
+ * the shapes of the events it knows. A field set here overrides it. */
4673
+ provider?: string;
4674
+ /** The request header naming a delivery's event. */
4675
+ event_header?: string;
4676
+ /** When set, the only events that start anything: another is answered 202
4677
+ * `ignored`, the provider's ping 200, and a listed event counts only when
4678
+ * the signed body has its shape. Unset: every delivery is handled. */
4679
+ events?: string[];
4680
+ /** The rules the body of a listed event must meet, for an event the
4681
+ * provider has no shape for, or in place of its. Each rule is a JSONPath
4682
+ * the body holds, `!path` for one it must not hold (missing or null), or
4683
+ * `path == <JSON string, number or boolean>` for a field's value, e.g.
4684
+ * `$.object_kind == "push"`. A fork merges key by key; an empty list
4685
+ * removes that event's shape. */
4686
+ event_shapes?: Record<string, string[]>;
4687
+ /** Conditions on the signed body every delivery must meet before anything
4688
+ * starts; one that misses answers 202 `filtered`. A fork replaces the
4689
+ * whole list; `[]` removes it. */
4690
+ filters?: WebhookDefFilter[];
4691
+ /** JSONPaths into the signed body whose values together name one event
4692
+ * (for a GitHub push: `$.repository.id`, `$.ref`, `$.after`). A delivery
4693
+ * with the same values is answered as a duplicate whatever its delivery id
4694
+ * or bytes, unless the run the first one started ended `failed`. A body
4695
+ * lacking one answers 400 `dedup_key_unresolvable`. 1 to 16 paths; a fork
4696
+ * replaces the list, `[]` removes it. */
4697
+ dedup_key?: string[];
4698
+ /** How long a `dedup_key` is held, in seconds: default 604800 (7 days),
4699
+ * at most 90 days. Only beside `dedup_key`. */
4700
+ dedup_ttl_seconds?: number;
4701
+ /** Non-secret metadata the agent receives as trusted. */
4702
+ metadata?: Record<string, unknown>;
4703
+ /** The tenant spawned runs execute in — taken from the def, never from the
4704
+ * payload. Your own unless you are an admin; omit it to use yours. */
4705
+ tenant_id?: string;
4706
+ /** Target → JSONPath into the request body (`$`, `.key` and `[N]` only).
4707
+ * Targets: `goal`, `user_id`, `user_credentials.<KEY>`,
4708
+ * `run_metadata.<key>`. */
4709
+ payload_mapping?: Record<string, string>;
4710
+ sync_response?: WebhookDefSyncResponse;
4711
+ on_complete?: ScheduledRunHook[];
4712
+ /** `delivery: "team"` only: the team, and each variable as a JSONPath into
4713
+ * the body (`$`, `.key` and `[N]` only). */
4714
+ team?: string;
4715
+ vars?: Record<string, string>;
4716
+ [extra: string]: unknown;
4717
+ }
4718
+ /** One WebhookDef version, as create / fork return it. */
4719
+ export interface WebhookDefRowResponse {
4720
+ def_id: string;
4721
+ name: string;
4722
+ version: number;
4723
+ parent_def_id?: string;
4724
+ description?: string;
4725
+ created_at: string;
4726
+ created_by_agent_id?: string;
4727
+ retired: boolean;
4728
+ bootstrapped_from_static: boolean;
4729
+ /** The stored definition, including the fields the server stamps. */
4730
+ definition: WebhookDefOverlay;
4731
+ promoted?: boolean;
4732
+ /** Same meaning as on {@link ScheduleDefRowResponse}. */
4733
+ disabled_until_credentials_supplied?: string[];
4734
+ unusable_credentials?: string[];
4735
+ /** `get` only: how the webhook's deliveries were answered. */
4736
+ status?: {
4737
+ deliveries?: WebhookDefDeliveries;
4738
+ };
4739
+ }
4740
+ /** A webhook's delivery counts, on `webhookDef({op: "get"})` as
4741
+ * `status.deliveries`. They belong to the webhook (its name in its tenant),
4742
+ * not to one version; every replica adds its counts every 30 seconds, so
4743
+ * they are up to that far behind. */
4744
+ export interface WebhookDefDeliveries {
4745
+ accepted: number;
4746
+ duplicate: number;
4747
+ ping: number;
4748
+ ignored: number;
4749
+ filtered: number;
4750
+ /** Refused deliveries by reason: `signature`, `secret`, `event`, `shape`,
4751
+ * `body`, `mapping`, `rate`, `dedup_key`, … */
4752
+ refused: Record<string, number>;
4753
+ /** Deliveries that ended otherwise (a sync `timeout`, `client_gone`). */
4754
+ other?: Record<string, number>;
4755
+ /** When a counted delivery was last written (RFC 3339). */
4756
+ last_at?: string;
4757
+ }
4758
+ /** Typed input for {@link LoomcycleClient.webhookDef}, one shape per op. */
4759
+ export type WebhookDefInput = {
4760
+ op: "create" | "fork";
4761
+ name: string;
4762
+ /** fork only. Default: the active version of `name`, or its yaml
4763
+ * template. */
4764
+ parent_def_id?: string;
4765
+ overlay?: WebhookDefOverlay;
4766
+ description?: string;
4767
+ /** Default true on both create and fork. */
4768
+ promote?: boolean;
4769
+ } | {
4770
+ op: "get";
4771
+ def_id: string;
4772
+ } | {
4773
+ op: "list";
4774
+ name: string;
4775
+ } | {
4776
+ op: "retire";
4777
+ def_id: string;
4778
+ retired: boolean;
4779
+ };
3835
4780
  /** Static-side agent definition body. Snake_case keys mirror
3836
4781
  * internal/lookup.SubstrateAgentDef so substrate-side and static-side
3837
4782
  * definitions share one renderer. Forward-compatible: unknown fields
@@ -4268,6 +5213,12 @@ export interface CredentialMeta {
4268
5213
  updated_at?: string;
4269
5214
  expires_at?: string;
4270
5215
  status?: string;
5216
+ /** The https URLs the value may be sent to, in canonical form. Absent for
5217
+ * an unrestricted credential; `[]` for one that is sent nowhere. */
5218
+ allowed_urls?: string[];
5219
+ /** The user name sent with the value where a destination takes one (HTTP
5220
+ * basic auth for a git source). Absent when none is stored. */
5221
+ username?: string;
4271
5222
  }
4272
5223
  /** CredentialListResponse is the {op:list} result: metadata for the given scope. */
4273
5224
  export interface CredentialListResponse {
@@ -4392,3 +5343,343 @@ export interface DecisionModelsResponse {
4392
5343
  default: string;
4393
5344
  models: DecisionModel[];
4394
5345
  }
5346
+ /** One name's version roll-up from a `list*DefNames` method. Shared by every
5347
+ * def family except OperatorTokenDef ({@link OperatorTokenDefNameSummary}). */
5348
+ export interface DefNameSummary {
5349
+ name: string;
5350
+ /** The owning tenant; absent for the shared "" tenant. */
5351
+ tenant_id?: string;
5352
+ version_count: number;
5353
+ active_def_id?: string;
5354
+ latest_version: number;
5355
+ /** When the newest version was created (RFC 3339). */
5356
+ last_updated: string;
5357
+ /** Versions not retired. Reported by the AgentDef, SkillDef, HookDef and
5358
+ * MCPServerDef families only. */
5359
+ live_version_count?: number;
5360
+ /** The active version is retired. Same families as `live_version_count`. */
5361
+ active_retired?: boolean;
5362
+ }
5363
+ /** Response of the `list*DefNames` methods. `names` is `[]`, never `null`,
5364
+ * when nothing is declared. */
5365
+ export interface DefNamesResponse {
5366
+ names: DefNameSummary[];
5367
+ }
5368
+ /** One token name's summary from {@link LoomcycleClient.listOperatorTokenDefNames}.
5369
+ * Carries no secret material. */
5370
+ export interface OperatorTokenDefNameSummary {
5371
+ name: string;
5372
+ tenant_id: string;
5373
+ subject: string;
5374
+ /** Every token minted under the name, rotated and retired ones included. */
5375
+ token_count: number;
5376
+ /** A non-retired token exists. */
5377
+ has_current: boolean;
5378
+ last_updated: string;
5379
+ }
5380
+ /** Response of {@link LoomcycleClient.listOperatorTokenDefNames}. */
5381
+ export interface OperatorTokenDefNamesResponse {
5382
+ names: OperatorTokenDefNameSummary[];
5383
+ }
5384
+ /** One schedule in {@link LoomcycleClient.listAllSchedules}: a static yaml
5385
+ * `scheduled_runs` entry, a ScheduleDef, or both under one name. */
5386
+ export interface ScheduleListEntry {
5387
+ name: string;
5388
+ source: "static-only" | "dynamic-only" | "both";
5389
+ in_static: boolean;
5390
+ in_substrate: boolean;
5391
+ version_count?: number;
5392
+ /** The def id the per-schedule methods take. Absent for a static-only
5393
+ * schedule, which has no ScheduleDef to address. */
5394
+ active_def_id?: string;
5395
+ latest_version?: number;
5396
+ /** When the newest ScheduleDef version was created. Absent for a
5397
+ * static-only schedule. */
5398
+ last_updated?: string;
5399
+ /** The yaml definition, for a static entry. */
5400
+ static_definition?: unknown;
5401
+ }
5402
+ /** Response of {@link LoomcycleClient.listAllSchedules}. */
5403
+ export interface ScheduleListResponse {
5404
+ entries: ScheduleListEntry[];
5405
+ }
5406
+ /** A run a schedule started and has not finished. */
5407
+ export interface ScheduleActiveRun {
5408
+ def_id: string;
5409
+ run_id: string;
5410
+ /** The slot the run was fired for. */
5411
+ slot_at: string;
5412
+ /** Fired for a missed slot rather than a live one. */
5413
+ catch_up?: boolean;
5414
+ started_at: string;
5415
+ /** The replica that claimed the slot; absent outside cluster mode. */
5416
+ claimed_by?: string;
5417
+ }
5418
+ /** A schedule's runtime state from {@link LoomcycleClient.getScheduleState}.
5419
+ * Credentials never appear here. An optional instant is absent when unset —
5420
+ * test for presence. (A server before the fix that dropped them sent
5421
+ * `last_run_at` and `paused_until` as "0001-01-01T00:00:00Z" instead.) */
5422
+ export interface ScheduleStateView {
5423
+ def_id: string;
5424
+ /** Absent until the schedule first fires. */
5425
+ last_run_at?: string;
5426
+ last_run_id?: string;
5427
+ /** completed | failed | cancelled | rejected | running | skipped_overlap | skipped… */
5428
+ last_status?: string;
5429
+ last_error?: string;
5430
+ next_run_at: string;
5431
+ /** Present while paused. {@link LoomcycleClient.pauseSchedule} sets it about
5432
+ * 100 years ahead: an indefinite pause. */
5433
+ paused_until?: string;
5434
+ /** Fires so far, the count `max_fires` is measured against. */
5435
+ fire_count: number;
5436
+ /** The last claim: which slot, which replica, when. */
5437
+ slot_at?: string;
5438
+ claimed_by?: string;
5439
+ claimed_at?: string;
5440
+ /** When the last tracked run finished. */
5441
+ finished_at?: string;
5442
+ /** Present while a `catch_up_max` backlog drains: its newest slot. */
5443
+ catch_up_until?: string;
5444
+ /** Slots the last outage dropped (older than `catch_up_max`). */
5445
+ missed_slots?: number;
5446
+ /** Every run the schedule started and has not finished — `[]`, never absent. */
5447
+ active_runs: ScheduleActiveRun[];
5448
+ }
5449
+ /** Result of {@link LoomcycleClient.runScheduleNow}. The run starts on the
5450
+ * scheduler's next tick, not during the call. */
5451
+ export interface ScheduleRunNowResult {
5452
+ def_id: string;
5453
+ scheduled: "next-tick";
5454
+ }
5455
+ /** Result of {@link LoomcycleClient.pauseSchedule} / {@link LoomcycleClient.resumeSchedule}. */
5456
+ export interface SchedulePauseResult {
5457
+ def_id: string;
5458
+ paused: boolean;
5459
+ }
5460
+ /** One configured model alias (the top-level `models:` map). */
5461
+ export interface ModelAlias {
5462
+ provider: string;
5463
+ model: string;
5464
+ /** chat | decision | embedder. Absent for an untagged alias, which is a chat
5465
+ * model. */
5466
+ kind?: string;
5467
+ }
5468
+ /** Response of {@link LoomcycleClient.listModels}: alias name → target. */
5469
+ export interface ModelAliasesResponse {
5470
+ aliases: Record<string, ModelAlias>;
5471
+ }
5472
+ /** A candidate's throughput estimate. `multiplier` is what a scaled timeout
5473
+ * would be multiplied by. */
5474
+ export interface RoutingThroughput {
5475
+ slowdown?: number;
5476
+ multiplier: number;
5477
+ samples: number;
5478
+ source: string;
5479
+ decode_tps?: number;
5480
+ prefill_tps?: number;
5481
+ ttft_ms?: number;
5482
+ cold_load_ms?: number;
5483
+ /** Admin only. */
5484
+ queue_ms_p50?: number;
5485
+ max_multiplier?: number;
5486
+ }
5487
+ /** One candidate in a routing cascade. */
5488
+ export interface RoutingCandidate {
5489
+ provider: string;
5490
+ model: string;
5491
+ /** First in the displayed cascade. */
5492
+ primary: boolean;
5493
+ available?: boolean;
5494
+ /** The first available candidate: what a run resolves to now. */
5495
+ selected?: boolean;
5496
+ stalled?: boolean;
5497
+ rate_limited?: boolean;
5498
+ reachable?: boolean;
5499
+ /** Absent when throughput estimation is off. */
5500
+ throughput?: RoutingThroughput;
5501
+ }
5502
+ /** One tier's ordered cascade, top first. */
5503
+ export interface RoutingTier {
5504
+ /** low | middle | high */
5505
+ tier: string;
5506
+ cascade: RoutingCandidate[];
5507
+ }
5508
+ /** One user tier's tiers. */
5509
+ export interface RoutingUserTier {
5510
+ /** "" when no user tiers are configured. */
5511
+ name: string;
5512
+ tiers: RoutingTier[];
5513
+ }
5514
+ /** One provider in the active-providers header. */
5515
+ export interface RoutingProvider {
5516
+ provider: string;
5517
+ reachable: boolean;
5518
+ excluded: boolean;
5519
+ /** The raw probe error — admin only. */
5520
+ last_error?: string;
5521
+ }
5522
+ /** One web-search provider in the search cascade. */
5523
+ export interface SearchRoutingProvider {
5524
+ provider: string;
5525
+ primary: boolean;
5526
+ /** This caller has a usable key. */
5527
+ keyable?: boolean;
5528
+ /** Keyable and not in a failure cooldown. */
5529
+ available?: boolean;
5530
+ selected?: boolean;
5531
+ reachable?: boolean;
5532
+ /** Admin only. */
5533
+ last_error?: string;
5534
+ }
5535
+ /** Response of {@link LoomcycleClient.getRouting}. */
5536
+ export interface RoutingResponse {
5537
+ generated_at: string;
5538
+ /** The caller gets the admin view: raw `last_error`, nothing filtered. */
5539
+ admin: boolean;
5540
+ providers?: RoutingProvider[];
5541
+ user_tiers: RoutingUserTier[];
5542
+ /** The operator-key gate is on and this tenant's view is filtered to the
5543
+ * providers it can key itself. */
5544
+ operator_key_restricted?: boolean;
5545
+ /** `timeout_scaling.mode` when throughput estimation is on. */
5546
+ throughput_mode?: string;
5547
+ /** Absent when no search providers are configured. */
5548
+ search?: SearchRoutingProvider[];
5549
+ }
5550
+ /** Response of {@link LoomcycleClient.listProviderModels}: a live listing from
5551
+ * the provider, not the cached probe matrix. */
5552
+ export interface ProviderModelsResponse {
5553
+ provider: string;
5554
+ fetched_at: string;
5555
+ duration_ms: number;
5556
+ /** Provider-native model ids. `[]` when the provider answered with none. */
5557
+ models: string[];
5558
+ }
5559
+ /** Options of {@link LoomcycleClient.createTeam}. */
5560
+ export interface CreateTeamOptions {
5561
+ signal?: AbortSignal;
5562
+ /** Make the new version the team's active one. The server default is true
5563
+ * for a create; pass `false` to author it without putting it in force
5564
+ * (then {@link LoomcycleClient.promoteTeam}). */
5565
+ promote?: boolean;
5566
+ /** Free-text rationale stored on the version. */
5567
+ description?: string;
5568
+ }
5569
+ /** Options of {@link LoomcycleClient.forkTeam}. Note `promote` defaults the
5570
+ * other way from a create: false. */
5571
+ export interface ForkTeamOptions extends CreateTeamOptions {
5572
+ /** Make the new version the team's active one. The server default is false:
5573
+ * a fork is authored first and put in force with
5574
+ * {@link LoomcycleClient.promoteTeam}. */
5575
+ promote?: boolean;
5576
+ /** Fork this version instead of the name's active one. */
5577
+ parentDefId?: string;
5578
+ }
5579
+ /** The kind of change a {@link MemoryChange} names. `memory.*` arrive on
5580
+ * {@link LoomcycleClient.streamMemoryChanges}, `document.chunk.*` on
5581
+ * {@link LoomcycleClient.streamDocumentChanges}. Mirrors the runtime's
5582
+ * `store.MemoryChangeType`. */
5583
+ export type MemoryChangeType = "memory.set" | "memory.delete" | "memory.scope_deleted" | "document.chunk.updated" | "document.chunk.deleted";
5584
+ /** The memory scope a change landed in. `global` is listed because the
5585
+ * runtime's scope enum has it and the feed passes the written scope through
5586
+ * unchanged, not because Memory writes it today. */
5587
+ export type MemoryChangeScope = "agent" | "user" | "tenant" | "global";
5588
+ /** One change coordinate, exactly as the runtime's `store.MemoryChange`
5589
+ * serialises.
5590
+ *
5591
+ * VALUE-FREE by design: it names WHAT changed, never the value — pull the
5592
+ * current value through the data API (`getMemoryEntry`, `document`). `key` is
5593
+ * set for `memory.set` / `memory.delete`; `chunk_id` for `document.chunk.*`;
5594
+ * neither for `memory.scope_deleted`, which covers the whole scope. */
5595
+ export interface MemoryChange {
5596
+ /** Monotonic cursor. Persist the last one you processed and pass it back as
5597
+ * `since` to resume after a disconnect. */
5598
+ seq: number;
5599
+ /** The caller's own tenant — the feed is never cross-tenant. Omitted for
5600
+ * the shared "" tenant. */
5601
+ tenant?: string;
5602
+ type: MemoryChangeType;
5603
+ scope: MemoryChangeScope;
5604
+ scope_id: string;
5605
+ key?: string;
5606
+ chunk_id?: string;
5607
+ /** RFC3339 time of the write. */
5608
+ at: string;
5609
+ }
5610
+ /** What the runtime's embedder has actually been doing, since boot. Mirrors
5611
+ * `providers.EmbedderHealth`.
5612
+ *
5613
+ * Carried on the change feed because an embedding failure on a content write
5614
+ * is NOT fatal — the body is stored and the embedding skipped — so an
5615
+ * embedder outage shows as a perfectly busy feed over rows that are no longer
5616
+ * searchable. `untried` is "configured, nothing embedded yet", not a warning;
5617
+ * `absent` is "no embedder configured". */
5618
+ export interface EmbedderHealth {
5619
+ state: "absent" | "untried" | "ok" | "failing";
5620
+ provider?: string;
5621
+ model?: string;
5622
+ calls: number;
5623
+ /** Failed embeddings since boot — roughly how many rows need
5624
+ * `backfillEmbeddings` to become searchable. */
5625
+ failures: number;
5626
+ /** A classified failure kind, never the raw error text (which can carry an
5627
+ * address). */
5628
+ last_failure_kind?: string;
5629
+ /** Unix seconds; absent when never. */
5630
+ last_ok_unix?: number;
5631
+ last_failure_unix?: number;
5632
+ }
5633
+ /** The opening frame of a change feed (`event: feed`). */
5634
+ export interface ChangeFeedStatus {
5635
+ /** Whether writes are being captured at all. `false` means the server runs
5636
+ * without `LOOMCYCLE_MEMORY_CHANGES_ENABLED`: the stream stays open and
5637
+ * idles, and NO change will ever arrive — check this before waiting. */
5638
+ enabled: boolean;
5639
+ /** The cursor the server accepted. `0` when `since` was absent OR
5640
+ * unparseable — the server does not reject a bad cursor. */
5641
+ since: number;
5642
+ /** Reported beside `enabled`, never folded into it: capturing and embedding
5643
+ * fail independently. Absent on a runtime older than the field. */
5644
+ embedder?: EmbedderHealth;
5645
+ }
5646
+ /** A change-feed `event: error` frame: the server could not read its change
5647
+ * log. NON-FATAL — the stream stays open, the server keeps retrying with
5648
+ * backoff, and its cursor does not advance, so change frames resume after
5649
+ * recovery without a gap. Sent once per failure streak, not per retry. */
5650
+ export interface ChangeFeedError {
5651
+ /** Machine-readable; `store_unavailable` today. Branch on this. */
5652
+ code: string;
5653
+ /** Human-readable description. */
5654
+ error: string;
5655
+ }
5656
+ /** Yielded by {@link LoomcycleClient.streamMemoryChanges} and
5657
+ * {@link LoomcycleClient.streamDocumentChanges}.
5658
+ *
5659
+ * Same `{ kind, payload }` shape as {@link RunStateStreamItem}: the first
5660
+ * item is `{ kind: "feed" }`, then one `{ kind: "change" }` per change, with
5661
+ * an occasional `{ kind: "error" }` (see {@link ChangeFeedError}) when the
5662
+ * server cannot read its change log — iteration continues past it. `kind`
5663
+ * rather than `type` so the wrapper's discriminator cannot be confused with
5664
+ * the change's own `payload.type`. */
5665
+ export type ChangeFeedFrame = {
5666
+ kind: "feed";
5667
+ payload: ChangeFeedStatus;
5668
+ } | {
5669
+ kind: "change";
5670
+ payload: MemoryChange;
5671
+ } | {
5672
+ kind: "error";
5673
+ payload: ChangeFeedError;
5674
+ };
5675
+ /** Options for {@link LoomcycleClient.streamMemoryChanges} /
5676
+ * {@link LoomcycleClient.streamDocumentChanges}. */
5677
+ export interface StreamChangesOptions {
5678
+ /** Resume cursor: deliver only changes with `seq` greater than this. Omit
5679
+ * (or `0`) to start from the oldest change the server still retains. Must
5680
+ * be a non-negative integer — the client throws rather than send a value
5681
+ * the server would silently read as `0` and replay everything. */
5682
+ since?: number;
5683
+ /** Abort to close the stream; the iterator then throws an `AbortError`. */
5684
+ signal?: AbortSignal;
5685
+ }