@deepnoodle/mobius 0.0.12 → 0.0.15

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.
@@ -335,6 +335,66 @@ export interface paths {
335
335
  patch?: never;
336
336
  trace?: never;
337
337
  };
338
+ "/v1/projects/{project}/runs/{id}/forks": {
339
+ parameters: {
340
+ query?: never;
341
+ header?: never;
342
+ path?: never;
343
+ cookie?: never;
344
+ };
345
+ get?: never;
346
+ put?: never;
347
+ /**
348
+ * Fork a terminal run from a specific step
349
+ * @description Creates a new active run that inherits step history before `from_step_id` and resumes execution at that step. The request must provide a new logical `external_id`. `external_id` keeps the normal project-wide run uniqueness semantics; retrying the same fork request with the same source run, fork step, `external_id`, and effective target definition version is idempotent and returns the existing forked run with `202` whether that fork is still active or already terminal. Omitting `definition_version_id` keeps the source run's definition version; supplying it pins post-fork execution to that explicit version, and a retry that changes this value is an `idempotency_conflict`.
350
+ */
351
+ post: operations["forkRun"];
352
+ delete?: never;
353
+ options?: never;
354
+ head?: never;
355
+ patch?: never;
356
+ trace?: never;
357
+ };
358
+ "/v1/projects/{project}/runs/{id}/steps": {
359
+ parameters: {
360
+ query?: never;
361
+ header?: never;
362
+ path?: never;
363
+ cookie?: never;
364
+ };
365
+ /**
366
+ * List run steps
367
+ * @description Lists durable `RunStep` records for a run. Run steps are the canonical execution history and remain available after terminal job rows are TTL-swept; use jobs only for live worker claim state.
368
+ */
369
+ get: operations["listRunSteps"];
370
+ put?: never;
371
+ post?: never;
372
+ delete?: never;
373
+ options?: never;
374
+ head?: never;
375
+ patch?: never;
376
+ trace?: never;
377
+ };
378
+ "/v1/projects/{project}/runs/{id}/steps/{step_id}": {
379
+ parameters: {
380
+ query?: never;
381
+ header?: never;
382
+ path?: never;
383
+ cookie?: never;
384
+ };
385
+ /**
386
+ * Get one run step
387
+ * @description Returns a single durable `RunStep` row for a workflow run. Run steps are the canonical execution history; linked job state, when present, is live worker-claim metadata and may disappear after terminal job retention.
388
+ */
389
+ get: operations["getRunStep"];
390
+ put?: never;
391
+ post?: never;
392
+ delete?: never;
393
+ options?: never;
394
+ head?: never;
395
+ patch?: never;
396
+ trace?: never;
397
+ };
338
398
  "/v1/projects/{project}/runs/{id}/action-log": {
339
399
  parameters: {
340
400
  query?: never;
@@ -390,6 +450,8 @@ export interface paths {
390
450
  * timestamps changed; `data` is a full WorkflowRun.
391
451
  * - `job_updated` — a single job's status or attempt
392
452
  * advanced; `data` is a full Job.
453
+ * - `run_step_updated` — a durable run-step row was created
454
+ * or advanced; `data` is a full RunStep.
393
455
  * - `action_appended` — one entry was appended to the run
394
456
  * timeline (worker job completed or platform action ran);
395
457
  * `data` is a WorkflowActionLog row.
@@ -399,9 +461,13 @@ export interface paths {
399
461
  * `data` is a full Interaction.
400
462
  * - `custom` — a worker emitted a domain-specific event via
401
463
  * `POST /v1/projects/{project}/jobs/{id}/events`. `data`
402
- * carries `{kind: "custom", type, job_id, data}` where
403
- * `type` is the worker-supplied name and inner `data` is
404
- * the worker payload.
464
+ * carries `{kind: "custom", type, job_id, data, step_id?,
465
+ * path_id?}` where `type` is the worker-supplied name and
466
+ * inner `data` is the worker payload. `step_id` is set when
467
+ * the originating job is owned by a workflow step and lets
468
+ * consumers correlate the event to the durable run step
469
+ * after the job is reaped on TTL; `path_id` mirrors the
470
+ * run's execution path for path-scoped consumers.
405
471
  *
406
472
  * Pass `?since=<seq>` on reconnect to replay any durable events the server has recorded past that cursor before switching back to live updates; clients should record the largest `seq` they have observed. Comment frames (`:keepalive`) are emitted every ~15s to keep intermediaries from closing the connection.
407
473
  *
@@ -683,7 +749,7 @@ export interface paths {
683
749
  put?: never;
684
750
  /**
685
751
  * Refresh the lease on a claimed workflow job
686
- * @description Extends the worker's lease on the job and returns server directives. Must include the `worker_id` + `attempt` fence from the original claim — a stale fence (e.g., from a previous attempt) is rejected with 409.
752
+ * @description Extends the worker's lease on the job and returns server directives. Must include the `worker_session_token` + `attempt` fence from the original claim — a stale fence (e.g., from a previous attempt or from a process that has since been taken over) is rejected with 409.
687
753
  *
688
754
  * Returns a small JSON envelope rather than 204 so the server can attach directives (e.g., `should_cancel`) without an additional round trip. Workers should call this at the interval specified in `JobClaim.heartbeat_interval_seconds` (recommended: 30s).
689
755
  *
@@ -707,7 +773,7 @@ export interface paths {
707
773
  put?: never;
708
774
  /**
709
775
  * Report terminal status for a claimed workflow job
710
- * @description Marks the job as completed or failed and advances workflow progression. Must include the `worker_id` + `attempt` fence from the claim — a stale fence is rejected with 409.
776
+ * @description Marks the job as completed or failed and advances workflow progression. Must include the `worker_session_token` + `attempt` fence from the claim — a stale fence is rejected with 409.
711
777
  *
712
778
  * On `status: completed`, `result_b64` (if provided) is base64- decoded and stored as the job's output bytes, which the workflow engine may pass as input to downstream steps.
713
779
  *
@@ -733,7 +799,7 @@ export interface paths {
733
799
  * Emit one or more custom events from a claimed workflow job
734
800
  * @description Publishes a batch of custom run events on behalf of the worker holding the job's current lease. Events are appended to the durable run event store (so they replay via `?since=<seq>`) and fanned out to any live SSE subscribers on the run.
735
801
  *
736
- * Authorization requires `mobius.work.execute`. Each event must present the active lease fence (`worker_id` + `attempt`); stale fences are rejected with 409.
802
+ * Authorization requires `mobius.work.execute`. Each event must present the active lease fence (`worker_session_token` + `attempt`); stale fences are rejected with 409.
737
803
  *
738
804
  * `type` is a caller-chosen identifier. The `mobius.` prefix is reserved for future server-emitted well-known kinds and is rejected with 400.
739
805
  *
@@ -923,7 +989,7 @@ export interface paths {
923
989
  };
924
990
  /**
925
991
  * List worker sessions
926
- * @description Returns worker sessions that have polled for jobs within the project. Each session's `stale` flag is computed at read time: if `last_seen_at` is older than 2 minutes (or absent), the session is considered stale. Stale sessions are retained for display but will not receive new job claims.
992
+ * @description Returns worker sessions registered against the project. Each session's `stale` flag is computed at read time: if `last_seen_at` is older than 2 minutes (or absent), the session is considered stale. Stale sessions are retained for display until the 30-day retention floor; rows older than that are hard-deleted by a background sweeper.
927
993
  */
928
994
  get: operations["listWorkerSessions"];
929
995
  put?: never;
@@ -1644,6 +1710,10 @@ export interface components {
1644
1710
  code: string;
1645
1711
  /** @description Human-readable error message */
1646
1712
  message: string;
1713
+ /** @description Optional structured details specific to a `code`. Endpoints that set this document the per-code shape inline. Absent for codes whose `code` + `message` are sufficient. */
1714
+ details?: {
1715
+ [key: string]: unknown;
1716
+ };
1647
1717
  };
1648
1718
  };
1649
1719
  /** @description Project ID. */
@@ -2422,12 +2492,20 @@ export interface components {
2422
2492
  waiting_on_signal_names: string[];
2423
2493
  interaction_ids: string[];
2424
2494
  };
2425
- /** @description Current job-claim summary for this run. `ready` counts pending jobs whose `scheduled_at` has arrived and can be claimed now; `scheduled` counts pending jobs intentionally waiting for a future retry/backoff; `claimed` counts jobs currently held by workers. */
2495
+ /** @description Live work-pool summary for this run. Reflects the transient state of the worker job queue, not durable step progress — terminal jobs are swept on a TTL and stop contributing to these counts. Use `step_counts` for run-progress UI; use this field to answer "is anything claimable right now and is a worker holding it?". `ready` counts pending jobs whose `scheduled_at` has arrived and can be claimed now; `scheduled` counts pending jobs intentionally waiting for a future retry/backoff; `claimed` counts jobs currently held by workers. */
2426
2496
  WorkflowRunJobCounts: {
2427
2497
  ready: number;
2428
2498
  scheduled: number;
2429
2499
  claimed: number;
2430
2500
  };
2501
+ /** @description Aggregate count of run-step rows for this run grouped by status. Counts every attempt of every step (one row per step x attempt x path), so it reflects durable progress rather than the live worker pool. Use this for run-progress UI; use `job_counts` for live claimability. */
2502
+ WorkflowRunStepCounts: {
2503
+ pending: number;
2504
+ running: number;
2505
+ completed: number;
2506
+ failed: number;
2507
+ cancelled: number;
2508
+ };
2431
2509
  WorkflowRunError: {
2432
2510
  path_id?: string;
2433
2511
  error_type: string;
@@ -2453,8 +2531,10 @@ export interface components {
2453
2531
  status: components["schemas"]["WorkflowRunStatus"];
2454
2532
  /** @description Current path counts derived from the run projection. */
2455
2533
  path_counts: components["schemas"]["WorkflowRunPathCounts"];
2456
- /** @description Current job claim summary derived from the run projection. */
2534
+ /** @description Live work-pool summary derived from the run projection. See `WorkflowRunJobCounts`. */
2457
2535
  job_counts: components["schemas"]["WorkflowRunJobCounts"];
2536
+ /** @description Durable run-step counts grouped by status. See `WorkflowRunStepCounts`. */
2537
+ step_counts: components["schemas"]["WorkflowRunStepCounts"];
2458
2538
  /** @description Always-present aggregate of waiting paths. */
2459
2539
  wait_summary: components["schemas"]["WorkflowRunWaitSummary"];
2460
2540
  /** @description Run-level errors that caused a failed lifecycle. */
@@ -2479,7 +2559,7 @@ export interface components {
2479
2559
  actor_id?: string;
2480
2560
  /** @description Human-readable label for the initiator (e.g. trigger name, API key name). */
2481
2561
  initiated_by?: string;
2482
- /** @description Caller-supplied idempotency key or correlation ID. */
2562
+ /** @description Caller-supplied logical correlation key for this run. Unique within the project; identifies a logical job across attempts. See the `external_id` description on `POST /runs` for the conflict semantics that govern duplicate values. */
2483
2563
  external_id?: string;
2484
2564
  /** @description Compatibility boolean set when cancellation was requested. Use `cancel_requested_at` for audit detail and `status` for terminal checks. */
2485
2565
  cancel_requested?: boolean;
@@ -2514,17 +2594,88 @@ export interface components {
2514
2594
  */
2515
2595
  wall_clock_deadline_at?: string;
2516
2596
  /**
2517
- * @description Typed run-level failure cause: `run_timeout`, `run_cancelled`, `job_failed`, or `run_failed`. Its own vocabulary, not a superset of the job-level `error_type`. Present when `status=failed`.
2597
+ * @description Typed run-level failure cause: `run_timeout`, `run_cancelled`, `step_failed`, or `run_failed`. Its own vocabulary, not a superset of the job-level `error_type`. Present when `status=failed`.
2518
2598
  * @enum {string}
2519
2599
  */
2520
- error_type?: "run_timeout" | "run_cancelled" | "job_failed" | "run_failed";
2600
+ error_type?: "run_timeout" | "run_cancelled" | "step_failed" | "run_failed";
2521
2601
  /** @description Run-level cascade config frozen when the run was started. */
2522
2602
  resolved_config?: components["schemas"]["ResolvedConfig"];
2523
- /** @description Default job-level cascade config inherited by jobs unless a step overrides it. */
2524
- default_job_config?: components["schemas"]["ResolvedConfig"];
2603
+ /** @description Default step-level cascade config inherited by each run step unless the step's own spec overrides it. */
2604
+ default_step_config?: components["schemas"]["ResolvedConfig"];
2605
+ /** @description Source run and step this run was forked from. */
2606
+ forked_from?: components["schemas"]["RunForkLineage"];
2525
2607
  } & {
2526
2608
  [key: string]: unknown;
2527
2609
  };
2610
+ RunForkLineage: {
2611
+ run_id: string;
2612
+ step_id: string;
2613
+ path_id: string;
2614
+ step_name: string;
2615
+ };
2616
+ /** @description Fork creation request. Tags are inherited from the source run and then overlaid with request tags using the same tag inheritance rules as run creation: request values replace matching source keys, and an empty string removes the inherited key. `definition_version_id` changes only the post-fork execution version; it does not affect inherited history. When omitted, the fork uses the source run's definition version. */
2617
+ RunForkRequest: {
2618
+ /** @description Run-step identifier to fork from. Use the `id` returned by `RunStep`. */
2619
+ from_step_id: string;
2620
+ /** @description Logical external identifier for the new forked run. It must be unique within the project, just like other workflow-run `external_id` values. */
2621
+ external_id: string;
2622
+ /** @description Optional target workflow definition version for post-fork execution. It must belong to the same workflow definition as the source run. Omit it to use the source run's original definition version. Inherited history remains tied to the source run. */
2623
+ definition_version_id?: string;
2624
+ /** @description Tags to overlay on the inherited source-run tags. Empty string values remove inherited keys. */
2625
+ tags?: components["schemas"]["TagMap"];
2626
+ };
2627
+ /** @enum {string} */
2628
+ RunStepSource: "executed" | "inherited";
2629
+ /** @enum {string} */
2630
+ RunStepStatus: "pending" | "running" | "completed" | "failed" | "cancelled";
2631
+ /** @description Durable execution-history row for one step attempt on one workflow path. RunStep is the canonical source for run history; linked Job rows are transient worker-claim records and may be TTL-swept after terminal retention. */
2632
+ RunStep: {
2633
+ /** @description Stable run-step identifier. Use this value as `{step_id}` in `GET /runs/{id}/steps/{step_id}` and as `from_step_id` in `POST /runs/{id}/forks`. */
2634
+ id: string;
2635
+ /** @description Workflow run that owns this step row. */
2636
+ run_id: string;
2637
+ /** @description Workflow path identifier for branch/fanout execution. */
2638
+ path_id: string;
2639
+ /** @description Step name from the workflow definition. */
2640
+ step_name: string;
2641
+ /** @description Action identifier for executable steps; empty for control-only steps. */
2642
+ action: string;
2643
+ /** @description Zero-based retry attempt for this step/path pair. */
2644
+ attempt: number;
2645
+ /** @description Whether this row was executed in this run or inherited from a source run during fork creation. */
2646
+ source: components["schemas"]["RunStepSource"];
2647
+ status: components["schemas"]["RunStepStatus"];
2648
+ /** @description Resolved parameters/input for this step attempt. */
2649
+ parameters: {
2650
+ [key: string]: unknown;
2651
+ };
2652
+ /** @description Linked live worker job when one exists. Terminal jobs may be reaped while the RunStep remains. */
2653
+ job_id?: string;
2654
+ /** @description Base64-encoded serialized step result, when present. */
2655
+ result_b64?: string;
2656
+ /** @description Base64-encoded serialized run state immediately after this step completed. Omitted unless requested with `include=run_state_after`. */
2657
+ run_state_after_b64?: string;
2658
+ error_type?: string;
2659
+ error_message?: string;
2660
+ /** Format: date-time */
2661
+ started_at?: string;
2662
+ /** Format: date-time */
2663
+ completed_at?: string;
2664
+ /** @description Originating run ID when this row was inherited or derived from another run. */
2665
+ source_run_id?: string;
2666
+ /** @description Originating step ID when this row was inherited or derived from another run. */
2667
+ source_step_id?: string;
2668
+ /** Format: date-time */
2669
+ created_at: string;
2670
+ /** Format: date-time */
2671
+ updated_at: string;
2672
+ };
2673
+ /** @description Paginated durable run-step history. Use this response for historical run inspection because linked job rows are live worker state and may be TTL-swept. */
2674
+ RunStepListResponse: {
2675
+ items: components["schemas"]["RunStep"][];
2676
+ has_more: boolean;
2677
+ next_cursor?: string;
2678
+ };
2528
2679
  /** @description Paginated list of workflow runs. */
2529
2680
  WorkflowRunListResponse: {
2530
2681
  /** @description The list of results for this page. */
@@ -2534,7 +2685,7 @@ export interface components {
2534
2685
  /** @description Opaque cursor for fetching the next page. Present only when has_more is true. */
2535
2686
  next_cursor?: string;
2536
2687
  };
2537
- /** @description Detailed workflow run including its spec snapshot, terminal result, and jobs. */
2688
+ /** @description Detailed workflow run including its spec snapshot, terminal result, and the first page of run steps. */
2538
2689
  WorkflowRunDetail: components["schemas"]["WorkflowRun"] & {
2539
2690
  /** @description Current path-level execution projection for this run. */
2540
2691
  paths: components["schemas"]["WorkflowRunPath"][];
@@ -2542,8 +2693,10 @@ export interface components {
2542
2693
  spec?: components["schemas"]["WorkflowSpec"];
2543
2694
  /** @description Base64-encoded terminal result blob */
2544
2695
  result_b64?: string;
2545
- /** @description Jobs spawned by this run. */
2546
- jobs?: components["schemas"]["Job"][];
2696
+ /** @description First page of durable run-step history. Use this canonical history for execution inspection and fork planning, including after terminal job rows have been TTL-swept. */
2697
+ steps: components["schemas"]["RunStep"][];
2698
+ /** @description Cursor for the next page of durable run-step history. */
2699
+ steps_next_cursor?: string;
2547
2700
  };
2548
2701
  /** @description Run a previously-created workflow definition. Selected by `mode: saved` on `POST /v1/projects/{project}/runs`. The run inherits the workflow definition's tags at start time; see the `tags` field below for the override rules. */
2549
2702
  StartSavedRunRequest: {
@@ -2566,7 +2719,7 @@ export interface components {
2566
2719
  };
2567
2720
  /** @description Tags applied on top of the workflow definition's inherited tags. Caller keys override on conflict; an entry whose value is the empty string opts the inherited key out entirely (so the run does not carry it). Setting a tag value to "" is therefore reserved as the opt-out signal — use a placeholder value if you actually want a stored empty value. */
2568
2721
  tags?: components["schemas"]["TagMap"];
2569
- /** @description Caller-supplied idempotency key or correlation ID attached to the run. */
2722
+ /** @description Caller-supplied logical correlation key for this run. Unique within the project. If the same external_id is reused while the prior run is still active, the existing run is returned idempotently. Once the prior run is terminal (completed or failed), a duplicate POST returns 409 with code `external_id_conflict` and the `existing_run_id` and `status` carried in `details`. To launch a fresh attempt for the same logical job after a terminal run, use a new external_id (e.g. suffix with an attempt counter). */
2570
2723
  external_id?: string;
2571
2724
  /** @description Run-level cascade config overrides applied when starting the run. */
2572
2725
  config?: components["schemas"]["ConfigEntries"];
@@ -2592,7 +2745,7 @@ export interface components {
2592
2745
  };
2593
2746
  /** @description Initial tags for this inline run. Inline runs have no parent workflow definition, so there is nothing to inherit from — every tag on the run comes from this map. */
2594
2747
  tags?: components["schemas"]["TagMap"];
2595
- /** @description Caller-supplied idempotency key or correlation ID attached to the run. */
2748
+ /** @description Caller-supplied logical correlation key for this run. Unique within the project. If the same external_id is reused while the prior run is still active, the existing run is returned idempotently. Once the prior run is terminal (completed or failed), a duplicate POST returns 409 with code `external_id_conflict` and the `existing_run_id` and `status` carried in `details`. To launch a fresh attempt for the same logical job after a terminal run, use a new external_id (e.g. suffix with an attempt counter). */
2596
2749
  external_id?: string;
2597
2750
  /** @description Run-level cascade config overrides applied when starting the run. */
2598
2751
  config?: components["schemas"]["ConfigEntries"];
@@ -2618,7 +2771,7 @@ export interface components {
2618
2771
  };
2619
2772
  /** @description Tags applied on top of the bound workflow definition's inherited tags. Caller keys override on conflict; an entry whose value is the empty string opts the inherited key out entirely (so the run does not carry it). Setting a tag value to "" is therefore reserved as the opt-out signal — use a placeholder value if you actually want a stored empty value. */
2620
2773
  tags?: components["schemas"]["TagMap"];
2621
- /** @description Caller-supplied idempotency key or correlation ID attached to the run. */
2774
+ /** @description Caller-supplied logical correlation key for this run. Unique within the project. If the same external_id is reused while the prior run is still active, the existing run is returned idempotently. Once the prior run is terminal (completed or failed), a duplicate POST returns 409 with code `external_id_conflict` and the `existing_run_id` and `status` carried in `details`. To launch a fresh attempt for the same logical job after a terminal run, use a new external_id (e.g. suffix with an attempt counter). */
2622
2775
  external_id?: string;
2623
2776
  /** @description Run-level cascade config overrides applied when starting the bound workflow. */
2624
2777
  config?: components["schemas"]["ConfigEntries"];
@@ -3005,9 +3158,17 @@ export interface components {
3005
3158
  /** @description Whether additional pages are available. */
3006
3159
  has_more: boolean;
3007
3160
  };
3161
+ /** @description Body for `POST /jobs/claim`. Workers identify themselves with `worker_instance_id` (the row key on the workers page) plus a per-boot `worker_session_token` (the fence value stamped onto each claimed job). `concurrency_limit` is the configured capacity used by the saturation bar. */
3008
3162
  JobClaimRequest: {
3009
- /** @description Caller-assigned stable identifier for this worker process. Used as the lease fence and for worker registry tracking. */
3010
- worker_id: string;
3163
+ /** @description Caller-configured stable identifier for the worker process. The SDK auto-detects this on Cloud Run, Kubernetes, Fly, Railway, and Render; otherwise it falls back to OS hostname then to a per-boot UUID. Stored on the claimed job as `claimed_by` for human-readable display. */
3164
+ worker_instance_id: string;
3165
+ /** @description Per-boot token generated by the SDK on Worker construction. Stamped onto the claimed job and re-presented as the lease fence on heartbeat / events / complete. Opaque to operators. */
3166
+ worker_session_token: string;
3167
+ /**
3168
+ * @description Maximum number of concurrent in-flight jobs this worker process intends to hold. Recorded on the worker_session row; used for the saturation bar in the admin UI. The server does not enforce the limit — the worker is trusted to gate its own claim loop.
3169
+ * @default 1
3170
+ */
3171
+ concurrency_limit: number;
3011
3172
  /** @description Durable agent identity the worker is acting on behalf of. */
3012
3173
  agent_id?: string;
3013
3174
  /** @description Live agent session the worker is acting on behalf of. */
@@ -3065,15 +3226,21 @@ export interface components {
3065
3226
  /** @description Server instructions the worker should observe after the heartbeat. */
3066
3227
  directives: components["schemas"]["JobHeartbeatDirectives"];
3067
3228
  };
3229
+ /** @description Lease fence presented on heartbeat. The worker presents the per-boot `worker_session_token` from the original claim along with the same `attempt`; the server compares the token against the job's `claimed_by_session_token` and returns 409 lease-lost on mismatch. */
3068
3230
  JobFenceRequest: {
3069
- /** @description Must match the `worker_id` from the original claim. */
3070
- worker_id: string;
3231
+ /** @description Echo of the `worker_instance_id` from the claim. Logged for audit; not the fence value. */
3232
+ worker_instance_id?: string;
3233
+ /** @description Per-boot token from the original claim. Compared against the job's `claimed_by_session_token`; mismatch returns 409 lease-lost. */
3234
+ worker_session_token: string;
3071
3235
  /** @description Must match the `attempt` from the original claim. */
3072
3236
  attempt: number;
3073
3237
  };
3238
+ /** @description Terminal report for a claimed job. The worker presents the per-boot `worker_session_token` from the original claim along with the same `attempt`; mismatch returns 409 lease-lost. */
3074
3239
  JobCompleteRequest: {
3075
- /** @description Must match the `worker_id` from the original claim. */
3076
- worker_id: string;
3240
+ /** @description Echo of the claim's `worker_instance_id`. Audit only. */
3241
+ worker_instance_id?: string;
3242
+ /** @description Per-boot token from the claim. Compared against the job's `claimed_by_session_token`; mismatch returns 409 lease-lost. */
3243
+ worker_session_token: string;
3077
3244
  /** @description Must match the `attempt` from the original claim. */
3078
3245
  attempt: number;
3079
3246
  /**
@@ -3104,10 +3271,12 @@ export interface components {
3104
3271
  [key: string]: unknown;
3105
3272
  } | unknown[] | string | number | boolean;
3106
3273
  };
3107
- /** @description Fenced batch of custom run events published by the worker holding a job's lease. The fence is per-request: every event in `events` is published under the same `worker_id` + `attempt` pair. */
3274
+ /** @description Fenced batch of custom run events published by the worker holding a job's lease. Every event in `events` is published under the same `worker_session_token` + `attempt` fence; mismatch against the job's `claimed_by_session_token` returns 409 lease-lost. */
3108
3275
  JobEventsRequest: {
3109
- /** @description Must match the `worker_id` from the original claim. */
3110
- worker_id: string;
3276
+ /** @description Echo of the claim's `worker_instance_id`. Audit only. */
3277
+ worker_instance_id?: string;
3278
+ /** @description Per-boot token from the claim. The lease fence value; mismatch against the job's `claimed_by_session_token` returns 409 lease-lost. */
3279
+ worker_session_token: string;
3111
3280
  /** @description Must match the `attempt` from the original claim. */
3112
3281
  attempt: number;
3113
3282
  /** @description The batch of events to publish. All events are validated atomically. */
@@ -3546,10 +3715,14 @@ export interface components {
3546
3715
  /** @description When supplied, replaces the user tag set on the trigger. System tags (`mobius:*`) are preserved. */
3547
3716
  tags?: components["schemas"]["TagMap"];
3548
3717
  };
3549
- /** @description Recently observed worker process for a project. Use sessions to see which machines, users, service accounts, or agents are polling for work and whether they appear stale. */
3718
+ /** @description Recently observed worker process for a project. Use sessions to see which machines, users, service accounts, or agents are polling for work, what their configured concurrency is, and whether they appear stale. */
3550
3719
  WorkerSession: {
3551
- /** @description Caller-assigned stable identifier for this worker process. */
3720
+ /** @description Server-assigned session row ID (`wsess_…`). Generated by the control plane on first registration; opaque to workers and stable across refreshes for a given live row. */
3552
3721
  id: string;
3722
+ /** @description Caller-configured stable identifier for the worker process. The SDK auto-detects this from the runtime platform (Cloud Run revision, Kubernetes pod, Fly machine, Railway replica, Render instance) and falls back to a UUID. Unique within `(org_id, project_id)`. */
3723
+ worker_instance_id: string;
3724
+ /** @description Configured maximum number of jobs this worker process will hold in flight simultaneously. Reported by the SDK on register; rendered as a saturation bar in the admin UI (`busy_job_count / concurrency_limit`). */
3725
+ concurrency_limit: number;
3553
3726
  /** @description Optional human-readable name supplied in the claim request. */
3554
3727
  name?: string;
3555
3728
  /** @description Optional version string supplied in the claim request. */
@@ -3559,6 +3732,11 @@ export interface components {
3559
3732
  * @description Timestamp of this session's most recent job claim poll. Updated on every `POST /v1/projects/{project}/jobs/claim` call regardless of whether a job was returned. Used to compute `stale`.
3560
3733
  */
3561
3734
  last_seen_at?: string;
3735
+ /**
3736
+ * Format: date-time
3737
+ * @description Most recent observed activity for this session, derived from `last_seen_at`, currently claimed job heartbeats, and the latest terminal job update.
3738
+ */
3739
+ last_activity_at?: string;
3562
3740
  /** @description Reserved for future capability-based job routing. Not currently used for filtering. */
3563
3741
  capabilities?: string[];
3564
3742
  /** @description Service account this session authenticated as on register/heartbeat. Set when a machine identity is polling; mutually exclusive with `user_id`. Stable across credential rotation — use this to group sessions by identity in the admin UI. */
@@ -3571,12 +3749,73 @@ export interface components {
3571
3749
  api_key_id?: string;
3572
3750
  /** @description Agent this session represents, when the polling process declared itself as a registered agent (via `agent_id` on the claim request or via inference from the service account). Absent for ad-hoc worker processes that are not tied to a declared agent. */
3573
3751
  agent_id?: string;
3574
- /** @description True when `last_seen_at` is older than 2 minutes or absent. Computed at read time, not stored. */
3752
+ /**
3753
+ * @description High-level lifecycle indicator for the row.
3754
+ * * `active` — recent heartbeat, healthy.
3755
+ * * `stale` — no heartbeat within the staleness window; row
3756
+ * retained for display until the 30-day delete floor.
3757
+ * * `draining` — explicit graceful-shutdown signal from the
3758
+ * SDK (reserved for future SDK releases).
3759
+ *
3760
+ * Conflicts (a different process tried to register this `worker_instance_id` within the takeover window and was rejected) are surfaced inline as a 409 from the worker protocol; the previous registration's row remains `active` and never appears as a separate "conflicting" entry.
3761
+ * @enum {string}
3762
+ */
3763
+ instance_status: "active" | "stale" | "draining";
3764
+ /** @description True when `last_seen_at` is older than 2 minutes or absent. Computed at read time, not stored. Equivalent to `instance_status == "stale"`; both are returned for backward compatibility while clients update. */
3575
3765
  stale: boolean;
3766
+ /** @description Number of jobs this worker session is currently holding. */
3767
+ busy_job_count: number;
3768
+ /** @description Currently claimed jobs held by this worker session. */
3769
+ current_jobs: components["schemas"]["WorkerSessionJobRef"][];
3770
+ /** @description Most recent completed or failed job this worker session handled. */
3771
+ last_job?: components["schemas"]["WorkerSessionJobRef"];
3772
+ };
3773
+ WorkerSessionJobRef: {
3774
+ /** @description Job ID. */
3775
+ id: string;
3776
+ /** @description Workflow run that owns the job. */
3777
+ run_id: string;
3778
+ /** @description Workflow step name. */
3779
+ step_name: string;
3780
+ /** @description Action executed by the worker. */
3781
+ action: string;
3782
+ /**
3783
+ * @description Current job lifecycle state.
3784
+ * @enum {string}
3785
+ */
3786
+ status: "pending" | "claimed" | "completed" | "failed";
3787
+ /**
3788
+ * Format: date-time
3789
+ * @description Timestamp when the worker claimed the job.
3790
+ */
3791
+ claimed_at?: string;
3792
+ /**
3793
+ * Format: date-time
3794
+ * @description Most recent heartbeat timestamp while the job is claimed.
3795
+ */
3796
+ heartbeat_at?: string;
3797
+ /**
3798
+ * Format: date-time
3799
+ * @description Last job update timestamp.
3800
+ */
3801
+ updated_at: string;
3576
3802
  };
3577
3803
  WorkerSessionListResponse: {
3578
3804
  /** @description The list of recently seen worker sessions. */
3579
3805
  items: components["schemas"]["WorkerSession"][];
3806
+ /** @description Aggregate counts across `items`, computed by the server so UIs do not need to re-derive them on every render. */
3807
+ totals: components["schemas"]["WorkerSessionTotals"];
3808
+ };
3809
+ /** @description Project-wide rollup of the rendered worker sessions. Useful for the page header — "3 active instances · 18 slots · 7 busy · 1 stale" — without iterating items client-side. */
3810
+ WorkerSessionTotals: {
3811
+ /** @description Count of `instance_status == "active"` rows. */
3812
+ active_instances: number;
3813
+ /** @description Sum of `concurrency_limit` across active rows. */
3814
+ slots: number;
3815
+ /** @description Sum of `busy_job_count` across active rows. */
3816
+ busy: number;
3817
+ /** @description Count of `instance_status == "stale"` rows. */
3818
+ stale: number;
3580
3819
  };
3581
3820
  /** @description Human identity known to the organization. User records are useful for membership lists, role assignment UIs, attribution, and displaying profile information next to actions. */
3582
3821
  User: {
@@ -5067,7 +5306,7 @@ export interface operations {
5067
5306
  };
5068
5307
  };
5069
5308
  responses: {
5070
- /** @description Accepted */
5309
+ /** @description Accepted. When `external_id` is set and matches an active run, the existing run is returned idempotently with this same status code instead of creating a new one. */
5071
5310
  202: {
5072
5311
  headers: {
5073
5312
  [name: string]: unknown;
@@ -5079,7 +5318,18 @@ export interface operations {
5079
5318
  400: components["responses"]["BadRequest"];
5080
5319
  401: components["responses"]["Unauthorized"];
5081
5320
  404: components["responses"]["NotFound"];
5082
- /** @description Conflict — the target project is archived. Code `project_archived`. Restore the project before starting new runs; in-flight runs continue regardless. */
5321
+ /**
5322
+ * @description Conflict. Possible codes:
5323
+ *
5324
+ * - `project_archived` — the target project is archived. Restore
5325
+ * the project before starting new runs; in-flight runs continue
5326
+ * regardless.
5327
+ * - `external_id_conflict` — `external_id` already belongs to a
5328
+ * terminal run in this project. The response `details` carry
5329
+ * `existing_run_id` (string), `status` (`completed` | `failed`),
5330
+ * and the offending `external_id`. Fetch the prior run for its
5331
+ * result, or POST a new attempt with a different external_id.
5332
+ */
5083
5333
  409: {
5084
5334
  headers: {
5085
5335
  [name: string]: unknown;
@@ -5106,6 +5356,8 @@ export interface operations {
5106
5356
  initiated_by?: string;
5107
5357
  /** @description Filter by caller-supplied external ID or correlation key. */
5108
5358
  external_id?: string;
5359
+ /** @description Filter to runs forked from the specified source run. */
5360
+ forked_from?: string;
5109
5361
  /** @description Cursor for pagination (opaque string from previous response) */
5110
5362
  cursor?: components["parameters"]["CursorParam"];
5111
5363
  /** @description Maximum number of items to return */
@@ -5148,7 +5400,7 @@ export interface operations {
5148
5400
  };
5149
5401
  };
5150
5402
  responses: {
5151
- /** @description Accepted */
5403
+ /** @description Accepted. When `external_id` is set and matches an active run in this project, the existing run is returned idempotently with this same status code instead of creating a new one. */
5152
5404
  202: {
5153
5405
  headers: {
5154
5406
  [name: string]: unknown;
@@ -5171,6 +5423,18 @@ export interface operations {
5171
5423
  * "completed": 0,
5172
5424
  * "failed": 0
5173
5425
  * },
5426
+ * "job_counts": {
5427
+ * "ready": 1,
5428
+ * "scheduled": 0,
5429
+ * "claimed": 0
5430
+ * },
5431
+ * "step_counts": {
5432
+ * "pending": 1,
5433
+ * "running": 0,
5434
+ * "completed": 0,
5435
+ * "failed": 0,
5436
+ * "cancelled": 0
5437
+ * },
5174
5438
  * "wait_summary": {
5175
5439
  * "waiting_paths": 0,
5176
5440
  * "kind_counts": {},
@@ -5202,7 +5466,18 @@ export interface operations {
5202
5466
  400: components["responses"]["BadRequest"];
5203
5467
  401: components["responses"]["Unauthorized"];
5204
5468
  404: components["responses"]["NotFound"];
5205
- /** @description Conflict — the target project is archived. Code `project_archived`. Restore the project before starting new runs; in-flight runs continue regardless. */
5469
+ /**
5470
+ * @description Conflict. Possible codes:
5471
+ *
5472
+ * - `project_archived` — the target project is archived. Restore
5473
+ * the project before starting new runs; in-flight runs continue
5474
+ * regardless.
5475
+ * - `external_id_conflict` — `external_id` already belongs to a
5476
+ * terminal run in this project. The response `details` carry
5477
+ * `existing_run_id` (string), `status` (`completed` | `failed`),
5478
+ * and the offending `external_id`. Fetch the prior run for its
5479
+ * result, or POST a new attempt with a different external_id.
5480
+ */
5206
5481
  409: {
5207
5482
  headers: {
5208
5483
  [name: string]: unknown;
@@ -5241,6 +5516,116 @@ export interface operations {
5241
5516
  404: components["responses"]["NotFound"];
5242
5517
  };
5243
5518
  };
5519
+ forkRun: {
5520
+ parameters: {
5521
+ query?: never;
5522
+ header?: never;
5523
+ path: {
5524
+ /** @description Project handle (unique per organization) */
5525
+ project: components["parameters"]["ProjectHandleParam"];
5526
+ /** @description Resource ID. */
5527
+ id: components["parameters"]["IDParam"];
5528
+ };
5529
+ cookie?: never;
5530
+ };
5531
+ requestBody: {
5532
+ content: {
5533
+ "application/json": components["schemas"]["RunForkRequest"];
5534
+ };
5535
+ };
5536
+ responses: {
5537
+ /** @description Fork created, or an existing fork returned for an idempotent retry with the same source run, `from_step_id`, `external_id`, and effective target definition version. */
5538
+ 202: {
5539
+ headers: {
5540
+ [name: string]: unknown;
5541
+ };
5542
+ content: {
5543
+ "application/json": components["schemas"]["WorkflowRun"];
5544
+ };
5545
+ };
5546
+ 400: components["responses"]["BadRequest"];
5547
+ 401: components["responses"]["Unauthorized"];
5548
+ 404: components["responses"]["NotFound"];
5549
+ /** @description Conflict. Expected fork-specific codes include `fork_source_active`, `idempotency_conflict`, and `external_id_conflict`. */
5550
+ 409: {
5551
+ headers: {
5552
+ [name: string]: unknown;
5553
+ };
5554
+ content: {
5555
+ "application/json": components["schemas"]["ErrorResponse"];
5556
+ };
5557
+ };
5558
+ };
5559
+ };
5560
+ listRunSteps: {
5561
+ parameters: {
5562
+ query?: {
5563
+ /** @description Filter steps by workflow path identifier. */
5564
+ path_id?: string;
5565
+ /** @description Filter steps by workflow step name. */
5566
+ step_name?: string;
5567
+ /** @description Filter steps by current run-step status. */
5568
+ status?: components["schemas"]["RunStepStatus"];
5569
+ /** @description Cursor for pagination (opaque string from previous response) */
5570
+ cursor?: components["parameters"]["CursorParam"];
5571
+ /** @description Maximum number of items to return */
5572
+ limit?: components["parameters"]["LimitParam"];
5573
+ };
5574
+ header?: never;
5575
+ path: {
5576
+ /** @description Project handle (unique per organization) */
5577
+ project: components["parameters"]["ProjectHandleParam"];
5578
+ /** @description Resource ID. */
5579
+ id: components["parameters"]["IDParam"];
5580
+ };
5581
+ cookie?: never;
5582
+ };
5583
+ requestBody?: never;
5584
+ responses: {
5585
+ /** @description OK */
5586
+ 200: {
5587
+ headers: {
5588
+ [name: string]: unknown;
5589
+ };
5590
+ content: {
5591
+ "application/json": components["schemas"]["RunStepListResponse"];
5592
+ };
5593
+ };
5594
+ 401: components["responses"]["Unauthorized"];
5595
+ 404: components["responses"]["NotFound"];
5596
+ };
5597
+ };
5598
+ getRunStep: {
5599
+ parameters: {
5600
+ query?: {
5601
+ /** @description Pass `run_state_after` to include `run_state_after_b64`; it is omitted otherwise. */
5602
+ include?: "run_state_after";
5603
+ };
5604
+ header?: never;
5605
+ path: {
5606
+ /** @description Project handle (unique per organization) */
5607
+ project: components["parameters"]["ProjectHandleParam"];
5608
+ /** @description Resource ID. */
5609
+ id: components["parameters"]["IDParam"];
5610
+ step_id: string;
5611
+ };
5612
+ cookie?: never;
5613
+ };
5614
+ requestBody?: never;
5615
+ responses: {
5616
+ /** @description OK */
5617
+ 200: {
5618
+ headers: {
5619
+ [name: string]: unknown;
5620
+ };
5621
+ content: {
5622
+ "application/json": components["schemas"]["RunStep"];
5623
+ };
5624
+ };
5625
+ 401: components["responses"]["Unauthorized"];
5626
+ 404: components["responses"]["NotFound"];
5627
+ };
5628
+ };
5244
5629
  listRunActionLog: {
5245
5630
  parameters: {
5246
5631
  query?: never;
@@ -5451,9 +5836,9 @@ export interface operations {
5451
5836
  };
5452
5837
  content: {
5453
5838
  /**
5454
- * @example event: job_updated
5839
+ * @example event: run_step_updated
5455
5840
  * id: 43
5456
- * data: {"type":"job_updated","run_id":"run_01hw1n1a2b3c4d5e6f7g8h9j0k","seq":43,"timestamp":"2026-04-24T14:46:00Z","data":{"job_id":"job_01hw1n2p3q4r5s6t7u8v9w0x1y","status":"completed"}}
5841
+ * data: {"type":"run_step_updated","run_id":"run_01hw1n1a2b3c4d5e6f7g8h9j0k","seq":43,"timestamp":"2026-04-24T14:46:00Z","data":{"id":"step_01hw1n2p3q4r5s6t7u8v9w0x1y","run_id":"run_01hw1n1a2b3c4d5e6f7g8h9j0k","path_id":"main","step_name":"summarize","action":"summarize-document","attempt":1,"source":"executed","status":"completed","parameters":{"document_id":"doc_01hw1m9z8y7x6w5v4u3t2s1r0q"},"job_id":"job_01hw1n2a3b4c5d6e7f8g9h0j1k","created_at":"2026-04-24T14:45:10Z","started_at":"2026-04-24T14:45:12Z","completed_at":"2026-04-24T14:46:00Z","updated_at":"2026-04-24T14:46:00Z"}}
5457
5842
  */
5458
5843
  "text/event-stream": string;
5459
5844
  };
@@ -5755,11 +6140,13 @@ export interface operations {
5755
6140
  content: {
5756
6141
  /**
5757
6142
  * @example {
5758
- * "worker_id": "worker-us-east-1a-03",
6143
+ * "worker_instance_id": "inv-abc123",
6144
+ * "worker_session_token": "<worker-session-token>",
6145
+ * "concurrency_limit": 8,
5759
6146
  * "agent_id": "agt_01hw1m5q9x7r2p4n6s8t0v3y5z",
5760
6147
  * "agent_session_id": "ags_01hw1m7c8d9e0f1g2h3j4k5m6n",
5761
- * "worker_name": "summarizer-pool",
5762
- * "worker_version": "2026.04.24",
6148
+ * "worker_name": "invoice-processor",
6149
+ * "worker_version": "2026.04.27",
5763
6150
  * "queues": [
5764
6151
  * "default"
5765
6152
  * ],
@@ -5809,6 +6196,15 @@ export interface operations {
5809
6196
  400: components["responses"]["BadRequest"];
5810
6197
  401: components["responses"]["Unauthorized"];
5811
6198
  404: components["responses"]["NotFound"];
6199
+ /** @description `worker_instance_conflict` — another live process has already registered with this `worker_instance_id` in the project under a different `worker_session_token` and the incumbent is still within the takeover window. Resolve by configuring distinct instance IDs or letting the SDK auto-detect them. */
6200
+ 409: {
6201
+ headers: {
6202
+ [name: string]: unknown;
6203
+ };
6204
+ content: {
6205
+ "application/json": components["schemas"]["ErrorResponse"];
6206
+ };
6207
+ };
5812
6208
  };
5813
6209
  };
5814
6210
  heartbeatJob: {
@@ -5827,7 +6223,8 @@ export interface operations {
5827
6223
  content: {
5828
6224
  /**
5829
6225
  * @example {
5830
- * "worker_id": "worker-us-east-1a-03",
6226
+ * "worker_instance_id": "inv-abc123",
6227
+ * "worker_session_token": "<worker-session-token>",
5831
6228
  * "attempt": 1
5832
6229
  * }
5833
6230
  */
@@ -5905,7 +6302,8 @@ export interface operations {
5905
6302
  content: {
5906
6303
  /**
5907
6304
  * @example {
5908
- * "worker_id": "worker-us-east-1a-03",
6305
+ * "worker_instance_id": "inv-abc123",
6306
+ * "worker_session_token": "<worker-session-token>",
5909
6307
  * "attempt": 1,
5910
6308
  * "events": [
5911
6309
  * {