lua-cli 3.42.0-beta.1 → 3.42.0-beta.3

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.
@@ -31,6 +31,163 @@ import { WorkflowShellValue } from '@lua/shared-types/workflow-exec';
31
31
  import { z } from 'zod';
32
32
  import { ZodType } from 'zod';
33
33
 
34
+ /**
35
+ * `auto` (default, today's behaviour): every user-owned connection of the agent's creator auto-mounts on
36
+ * the creator's exclusive agents. `explicit`: NO user connection auto-mounts; a mount needs a confirmed
37
+ * assignment (c). Stored as `SubAgent.connectionPolicy` (absent ⇒ `auto`).
38
+ */
39
+ declare const AGENT_CONNECTION_POLICIES: readonly ["auto", "explicit"];
40
+
41
+ declare const AGENT_OBJECTIVE_STATUSES: readonly ["proposed", "active", "paused", "retired", "rejected"];
42
+
43
+ /** `lease.get` / the dashboard field / lua-cli status: the lease (if live) and the human-activity signal. */
44
+ declare interface AgentChangeActivity {
45
+ lease: AgentChangeLease | null;
46
+ /** ISO of the latest version create / promote or backup push whose actor is `human`. */
47
+ lastHumanChangeAt?: string;
48
+ /** ISO of the latest such change by an `agent:<id>` actor. */
49
+ lastAgentChangeAt?: string;
50
+ }
51
+
52
+ /** The ONE active lease of an agent (agents DB `agentChangeLeases`, one row per agent, `_id = agentId`). */
53
+ declare interface AgentChangeLease {
54
+ leaseId: string;
55
+ agentId: string;
56
+ holderAgentId: string;
57
+ reason: string;
58
+ /** ISO. */
59
+ acquiredAt: string;
60
+ expiresAt: string;
61
+ }
62
+
63
+ /** `Agents.config(id).set(...)` (`act`). `env` holds NON-secret keys only. */
64
+ declare interface AgentConfigSetInput {
65
+ model?: string;
66
+ name?: string;
67
+ env?: Record<string, string>;
68
+ }
69
+
70
+ /** What `config.set` wrote. Env VALUES are never echoed back. */
71
+ declare interface AgentConfigSetResult {
72
+ agentId: string;
73
+ updated: Array<'model' | 'name' | 'env'>;
74
+ /** The env keys written (merged into the agent's env; other keys are untouched). */
75
+ envKeys: string[];
76
+ }
77
+
78
+ declare type AgentConnectionPolicy = (typeof AGENT_CONNECTION_POLICIES)[number];
79
+
80
+ /**
81
+ * The member's consent given through a workflow `approval` step of the CALLER's own run (an alternative to
82
+ * `consentId`). `runId` is the code step's `ctx.runId`; name the approval by `stepId` (the approval node's id, what
83
+ * a code step knows) or by `approvalId` (`wfa_…`, from the run's approvals). Exactly one of `stepId` / `approvalId`.
84
+ * Only the ids are read: lua-api derives everything else (decision, decider, payload) from the stored rows.
85
+ */
86
+ declare type AgentCreateApprovalRef = {
87
+ runId: string;
88
+ approvalId: string;
89
+ } | {
90
+ runId: string;
91
+ stepId: string;
92
+ };
93
+
94
+ /** `Agents.create` first argument. */
95
+ declare interface AgentCreateInput {
96
+ name: string;
97
+ model: string;
98
+ persona?: string;
99
+ /** The member's user-owned connection ids to mount (explicit policy: these are confirmed by the consent). */
100
+ connections?: string[];
101
+ /** The provisioner's supervision actions on the new agent (bounded by the policy). */
102
+ supervise?: ProvisionedSupervisionAction[];
103
+ /**
104
+ * The PROVISIONER's own workflow ids written on its grant (the supervision PAP's fields, not the new agent's
105
+ * workflows): `releaseWorkflowIds` names which of its workflows may run the `release` the member consented to
106
+ * (they only narrow it: a grant naming none cannot release at all).
107
+ */
108
+ releaseWorkflowIds?: string[];
109
+ /**
110
+ * Refused (non-empty) on provisioning for now: unattended staging keys are minted with the member as owner,
111
+ * and the member's consent does not cover them.
112
+ */
113
+ unattendedWorkflowIds?: string[];
114
+ /**
115
+ * U9 — `{ pendingFor }` secret requests to attach to the new agent (U9's `attachPending`). Only while
116
+ * `LUA_SECRET_REQUESTS_ENABLED` is on; each must be a stored, `ok`-tested request THIS provisioner made for
117
+ * the member in this org, and the member's consent must name the same ids.
118
+ */
119
+ pendingSecretRequestIds?: string[];
120
+ }
121
+
122
+ /** `Agents.create` second argument: exactly one of `consentId` or `approval`. */
123
+ declare interface AgentCreateOptions {
124
+ /** The member the agent is created for; must be a member of the caller's org. */
125
+ onBehalfOf: string;
126
+ /** Minted by that member's chat confirmation (`POST /developer/agent-provisioning/consents`). */
127
+ consentId?: string;
128
+ /**
129
+ * …or the member's decision on a workflow `approval` step whose payload carries
130
+ * `{ [AGENT_PROVISIONING_APPROVAL_PAYLOAD_KEY]: AgentProvisioningApprovalPayload }` describing this create.
131
+ */
132
+ approval?: AgentCreateApprovalRef;
133
+ }
134
+
135
+ declare interface AgentCreateResult {
136
+ agentId: string;
137
+ name: string;
138
+ isPrivate: true;
139
+ createdBy: string;
140
+ connectionPolicy: AgentConnectionPolicy;
141
+ /** The scaffold backup version seeded at create (always 1). */
142
+ backupVersion: 1;
143
+ mountedConnectionIds: string[];
144
+ /** The provisioner's grant on the new agent (absent when `supervise` was empty). */
145
+ grant?: {
146
+ grantId: string;
147
+ actions: ProvisionedSupervisionAction[];
148
+ };
149
+ /** U9 — env keys attached from pending secret requests (never values). */
150
+ attachedSecretKeys?: string[];
151
+ }
152
+
153
+ /** `Agents.lifecycle(id).delete({ confirmName })` — must equal the agent's current name exactly. */
154
+ declare interface AgentDeleteInput {
155
+ confirmName: string;
156
+ }
157
+
158
+ /** How the agent is built: from a source backup, in the dashboard, or from a repo (a `commitHash` on its versions). */
159
+ declare type AgentDirectoryBuildKind = 'backup-source' | 'dashboard' | 'repo';
160
+
161
+ /**
162
+ * One agent the turn's DELEGATED user can see (same visibility as the user's own agent list: private
163
+ * agents only for their creator / agent-grant holders; PDP-checked). Metadata only.
164
+ */
165
+ declare interface AgentDirectoryEntry {
166
+ agentId: string;
167
+ name?: string;
168
+ /** The creator's user id (never their email). */
169
+ ownerUserId?: string;
170
+ isPrivate: boolean;
171
+ buildKind: AgentDirectoryBuildKind;
172
+ /**
173
+ * ISO — the latest counted activity: the newest persisted chat turn or workflow run. Job / trigger / webhook
174
+ * executions are not counted (U29 v1). When the live chat read fails the directory falls back to the nightly
175
+ * evidence rollup, and the chat half is then the UTC day of the latest exchanges.
176
+ */
177
+ lastActivityAt?: string;
178
+ /**
179
+ * Chat turns + workflow runs over the last 30 days, read live. A chat turn is a row in `chats.messages`: one
180
+ * per user turn the platform persisted, on ANY channel — production and sandbox (`lua chat -e sandbox`, the
181
+ * `dev` channel) alike. Not counted: version previews and test-session / test-traffic turns (never persisted),
182
+ * and job / trigger / webhook executions (U29 v1). A sub-agent's turns count on its own entry. `lua logs`
183
+ * counts differently (one log row per user message AND per agent response, plus tool / runtime rows), so a
184
+ * log count is typically about twice this number.
185
+ */
186
+ volume30d: number;
187
+ /** The supervision actions the CALLER already holds on it. */
188
+ callerActions: string[];
189
+ }
190
+
34
191
  /**
35
192
  * Narrowed, wire-safe output for `Agents.invoke`. A slice of the internal
36
193
  * `FullOutput` shape — raw Mastra steps / tripwire payloads are intentionally
@@ -44,7 +201,7 @@ declare interface AgentInvocationEffects {
44
201
  blocker?: TaskRunBlocker;
45
202
  }
46
203
 
47
- declare interface AgentInvocationInput {
204
+ export declare interface AgentInvocationInput {
48
205
  /** Shortcut: plain-text prompt. Mutually exclusive with `messages`. */
49
206
  prompt?: string;
50
207
  /** AI SDK `UserContent` (text/image/file parts). Mutually exclusive with `prompt`. */
@@ -271,6 +428,79 @@ declare interface AgentInvocationOutput {
271
428
  threadId?: string;
272
429
  }
273
430
 
431
+ /**
432
+ * U4b (wave 2) — archive / delete with confirmation, the owner-departure policy, and non-secret config
433
+ * writes. Owner: U4b (the ONE owner-departure hook: pause agents, suspend grants, notify org admins; U1
434
+ * only suspends grants when a provisioning policy is revoked). Contract: docs/agent-builder/wave2-contracts.md §U4b.
435
+ */
436
+ /**
437
+ * What archive and delete do (U4b spec): unmount connections (never revoke them at the provider), delete
438
+ * the agent's secrets, cancel its runs, revoke grants on it, and keep external records.
439
+ */
440
+ declare interface AgentLifecycleResult {
441
+ agentId: string;
442
+ action: 'archive' | 'delete';
443
+ unmountedConnectionIds: string[];
444
+ deletedSecretKeys: number;
445
+ cancelledRunIds: string[];
446
+ /** The supervision grants revoked: every one ON the agent and every one it held on other agents. */
447
+ revokedGrantIds: string[];
448
+ /** Member access grants (roster and org-wide) the archive revoked or suspended; counted, not listed. */
449
+ memberGrantsRevoked?: number;
450
+ /** ISO. When the agent was archived (a re-archive keeps the first date). */
451
+ archivedAt?: string;
452
+ /**
453
+ * ISO. When the purge sweep may hard-delete the agent's Lua-held data. `archive` keeps the 30-day grace
454
+ * (`restore` works until then); `delete` sets it to now, so the agent cannot be restored.
455
+ */
456
+ purgeAfter?: string;
457
+ /** True when the agent was already archived (a race with another archive) and this call re-ran the teardown. */
458
+ resumed?: boolean;
459
+ /**
460
+ * Best-effort steps that did not complete (channel teardown, a run cancel, an unmount…). The call also revokes the
461
+ * caller's own grant on the agent, so a supervisor cannot re-run it: finishing a partial teardown (or deleting an
462
+ * already-archived agent) is a staff action.
463
+ */
464
+ warnings?: string[];
465
+ }
466
+
467
+ /** `Agents.metrics(id).query(...)` and the owners' REST twin. */
468
+ export declare interface AgentMetricQueryInput {
469
+ /** A recorded metric name, or … */
470
+ name?: string;
471
+ /** … an objective (its metric definition is resolved server-side). */
472
+ objectiveId?: string;
473
+ /** ISO. */
474
+ from: string;
475
+ /** ISO. */
476
+ to: string;
477
+ interval: '1h' | '1d';
478
+ /**
479
+ * How each bucket reduces (added by U30): default `sum` for a name, the objective's own aggregation for an
480
+ * `objectiveId`. Buckets show the mean for `p50` / `p95` (percentiles are window-level, see the evaluator).
481
+ */
482
+ aggregation?: AgentObjectiveAggregation;
483
+ }
484
+
485
+ export declare interface AgentMetricQueryResult {
486
+ name: string;
487
+ interval: '1h' | '1d';
488
+ series: Array<{
489
+ tags: Record<string, string>;
490
+ points: Array<{
491
+ t: string;
492
+ value: number;
493
+ count: number;
494
+ }>;
495
+ }>;
496
+ }
497
+
498
+ export declare interface AgentMetricRecordReceipt {
499
+ accepted: boolean;
500
+ /** Present when `accepted: false`. */
501
+ code?: string;
502
+ }
503
+
274
504
  /**
275
505
  * Per-agent LLM call settings PLUS normalized reasoning config. The
276
506
  * `CallSettings` leafs (`temperature`, `topP`, …) map directly onto Mastra's
@@ -320,6 +550,90 @@ export declare interface AgentModelSettings {
320
550
  };
321
551
  }
322
552
 
553
+ /** One objective (agents DB `agentObjectives`). Only `active` objectives are evaluated and can breach. */
554
+ export declare interface AgentObjective {
555
+ id: string;
556
+ agentId: string;
557
+ statement: string;
558
+ metric: AgentObjectiveMetric;
559
+ baseline?: number;
560
+ target?: number;
561
+ guardrails: AgentObjectiveGuardrail[];
562
+ confidence: 'low' | 'medium' | 'high';
563
+ status: AgentObjectiveStatus;
564
+ /** `user:<id>` or `service:agent:<id>` (a supervisor's proposal). */
565
+ proposedBy: string;
566
+ /** The OWNER who confirmed it (absent while `proposed`). */
567
+ confirmedBy?: string;
568
+ confirmedAt?: string;
569
+ lastEvaluatedAt?: string;
570
+ lastValue?: number;
571
+ /**
572
+ * A supervisor's `update` / `retire` proposal (U30): a separate `proposed` row that names the objective it
573
+ * would change. The target objective is untouched until the owner confirms this row; confirming applies
574
+ * `patch` (or retires the target) and marks this row `retired`. Absent on `create` proposals and owner rows.
575
+ */
576
+ pendingChange?: AgentObjectivePendingChange;
577
+ createdAt: string;
578
+ updatedAt: string;
579
+ }
580
+
581
+ /**
582
+ * How a window's points reduce to one value. `rate` is the mean of the recorded values (for 0/1 outcome
583
+ * metrics: the success rate); `p50` / `p95` are over at most the newest 10,000 points in the window.
584
+ */
585
+ declare type AgentObjectiveAggregation = 'count' | 'sum' | 'avg' | 'rate' | 'p50' | 'p95' | 'min' | 'max';
586
+
587
+ export declare interface AgentObjectiveGuardrail {
588
+ id: string;
589
+ metric: AgentObjectiveMetric;
590
+ op: 'lt' | 'lte' | 'gt' | 'gte';
591
+ value: number;
592
+ }
593
+
594
+ /**
595
+ * What an objective measures. `definition` is source-specific and validated server-side: `custom` = a
596
+ * `Metrics.record` name; `runs` = `{ workflowId?, status? }`; `logs` = `{ level?, logSource? }`; `evals` =
597
+ * `{ suiteKey | monitorKey }`; `data` = `{ collection, filter }` (read through the owner's Data).
598
+ */
599
+ export declare interface AgentObjectiveMetric {
600
+ source: AgentObjectiveMetricSource;
601
+ definition: Record<string, unknown> | string;
602
+ aggregation: AgentObjectiveAggregation;
603
+ window: AgentObjectiveWindow;
604
+ }
605
+
606
+ declare type AgentObjectiveMetricSource = 'logs' | 'runs' | 'evals' | 'data' | 'custom';
607
+
608
+ /** The fields an owner `PATCH` (or a confirmed `update` proposal) may change. */
609
+ declare type AgentObjectivePatch = Partial<Pick<AgentObjective, 'statement' | 'metric' | 'baseline' | 'target' | 'guardrails' | 'confidence'>>;
610
+
611
+ declare type AgentObjectivePendingChange = {
612
+ op: 'update';
613
+ objectiveId: string;
614
+ patch: AgentObjectivePatch;
615
+ } | {
616
+ op: 'retire';
617
+ objectiveId: string;
618
+ };
619
+
620
+ /** `objectives.propose` (supervisor, `act`): never effective until the owner confirms. */
621
+ export declare type AgentObjectiveProposal = {
622
+ op: 'create';
623
+ objective: Omit<AgentObjective, 'id' | 'agentId' | 'status' | 'proposedBy' | 'createdAt' | 'updatedAt'>;
624
+ } | {
625
+ op: 'update';
626
+ objectiveId: string;
627
+ patch: AgentObjectivePatch;
628
+ } | {
629
+ op: 'retire';
630
+ objectiveId: string;
631
+ };
632
+
633
+ export declare type AgentObjectiveStatus = (typeof AGENT_OBJECTIVE_STATUSES)[number];
634
+
635
+ declare type AgentObjectiveWindow = '1d' | '7d' | '30d';
636
+
323
637
  export declare const Agents: AgentsApi;
324
638
 
325
639
  /**
@@ -406,6 +720,79 @@ export declare interface AgentsApi {
406
720
  promote(version: number, opts: {
407
721
  expectActive: number | null;
408
722
  }): Promise<unknown>;
723
+ /**
724
+ * Soft-delete `version` (`supervision:release`; only from a named workflow step). Refused
725
+ * (409 `supervision_version_not_superseded`) unless the version is `superseded` — never the
726
+ * active version, never the last one.
727
+ */
728
+ delete(version: number): Promise<{
729
+ deleted: true;
730
+ version: number;
731
+ }>;
732
+ /**
733
+ * Open a TEST SESSION on staged `opts.version` (`supervision:preview`, U11 / DOC2 §6.1): multi-turn chat and
734
+ * fire against the staged version with side effects recorded instead of executed. A supervisor session runs
735
+ * with no tools (the preview posture) and never gets `egress: 'live'`.
736
+ */
737
+ session(opts: TestSessionOpenInput): Promise<{
738
+ sessionId: string;
739
+ version: number;
740
+ session: TestSessionRecord;
741
+ chat(input: string | {
742
+ prompt?: string;
743
+ messages?: unknown[];
744
+ threadId?: string;
745
+ }): Promise<{
746
+ sessionId: string;
747
+ threadId: string;
748
+ version: number;
749
+ text: string;
750
+ toolsUsed: string[];
751
+ }>;
752
+ fire(input: TestSessionFireInput): Promise<unknown>;
753
+ effects(): Promise<{
754
+ effects: TestSessionEffect[];
755
+ }>;
756
+ close(): Promise<{
757
+ id: string;
758
+ status: 'closed';
759
+ shadowPurged: boolean;
760
+ }>;
761
+ }>;
762
+ };
763
+ /** A workflow of the target: read it (`supervision:observe`), create and release it (`supervision:release`). */
764
+ workflows(agentId: string): {
765
+ /**
766
+ * The workflow's live `activeVersionId` (the value `deploy` takes as `expectActive`; null = none live) and
767
+ * its newest 20 versions — metadata only (`supervision:observe`).
768
+ */
769
+ get(workflowId: string): Promise<SupervisedWorkflow>;
770
+ /**
771
+ * Create workflow `name` on the target, or answer the one a previous `create` made (`created: false`), so a
772
+ * retried release step converges; a person's or a chat-composed workflow of that name is a 409
773
+ * `WORKFLOW_NAME_TAKEN`. INERT: inactive, no version; `push` then adds an inactive version and `deploy`
774
+ * (with `expectActive: null`) publishes it. It has no human author (what you write never runs as a person),
775
+ * so a SCHEDULED version on it is refused at deploy (`WORKFLOW_SCHEDULE_OWNER_UNKNOWN`); start it from a
776
+ * trigger or `Workflows.start` instead. Release-bound like `push` / `deploy` (`supervision:release`).
777
+ */
778
+ create(name: string, opts?: {
779
+ description?: string;
780
+ form?: 'graph' | 'script';
781
+ }): Promise<SupervisedWorkflowCreated>;
782
+ /**
783
+ * Push a new version of workflow `workflowId` (the same body `lua push workflow` sends). The version is
784
+ * NEVER activated: `activate` is forced to `false`. Deploy it with `deploy`.
785
+ */
786
+ push(workflowId: string, definition: Record<string, unknown>): Promise<unknown>;
787
+ /**
788
+ * Publish workflow `version` (a semver). Compare-and-swap: refused (409 `WORKFLOW_DEPLOY_CONFLICT`, the
789
+ * message names the live version) unless `expectActive` is the workflow's live version ID (null = none live).
790
+ * A deploy also records a new active agent version, so a later `versions.promote` needs a fresh
791
+ * `expectActive`.
792
+ */
793
+ deploy(workflowId: string, version: string, opts: {
794
+ expectActive: string | null;
795
+ }): Promise<unknown>;
409
796
  };
410
797
  persona(agentId: string): {
411
798
  versions(): Promise<unknown>;
@@ -433,6 +820,286 @@ export declare interface AgentsApi {
433
820
  keys: string[];
434
821
  }>;
435
822
  };
823
+ /**
824
+ * Supervision events of the target (`supervision:observe`). Each event of a subscribed kind
825
+ * (`governance.blocked`, `workflow.run_failed`, `workflow.run_gated`, `connection.unhealthy`, …)
826
+ * starts one of YOUR agent's triggers, `triggerName`, with a
827
+ * `SupervisionEventEnvelope` body (`source: 'supervision'`). The grant is re-checked on every
828
+ * delivery: a revoked grant stops the events. Not available offline.
829
+ */
830
+ events(agentId: string): {
831
+ /** Upsert by `triggerName` (one of your own triggers); at most 10 per supervised agent. */
832
+ subscribe(opts: {
833
+ kinds: SupervisionEventKind[];
834
+ triggerName: string;
835
+ }): Promise<SupervisionEventSubscription>;
836
+ unsubscribe(triggerName: string): Promise<{
837
+ removed: boolean;
838
+ }>;
839
+ /** Your own subscriptions on this agent. */
840
+ list(): Promise<SupervisionEventSubscription[]>;
841
+ };
842
+ /**
843
+ * Create a PRIVATE agent for a member of your organization (`onBehalfOf`), owned by them. Needs the org's
844
+ * agent-provisioning policy to name your agent, and the member's consent — exactly one of:
845
+ * - `consentId`: from their chat confirmation (single use, 10 minutes);
846
+ * - `approval: { runId, stepId }`: the member approved an `approval` step of YOUR workflow run. The step before
847
+ * the approval outputs EXACTLY `{ agentProvisioning: { name, model, supervise, connections, releaseWorkflowIds,
848
+ * pendingSecretRequestIds } }` (the approval's payload; no other key — the platform renders the card from it),
849
+ * the approval is `approver: 'creator'` and is not editable, and a later code step calls `Agents.create` with
850
+ * exactly that input, `runId: ctx.runId` and `stepId` = the approval step's id as stored (`confirm`; inside a
851
+ * loop / foreach `confirm#n` / `confirm[i]`), or `approvalId` when you hold the `wfa_…` id. The run must have
852
+ * been started by the member and still be running, and the member must have approved in their own signed-in
853
+ * session (Lua Desktop / the inbox — not a chat card, a channel reply or an API key) within the last 10
854
+ * minutes; each approval creates one agent. Set no `details` on the approval, or details equal in shape to the
855
+ * payload. Call it from a regular code step (not `tier: 'job'`); graph workflows only.
856
+ * The policy bounds the model, how many agents a member may hold and the supervision actions (`supervise`) your
857
+ * agent gets on the new one. Refused offline (`supervision_offline_unsupported`) and while the platform has
858
+ * provisioning disabled (`agent_provisioning_disabled`).
859
+ *
860
+ * @example
861
+ * ```typescript
862
+ * const created = await Agents.create(
863
+ * { name: 'Inbox helper', model: 'google/gemini-2.5-flash', supervise: ['observe'] },
864
+ * { onBehalfOf: userId, consentId }
865
+ * );
866
+ * ```
867
+ *
868
+ * @example
869
+ * ```typescript
870
+ * // A workflow the member starts (e.g. from chat): plan → confirm (the member approves) → create.
871
+ * const plan = { name: 'Inbox helper', model: 'google/gemini-2.5-flash', supervise: ['observe' as const] };
872
+ * const propose = createStep({
873
+ * id: 'propose', inputSchema: z.object({ memberId: z.string() }), outputSchema: z.any(),
874
+ * execute: async () => ({ agentProvisioning: plan }), // the approval's payload: what the member sees
875
+ * });
876
+ * const create = createStep({
877
+ * id: 'create', inputSchema: z.any(), outputSchema: z.any(),
878
+ * execute: async (ctx) => {
879
+ * if (!ctx.inputData.approved) return { created: false };
880
+ * return Agents.create(plan, {
881
+ * onBehalfOf: ctx.getInitData<{ memberId: string }>().memberId, // must be the run's creator
882
+ * approval: { runId: ctx.runId, stepId: 'confirm' },
883
+ * });
884
+ * },
885
+ * });
886
+ * createWorkflow({ ... })
887
+ * .then(propose)
888
+ * .approval('confirm', { title: 'Create “Inbox helper” for you?', approver: 'creator' })
889
+ * .then(create)
890
+ * .commit();
891
+ * ```
892
+ */
893
+ create(input: AgentCreateInput, opts: AgentCreateOptions): Promise<AgentCreateResult>;
894
+ /**
895
+ * The supervised agent's connections (`supervision:observe`): what `Integrations.list()` shows, without
896
+ * any person's identity (no owner user ids; no account identity on personal connections), and READ
897
+ * catalogue checks only — a check that writes is refused.
898
+ */
899
+ integrations(agentId: string): {
900
+ list(): Promise<IntegrationConnectionSummary[]>;
901
+ check(connectionId: string, check: ConnectionCheckName): Promise<ConnectionCheckOutcome>;
902
+ };
903
+ /**
904
+ * Metrics the target recorded with `Metrics.record` (`supervision:observe`): one `name` (or the metric of one
905
+ * `objectiveId`), bucketed by `1h` (≤ 7 days) or `1d` (≤ 400 days).
906
+ */
907
+ metrics(agentId: string): {
908
+ query(q: AgentMetricQueryInput): Promise<AgentMetricQueryResult>;
909
+ };
910
+ /**
911
+ * The target's objectives. `list` (`supervision:observe`) shows confirmed and proposed ones; `propose`
912
+ * (`supervision:act`) adds a `proposed` create / update / retire that takes effect ONLY when the agent's owner
913
+ * confirms it. Offline, `list` reads with your developer credential and `propose` is refused.
914
+ */
915
+ objectives(agentId: string): {
916
+ list(opts?: {
917
+ status?: AgentObjectiveStatus;
918
+ }): Promise<AgentObjective[]>;
919
+ propose(proposal: AgentObjectiveProposal): Promise<AgentObjective>;
920
+ };
921
+ /**
922
+ * The target's advisory change lease. A lease never blocks anyone's push: the agent's humans see it
923
+ * (`lua push` / `lua status` print a warning, and the dashboard shows it) and another supervisor cannot take
924
+ * it while it is live. Use it to say "I am working on this agent until …".
925
+ *
926
+ * @example
927
+ * ```typescript
928
+ * const { lease, lastHumanChangeAt } = await Agents.lease(agentId).get();
929
+ * // Back off while a person changed the agent in the last hour.
930
+ * if (lastHumanChangeAt && Date.now() - Date.parse(lastHumanChangeAt) < 3_600_000) return;
931
+ * await Agents.lease(agentId).acquire({ ttlMinutes: 30, reason: 'Tuning the refund skill' });
932
+ * // ... change the agent ...
933
+ * await Agents.lease(agentId).release();
934
+ * ```
935
+ */
936
+ lease(agentId: string): {
937
+ /**
938
+ * The live lease (null when none, or expired) and when a human (`lastHumanChangeAt`) or a supervisor agent
939
+ * (`lastAgentChangeAt`) last created or promoted a version or pushed the source (`supervision:observe`).
940
+ */
941
+ get(): Promise<AgentChangeActivity>;
942
+ /**
943
+ * Take the lease for YOUR agent, or renew the one you hold (`supervision:act`). `ttlMinutes` is 1-240,
944
+ * `reason` (at most 300 characters) is shown to the agent's humans. Refused (409 `change_lease_held`) while
945
+ * another agent's lease is live. Not available offline.
946
+ */
947
+ acquire(opts: {
948
+ ttlMinutes: number;
949
+ reason: string;
950
+ }): Promise<AgentChangeLease>;
951
+ /** Drop the lease you hold (`supervision:act`); `released: false` when you hold none. Not available offline. */
952
+ release(): Promise<{
953
+ released: boolean;
954
+ }>;
955
+ };
956
+ /**
957
+ * Archive or delete a supervised agent (`supervision:act`, on a grant written by an org owner or by the agent's
958
+ * creator). Both remove its connections from the agent without revoking them at the provider, delete its
959
+ * secrets (env), cancel its workflow runs and revoke every grant on it, yours included (so you cannot call it twice
960
+ * on the same agent: archive OR delete, and `warnings` lists anything staff must finish); records outside Lua are
961
+ * kept. Archive is reversible by staff for 30 days; `delete` needs the agent's exact current name and cannot be
962
+ * undone.
963
+ * Refused offline and while the platform has it disabled (`supervised_lifecycle_disabled`).
964
+ *
965
+ * @example
966
+ * ```typescript
967
+ * await Agents.lifecycle(agentId).delete({ confirmName: 'Old intake bot' });
968
+ * ```
969
+ */
970
+ lifecycle(agentId: string): {
971
+ archive(): Promise<AgentLifecycleResult>;
972
+ delete(opts: AgentDeleteInput): Promise<AgentLifecycleResult>;
973
+ };
974
+ /**
975
+ * Change a supervised agent's settings (`supervision:act`): its model, its name, or NON-secret env keys (merged;
976
+ * other keys untouched). A key ending SECRET, TOKEN, KEY or PASSWORD refuses the whole call
977
+ * (`agent_config_secret_key_refused`): secrets are set by the agent's owner. Refused offline.
978
+ */
979
+ config(agentId: string): {
980
+ set(input: AgentConfigSetInput): Promise<AgentConfigSetResult>;
981
+ };
982
+ /**
983
+ * Agents the DELEGATED user of the current turn can see (private agents only for their owner or agent-grant
984
+ * holders), with owner, privacy, build kind, last activity, 30-day volume and the actions you hold on each.
985
+ * Refused with `agent_directory_requires_user` on a turn with no user (or a user outside your org), a turn
986
+ * whose user an invoking agent chose, code in a Job or workflow run, and any turn invoked onward from those.
987
+ */
988
+ directory(): Promise<AgentDirectoryEntry[]>;
989
+ /**
990
+ * Ask for supervision actions on `agentId`. The request goes to the owner of a private agent, or to the org
991
+ * admins / agent builders of a shared one, as an inbox card; approving creates the grant (expiring at
992
+ * `expiresAt`, when given). One pending request per agent; a pending request lapses after 7 days. Refused
993
+ * with `supervision_access_no_approver` when nobody can approve (a departed owner, no admin / builder).
994
+ *
995
+ * Where the platform enables them, a request may also name `releaseWorkflowIds` / `unattendedWorkflowIds` (YOUR
996
+ * own workflows: release only ever happens in those workflows' code steps) and `dataCollections`
997
+ * (`supervision_access_bindings_disabled` otherwise), and `notifyOwner: true` (the owner opts in to `notifyOwner` by
998
+ * approving it). When you already hold a grant on the agent, the request UPGRADES it: the approver sees exactly
999
+ * what is added (`adds`), nothing is ever removed, and approval is refused (`supervision_access_grant_changed`) if
1000
+ * your access changed after you asked (`supervision_access_upgrades_disabled` / `_grant_exists` where off).
1001
+ */
1002
+ requestAccess(agentId: string, opts: SupervisionAccessRequestInput): Promise<SupervisionAccessRequest>;
1003
+ /** Your own access requests, newest first (at most 50). */
1004
+ accessRequests(): Promise<SupervisionAccessRequest[]>;
1005
+ /** Withdraw one of your own pending requests. */
1006
+ cancelAccessRequest(requestId: string): Promise<SupervisionAccessRequest>;
1007
+ /**
1008
+ * Eval suites of a supervised agent (U12). Reads need `supervision:observe`; `run` and `cancel` need
1009
+ * `supervision:preview`. `run` executes a STAGED (unpromoted) version — or `'active'` — against a suite the agent's
1010
+ * owner defined, isolated from live tools unless the owner opted some in. Bounded by the suite budget, the agent's
1011
+ * monthly eval allowance and a per-day cap of supervised runs per agent (`supervision_eval_runs_rate_limited`).
1012
+ * Per-check `detail`, the judge's `reasoning` and transcripts need `observe-content`. `cancel` stops only runs you
1013
+ * started, and works even after the platform turns evals or preview off. Suites are written by the owner
1014
+ * (`lua evals push`), never by a supervisor. Off until the platform enables evals (`agent_evals_disabled`).
1015
+ * Offline (`lua test`): reads use your developer credential; `run` / `cancel` are refused.
1016
+ *
1017
+ * @example
1018
+ * ```typescript
1019
+ * const { runId } = await Agents.evals(agentId).run({ suite: 'release-gate', version: staged });
1020
+ * const run = await Agents.evals(agentId).getRun(runId); // poll (or wait in a workflow step) until it finishes
1021
+ * if (run.passed === false) { ... }
1022
+ * ```
1023
+ */
1024
+ evals(agentId: string): {
1025
+ suites(): Promise<Array<{
1026
+ key: string;
1027
+ revision: number;
1028
+ caseCount: number;
1029
+ minPassRate: number;
1030
+ updatedAt?: string;
1031
+ }>>;
1032
+ suite(key: string): Promise<EvalSuite>;
1033
+ run(opts: {
1034
+ suite: string;
1035
+ version: number | 'active';
1036
+ maxCredits?: number;
1037
+ caseIds?: string[];
1038
+ }): Promise<EvalRunReceipt>;
1039
+ runs(opts?: {
1040
+ suite?: string;
1041
+ version?: number;
1042
+ status?: string;
1043
+ limit?: number;
1044
+ before?: string;
1045
+ }): Promise<EvalSuiteRunSummary[]>;
1046
+ getRun(runId: string): Promise<EvalSuiteRunSummary>;
1047
+ transcript(runId: string, caseId: string): Promise<EvalCaseTranscript>;
1048
+ cancel(runId: string): Promise<EvalSuiteRunSummary>;
1049
+ };
1050
+ /**
1051
+ * Message the OWNER of a supervised agent: a plain message (no model turn) in their home thread with YOUR agent,
1052
+ * from any run — a schedule or an event trigger included, not only your own notify list. Needs `supervision:observe`
1053
+ * and the owner's opt-in on your grant (they approved a `requestAccess({ notifyOwner: true })` themselves, or turned
1054
+ * it on from the agent's supervisors list). Refused `supervision_owner_notify_not_opted_in` otherwise, and when the
1055
+ * agent changed owner or the owner left. Shares `Threads.followUp`'s rate limits. Off until the platform enables it
1056
+ * (`supervision_owner_notify_disabled`); not available offline.
1057
+ *
1058
+ * Pass an optional `idempotencyKey` (1-256 characters) to make retries safe: a second call from your agent with the
1059
+ * same key within 24 hours posts nothing and resolves the FIRST call's receipt (same `followUpId` and `threadId`).
1060
+ * A duplicate sent while the first is still posting waits for it, or is refused `thread_follow_up_in_progress`
1061
+ * (retry it). A key already used for ANOTHER target agent is refused `supervision_owner_notify_invalid`. At most
1062
+ * once unless the platform's key store fails mid-delivery. Without a key every call posts.
1063
+ *
1064
+ * @example
1065
+ * ```typescript
1066
+ * await Agents.notifyOwner(targetId, { message: 'Lead Desk is failing', idempotencyKey: `incident-${incidentId}` });
1067
+ * ```
1068
+ */
1069
+ notifyOwner(agentId: string, input: SupervisionOwnerNotifyInput): Promise<SupervisionOwnerNotifyReceipt>;
1070
+ /**
1071
+ * Hand one of the agent OWNER's own personal connections to the agent (`supervision:act`), with the owner's consent
1072
+ * on Lua's own approval card, decided in their signed-in Desktop or inbox session (a chat-card, channel-reply or
1073
+ * API-key decision does not count). From a run the owner started, suspend on
1074
+ * `.approval(step, { approver: 'creator', title })` with the payload exactly
1075
+ * `{ connectionAssignment: { connectionId, agentId, agentName, supervisorName, integration, account } }` — the
1076
+ * agent's and YOUR agent's current names, the connection's integration type and its label (display name, else first
1077
+ * email), each checked against what Lua stores — and `title` exactly
1078
+ * `Give your <integration> connection to "<agentName>"?` (`connectionHandoverApprovalTitle`); no artefacts. Then call
1079
+ * `assign(connectionId, { approval: { runId, stepId } })` from a code step of THAT run within 10 minutes. One
1080
+ * assignment per approval. Refused `connection_handover_account_unidentified` / `connection_handover_agent_unidentified`
1081
+ * when the card could not say which account / agent (no label, a duplicate label or name, invisible characters). Refused `connection_handover_not_assignable` unless the connection is the owner's own and the agent is
1082
+ * their private agent. Off until the platform enables it (`connection_handover_disabled`); not available offline.
1083
+ */
1084
+ connections(agentId: string): {
1085
+ assign(connectionId: string, opts: {
1086
+ approval: AgentCreateApprovalRef;
1087
+ }): Promise<ConnectionHandoverResult>;
1088
+ };
1089
+ /**
1090
+ * Keys for an agent that already exists. On the owner's live chat turn, ask with `Secrets.request({ provider, key,
1091
+ * target: { pendingFor, agentId } })` (needs `supervision:act` on `agentId`, an agent of your org created by the
1092
+ * person you are talking to; never a `LUA_` / `NODE_` key). The OWNER submits it signed in
1093
+ * (`POST /developer/secrets/held-requests/:requestId/submit`; the public secret page refuses these), Lua tests it and
1094
+ * holds it encrypted; then attach it with `Agents.secrets(agentId).attach([requestId])`, again on the owner's live
1095
+ * chat turn (never a scheduled task, Job, workflow step or a user another agent chose). Only `ok`-tested requests you
1096
+ * held and the owner submitted are taken, all or none, and a key the agent already has is never replaced
1097
+ * (`secret_key_exists`). Off until `LUA_SECRET_ATTACH_EXISTING_ENABLED` is on (`secret_attach_existing_disabled`);
1098
+ * not available offline.
1099
+ */
1100
+ secrets(agentId: string): {
1101
+ attach(requestIds: string[]): Promise<SecretAttachResult>;
1102
+ };
436
1103
  }
437
1104
 
438
1105
  export declare interface AgentStepOptions {
@@ -557,16 +1224,30 @@ export declare interface AiApi {
557
1224
  generate(prompt: string, content?: UserContent): Promise<string>;
558
1225
  /**
559
1226
  * Generate text with full options — a serializable subset of `generateText`
560
- * (`model`, `system`, `prompt`, `messages`, `temperature`, `maxOutputTokens`).
1227
+ * (`model`, `system`, `prompt`, `messages`, `temperature`, `maxOutputTokens`,
1228
+ * `structuredOutput`, `reasoning`).
561
1229
  * Returns the full AI SDK–aligned result including `text`, `finishReason`, `usage`,
562
1230
  * `sources` (Google Search grounding), `reasoning`, `warnings`, and more.
563
1231
  *
1232
+ * `reasoning` takes the same `{ effort?, show? }` as an agent's `modelSettings.reasoning`:
1233
+ * `effort` (`'off' | 'minimal' | 'low' | 'medium' | 'high' | 'max'`) is translated for the
1234
+ * model's provider and clamped to the levels that model supports; `show: false` omits
1235
+ * `reasoning` / `reasoningText` from the result (the count stays on `usage.reasoningTokens`).
1236
+ * The call's `reasoning` outranks the model's catalog default. The agent's own
1237
+ * `modelSettings.reasoning` is not applied to `AI.generate`.
1238
+ *
564
1239
  * @example
565
1240
  * ```typescript
566
1241
  * const { text, finishReason, usage, sources } = await AI.generate({
567
1242
  * system: 'You are concise.',
568
1243
  * prompt: 'Say hi.',
569
1244
  * });
1245
+ *
1246
+ * // Think harder, but keep the trace out of the result.
1247
+ * const { text: plan } = await AI.generate({
1248
+ * prompt: 'Plan the migration in five steps.',
1249
+ * reasoning: { effort: 'high', show: false },
1250
+ * });
570
1251
  * ```
571
1252
  */
572
1253
  generate(options: AiGenerateInput): Promise<AiGenerateOutput>;
@@ -584,6 +1265,11 @@ export declare interface AiGenerateInput {
584
1265
  messages?: ModelMessage[];
585
1266
  temperature?: number;
586
1267
  maxOutputTokens?: number;
1268
+ /**
1269
+ * Reasoning effort / visibility — the same shape and semantics as an agent's
1270
+ * `modelSettings.reasoning` (see {@link AiGenerateReasoningOptions}).
1271
+ */
1272
+ reasoning?: AiGenerateReasoningOptions;
587
1273
  /**
588
1274
  * When set, constrains the response to match the JSON Schema. The parsed result
589
1275
  * lands on `AiGenerateOutput.output`. Mirrors AI SDK `Output.object({ schema })`.
@@ -599,6 +1285,19 @@ export declare interface AiGenerateInput {
599
1285
  */
600
1286
  export declare type AiGenerateJsonSchema = Record<string, unknown>;
601
1287
 
1288
+ /**
1289
+ * Why the served model differs from the requested one:
1290
+ * - `not-approved`: the resolved model (the agent's own pin, when the call named none) is not in the model
1291
+ * catalogue, so the platform default ran. A model the CALLER names is never swapped this way on
1292
+ * `AI.generate` — it is refused with a 400 `MODEL_NOT_AVAILABLE` instead.
1293
+ * - `provider-unavailable`: the requested model's provider failed transiently and a fallback leg served.
1294
+ */
1295
+ declare interface AiGenerateModelFallback {
1296
+ requestedModel: string;
1297
+ servedModel: string;
1298
+ reason: 'not-approved' | 'provider-unavailable';
1299
+ }
1300
+
602
1301
  /**
603
1302
  * Wire-format output from `AI.generate` / `POST .../generate`.
604
1303
  * Fields mirror AI SDK `GenerateTextResult` — uses AI SDK types where exported.
@@ -627,8 +1326,29 @@ export declare interface AiGenerateOutput {
627
1326
  output?: unknown;
628
1327
  /** Provider warnings (e.g. unsupported settings) — AI SDK `CallWarning[]` */
629
1328
  warnings?: CallWarning[];
1329
+ /**
1330
+ * The model that actually produced `text` (`provider/model`). Present on every response from builds that
1331
+ * report it; absent only from older servers.
1332
+ */
1333
+ model?: string;
1334
+ /** Present only when `model` is NOT the model the call resolved to — see {@link AiGenerateModelFallback}. */
1335
+ modelFallback?: AiGenerateModelFallback;
630
1336
  }
631
1337
 
1338
+ /**
1339
+ * Reasoning options for `AI.generate` — the same shape and semantics as an agent's
1340
+ * `modelSettings.reasoning` (and the chat request's `options.reasoning`):
1341
+ *
1342
+ * - `effort` — `'off' | 'minimal' | 'low' | 'medium' | 'high' | 'max'`, translated per
1343
+ * provider (Anthropic `thinking`, OpenAI `reasoningEffort`, Gemini `thinkingConfig`, …)
1344
+ * and clamped to the levels the served model supports, exactly as on an agent turn.
1345
+ * Unset = the model's catalog default.
1346
+ * - `show` — whether the reasoning trace is returned. `false` asks the provider to omit
1347
+ * its summaries AND drops `reasoning` / `reasoningText` from the response (the token
1348
+ * count stays on `usage.reasoningTokens`). Default `true`.
1349
+ */
1350
+ export declare type AiGenerateReasoningOptions = ModelReasoningOptions;
1351
+
632
1352
  /**
633
1353
  * URL source from Google Search grounding.
634
1354
  * Mirrors `LanguageModelV2Source` (AI SDK `Source` type — not exported from `ai` as of v5).
@@ -751,6 +1471,14 @@ export declare interface ApprovalOptions {
751
1471
  fourEyes?: WorkflowFourEyes;
752
1472
  /** default 168; a binding is resolved at suspend time and must yield 1..720 */
753
1473
  timeoutHours?: number | TemplateBinding;
1474
+ /**
1475
+ * Re-send the approval push to the approvers who have not decided yet, every `remindAfterHours` hours while the
1476
+ * approval is pending — at most 3 reminders per ask (an escalation hop starts a new ask), and never after the
1477
+ * deadline. A plain number in 1..720 (no binding); a value at or above a numeric `timeoutHours` never fires (a
1478
+ * push warning). Absent ⇒ no reminder. Reminders ride the approval push, so they reach the approvers an agent's
1479
+ * approval routing names (Settings → Approvals); they are sent on the platform's sweep cadence.
1480
+ */
1481
+ remindAfterHours?: number;
754
1482
  /** 'deny' (default) | 'cancel-run' | 'fail' | a chain of ≤ 3 hops ending in one terminal member */
755
1483
  onTimeout?: WorkflowSuspendTimeoutChain;
756
1484
  /** default 'continue' (denial is data unless 'fail') */
@@ -1060,7 +1788,7 @@ export declare enum BasketStatus {
1060
1788
  * Per-agent message batching/debounce configuration.
1061
1789
  * Overrides platform-wide env var defaults for this specific agent.
1062
1790
  */
1063
- declare interface BatchingConfig {
1791
+ export declare interface BatchingConfig {
1064
1792
  /** Hold first message N ms before processing, to allow rapid follow-ups to batch together. 0 = disabled. */
1065
1793
  firstMessageDelayMs?: number;
1066
1794
  /** Window to collect subsequent messages while one is in-flight (ms). 0 = batching disabled. */
@@ -1089,7 +1817,7 @@ declare interface BatchingConfig {
1089
1817
  * local browser (desktop) or the Browser-Use cloud fallback. The object form
1090
1818
  * adds optional policy.
1091
1819
  */
1092
- declare interface BrowserSwitchConfig {
1820
+ export declare interface BrowserSwitchConfig {
1093
1821
  /** Preferred engine; 'auto' lets the platform pick local (desktop) vs cloud. */
1094
1822
  engine?: 'auto' | 'browser-use' | 'agent-browser';
1095
1823
  /** Egress allowlist — domains the browser may navigate/sub-request. */
@@ -1175,10 +1903,6 @@ export declare const CDN: {
1175
1903
  get(fileId: string): Promise<File>;
1176
1904
  };
1177
1905
 
1178
- /**
1179
- * Lua Runtime Interfaces
1180
- * Request-level runtime information available in the execution sandbox
1181
- */
1182
1906
  /**
1183
1907
  * Channel type.
1184
1908
  * Represents the communication channel through which a request originated.
@@ -1310,6 +2034,25 @@ export declare interface ChannelsApi {
1310
2034
  * ```
1311
2035
  */
1312
2036
  sendReaction(input: WhatsAppReactionSendInput): Promise<ChannelSendOutput>;
2037
+ /**
2038
+ * Ask a WhatsApp user to share their phone number. WhatsApp shows `text`
2039
+ * with a share button. If they tap it, their own number is saved on their
2040
+ * profile (when it has none) and is in `user._luaProfile.mobileNumbers`
2041
+ * on that same turn. Users who hide their number behind a WhatsApp
2042
+ * username otherwise reach you without one.
2043
+ *
2044
+ * Needs an open 24h window (the user wrote in the last 24 hours); a
2045
+ * closed window throws. Declining sends nothing back.
2046
+ *
2047
+ * @example
2048
+ * ```typescript
2049
+ * await Channels.whatsapp.requestPhoneNumber({
2050
+ * to: { userId: user._luaProfile.userId },
2051
+ * text: 'Please share your phone number so we can confirm you are registered.',
2052
+ * });
2053
+ * ```
2054
+ */
2055
+ requestPhoneNumber(input: WhatsAppPhoneRequestInput): Promise<ChannelSendOutput>;
1313
2056
  };
1314
2057
  /** Email-specific send operations. */
1315
2058
  email: {
@@ -1369,6 +2112,11 @@ export declare interface ChannelSendInput {
1369
2112
  export declare interface ChannelSendOptions {
1370
2113
  /** Pin a specific channel config (must belong to the sending agent). */
1371
2114
  channelIdentifier?: string;
2115
+ /**
2116
+ * Send even while a staff member holds the conversation. By default a held
2117
+ * conversation refuses proactive sends with 409 `CONVERSATION_HELD`.
2118
+ */
2119
+ ignoreHold?: boolean;
1372
2120
  /** WhatsApp-specific send options. */
1373
2121
  whatsapp?: {
1374
2122
  /**
@@ -1432,12 +2180,16 @@ export declare interface ChannelSendOutput {
1432
2180
  * - slack: `Lua.request.conversation.externalId` (`T…:A…:C…[:threadTs]`), a
1433
2181
  * channel id (`C…`, top level), `C…:threadTs` (a reply in that thread), a
1434
2182
  * member id (`U…`, their DM with the bot) or 2–8 member ids (`U…,U…`, a group
1435
- * DM). The bot must be in the channel. */
2183
+ * DM). The bot must be in the channel.
2184
+ *
2185
+ * `identity` names one of the agent's users by a channel id, as `Lua.request.sender`
2186
+ * gives it: a `whatsapp_bsuid` on whatsapp, a `slack_user` on slack. */
1436
2187
  export declare interface ChannelSendTarget {
1437
2188
  userId?: string;
1438
2189
  phoneNumber?: string;
1439
2190
  email?: string;
1440
2191
  conversationId?: string;
2192
+ identity?: UserIdentityRef;
1441
2193
  }
1442
2194
 
1443
2195
  /**
@@ -1542,6 +2294,105 @@ export declare interface ChatHistoryMessage {
1542
2294
  */
1543
2295
  export declare type ChatMessage = TextMessage | ImageMessage | FileMessage;
1544
2296
 
2297
+ /** wave 2 U33 — the typed refusal `Integrations.checkAsUser` raises outside a live chat turn. */
2298
+ export declare function checkAsUserRequiresUser(): Error;
2299
+
2300
+ /**
2301
+ * U6 (wave 2) — connection inspection, account pinning and capability checks; U33 — the same checks run
2302
+ * with the CONVERSATION USER's principal. Owner: U6 (catalogue, list, pin, check, cleanup); U33 owns only
2303
+ * `checkAsUser`. Contract: docs/agent-builder/wave2-contracts.md §U6, §U33.
2304
+ *
2305
+ * The check catalogue is SERVER-OWNED (lua-api `services/connection-checks/`): a caller can only NAME a
2306
+ * check; the probe, its request and its interpretation live on the server. Results are a fixed enum
2307
+ * plus SAFE metadata (account identity, counts) — never a provider body.
2308
+ */
2309
+ declare const CONNECTION_CHECK_RESULTS: readonly ["ok", "unauthorized", "insufficient_scope", "not_found", "unreachable", "unsupported"];
2310
+
2311
+ /** u21 doc §5.1 — the request row's state machine (transition table in §6.3). */
2312
+ declare const CONNECTION_REQUEST_STATES: readonly ["pending", "opened", "authorizing", "remote_created", "finalizing", "connected", "identity_mismatch", "declined", "expired", "cancelled", "exhausted", "manual_review"];
2313
+
2314
+ /**
2315
+ * A check id. `identity` exists for every catalogued integration; the rest are per integration
2316
+ * ({@link CONNECTION_CHECK_CATALOGUE_V1}). An uncatalogued pair answers `unsupported`, never an error.
2317
+ */
2318
+ declare type ConnectionCheckName = 'identity' | (string & {});
2319
+
2320
+ declare interface ConnectionCheckOptions {
2321
+ /** Required (`true`) for a `reversible-write` catalogue entry; refused otherwise. */
2322
+ allowWrite?: boolean;
2323
+ }
2324
+
2325
+ declare interface ConnectionCheckOutcome {
2326
+ connectionId: string;
2327
+ integrationType: string;
2328
+ check: ConnectionCheckName;
2329
+ result: ConnectionCheckResult;
2330
+ /** ISO. */
2331
+ checkedAt: string;
2332
+ metadata?: ConnectionCheckSafeMetadata;
2333
+ /** Present only for a `reversible-write` check: `pending` ⇒ a leftover is queued for cleanup retry. */
2334
+ cleanup?: 'done' | 'pending';
2335
+ }
2336
+
2337
+ declare type ConnectionCheckResult = (typeof CONNECTION_CHECK_RESULTS)[number];
2338
+
2339
+ /** The ONLY metadata a check may return (allow-listed fields; no provider body, ever). */
2340
+ declare interface ConnectionCheckSafeMetadata {
2341
+ accountEmail?: string;
2342
+ accountId?: string;
2343
+ accountName?: string;
2344
+ /** Small named counts, e.g. `{ teams: 3 }`. */
2345
+ counts?: Record<string, number>;
2346
+ /** Unified scope names the probe found missing (`insufficient_scope`). */
2347
+ missingScopes?: string[];
2348
+ }
2349
+
2350
+ declare interface ConnectionHandoverResult {
2351
+ agentId: string;
2352
+ connectionId: string;
2353
+ integration: string;
2354
+ status: 'assigned';
2355
+ }
2356
+
2357
+ /** `Integrations.requestConnection(...)` (u21 doc §15.2). The agent id comes from the runtime credential. */
2358
+ export declare interface ConnectionRequestCreateInput {
2359
+ integrationType: string;
2360
+ invitee: {
2361
+ email: string;
2362
+ };
2363
+ scopes?: string[];
2364
+ /** Default false. */
2365
+ unattended?: boolean;
2366
+ /** Default 72, max 168. */
2367
+ expiresInHours?: number;
2368
+ }
2369
+
2370
+ declare type ConnectionRequestHolderClass = 'member' | 'nonmember';
2371
+
2372
+ declare type ConnectionRequestKind = 'connect' | 'reconnect';
2373
+
2374
+ export declare type ConnectionRequestState = (typeof CONNECTION_REQUEST_STATES)[number];
2375
+
2376
+ /** What the requester (SDK, CLI, Desktop card) may read — never the token, never the hosted URL. */
2377
+ export declare interface ConnectionRequestStatus {
2378
+ requestId: string;
2379
+ kind: ConnectionRequestKind;
2380
+ agentId: string;
2381
+ integrationType: string;
2382
+ state: ConnectionRequestState;
2383
+ /** A display label for the invitee (name, else the email's local part). */
2384
+ inviteeLabel: string;
2385
+ holderClass: ConnectionRequestHolderClass;
2386
+ unattended: boolean;
2387
+ /** ISO. */
2388
+ expiresAt: string;
2389
+ /** Present once `connected`. */
2390
+ connectionId?: string;
2391
+ /** Present once `connected`: the remote identity the holder signed in with. */
2392
+ connectedAs?: string;
2393
+ lastErrorCode?: string;
2394
+ }
2395
+
1545
2396
  /**
1546
2397
  * A container arm: a `StepRef` — a `createStep` object, or a string naming an entry declared elsewhere in the chain
1547
2398
  * (`agentStep` / `specialistStep` / `toolStep` / `workflow`, and since LUA-684 `approval` / `waitForSignal`, so an
@@ -1713,12 +2564,25 @@ declare interface CustomDataAPI {
1713
2564
  * @returns Promise resolving to update response
1714
2565
  */
1715
2566
  update(collectionName: string, entryId: string, data: Record<string, any>, optionsOrSearchText?: string | CreateCustomDataOptions): Promise<UpdateCustomDataResponse>;
1716
- /** Atomically sets and removes top-level entry fields and optionally changes search text. */
2567
+ /**
2568
+ * Atomically sets and removes top-level entry fields and optionally changes search text.
2569
+ * `options.ifVersion` makes it a compare-and-swap: a stale version rejects with
2570
+ * `code === 'data_version_conflict'` (409) and writes nothing.
2571
+ */
1717
2572
  patch(collectionName: string, entryId: string, mutation: {
1718
2573
  set?: Record<string, any>;
1719
2574
  unset?: string[];
1720
2575
  searchText?: string | null;
2576
+ }, options?: {
2577
+ ifVersion?: number;
1721
2578
  }): Promise<UpdateCustomDataResponse>;
2579
+ /**
2580
+ * Atomically adds `by` (default 1) to a top-level numeric field and resolves the new value.
2581
+ * A missing field starts at 0; `options.upsert` creates a missing entry under `entryId`.
2582
+ */
2583
+ increment(collectionName: string, entryId: string, field: string, by?: number, options?: {
2584
+ upsert?: boolean;
2585
+ }): Promise<number>;
1722
2586
  /**
1723
2587
  * Performs vector search on a collection.
1724
2588
  * @param collectionName - Collection name
@@ -1758,6 +2622,12 @@ declare interface CustomDataEntry extends IdentifiedEntity, TimestampedEntity {
1758
2622
  createdAt: number;
1759
2623
  updatedAt: number;
1760
2624
  searchText?: string;
2625
+ /**
2626
+ * Write counter for compare-and-swap (LUA-963): pass it back as
2627
+ * `Data.patch(c, id, mutation, { ifVersion })`. Every write bumps it;
2628
+ * entries not written since versioning was introduced report 0.
2629
+ */
2630
+ version?: number;
1761
2631
  }
1762
2632
 
1763
2633
  /**
@@ -1863,6 +2733,74 @@ export declare const Data: {
1863
2733
  * @returns Promise resolving to update response
1864
2734
  */
1865
2735
  update(collectionName: string, entryId: string, data: Record<string, any>, optionsOrSearchText?: string | CreateCustomDataOptions): Promise<UpdateCustomDataResponse>;
2736
+ /**
2737
+ * Atomically sets and removes top-level fields of an entry in ONE write (no
2738
+ * read-merge), optionally changing its search text.
2739
+ *
2740
+ * Compare-and-swap: pass `{ ifVersion }` to apply the patch only if nobody
2741
+ * wrote the entry since you read it. Every entry carries a `version`
2742
+ * (`entry.version` from `Data.get`, `entry._version` on the instance from
2743
+ * `Data.getEntry` / `Data.create`) that every write bumps. On a mismatch
2744
+ * nothing is written and the call rejects with an error whose
2745
+ * `code === 'data_version_conflict'` (`status` 409, plus `currentVersion`
2746
+ * and `expectedVersion`): re-read and retry. A present `ifVersion` that is
2747
+ * not a non-negative integer (even `undefined`) throws a TypeError and
2748
+ * sends nothing; omit the key for an unconditional patch. A CAS patch is
2749
+ * sent once (not retried), so after a network error re-read the entry to
2750
+ * see whether it landed.
2751
+ *
2752
+ * ```typescript
2753
+ * const entry = await Data.getEntry('seats', seatId);
2754
+ * if (entry.data.heldBy) return 'taken';
2755
+ * try {
2756
+ * await Data.patch('seats', seatId, { set: { heldBy: userId } }, { ifVersion: entry._version });
2757
+ * } catch (error: any) {
2758
+ * if (error?.code === 'data_version_conflict') return 'taken'; // someone else won
2759
+ * throw error;
2760
+ * }
2761
+ * ```
2762
+ *
2763
+ * @param collectionName - Name of the collection
2764
+ * @param entryId - ID of the entry
2765
+ * @param mutation - `{ set?, unset?, searchText? }` (`searchText: null` clears it)
2766
+ * @param options - `{ ifVersion? }` for compare-and-swap
2767
+ * @returns Promise resolving to `{ status, message, version }` (`version` = the entry's new version)
2768
+ */
2769
+ patch(collectionName: string, entryId: string, mutation: {
2770
+ set?: Record<string, any>;
2771
+ unset?: string[];
2772
+ searchText?: string | null;
2773
+ }, options?: PatchCustomDataOptions): Promise<UpdateCustomDataResponse>;
2774
+ /**
2775
+ * Atomically adds `by` (default 1; negative and fractional amounts allowed)
2776
+ * to a top-level numeric field and resolves the field's NEW value. Safe
2777
+ * under concurrency: unlike `get` + `update`, simultaneous increments
2778
+ * never lose a count. A missing field starts at 0.
2779
+ *
2780
+ * ```typescript
2781
+ * const views = await Data.increment('stats', 'homepage', 'views');
2782
+ * await Data.increment('stock', sku, 'available', -1);
2783
+ * // Daily counter: one long-lived entry, one field per day (a missing field starts at 0).
2784
+ * await Data.increment('stats', 'calls', `day-${today}`);
2785
+ * ```
2786
+ *
2787
+ * Errors: 404 when the entry does not exist (unless `upsert`), 400 when the
2788
+ * field holds a non-number. `upsert` is NOT safe for an entry many
2789
+ * conversations may create at once: concurrent first-time upserts of the
2790
+ * same new id can create duplicate entries, and the count in one of them is
2791
+ * lost. Do not upsert a fresh id per day or per event under load; create the
2792
+ * entry once from a non-concurrent path, then increment it.
2793
+ * The SDK sends the request once and does not retry it, so a network
2794
+ * failure means the increment may or may not have been applied.
2795
+ *
2796
+ * @param collectionName - Name of the collection
2797
+ * @param entryId - ID of the entry (the id to create under when upserting)
2798
+ * @param field - Top-level field name (no dots, no `$` prefix)
2799
+ * @param by - Amount to add (default 1)
2800
+ * @param options - `{ upsert? }`
2801
+ * @returns Promise resolving to the field's value after the increment
2802
+ */
2803
+ increment(collectionName: string, entryId: string, field: string, by?: number, options?: IncrementCustomDataOptions): Promise<number>;
1866
2804
  /**
1867
2805
  * Performs vector search on a collection.
1868
2806
  *
@@ -1893,6 +2831,12 @@ export declare class DataEntryInstance {
1893
2831
  id: string;
1894
2832
  collectionName: string;
1895
2833
  score?: number;
2834
+ /**
2835
+ * The entry's write version for compare-and-swap (LUA-963):
2836
+ * `entry.patch(m, { ifVersion: entry._version })`. Underscored so it never
2837
+ * shadows a user `data.version` field through the property proxy.
2838
+ */
2839
+ _version: number;
1896
2840
  private customDataAPI;
1897
2841
  [key: string]: any;
1898
2842
  /**
@@ -1916,10 +2860,18 @@ export declare class DataEntryInstance {
1916
2860
  * @throws Error if the update fails
1917
2861
  */
1918
2862
  update(data: Record<string, any>, searchText?: string): Promise<Record<string, any>>;
2863
+ /**
2864
+ * Atomically sets/unsets fields. `options.ifVersion` makes it a
2865
+ * compare-and-swap (pass `entry._version`); a stale version rejects with
2866
+ * `code === 'data_version_conflict'` (status 409) and leaves the entry (and
2867
+ * this instance) unchanged.
2868
+ */
1919
2869
  patch(mutation: {
1920
2870
  set?: Record<string, any>;
1921
2871
  unset?: string[];
1922
2872
  searchText?: string | null;
2873
+ }, options?: {
2874
+ ifVersion?: number;
1923
2875
  }): Promise<Record<string, any>>;
1924
2876
  unset(...fields: string[]): Promise<Record<string, any>>;
1925
2877
  /**
@@ -2325,6 +3277,219 @@ export { EnvRefBinding }
2325
3277
 
2326
3278
  export declare const eq: <T>(l: TypedRef<T>, r: TypedRef<T> | Literal<T>) => LuaPredicate;
2327
3279
 
3280
+ /** DOC3 §4.3 — deterministic check kinds (`side_effect` / `no_side_effect` / `no_log_errors` are Phase 2). */
3281
+ declare const EVAL_CHECK_KINDS: readonly ["contains", "regex", "not_contains", "not_regex", "tool_called", "tool_not_called", "tool_args", "max_latency_ms", "no_log_errors", "side_effect", "no_side_effect", "finish_reason"];
3282
+
3283
+ declare const EVAL_SUITE_RUN_STATUSES: readonly ["queued", "running", "completed", "failed", "cancelled", "budget_exhausted"];
3284
+
3285
+ declare type EvalCase = EvalConversationCase | EvalEventCase;
3286
+
3287
+ declare interface EvalCaseResult {
3288
+ caseId: string;
3289
+ status: EvalCaseStatus;
3290
+ checks: Array<{
3291
+ kind: string;
3292
+ passed: boolean;
3293
+ detail?: string;
3294
+ }>;
3295
+ judge?: {
3296
+ score: number;
3297
+ passed: boolean;
3298
+ reasoning?: string;
3299
+ };
3300
+ turns: number;
3301
+ durationMs?: number;
3302
+ credits?: number;
3303
+ holdout?: boolean;
3304
+ }
3305
+
3306
+ declare type EvalCaseStatus = 'pending' | 'passed' | 'failed' | 'error' | 'skipped';
3307
+
3308
+ /** `evalCaseTranscripts` (agents DB, 30-day TTL) — what the transcript route returns. */
3309
+ declare interface EvalCaseTranscript {
3310
+ runId: string;
3311
+ caseId: string;
3312
+ agentId: string;
3313
+ turns: EvalTranscriptTurn[];
3314
+ judge?: {
3315
+ score: number;
3316
+ passed: boolean;
3317
+ reasoning?: string;
3318
+ };
3319
+ error?: string;
3320
+ holdout?: boolean;
3321
+ /** Always true until the U19 scrubber lands: bodies are stored through `redactTranscript` (DOC3 §4.6). */
3322
+ redacted: boolean;
3323
+ }
3324
+
3325
+ /** One check. Fields beyond `kind` are per kind (DOC3 §4.2 examples); the parser validates them. */
3326
+ declare interface EvalCheck {
3327
+ kind: EvalCheckKind;
3328
+ [field: string]: unknown;
3329
+ }
3330
+
3331
+ declare type EvalCheckKind = (typeof EVAL_CHECK_KINDS)[number];
3332
+
3333
+ declare interface EvalConversationCase {
3334
+ id: string;
3335
+ kind: 'conversation';
3336
+ turns?: Array<{
3337
+ role: 'user' | 'assistant';
3338
+ content: string;
3339
+ }>;
3340
+ simulatedUser?: {
3341
+ persona: string;
3342
+ goal: string;
3343
+ stopWhen: string;
3344
+ maxTurns: number;
3345
+ };
3346
+ checks: EvalCheck[];
3347
+ rubric?: EvalRubric;
3348
+ toolDoubles?: EvalToolDouble[];
3349
+ tags?: string[];
3350
+ }
3351
+
3352
+ declare interface EvalEventCase {
3353
+ id: string;
3354
+ kind: 'event';
3355
+ fire: {
3356
+ trigger: string;
3357
+ } | {
3358
+ job: string;
3359
+ } | {
3360
+ workflow: string;
3361
+ } | {
3362
+ webhook: string;
3363
+ };
3364
+ payload: unknown;
3365
+ checks: EvalCheck[];
3366
+ rubric?: EvalRubric;
3367
+ toolDoubles?: EvalToolDouble[];
3368
+ }
3369
+
3370
+ declare interface EvalRubric {
3371
+ text: string;
3372
+ /** 0..1; default the suite's judge threshold (default 0.7). */
3373
+ threshold?: number;
3374
+ }
3375
+
3376
+ declare interface EvalRunReceipt {
3377
+ runId: string;
3378
+ estimate: {
3379
+ credits: number;
3380
+ cases: number;
3381
+ };
3382
+ }
3383
+
3384
+ /** `evalSuites` (agents DB), one per `(agentId, key)`. Only the OWNER writes the `live*` lists. */
3385
+ declare interface EvalSuite {
3386
+ id: string;
3387
+ agentId: string;
3388
+ key: string;
3389
+ revision: number;
3390
+ source: EvalSuiteSource;
3391
+ minPassRate: number;
3392
+ judge: {
3393
+ model?: string;
3394
+ threshold: number;
3395
+ };
3396
+ budget: {
3397
+ maxCredits: number;
3398
+ maxTurnsPerCase: number;
3399
+ maxCases: number;
3400
+ };
3401
+ toolDoubles: EvalToolDouble[];
3402
+ liveSkills: string[];
3403
+ liveBuiltins: string[];
3404
+ liveAgentTools: string[];
3405
+ monitors: EvalSuiteMonitor[];
3406
+ cases: EvalCase[];
3407
+ updatedBy: string;
3408
+ }
3409
+
3410
+ /** DOC3 §4.9 — a suite monitor (template `EvalSetMonitor` + `appliesTo` / `threshold`). */
3411
+ declare interface EvalSuiteMonitor {
3412
+ key: string;
3413
+ title: string;
3414
+ rubric: string;
3415
+ samplingRate: number;
3416
+ appliesTo: Array<'chat' | 'workflow' | 'trigger' | 'job'>;
3417
+ threshold: number;
3418
+ }
3419
+
3420
+ declare type EvalSuiteRunStatus = (typeof EVAL_SUITE_RUN_STATUSES)[number];
3421
+
3422
+ /** `evalSuiteRuns` (agents DB) — what `Evals.runs(id).get` returns (no transcripts). */
3423
+ declare interface EvalSuiteRunSummary {
3424
+ id: string;
3425
+ agentId: string;
3426
+ suiteKey: string;
3427
+ suiteRevision: number;
3428
+ version: number;
3429
+ sourceDigest?: string;
3430
+ /** U11 session, when the run used one. */
3431
+ testSessionId?: string;
3432
+ /** `user:<id>` | `apiKey:<id>` | `service:agent:<id>`. */
3433
+ initiatedBy: string;
3434
+ status: EvalSuiteRunStatus;
3435
+ budget: {
3436
+ maxCredits: number;
3437
+ reserved: number;
3438
+ spent: {
3439
+ credits: number;
3440
+ agentCredits: number;
3441
+ judgeCredits: number;
3442
+ simulatorCredits: number;
3443
+ };
3444
+ };
3445
+ cases: EvalCaseResult[];
3446
+ passRate?: number;
3447
+ passed?: boolean;
3448
+ /**
3449
+ * Why a run stopped early when it was not the run budget: `EVAL_MONTHLY_CAP_REACHED` (the agent's
3450
+ * monthly allowance ran out mid-run) or `EVAL_CAP_UNAVAILABLE` (the cap store was down; fail closed).
3451
+ * Absent for plain per-run `budget_exhausted`.
3452
+ */
3453
+ error?: string;
3454
+ startedAt?: string;
3455
+ finishedAt?: string;
3456
+ }
3457
+
3458
+ declare type EvalSuiteSource = {
3459
+ kind: 'agent';
3460
+ } | {
3461
+ kind: 'template';
3462
+ templateId: string;
3463
+ evalSetRevision: number;
3464
+ } | {
3465
+ kind: 'builder';
3466
+ projectId: string;
3467
+ };
3468
+
3469
+ /** Shape of `agent-template.eval-set.schema.ts` `EvalSetToolDouble` (reused, not redefined). */
3470
+ declare interface EvalToolDouble {
3471
+ tool: string;
3472
+ server?: string;
3473
+ kind?: 'mcp' | 'skill' | 'builtin';
3474
+ result: unknown;
3475
+ /** When set, the double returns an isError result with this text (template `EvalSetToolDouble.error`). */
3476
+ error?: string;
3477
+ }
3478
+
3479
+ /** One recorded turn of a case transcript. */
3480
+ declare interface EvalTranscriptTurn {
3481
+ role: 'user' | 'assistant';
3482
+ content: string;
3483
+ /** `script` for a scripted turn, `simulator` for a simulated-user message, `agent` for a reply. */
3484
+ source: 'script' | 'simulator' | 'agent';
3485
+ toolCalls?: Array<{
3486
+ name: string;
3487
+ input?: string;
3488
+ }>;
3489
+ latencyMs?: number;
3490
+ finishReason?: string;
3491
+ }
3492
+
2328
3493
  export declare const exists: (ref: TypedRef<unknown>) => LuaPredicate;
2329
3494
 
2330
3495
  export declare const falsy: (ref: TypedRef<unknown>) => LuaPredicate;
@@ -2410,7 +3575,7 @@ declare interface GetJobsResponseData {
2410
3575
  * platform resolves it from the `GOVERNANCE_API_KEY` env var. This
2411
3576
  * keeps secrets out of MongoDB, support logs, and backups.
2412
3577
  */
2413
- declare interface GovernanceConfig {
3578
+ export declare interface GovernanceConfig {
2414
3579
  mode: 'sdk' | 'api';
2415
3580
  /**
2416
3581
  * SDK mode — a named governance-sdk preset composed as the base rule set. The platform builder
@@ -2584,6 +3749,15 @@ declare abstract class HttpClient {
2584
3749
  * @protected
2585
3750
  */
2586
3751
  protected httpPatch<T>(url: string, data?: any, headers?: Record<string, string>): Promise<ApiResponse<T>>;
3752
+ /**
3753
+ * Performs one HTTP PATCH attempt (no client retry).
3754
+ *
3755
+ * For a conditional write whose retry is not safe: a compare-and-swap PATCH
3756
+ * (`Data.patch(..., { ifVersion })`, LUA-963) that landed but lost its
3757
+ * response would, on retry, find the version already bumped and report a
3758
+ * false conflict. An ambiguous failure surfaces instead.
3759
+ */
3760
+ protected httpPatchOnce<T>(url: string, data?: any, headers?: Record<string, string>): Promise<ApiResponse<T>>;
2587
3761
  /**
2588
3762
  * Opens a Server-Sent Events stream (WF-204 — 03 §3.10 `watch`; 09 §9.10 `watchEvents`).
2589
3763
  *
@@ -2633,6 +3807,8 @@ declare interface ImmutableUserProfile {
2633
3807
  fullName: string;
2634
3808
  mobileNumbers: string[];
2635
3809
  emailAddresses: string[];
3810
+ /** The person's channel ids (WhatsApp, Slack, ...). Absent when they could not be loaded. */
3811
+ identities?: UserIdentity[];
2636
3812
  }
2637
3813
 
2638
3814
  /**
@@ -2701,6 +3877,12 @@ declare interface InboxPushReceipt {
2701
3877
  reason?: string;
2702
3878
  }
2703
3879
 
3880
+ /** Options for `Data.increment` (LUA-963). */
3881
+ export declare interface IncrementCustomDataOptions {
3882
+ /** Create the entry (`data: { [field]: by }`) under the given id if it does not exist. Default false. */
3883
+ upsert?: boolean;
3884
+ }
3885
+
2704
3886
  export declare const init: <T = unknown>(path: string) => TypedRef<T>;
2705
3887
 
2706
3888
  export declare const inSet: <T extends string | number | boolean | null>(v: TypedRef<T>, set: T[]) => LuaPredicate;
@@ -2708,8 +3890,91 @@ export declare const inSet: <T extends string | number | boolean | null>(v: Type
2708
3890
  /** HTTP methods the passthrough relay accepts. */
2709
3891
  declare const INTEGRATION_PASSTHROUGH_METHODS: readonly ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"];
2710
3892
 
3893
+ declare type IntegrationConnectionStatus = 'active' | 'paused' | 'unhealthy' | 'needs_reconnect';
3894
+
3895
+ /** One row of `Integrations.list()` / `Agents.integrations(id).list()`: a connection VISIBLE to the agent. */
3896
+ declare interface IntegrationConnectionSummary {
3897
+ connectionId: string;
3898
+ integrationType: string;
3899
+ displayName?: string;
3900
+ /** Remote account identity as captured at finalize or by the last `identity` check. */
3901
+ account?: {
3902
+ email?: string;
3903
+ id?: string;
3904
+ name?: string;
3905
+ };
3906
+ /** Provider-granted unified scopes (`grantedScopes`), else the requested filter. */
3907
+ scopes: string[];
3908
+ status: IntegrationConnectionStatus;
3909
+ owner: {
3910
+ type: 'agent' | 'user' | 'org';
3911
+ userId?: string;
3912
+ };
3913
+ /** Agents the connection is mounted on that the CALLER may know about (same org). */
3914
+ agentIds: string[];
3915
+ /** U2 (d): `check-only` mounts are listed but not usable as tools. */
3916
+ mount?: 'tools' | 'check-only';
3917
+ }
3918
+
3919
+ /**
3920
+ * LUA-860 — the typed members `IntegrationPassthroughError` carries beside `message`: the fields lua-api serves on a
3921
+ * route-level refusal of `Integrations.passthrough` (`ApiResponse.error`), copied APPEND-ONLY — a member absent on the
3922
+ * wire is absent on the error, never `undefined`-valued — so skill code branches on `code` (and, for one release,
3923
+ * `legacyCode`) on the in-process path (`lua test`, `lua dev`, the api-exports `Integrations` namespace) exactly as it
3924
+ * does on the production runtime. Parity is complete (LUA-862, #2737, commit 90f05540b — in the lua-cli@3.33.0 tree;
3925
+ * this comment corrected under BAC-551): every production hop relays the same members append-only — lua-core's
3926
+ * `callInternalUnifiedPassthrough` (`unified-passthrough.tool.ts`, via `pickVendorFaultRelayFields` in
3927
+ * `vendor-fault-relay.ts`), the seam envelope (`InternalSandboxSeamController.run` on the fast / worker planes and
3928
+ * `sandbox-passthrough.controller.ts` on the Job tier), the remote-runner bridge (`lua-sandbox-runner/src/executor/
3929
+ * bridge-deps.ts`, the `seamFetch` rebuild) and the Job pod (`lua-workflow-job/src/protocol-client.ts` +
3930
+ * `code-step-ipc.ts`) — so `retryAfterSeconds` / `vendor` / `vendorStatus` / `requestId` are identical on the
3931
+ * in-process path and the production routing, and "absent on the wire ⇒ absent on the error" holds at every hop (a
3932
+ * withheld `retryAfterSeconds` is lua-api's unsafe-to-retry marker, never defaulted). The class is not on the public
3933
+ * `lua-cli` surface — skill code duck-types on `name === 'IntegrationPassthroughError'` and `code`. Before this, the
3934
+ * in-process path threw a bare `Error(message)`: no `code` could reach skill code, so a shipped 3.32.x client could
3935
+ * only be steered server-side through the message text (the LUA-826 `(503 Service Unavailable)` suffix — the shim
3936
+ * this replaces).
3937
+ */
3938
+ export declare interface IntegrationPassthroughErrorFields {
3939
+ /**
3940
+ * The server's discriminator — `VENDOR_UNAVAILABLE` (503, the vendor behind the relay failed: transient) ·
3941
+ * `VENDOR_REJECTED` (422, the vendor refused the request as sent: deterministic) · `passthrough_disabled` ·
3942
+ * `passthrough_no_connection` · `passthrough_rate_limited` · `passthrough_invalid_request` · … Absent when the
3943
+ * server served none, or the request never reached it.
3944
+ */
3945
+ code?: string;
3946
+ /** lua-api's own HTTP status; `0` for a transport failure (no answer / timeout). Never the vendor's: that is `vendorStatus`. */
3947
+ statusCode?: number;
3948
+ /** Alias of `statusCode` — the member lua-core's production `IntegrationPassthroughError` exposes under that name. */
3949
+ status?: number;
3950
+ /**
3951
+ * LUA-826, ONE release: the code a vendor-fault site served before it moved to `VENDOR_UNAVAILABLE`
3952
+ * (`passthrough_upstream_error`) and the line it served under it. Branch on `code`; these exist for skill code that
3953
+ * still greps the old string, and go away the release after.
3954
+ */
3955
+ legacyCode?: string;
3956
+ legacyMessage?: string;
3957
+ /**
3958
+ * Seconds to wait before retrying. On a 503 `VENDOR_UNAVAILABLE`: present ONLY when the server says a blind retry is
3959
+ * safe — a read, or a write whose duplicate is inert. On a 429 `passthrough_rate_limited` (LUA-968): always present —
3960
+ * the seconds left in the caller's shared per-minute window (also served as the `Retry-After` header).
3961
+ */
3962
+ retryAfterSeconds?: number;
3963
+ /** The third-party vendor behind the fault (`unified` | `github` | `google` | …) and its own status when it answered. */
3964
+ vendor?: string;
3965
+ vendorStatus?: number;
3966
+ /** The id on the server's matching error log line — the one to quote. */
3967
+ requestId?: string;
3968
+ }
3969
+
2711
3970
  export declare type IntegrationPassthroughMethod = (typeof INTEGRATION_PASSTHROUGH_METHODS)[number];
2712
3971
 
3972
+ /** `Integrations.passthrough(type, request, options)` — the third argument (U6 pin). */
3973
+ declare interface IntegrationPassthroughPinOptions {
3974
+ /** Use exactly this connection (it must be visible to the agent); the server pin in `pickConnection`. */
3975
+ connectionId?: string;
3976
+ }
3977
+
2713
3978
  /**
2714
3979
  * One raw provider API call, relative to the provider's API base URL
2715
3980
  * (e.g. `repos/{owner}/{repo}/pulls/42/files` against GitHub).
@@ -2786,7 +4051,86 @@ export declare interface IntegrationsApi {
2786
4051
  * });
2787
4052
  * ```
2788
4053
  */
2789
- passthrough(integrationType: string, request: IntegrationPassthroughRequest): Promise<IntegrationPassthroughResponse>;
4054
+ passthrough(integrationType: string, request: IntegrationPassthroughRequest,
4055
+ /**
4056
+ * `{ connectionId }` pins one connection (from {@link IntegrationsApi.list}) when the agent has several of
4057
+ * the same type. The pin must be a connection this agent may use: it narrows the choice, never widens it.
4058
+ */
4059
+ options?: IntegrationPassthroughPinOptions): Promise<IntegrationPassthroughResponse>;
4060
+ /**
4061
+ * The connections visible to this agent: integration type, remote account identity, scopes, status,
4062
+ * owner and the agents (of your organization) each one is mounted on. A personal connection is listed
4063
+ * only for the person it belongs to.
4064
+ *
4065
+ * @example
4066
+ * ```typescript
4067
+ * const gmail = (await Integrations.list()).filter((c) => c.integrationType === 'googlemail');
4068
+ * ```
4069
+ */
4070
+ list(): Promise<IntegrationConnectionSummary[]>;
4071
+ /**
4072
+ * Run one platform-owned check on a visible connection: `identity` exists for every catalogued
4073
+ * integration; others are per integration (`mail.list`, `teams.list`, `issue.create-permission`,
4074
+ * `refund.calculate`, …). The answer is a fixed `result` (`ok` | `unauthorized` | `insufficient_scope`
4075
+ * | `not_found` | `unreachable` | `unsupported`) plus safe metadata (account email/id, counts) — never a
4076
+ * provider body. A check that writes and then undoes (`mail.draft-create-delete`) runs only with
4077
+ * `{ allowWrite: true }`.
4078
+ *
4079
+ * @example
4080
+ * ```typescript
4081
+ * const { result, metadata } = await Integrations.check(gmail.connectionId, 'identity');
4082
+ * ```
4083
+ */
4084
+ check(connectionId: string, check: ConnectionCheckName, options?: ConnectionCheckOptions): Promise<ConnectionCheckOutcome>;
4085
+ /**
4086
+ * Run one server-owned catalogue check (`identity`, `mail.list`, …) on a connection the CONVERSATION USER
4087
+ * owns, with that user as the principal. The answer is a fixed result enum (`ok`, `unauthorized`,
4088
+ * `insufficient_scope`, `not_found`, `unreachable`, `unsupported`) plus safe metadata — never a provider body.
4089
+ *
4090
+ * Only during a chat turn with a live user: jobs, triggers, webhooks, workflows and background turns throw
4091
+ * `connection_check_requires_user`; a connection the user does not own throws `connection_check_not_owner`.
4092
+ * Read checks only. Every call is audited on the agent's logs. Off unless the platform enables
4093
+ * `LUA_CONNECTION_CHECK_AS_USER_ENABLED` (`connection_checks_disabled`).
4094
+ *
4095
+ * Offline (`lua test`) there is no live user, so it always throws `connection_check_requires_user`.
4096
+ *
4097
+ * @example
4098
+ * ```typescript
4099
+ * const outcome = await Integrations.checkAsUser(connectionId, 'identity');
4100
+ * if (outcome.result !== 'ok') return `Your connection needs attention: ${outcome.result}`;
4101
+ * ```
4102
+ */
4103
+ checkAsUser(connectionId: string, check: string): Promise<ConnectionCheckOutcome>;
4104
+ /**
4105
+ * Ask someone else to connect their account to THIS agent. The invitee gets the link from Lua (never from
4106
+ * your code): this returns the request's id, state and expiry only — never a token or URL. Refused off a
4107
+ * user's own turn (a job, webhook, trigger, workflow or `Agents.invoke` call) with `REQUESTER_UNAUTHORIZED`.
4108
+ * Failures throw an `Error` with `name === 'ConnectionRequestError'` and the server's `code`.
4109
+ *
4110
+ * @example
4111
+ * ```typescript
4112
+ * const { requestId } = await Integrations.requestConnection({
4113
+ * integrationType: 'googlemail',
4114
+ * invitee: { email: 'ceo@acme.io' },
4115
+ * expiresInHours: 72, // 1..168, default 72
4116
+ * });
4117
+ * ```
4118
+ */
4119
+ requestConnection(input: ConnectionRequestCreateInput): Promise<{
4120
+ requestId: string;
4121
+ state: ConnectionRequestState;
4122
+ expiresAt: string;
4123
+ }>;
4124
+ /** Ask the holder of a delegated connection to reconnect it (e.g. after its token was revoked). */
4125
+ requestReconnect(connectionId: string): Promise<{
4126
+ requestId: string;
4127
+ state: ConnectionRequestState;
4128
+ expiresAt: string;
4129
+ }>;
4130
+ /** Read one of this agent's connection requests. Never carries a token or URL. */
4131
+ connectionRequest(requestId: string): Promise<ConnectionRequestStatus>;
4132
+ /** Cancel a pending connection request. */
4133
+ cancelConnectionRequest(requestId: string): Promise<void>;
2790
4134
  }
2791
4135
 
2792
4136
  /**
@@ -2805,7 +4149,10 @@ export declare interface InvokedBy {
2805
4149
  supervisor: boolean;
2806
4150
  /** The caller's supervision scopes on this agent (e.g. `supervision:act`); `[]` on preview turns. */
2807
4151
  scopes: string[];
2808
- /** Set when the caller passed `input.userId` to `Agents.invoke` (a delegated turn). */
4152
+ /**
4153
+ * Set when the caller passed `input.userId` to `Agents.invoke` (a delegated turn), and when the caller's own
4154
+ * turn had such a user or ran in a Job / workflow run (the platform did not pick the user).
4155
+ */
2809
4156
  delegatedUserId?: string;
2810
4157
  }
2811
4158
 
@@ -3043,6 +4390,17 @@ export declare class JobInstance {
3043
4390
  /** The active version of the job (if one exists) */
3044
4391
  readonly activeVersion?: JobVersion;
3045
4392
  metadata: Record<string, any>;
4393
+ /**
4394
+ * Per-run execution identity, set by the platform when the job runs. `occurrenceId` is the stable
4395
+ * dedupe key across retries of the same fire; `scheduledTime` is set on scheduled fires only.
4396
+ * Undefined when the platform did not supply it, so read it as `job.execution?.occurrenceId`.
4397
+ */
4398
+ execution?: {
4399
+ executionId: string;
4400
+ attempt: number;
4401
+ occurrenceId: string;
4402
+ scheduledTime?: string;
4403
+ };
3046
4404
  private userApi?;
3047
4405
  constructor(jobApi: JobApi, jobData: Job);
3048
4406
  /**
@@ -4009,6 +5367,11 @@ export declare interface LuaRequest {
4009
5367
  userId?: string;
4010
5368
  /** The id of the agent handling this turn. */
4011
5369
  agentId?: string;
5370
+ /**
5371
+ * The organization the agent belongs to. Present on deployed runtimes that know it (absent offline in `lua test`
5372
+ * and on older runtimes) — read it defensively.
5373
+ */
5374
+ orgId?: string;
4012
5375
  /**
4013
5376
  * The group conversation this turn belongs to, with its participants and the
4014
5377
  * current speaker. Undefined on 1:1 turns and on non-chat executions.
@@ -4020,6 +5383,12 @@ export declare interface LuaRequest {
4020
5383
  * `lua test`). Read it defensively — older runtimes do not set it.
4021
5384
  */
4022
5385
  invokedBy?: InvokedBy;
5386
+ /**
5387
+ * The channel identity that sent this message, e.g. `{ kind: 'whatsapp_bsuid', scope, value }` or a
5388
+ * `slack_user`. Present only when Lua confirmed it belongs to this turn's user on this channel;
5389
+ * absent on other channels, voice, jobs and webhooks. Match it against `user._luaProfile.identities`.
5390
+ */
5391
+ sender?: UserIdentityRef;
4023
5392
  }
4024
5393
 
4025
5394
  /**
@@ -4122,7 +5491,7 @@ export declare class LuaSkill {
4122
5491
  * Lua Skill configuration.
4123
5492
  * Used to initialize a new LuaSkill instance.
4124
5493
  */
4125
- declare interface LuaSkillConfig {
5494
+ export declare interface LuaSkillConfig {
4126
5495
  /** Skill name (required; used as the server-side identifier). */
4127
5496
  name: string;
4128
5497
  /** Short description of the skill (1-2 sentences) */
@@ -4179,7 +5548,7 @@ export declare interface LuaTool<TInput extends ZodType = ZodType> {
4179
5548
  * voice: { say } }`. Tools that want to act differently inside a voice
4180
5549
  * call check for `ctx?.voice` and use the typed surface.
4181
5550
  */
4182
- declare interface LuaToolCtx {
5551
+ export declare interface LuaToolCtx {
4183
5552
  /** LiveKit's tool-call id (voice only). */
4184
5553
  toolCallId?: string;
4185
5554
  /** Voice-runtime delegates. Only set when the tool runs over voice. */
@@ -4411,13 +5780,13 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4411
5780
  }, "strip", z.ZodTypeAny, {
4412
5781
  voice?: string;
4413
5782
  kind?: "inference";
4414
- options?: Record<string, unknown>;
4415
5783
  model?: string;
5784
+ options?: Record<string, unknown>;
4416
5785
  }, {
4417
5786
  voice?: string;
4418
5787
  kind?: "inference";
4419
- options?: Record<string, unknown>;
4420
5788
  model?: string;
5789
+ options?: Record<string, unknown>;
4421
5790
  }>, z.ZodObject<{
4422
5791
  kind: z.ZodLiteral<"plugin">;
4423
5792
  provider: z.ZodEnum<["deepgram", "elevenlabs"]>;
@@ -4431,13 +5800,13 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4431
5800
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4432
5801
  }, "strip", z.ZodTypeAny, {
4433
5802
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4434
- provider?: "deepgram" | "elevenlabs";
4435
5803
  kind?: "plugin";
5804
+ provider?: "deepgram" | "elevenlabs";
4436
5805
  options?: Record<string, unknown>;
4437
5806
  }, {
4438
5807
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4439
- provider?: "deepgram" | "elevenlabs";
4440
5808
  kind?: "plugin";
5809
+ provider?: "deepgram" | "elevenlabs";
4441
5810
  options?: Record<string, unknown>;
4442
5811
  }>, z.ZodObject<{
4443
5812
  kind: z.ZodLiteral<"realtime">;
@@ -4450,12 +5819,12 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4450
5819
  */
4451
5820
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4452
5821
  }, "strip", z.ZodTypeAny, {
4453
- provider?: "google" | "xai" | "openai";
4454
5822
  kind?: "realtime";
5823
+ provider?: "openai" | "google" | "xai";
4455
5824
  options?: Record<string, unknown>;
4456
5825
  }, {
4457
- provider?: "google" | "xai" | "openai";
4458
5826
  kind?: "realtime";
5827
+ provider?: "openai" | "google" | "xai";
4459
5828
  options?: Record<string, unknown>;
4460
5829
  }>]>;
4461
5830
  stt: z.ZodOptional<z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
@@ -4477,13 +5846,13 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4477
5846
  }, "strip", z.ZodTypeAny, {
4478
5847
  voice?: string;
4479
5848
  kind?: "inference";
4480
- options?: Record<string, unknown>;
4481
5849
  model?: string;
5850
+ options?: Record<string, unknown>;
4482
5851
  }, {
4483
5852
  voice?: string;
4484
5853
  kind?: "inference";
4485
- options?: Record<string, unknown>;
4486
5854
  model?: string;
5855
+ options?: Record<string, unknown>;
4487
5856
  }>, z.ZodObject<{
4488
5857
  kind: z.ZodLiteral<"plugin">;
4489
5858
  provider: z.ZodEnum<["deepgram", "elevenlabs"]>;
@@ -4497,13 +5866,13 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4497
5866
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4498
5867
  }, "strip", z.ZodTypeAny, {
4499
5868
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4500
- provider?: "deepgram" | "elevenlabs";
4501
5869
  kind?: "plugin";
5870
+ provider?: "deepgram" | "elevenlabs";
4502
5871
  options?: Record<string, unknown>;
4503
5872
  }, {
4504
5873
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4505
- provider?: "deepgram" | "elevenlabs";
4506
5874
  kind?: "plugin";
5875
+ provider?: "deepgram" | "elevenlabs";
4507
5876
  options?: Record<string, unknown>;
4508
5877
  }>, z.ZodObject<{
4509
5878
  kind: z.ZodLiteral<"realtime">;
@@ -4516,12 +5885,12 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4516
5885
  */
4517
5886
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4518
5887
  }, "strip", z.ZodTypeAny, {
4519
- provider?: "google" | "xai" | "openai";
4520
5888
  kind?: "realtime";
5889
+ provider?: "openai" | "google" | "xai";
4521
5890
  options?: Record<string, unknown>;
4522
5891
  }, {
4523
- provider?: "google" | "xai" | "openai";
4524
5892
  kind?: "realtime";
5893
+ provider?: "openai" | "google" | "xai";
4525
5894
  options?: Record<string, unknown>;
4526
5895
  }>]>>;
4527
5896
  tts: z.ZodOptional<z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
@@ -4543,13 +5912,13 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4543
5912
  }, "strip", z.ZodTypeAny, {
4544
5913
  voice?: string;
4545
5914
  kind?: "inference";
4546
- options?: Record<string, unknown>;
4547
5915
  model?: string;
5916
+ options?: Record<string, unknown>;
4548
5917
  }, {
4549
5918
  voice?: string;
4550
5919
  kind?: "inference";
4551
- options?: Record<string, unknown>;
4552
5920
  model?: string;
5921
+ options?: Record<string, unknown>;
4553
5922
  }>, z.ZodObject<{
4554
5923
  kind: z.ZodLiteral<"plugin">;
4555
5924
  provider: z.ZodEnum<["deepgram", "elevenlabs"]>;
@@ -4563,13 +5932,13 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4563
5932
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4564
5933
  }, "strip", z.ZodTypeAny, {
4565
5934
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4566
- provider?: "deepgram" | "elevenlabs";
4567
5935
  kind?: "plugin";
5936
+ provider?: "deepgram" | "elevenlabs";
4568
5937
  options?: Record<string, unknown>;
4569
5938
  }, {
4570
5939
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4571
- provider?: "deepgram" | "elevenlabs";
4572
5940
  kind?: "plugin";
5941
+ provider?: "deepgram" | "elevenlabs";
4573
5942
  options?: Record<string, unknown>;
4574
5943
  }>, z.ZodObject<{
4575
5944
  kind: z.ZodLiteral<"realtime">;
@@ -4582,12 +5951,12 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4582
5951
  */
4583
5952
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4584
5953
  }, "strip", z.ZodTypeAny, {
4585
- provider?: "google" | "xai" | "openai";
4586
5954
  kind?: "realtime";
5955
+ provider?: "openai" | "google" | "xai";
4587
5956
  options?: Record<string, unknown>;
4588
5957
  }, {
4589
- provider?: "google" | "xai" | "openai";
4590
5958
  kind?: "realtime";
5959
+ provider?: "openai" | "google" | "xai";
4591
5960
  options?: Record<string, unknown>;
4592
5961
  }>]>>;
4593
5962
  vad: z.ZodOptional<z.ZodString>;
@@ -4751,47 +6120,47 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4751
6120
  stt?: {
4752
6121
  voice?: string;
4753
6122
  kind?: "inference";
4754
- options?: Record<string, unknown>;
4755
6123
  model?: string;
6124
+ options?: Record<string, unknown>;
4756
6125
  } | {
4757
6126
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4758
- provider?: "deepgram" | "elevenlabs";
4759
6127
  kind?: "plugin";
6128
+ provider?: "deepgram" | "elevenlabs";
4760
6129
  options?: Record<string, unknown>;
4761
6130
  } | {
4762
- provider?: "google" | "xai" | "openai";
4763
6131
  kind?: "realtime";
6132
+ provider?: "openai" | "google" | "xai";
4764
6133
  options?: Record<string, unknown>;
4765
6134
  };
4766
6135
  volume?: number;
4767
6136
  llm?: {
4768
6137
  voice?: string;
4769
6138
  kind?: "inference";
4770
- options?: Record<string, unknown>;
4771
6139
  model?: string;
6140
+ options?: Record<string, unknown>;
4772
6141
  } | {
4773
6142
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4774
- provider?: "deepgram" | "elevenlabs";
4775
6143
  kind?: "plugin";
6144
+ provider?: "deepgram" | "elevenlabs";
4776
6145
  options?: Record<string, unknown>;
4777
6146
  } | {
4778
- provider?: "google" | "xai" | "openai";
4779
6147
  kind?: "realtime";
6148
+ provider?: "openai" | "google" | "xai";
4780
6149
  options?: Record<string, unknown>;
4781
6150
  };
4782
6151
  tts?: {
4783
6152
  voice?: string;
4784
6153
  kind?: "inference";
4785
- options?: Record<string, unknown>;
4786
6154
  model?: string;
6155
+ options?: Record<string, unknown>;
4787
6156
  } | {
4788
6157
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4789
- provider?: "deepgram" | "elevenlabs";
4790
6158
  kind?: "plugin";
6159
+ provider?: "deepgram" | "elevenlabs";
4791
6160
  options?: Record<string, unknown>;
4792
6161
  } | {
4793
- provider?: "google" | "xai" | "openai";
4794
6162
  kind?: "realtime";
6163
+ provider?: "openai" | "google" | "xai";
4795
6164
  options?: Record<string, unknown>;
4796
6165
  };
4797
6166
  vadOptions?: {
@@ -4845,47 +6214,47 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4845
6214
  stt?: {
4846
6215
  voice?: string;
4847
6216
  kind?: "inference";
4848
- options?: Record<string, unknown>;
4849
6217
  model?: string;
6218
+ options?: Record<string, unknown>;
4850
6219
  } | {
4851
6220
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4852
- provider?: "deepgram" | "elevenlabs";
4853
6221
  kind?: "plugin";
6222
+ provider?: "deepgram" | "elevenlabs";
4854
6223
  options?: Record<string, unknown>;
4855
6224
  } | {
4856
- provider?: "google" | "xai" | "openai";
4857
6225
  kind?: "realtime";
6226
+ provider?: "openai" | "google" | "xai";
4858
6227
  options?: Record<string, unknown>;
4859
6228
  };
4860
6229
  volume?: number;
4861
6230
  llm?: {
4862
6231
  voice?: string;
4863
6232
  kind?: "inference";
4864
- options?: Record<string, unknown>;
4865
6233
  model?: string;
6234
+ options?: Record<string, unknown>;
4866
6235
  } | {
4867
6236
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4868
- provider?: "deepgram" | "elevenlabs";
4869
6237
  kind?: "plugin";
6238
+ provider?: "deepgram" | "elevenlabs";
4870
6239
  options?: Record<string, unknown>;
4871
6240
  } | {
4872
- provider?: "google" | "xai" | "openai";
4873
6241
  kind?: "realtime";
6242
+ provider?: "openai" | "google" | "xai";
4874
6243
  options?: Record<string, unknown>;
4875
6244
  };
4876
6245
  tts?: {
4877
6246
  voice?: string;
4878
6247
  kind?: "inference";
4879
- options?: Record<string, unknown>;
4880
6248
  model?: string;
6249
+ options?: Record<string, unknown>;
4881
6250
  } | {
4882
6251
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4883
- provider?: "deepgram" | "elevenlabs";
4884
6252
  kind?: "plugin";
6253
+ provider?: "deepgram" | "elevenlabs";
4885
6254
  options?: Record<string, unknown>;
4886
6255
  } | {
4887
- provider?: "google" | "xai" | "openai";
4888
6256
  kind?: "realtime";
6257
+ provider?: "openai" | "google" | "xai";
4889
6258
  options?: Record<string, unknown>;
4890
6259
  };
4891
6260
  vadOptions?: {
@@ -4939,47 +6308,47 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4939
6308
  stt?: {
4940
6309
  voice?: string;
4941
6310
  kind?: "inference";
4942
- options?: Record<string, unknown>;
4943
6311
  model?: string;
6312
+ options?: Record<string, unknown>;
4944
6313
  } | {
4945
6314
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4946
- provider?: "deepgram" | "elevenlabs";
4947
6315
  kind?: "plugin";
6316
+ provider?: "deepgram" | "elevenlabs";
4948
6317
  options?: Record<string, unknown>;
4949
6318
  } | {
4950
- provider?: "google" | "xai" | "openai";
4951
6319
  kind?: "realtime";
6320
+ provider?: "openai" | "google" | "xai";
4952
6321
  options?: Record<string, unknown>;
4953
6322
  };
4954
6323
  volume?: number;
4955
6324
  llm?: {
4956
6325
  voice?: string;
4957
6326
  kind?: "inference";
4958
- options?: Record<string, unknown>;
4959
6327
  model?: string;
6328
+ options?: Record<string, unknown>;
4960
6329
  } | {
4961
6330
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4962
- provider?: "deepgram" | "elevenlabs";
4963
6331
  kind?: "plugin";
6332
+ provider?: "deepgram" | "elevenlabs";
4964
6333
  options?: Record<string, unknown>;
4965
6334
  } | {
4966
- provider?: "google" | "xai" | "openai";
4967
6335
  kind?: "realtime";
6336
+ provider?: "openai" | "google" | "xai";
4968
6337
  options?: Record<string, unknown>;
4969
6338
  };
4970
6339
  tts?: {
4971
6340
  voice?: string;
4972
6341
  kind?: "inference";
4973
- options?: Record<string, unknown>;
4974
6342
  model?: string;
6343
+ options?: Record<string, unknown>;
4975
6344
  } | {
4976
6345
  class?: "LLM" | "STT" | "STTv2" | "TTS";
4977
- provider?: "deepgram" | "elevenlabs";
4978
6346
  kind?: "plugin";
6347
+ provider?: "deepgram" | "elevenlabs";
4979
6348
  options?: Record<string, unknown>;
4980
6349
  } | {
4981
- provider?: "google" | "xai" | "openai";
4982
6350
  kind?: "realtime";
6351
+ provider?: "openai" | "google" | "xai";
4983
6352
  options?: Record<string, unknown>;
4984
6353
  };
4985
6354
  vadOptions?: {
@@ -5033,47 +6402,47 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
5033
6402
  stt?: {
5034
6403
  voice?: string;
5035
6404
  kind?: "inference";
5036
- options?: Record<string, unknown>;
5037
6405
  model?: string;
6406
+ options?: Record<string, unknown>;
5038
6407
  } | {
5039
6408
  class?: "LLM" | "STT" | "STTv2" | "TTS";
5040
- provider?: "deepgram" | "elevenlabs";
5041
6409
  kind?: "plugin";
6410
+ provider?: "deepgram" | "elevenlabs";
5042
6411
  options?: Record<string, unknown>;
5043
6412
  } | {
5044
- provider?: "google" | "xai" | "openai";
5045
6413
  kind?: "realtime";
6414
+ provider?: "openai" | "google" | "xai";
5046
6415
  options?: Record<string, unknown>;
5047
6416
  };
5048
6417
  volume?: number;
5049
6418
  llm?: {
5050
6419
  voice?: string;
5051
6420
  kind?: "inference";
5052
- options?: Record<string, unknown>;
5053
6421
  model?: string;
6422
+ options?: Record<string, unknown>;
5054
6423
  } | {
5055
6424
  class?: "LLM" | "STT" | "STTv2" | "TTS";
5056
- provider?: "deepgram" | "elevenlabs";
5057
6425
  kind?: "plugin";
6426
+ provider?: "deepgram" | "elevenlabs";
5058
6427
  options?: Record<string, unknown>;
5059
6428
  } | {
5060
- provider?: "google" | "xai" | "openai";
5061
6429
  kind?: "realtime";
6430
+ provider?: "openai" | "google" | "xai";
5062
6431
  options?: Record<string, unknown>;
5063
6432
  };
5064
6433
  tts?: {
5065
6434
  voice?: string;
5066
6435
  kind?: "inference";
5067
- options?: Record<string, unknown>;
5068
6436
  model?: string;
6437
+ options?: Record<string, unknown>;
5069
6438
  } | {
5070
6439
  class?: "LLM" | "STT" | "STTv2" | "TTS";
5071
- provider?: "deepgram" | "elevenlabs";
5072
6440
  kind?: "plugin";
6441
+ provider?: "deepgram" | "elevenlabs";
5073
6442
  options?: Record<string, unknown>;
5074
6443
  } | {
5075
- provider?: "google" | "xai" | "openai";
5076
6444
  kind?: "realtime";
6445
+ provider?: "openai" | "google" | "xai";
5077
6446
  options?: Record<string, unknown>;
5078
6447
  };
5079
6448
  vadOptions?: {
@@ -5160,7 +6529,7 @@ export declare interface LuaVoiceHookContext {
5160
6529
  * The constructor below stores the raw input as-is — the runtime classes
5161
6530
  * never execute as part of the push pipeline.
5162
6531
  */
5163
- declare type LuaVoiceModelInput = string | object;
6532
+ export declare type LuaVoiceModelInput = string | object;
5164
6533
 
5165
6534
  export declare class LuaVoiceTool<TInput extends ZodType = ZodType> implements LuaTool<TInput> {
5166
6535
  readonly name: string;
@@ -5378,6 +6747,7 @@ export declare class LuaWebhook {
5378
6747
  private readonly headerSchema?;
5379
6748
  private readonly bodySchema?;
5380
6749
  private readonly secret?;
6750
+ private readonly enforceSchemas?;
5381
6751
  private readonly executeFunction;
5382
6752
  /**
5383
6753
  * Creates a new LuaWebhook instance.
@@ -5388,6 +6758,7 @@ export declare class LuaWebhook {
5388
6758
  * @param config.querySchema - Optional Zod schema for query parameter validation
5389
6759
  * @param config.headerSchema - Optional Zod schema for header validation
5390
6760
  * @param config.bodySchema - Optional Zod schema for body validation
6761
+ * @param config.enforceSchemas - Reject schema-violating requests with HTTP 400 (default: log a warning only)
5391
6762
  * @param config.execute - Function that processes the webhook request
5392
6763
  */
5393
6764
  constructor(config: LuaWebhookConfig);
@@ -5412,6 +6783,7 @@ export declare class LuaWebhook {
5412
6783
  * @param query - Query parameters object
5413
6784
  * @param headers - Headers object
5414
6785
  * @param body - Request body
6786
+ * @param rawBody - Exact request bytes (utf8), delivered as `event.rawBody` when given
5415
6787
  * @returns Promise resolving to webhook execution result
5416
6788
  * @throws Error if validation fails for any input
5417
6789
  *
@@ -5424,7 +6796,7 @@ export declare class LuaWebhook {
5424
6796
  * );
5425
6797
  * ```
5426
6798
  */
5427
- execute(query?: Record<string, any>, headers?: Record<string, any>, body?: any): Promise<any>;
6799
+ execute(query?: Record<string, any>, headers?: Record<string, any>, body?: any, rawBody?: string): Promise<any>;
5428
6800
  }
5429
6801
 
5430
6802
  /**
@@ -5450,6 +6822,13 @@ export declare interface LuaWebhookConfig {
5450
6822
  * it and re-deploying.
5451
6823
  */
5452
6824
  secret?: string;
6825
+ /**
6826
+ * Opt in to rejecting requests that violate `querySchema` / `headerSchema` /
6827
+ * `bodySchema`. Default (`false`): violations are logged as a
6828
+ * `[lua:webhook-schema] would-reject` warning and `execute` still runs.
6829
+ * `true`: a violating request is rejected with HTTP 400 before `execute`.
6830
+ */
6831
+ enforceSchemas?: boolean;
5453
6832
  /** Function that executes the webhook logic */
5454
6833
  execute: (event: LuaWebhookEvent) => Promise<any>;
5455
6834
  }
@@ -5457,13 +6836,23 @@ export declare interface LuaWebhookConfig {
5457
6836
  /**
5458
6837
  * Event payload delivered to webhook execute functions.
5459
6838
  */
5460
- declare interface LuaWebhookEvent {
6839
+ export declare interface LuaWebhookEvent {
5461
6840
  /** Parsed query parameters */
5462
6841
  query?: Record<string, any>;
5463
6842
  /** Request headers */
5464
6843
  headers?: Record<string, any>;
5465
6844
  /** Request body (JSON or raw data) */
5466
6845
  body?: any;
6846
+ /**
6847
+ * The EXACT unparsed request bytes, as a utf8 string. Use it to verify a
6848
+ * vendor's own signature scheme (Stripe `t=…,v1=…`, GitHub `sha256=…`, Slack
6849
+ * `v0:…`) in `execute` — those HMACs cover the wire bytes, which
6850
+ * `JSON.stringify(body)` does not reproduce. Present for JSON requests
6851
+ * (`''` for an empty body); absent for form-encoded / text bodies and for
6852
+ * webhooks fired by platform events. Header keys arrive lowercased, e.g.
6853
+ * `event.headers['x-hub-signature-256']`.
6854
+ */
6855
+ rawBody?: string;
5467
6856
  /** ISO timestamp when the webhook was received */
5468
6857
  timestamp: string;
5469
6858
  }
@@ -5503,7 +6892,9 @@ export declare type LuaWorkflowBuildCode = 'duplicate-step-id' | 'unknown-step-r
5503
6892
  * chain — the code is `node-type-unsupported-in-container`. Kept for one minor so a consumer switching on the
5504
6893
  * union still compiles; removed in the next.
5505
6894
  */
5506
- | 'approval-inside-container' | 'node-type-unsupported-in-container' | 'empty-graph' | 'ephemeral-role-too-long' | 'role-ref-and-inline' | 'approver-excludes-only-candidate' | 'four-eyes-requires-editable' | 'escalation-chain-not-terminal' | 'escalation-chain-too-long' | 'editable-path-invalid' | 'env-template-secret-key' | 'invalid-envelope' | 'invalid-step' | 'invalid-step-id' | 'invalid-workflow-name' | 'schedule-input-required' | 'schedule-input-invalid' | 'hitl-duration-defaulted' | 'WORKFLOW_UNPLACED_STEP';
6895
+ | 'approval-inside-container' | 'node-type-unsupported-in-container' | 'empty-graph' | 'ephemeral-role-too-long' | 'role-ref-and-inline' | 'approver-excludes-only-candidate' | 'four-eyes-requires-editable' | 'escalation-chain-not-terminal' | 'escalation-chain-too-long'
6896
+ /** LUA-973: `remindAfterHours` is not a number of hours in 1..720 (`validateApprovalReminder`). */
6897
+ | 'remind-after-invalid' | 'editable-path-invalid' | 'env-template-secret-key' | 'invalid-envelope' | 'invalid-step' | 'invalid-step-id' | 'invalid-workflow-name' | 'schedule-input-required' | 'schedule-input-invalid' | 'hitl-duration-defaulted' | 'WORKFLOW_UNPLACED_STEP';
5507
6898
 
5508
6899
  export declare interface LuaWorkflowBuilder {
5509
6900
  then(step: StepRef): this;
@@ -5685,6 +7076,12 @@ export declare interface MCPServerBaseConfig {
5685
7076
  description?: string;
5686
7077
  /** Optional timeout in milliseconds (default: 60000) */
5687
7078
  timeout?: number;
7079
+ /**
7080
+ * Optional tool allow/deny list, applied by the platform when it discovers
7081
+ * this server's tools. Use it to expose only the tools the agent needs.
7082
+ * See {@link MCPToolFilter}.
7083
+ */
7084
+ tools?: MCPToolFilter;
5688
7085
  }
5689
7086
 
5690
7087
  /**
@@ -5776,6 +7173,29 @@ export declare interface MCPStreamableHttpServerConfig extends MCPServerBaseConf
5776
7173
  headers?: Record<string, string> | HeadersResolverFunction;
5777
7174
  }
5778
7175
 
7176
+ /**
7177
+ * Per-server tool allow/deny list for an MCP server.
7178
+ *
7179
+ * Entries are the server's own (raw) tool names — not the namespaced
7180
+ * `${serverName}_${tool}` id the agent sees — matched exactly, or as a prefix
7181
+ * when the entry ends in `*` (e.g. `'read_*'`).
7182
+ *
7183
+ * - `deny` always wins over `allow`.
7184
+ * - `allow` omitted ⇒ every tool the server lists (minus `deny`).
7185
+ * - `allow: []` ⇒ no tools from this server.
7186
+ *
7187
+ * @example
7188
+ * ```typescript
7189
+ * tools: { allow: ['search', 'read_*'], deny: ['read_secrets'] }
7190
+ * ```
7191
+ */
7192
+ export declare interface MCPToolFilter {
7193
+ /** Only these tools are exposed to the agent. */
7194
+ allow?: string[];
7195
+ /** These tools are never exposed to the agent (wins over `allow`). */
7196
+ deny?: string[];
7197
+ }
7198
+
5779
7199
  /**
5780
7200
  * MCP Server transport type - determines how to connect to the server.
5781
7201
  *
@@ -5788,6 +7208,35 @@ export declare type MCPTransport = 'sse' | 'streamable-http';
5788
7208
 
5789
7209
  declare type Message = TextMessage_2 | ImageMessage_2 | FileMessage_2;
5790
7210
 
7211
+ export declare const Metrics: MetricsApi;
7212
+
7213
+ /**
7214
+ * Record a number your agent cares about (orders completed, a latency, a 0/1 outcome) so its owner's objectives
7215
+ * — and supervisor agents holding `supervision:observe` — can track it.
7216
+ */
7217
+ export declare interface MetricsApi {
7218
+ /**
7219
+ * Record one point. `name`: lower-case, dotted / underscored, ≤ 64 chars. `tags`: at most 4 short string pairs
7220
+ * (each distinct tag set is a series; an agent keeps at most 200 live series). Rate-limited per agent.
7221
+ *
7222
+ * Never throws: the receipt says whether the point was stored (`accepted`) or why not (`code`, e.g.
7223
+ * `agent_metrics_disabled`, `agent_metric_rate_limited`). In `lua test` / `lua dev` the point is checked but
7224
+ * recorded nowhere (`agent_metrics_offline`).
7225
+ *
7226
+ * @example
7227
+ * ```typescript
7228
+ * await Metrics.record('orders.completed', 1, { channel: Lua.request.channel });
7229
+ * ```
7230
+ */
7231
+ record(name: string, value: number, tags?: Record<string, string>): Promise<AgentMetricRecordReceipt>;
7232
+ }
7233
+
7234
+ declare interface ModelReasoningOptions {
7235
+ effort?: ReasoningEffort;
7236
+ /** Whether to surface the reasoning trace to the caller. Default true. */
7237
+ show?: boolean;
7238
+ }
7239
+
5791
7240
  export declare const ne: <T>(l: TypedRef<T>, r: TypedRef<T> | Literal<T>) => LuaPredicate;
5792
7241
 
5793
7242
  /** `.workflow(id, ref, input?, opts?)` — a nested run (a `subrun` row). */
@@ -5861,7 +7310,7 @@ declare class OrderApi extends HttpClient implements OrderAPI {
5861
7310
  create(orderData: CreateOrderRequest): Promise<OrderInstance>;
5862
7311
  /**
5863
7312
  * Updates the status of an existing order
5864
- * @param status - The new order status (e.g., 'pending', 'processing', 'shipped', 'delivered', 'cancelled')
7313
+ * @param status - The new order status (e.g., 'pending', 'confirmed', 'fulfilled', 'cancelled'). `OrderStatus.FULFILLED` is sent as the platform value `fullfilled`.
5865
7314
  * @param orderId - The unique identifier of the order to update
5866
7315
  * @returns Promise resolving to the updated OrderResponse
5867
7316
  * @throws Error if the order is not found or the status update fails
@@ -5877,7 +7326,7 @@ declare class OrderApi extends HttpClient implements OrderAPI {
5877
7326
  updateData(data: Record<string, any>, orderId: string): Promise<OrderResponse>;
5878
7327
  /**
5879
7328
  * Retrieves all user orders with optional status filtering
5880
- * @param status - Optional order status to filter by (e.g., 'pending', 'processing', 'shipped', 'delivered', 'cancelled')
7329
+ * @param status - Optional order status to filter by (e.g., 'pending', 'confirmed', 'fulfilled', 'cancelled'). `OrderStatus.FULFILLED` is sent as the platform value `fullfilled`.
5881
7330
  * @returns Promise resolving to an array of OrderInstance objects
5882
7331
  * @throws Error if the request fails or orders cannot be retrieved
5883
7332
  */
@@ -5896,7 +7345,8 @@ declare class OrderApi extends HttpClient implements OrderAPI {
5896
7345
  * Calculated/derived properties maintained by the system.
5897
7346
  */
5898
7347
  declare interface OrderCommon {
5899
- status: 'pending' | 'confirmed' | 'fulfilled' | 'cancelled';
7348
+ /** The platform stores and returns the misspelt 'fullfilled'. */
7349
+ status: 'pending' | 'confirmed' | 'fulfilled' | 'fullfilled' | 'cancelled';
5900
7350
  totalAmount: string | number;
5901
7351
  currency: string;
5902
7352
  itemCount: number;
@@ -6062,6 +7512,17 @@ declare interface Pagination {
6062
7512
  prevPage: number | null;
6063
7513
  }
6064
7514
 
7515
+ /** Options for `Data.patch` (LUA-963). */
7516
+ export declare interface PatchCustomDataOptions {
7517
+ /**
7518
+ * Compare-and-swap: apply the patch only if the entry is still at this
7519
+ * version (`entry.version` from `Data.get`, `entry._version` on a
7520
+ * `DataEntryInstance`). A mismatch writes nothing and rejects with
7521
+ * `code === 'data_version_conflict'`.
7522
+ */
7523
+ ifVersion?: number;
7524
+ }
7525
+
6065
7526
  export { PathOrLiteral }
6066
7527
 
6067
7528
  /** P split on '.' walked into T; `unknown` past depth 4 or through an index. */
@@ -6316,9 +7777,10 @@ declare interface ProductAPI {
6316
7777
  /**
6317
7778
  * Searches products.
6318
7779
  * @param query - Search query
7780
+ * @param limit - Max products to return (default 5)
6319
7781
  * @returns Promise resolving to search results
6320
7782
  */
6321
- search(query: string): Promise<any>;
7783
+ search(query: string, limit?: number): Promise<any>;
6322
7784
  }
6323
7785
 
6324
7786
  /**
@@ -6533,9 +7995,10 @@ export declare const Products: {
6533
7995
  * Searches products by query string.
6534
7996
  *
6535
7997
  * @param query - Search query
7998
+ * @param limit - Max products to return (default 5)
6536
7999
  * @returns Promise resolving to search results
6537
8000
  */
6538
- search(query: string): Promise<ProductSearchInstance>;
8001
+ search(query: string, limit?: number): Promise<ProductSearchInstance>;
6539
8002
  /**
6540
8003
  * Retrieves a specific product by ID.
6541
8004
  *
@@ -6656,6 +8119,87 @@ export declare interface ProfileResponse {
6656
8119
  };
6657
8120
  }
6658
8121
 
8122
+ /**
8123
+ * Progress API — show live progress for a long-running tool in the chat that called it.
8124
+ *
8125
+ * Each call updates ONE progress card for the current tool call; the card closes on its own when the tool
8126
+ * returns. It is best-effort: it never throws, and resolves `{ emitted: false }` when the chat surface cannot
8127
+ * show it (no live stream, a text-only channel, or offline in `lua test`).
8128
+ *
8129
+ * @example
8130
+ * ```typescript
8131
+ * import { Progress } from 'lua-cli';
8132
+ *
8133
+ * for (let i = 0; i < files.length; i++) {
8134
+ * await Progress.update({ label: 'Importing files', fraction: i / files.length, phase: files[i].name });
8135
+ * await importFile(files[i]);
8136
+ * }
8137
+ * ```
8138
+ */
8139
+ export declare const Progress: ProgressApi;
8140
+
8141
+ /**
8142
+ * wave 2 U15 — `Progress.update(...)` outside a deployed agent.
8143
+ *
8144
+ * In a deployed agent the `lua-cli` import is stripped at compile time and the sandbox's own `Progress` global
8145
+ * serves the call, putting a live progress card on the chat turn. Offline (`lua test`, `lua dev`, or a plain
8146
+ * Node import) there is no live chat stream to show it on, so every call is a no-op answering
8147
+ * `{ emitted: false }`. It never throws.
8148
+ */
8149
+ export declare interface ProgressApi {
8150
+ /**
8151
+ * Show or update this tool's progress card in the chat that called it.
8152
+ *
8153
+ * - `label`: card title; the first call's label (or the tool's name) is kept when you leave it out.
8154
+ * - `fraction`: 0..1 (clamped); leave it out for an indeterminate bar.
8155
+ * - `phase`: what the tool is doing now, e.g. "Reading sources (3/12)".
8156
+ *
8157
+ * Resolves `{ emitted: true }` when the card was (or, for a burst of calls, will be) shown, and
8158
+ * `{ emitted: false }` when there is nothing to show it on. It never throws.
8159
+ */
8160
+ update(input?: ProgressUpdateInput): Promise<ProgressUpdateReceipt>;
8161
+ }
8162
+
8163
+ /**
8164
+ * U15 (wave 2) — run cards for SDK-started runs and `Progress.update`. Owner: U15.
8165
+ * Contract: docs/agent-builder/wave2-contracts.md §U15.
8166
+ *
8167
+ * - An SDK-started workflow run (`Workflows.start`) carrying `originThreadId` emits the EXISTING
8168
+ * `data-lua-workflow-run` parts into that thread (lua-core `workflow-part-emitter.ts`), so Desktop shows
8169
+ * the live run card. No new part type.
8170
+ * - `Progress.update(...)` from a long custom tool emits the EXISTING `data-lua-job-progress` part
8171
+ * (`LuaJobProgressData`, `source: 'sdk-job'`) through lua-core `job-progress-emitter.ts` — only when a
8172
+ * live stream writer exists and the surface declared the `jobs` client capability; otherwise a no-op.
8173
+ */
8174
+ /** `Progress.update(input)`. */
8175
+ export declare interface ProgressUpdateInput {
8176
+ /** Card label; the first call's label (or the tool's name) is kept when absent. */
8177
+ label?: string;
8178
+ /** Determinate progress 0..1 (clamped); absent ⇒ indeterminate. */
8179
+ fraction?: number;
8180
+ /** Current phase text, e.g. "Reading sources (3/12)". */
8181
+ phase?: string;
8182
+ }
8183
+
8184
+ export declare interface ProgressUpdateReceipt {
8185
+ /** `false` when there is no live stream to show it on (a no-op, never an error). */
8186
+ emitted: boolean;
8187
+ }
8188
+
8189
+ /**
8190
+ * U1 (wave 2) — provision agents for a user: `Agents.create(input, { onBehalfOf, consentId })` under an
8191
+ * org provisioning policy. Owner: U1. Consumers: U17 (one-per-member instances), U9 (pending secrets
8192
+ * attach on create), U4b (suspension reasons). Contract: docs/agent-builder/wave2-contracts.md §U1.
8193
+ *
8194
+ * What a create does (U1 spec): a PRIVATE agent with `createdBy = onBehalfOf` (an org member), an empty
8195
+ * scaffold backup v1 (shared-source-sync) so restore works, `connectionPolicy: 'explicit'` (U2), and a
8196
+ * supervision grant for the CALLING agent on the new agent with `createdByUserId = onBehalfOf`,
8197
+ * `source: 'provisioning'`, `consentId`, its actions bounded by the policy.
8198
+ */
8199
+
8200
+ /** Supervision actions a provisioning grant may carry (`@lua/authz` `SUPERVISION_ACTIONS`). */
8201
+ declare type ProvisionedSupervisionAction = 'observe' | 'observe-content' | 'preview' | 'release' | 'act';
8202
+
6659
8203
  declare interface PushJobVersionDTO {
6660
8204
  name: string;
6661
8205
  version: string;
@@ -6792,39 +8336,226 @@ export declare const rows: (s: LuaWorkflowStep<any, any, any> | string, path: st
6792
8336
  /** Where an incident notice goes beyond the inbox card (which always lands). */
6793
8337
  declare const SCHEDULE_HEALTH_NOTIFY_CHANNELS: readonly ["app", "email", "emailApp"];
6794
8338
 
6795
- /** The declaration an author writes. At least one threshold is required. */
6796
- declare interface ScheduleHealthConfig {
6797
- /** Alert when no scheduled run has completed successfully for this many minutes (5..43200). */
6798
- maxSilenceMinutes?: number;
8339
+ /** The declaration an author writes. At least one threshold is required. */
8340
+ declare interface ScheduleHealthConfig {
8341
+ /** Alert when no scheduled run has completed successfully for this many minutes (5..43200). */
8342
+ maxSilenceMinutes?: number;
8343
+ /**
8344
+ * Alert when this many scheduled runs in a row failed. Workflows and agent tasks are parked by the
8345
+ * platform after 3 consecutive failures, so for them the value is 1..3; code jobs accept 1..50.
8346
+ */
8347
+ alertAfterConsecutiveFailures?: number;
8348
+ /** Out-of-inbox routing for the notice: 'app' (push), 'email', or 'emailApp' (both). Default 'emailApp'. */
8349
+ notify?: ScheduleHealthNotify;
8350
+ }
8351
+
8352
+ declare type ScheduleHealthNotify = (typeof SCHEDULE_HEALTH_NOTIFY_CHANNELS)[number];
8353
+
8354
+ /**
8355
+ * Additive field on primitive publish responses. When the agent is under
8356
+ * versioning the server performs a scoped promote and returns the newly
8357
+ * minted + promoted agent version here; absent when the agent has no versions.
8358
+ */
8359
+ declare interface ScopedPromoteFields {
8360
+ agentVersion?: number;
8361
+ }
8362
+
8363
+ /**
8364
+ * Response from product search.
8365
+ */
8366
+ declare interface SearchProductsResponse {
8367
+ success: boolean;
8368
+ message: string;
8369
+ data: Product[];
8370
+ }
8371
+
8372
+ /** Datadog's validate host is per region; the caller picks only from this enum. */
8373
+ declare const SECRET_DATADOG_REGIONS: readonly ["us1", "eu1"];
8374
+
8375
+ declare const SECRET_REQUEST_STATES: readonly ["pending", "submitted", "stored", "attached", "expired", "cancelled"];
8376
+
8377
+ /**
8378
+ * U9 (wave 2) — secret requests tested on the server. Owner: U9 (SDK `Secrets.*`, lua-api secrets service,
8379
+ * provider test catalogue, hosted-page token routes, the lua-core `requestSecret` echo tool). Consumers:
8380
+ * U9D (lua-desktop masked card), U1 (calls U9's attach for pending secrets at provisioning).
8381
+ * Contract: docs/agent-builder/wave2-contracts.md §U9.
8382
+ *
8383
+ * Values are stored through the EXISTING agent env path (lua-agents `agentenvs`). That path stores `data` as
8384
+ * plain text in the document, so an agent-target value is encrypted at rest only by the storage layer (the
8385
+ * database's own encryption), not by the application; a pending-target value is a KMS envelope until it is
8386
+ * attached. Values are never returned by any route, SDK call, log or outcome turn. The provider test catalogue is
8387
+ * SERVER-OWNED: a caller can only name a provider; the request, host and interpretation are fixed.
8388
+ */
8389
+ declare const SECRET_TEST_RESULTS: readonly ["ok", "unauthorized", "wrong_key_type", "insufficient_permission", "unreachable", "unverified"];
8390
+
8391
+ /**
8392
+ * `Agents.secrets(agentId).attach(requestIds)` (supervision op `secrets.attach`): the env keys set on the agent.
8393
+ * Never a value.
8394
+ */
8395
+ declare interface SecretAttachResult {
8396
+ agentId: string;
8397
+ attached: string[];
8398
+ envKeys: string[];
8399
+ }
8400
+
8401
+ declare type SecretDatadogRegion = (typeof SECRET_DATADOG_REGIONS)[number];
8402
+
8403
+ /**
8404
+ * `Secrets.request(...)` input. `key` is the env key a single-field secret is stored under; a bundle
8405
+ * stores each field under `fields[i].envKey`. Env keys match {@link SECRET_ENV_KEY_PATTERN}.
8406
+ */
8407
+ export declare interface SecretRequestInput {
8408
+ provider: string;
8409
+ key: string;
8410
+ target?: SecretRequestTarget;
8411
+ fields?: Array<{
8412
+ name: string;
8413
+ envKey: string;
8414
+ label?: string;
8415
+ }>;
8416
+ region?: SecretDatadogRegion;
8417
+ /** One line shown on the card / hosted page. */
8418
+ reason?: string;
8419
+ }
8420
+
8421
+ export declare interface SecretRequestReceipt {
8422
+ requestId: string;
8423
+ key: string;
8424
+ state: SecretRequestState;
8425
+ /** ISO. */
8426
+ expiresAt: string;
6799
8427
  /**
6800
- * Alert when this many scheduled runs in a row failed. Workflows and agent tasks are parked by the
6801
- * platform after 3 consecutive failures, so for them the value is 1..3; code jobs accept 1..50.
8428
+ * The one-time hosted-page token (`/secret-requests/:token`). Returned ONCE, to the creator only, at
8429
+ * creation; the server stores only its sha256 and stops resolving it once the request is done (stored,
8430
+ * cancelled, or out of attempts). Absent on every later read.
8431
+ *
8432
+ * It is a bearer CREDENTIAL: whoever holds it can write a value into the target agent's env. Hand it only
8433
+ * to the person who should enter the secret (as the hosted-page link); never return it to the model as a
8434
+ * tool result, put it in chat history, or log it.
6802
8435
  */
6803
- alertAfterConsecutiveFailures?: number;
6804
- /** Out-of-inbox routing for the notice: 'app' (push), 'email', or 'emailApp' (both). Default 'emailApp'. */
6805
- notify?: ScheduleHealthNotify;
8436
+ pageToken?: string;
6806
8437
  }
6807
8438
 
6808
- declare type ScheduleHealthNotify = (typeof SCHEDULE_HEALTH_NOTIFY_CHANNELS)[number];
8439
+ declare type SecretRequestState = (typeof SECRET_REQUEST_STATES)[number];
6809
8440
 
6810
8441
  /**
6811
- * Additive field on primitive publish responses. When the agent is under
6812
- * versioning the server performs a scoped promote and returns the newly
6813
- * minted + promoted agent version here; absent when the agent has no versions.
8442
+ * `Secrets.requestStatus(requestId)` — one request THIS agent created (including a `{ pendingFor }` request for
8443
+ * an agent that does not exist yet), in the caller's org. Any other id answers `secret_request_not_found`.
8444
+ * Never the value, the hosted-page token, or the person it was for.
6814
8445
  */
6815
- declare interface ScopedPromoteFields {
6816
- agentVersion?: number;
8446
+ export declare interface SecretRequestStatus {
8447
+ requestId: string;
8448
+ key: string;
8449
+ provider: string;
8450
+ /** `expired` once a `pending` / `submitted` request is past `expiresAt`. A failed test leaves it `pending`. */
8451
+ state: SecretRequestState;
8452
+ /** The last server-side test of a submitted value (absent until the person submits). */
8453
+ lastTest?: {
8454
+ result: SecretTestResult; /** ISO. */
8455
+ at: string;
8456
+ };
8457
+ /** ISO. */
8458
+ expiresAt: string;
8459
+ /**
8460
+ * The agent a `{ pendingFor }` request's value was attached to (U1 provisioning), once `attached`. Omitted (with
8461
+ * `state` still `attached`) when that agent is not in the caller's org.
8462
+ */
8463
+ attachedAgentId?: string;
6817
8464
  }
6818
8465
 
6819
8466
  /**
6820
- * Response from product search.
8467
+ * Where the secret goes. `'self'` = the calling agent; a string = that agent id (must be one the caller
8468
+ * may configure); `{ pendingFor }` = a not-yet-created agent: the value is held (encrypted) on the
8469
+ * request row and attached when U1 provisioning creates the agent with that request id.
8470
+ *
8471
+ * `{ pendingFor, agentId }` (held for an EXISTING agent, `LUA_SECRET_ATTACH_EXISTING_ENABLED`): the value is held
8472
+ * (encrypted) the same way, named for `agentId` — an agent of the caller's org, not the caller, created by the
8473
+ * conversation's person — and is attached only by the supervision op `secrets.attach` on that agent
8474
+ * (`Agents.secrets(agentId).attach([requestId])`, `act` grant, on the owner's own turn). Never by U1.
6821
8475
  */
6822
- declare interface SearchProductsResponse {
6823
- success: boolean;
6824
- message: string;
6825
- data: Product[];
8476
+ export declare type SecretRequestTarget = 'self' | string | {
8477
+ pendingFor: string;
8478
+ agentId?: string;
8479
+ };
8480
+
8481
+ export declare const Secrets: SecretsApi;
8482
+
8483
+ /**
8484
+ * Secrets API — ask a person for a credential this agent needs, tested by Lua on the server before it is
8485
+ * stored in the agent's env. Values never pass through your code: they are entered on the masked Desktop
8486
+ * card or the hosted secret page, and no call here ever returns one.
8487
+ *
8488
+ * Off unless the platform enables secret requests (`secret_requests_disabled` otherwise).
8489
+ */
8490
+ export declare interface SecretsApi {
8491
+ /**
8492
+ * Open a request for a provider credential. `target` defaults to this agent (`'self'`); `{ pendingFor }`
8493
+ * holds the value for an agent that is provisioned later on the requesting person's behalf;
8494
+ * `{ pendingFor, agentId }` holds it for an EXISTING agent the person created (attach it with
8495
+ * `Agents.secrets(agentId).attach`).
8496
+ * The receipt's `pageToken` (returned once) opens the hosted secret page.
8497
+ *
8498
+ * **`pageToken` is a credential**: anyone holding it can write a value into this agent's env until the
8499
+ * request is done. Send it only to the person who should enter the secret (as the hosted-page link). Never
8500
+ * return the receipt (or the token) from a tool as-is, put it in a message to the model, or log it; return
8501
+ * `requestId` / `key` / `state` instead.
8502
+ *
8503
+ * @example
8504
+ * ```typescript
8505
+ * const { requestId, key, state } = await Secrets.request({
8506
+ * provider: 'stripe',
8507
+ * key: 'STRIPE_SECRET_KEY',
8508
+ * reason: 'Issue refunds for support tickets',
8509
+ * });
8510
+ * return { requestId, key, state }; // never the pageToken
8511
+ * ```
8512
+ */
8513
+ request(input: SecretRequestInput): Promise<SecretRequestReceipt>;
8514
+ /** Whether `key` is set, its provider, the last test result and any open request — never the value. */
8515
+ status(key: string): Promise<SecretStatus>;
8516
+ /** Re-test the stored value against the provider's fixed probe. `result` is a fixed enum. */
8517
+ test(key: string): Promise<SecretTestOutcome>;
8518
+ /**
8519
+ * The state of ONE request this agent created — notably a `{ pendingFor }` request for an agent that does not
8520
+ * exist yet, which `status(key)` cannot see. Answers `{ requestId, key, provider, state, lastTest?: { result, at },
8521
+ * expiresAt, attachedAgentId? }`: `state` `stored` means the person submitted and the server test passed
8522
+ * (`lastTest.result` `ok`, or `unverified` for an uncatalogued provider); a failed test leaves it `pending` with
8523
+ * `lastTest` set; `attached` (with `attachedAgentId`) once provisioning attached it. Never the value or the token.
8524
+ * A request another agent created, or from another org, answers `secret_request_not_found` like an unknown id.
8525
+ * Platform only: refused offline (`secrets_unavailable`).
8526
+ *
8527
+ * @example
8528
+ * ```typescript
8529
+ * const s = await Secrets.requestStatus(requestId);
8530
+ * if (s.state === 'stored' && s.lastTest?.result === 'ok') { ... }
8531
+ * ```
8532
+ */
8533
+ requestStatus(requestId: string): Promise<SecretRequestStatus>;
8534
+ }
8535
+
8536
+ /** `Secrets.status(key)` — never the value. */
8537
+ export declare interface SecretStatus {
8538
+ key: string;
8539
+ present: boolean;
8540
+ provider?: string;
8541
+ lastTest?: {
8542
+ result: SecretTestResult;
8543
+ testedAt: string;
8544
+ };
8545
+ pendingRequestId?: string;
8546
+ }
8547
+
8548
+ /** `Secrets.test(key)`. */
8549
+ export declare interface SecretTestOutcome {
8550
+ key: string;
8551
+ provider: string;
8552
+ result: SecretTestResult;
8553
+ /** ISO. */
8554
+ testedAt: string;
6826
8555
  }
6827
8556
 
8557
+ export declare type SecretTestResult = (typeof SECRET_TEST_RESULTS)[number];
8558
+
6828
8559
  declare interface SendTemplateButtonValue {
6829
8560
  sub_type: WhatsAppTemplateButtonType;
6830
8561
  index: string;
@@ -6838,12 +8569,19 @@ export declare interface SendTemplateData {
6838
8569
  }
6839
8570
 
6840
8571
  export declare interface SendTemplateResponse {
6841
- results: any[];
8572
+ results: SendTemplateResult[];
6842
8573
  errors: any[];
6843
8574
  totalProcessed: number;
6844
8575
  totalErrors: number;
6845
8576
  }
6846
8577
 
8578
+ export declare interface SendTemplateResult {
8579
+ phoneNumber: string;
8580
+ ok: boolean;
8581
+ messageId?: string;
8582
+ error?: string;
8583
+ }
8584
+
6847
8585
  export declare interface SendTemplateValues {
6848
8586
  header?: Record<string, string> & {
6849
8587
  image_url?: string;
@@ -6875,7 +8613,7 @@ declare interface SignalRunResult {
6875
8613
  * and agent `persona` play different semantic roles. Sharing the structural
6876
8614
  * shape today keeps the runtime lean; future divergence is a one-line change.
6877
8615
  */
6878
- declare type SkillContextText = string | {
8616
+ export declare type SkillContextText = string | {
6879
8617
  base?: string;
6880
8618
  voice?: string;
6881
8619
  text?: string;
@@ -6954,6 +8692,275 @@ declare interface SupervisedAgentSummary {
6954
8692
  actions: string[];
6955
8693
  }
6956
8694
 
8695
+ /** `workflows.get` — metadata only: never the graph, script, code or tools. */
8696
+ declare interface SupervisedWorkflow {
8697
+ workflowId: string;
8698
+ name?: string;
8699
+ /** The value `workflows.deploy` takes as `expectActive` (null = nothing live). */
8700
+ activeVersionId: string | null;
8701
+ /** Newest first, at most {@link SUPERVISED_WORKFLOW_VERSIONS_MAX}. */
8702
+ versions: SupervisedWorkflowVersion[];
8703
+ }
8704
+
8705
+ /** `workflows.create` — the workflow `push` / `deploy` take as `workflowId`. `created: false` = it already existed. */
8706
+ declare interface SupervisedWorkflowCreated {
8707
+ workflowId: string;
8708
+ name: string;
8709
+ created: boolean;
8710
+ }
8711
+
8712
+ declare interface SupervisedWorkflowVersion {
8713
+ versionId: string;
8714
+ version: string;
8715
+ /** `active` = the workflow's `activeVersionId`; `sandbox` = a mutable `-sandbox` version; else `inactive`. */
8716
+ status: 'active' | 'inactive' | 'sandbox';
8717
+ createdAt?: string;
8718
+ }
8719
+
8720
+ declare const SUPERVISION_ACCESS_REQUEST_STATES: readonly ["pending", "approved", "denied", "cancelled", "expired", "revoked"];
8721
+
8722
+ /**
8723
+ * U25 (LUA-959) — the supervision event kinds. An emitter writes one outbox row
8724
+ * per event of a target agent that some supervisor subscribed to; lua-core then
8725
+ * starts each subscribed supervisor's trigger, re-checking the `supervision:observe`
8726
+ * grant at delivery time.
8727
+ *
8728
+ * `trigger.held` and `agent.paused` were typed extension points; SV (supervisor platform) gave them their
8729
+ * emitters: lua-core's trigger dispatch emits `trigger.held` when a delivery to an inactive or paused trigger
8730
+ * is held (one per trigger per hour), lua-api's agent pause emits `agent.paused`.
8731
+ *
8732
+ * Wave 2 adds three more extension points the same way (no emitter until the owning item lands):
8733
+ * `objective.breached` (U30), `judge.score_below_threshold` (U25c, DOC3 §4.9) and
8734
+ * `never_rule.violated` (U25c). Only the owning item writes an emitter for its kind.
8735
+ */
8736
+ declare const SUPERVISION_EVENT_KINDS: readonly ["governance.blocked", "workflow.run_failed", "workflow.run_gated", "connection.unhealthy", "trigger.held", "agent.paused", "objective.breached", "judge.score_below_threshold", "never_rule.violated", "tool.auth_failed", "tool.errors_repeated"];
8737
+
8738
+ /**
8739
+ * The approver: the OWNER (creator) for a private agent; org admins / agent builders (holders of
8740
+ * `members:assign-role` or `agents:manage` on the agent) for a shared one.
8741
+ */
8742
+ declare type SupervisionAccessApproverKind = 'owner' | 'org_admin';
8743
+
8744
+ /** What approving the request adds (empty lists omitted). `expiry` says how the grant's expiry changes. */
8745
+ declare interface SupervisionAccessGrantDelta {
8746
+ actions?: string[];
8747
+ releaseWorkflowIds?: string[];
8748
+ unattendedWorkflowIds?: string[];
8749
+ dataCollections?: string[];
8750
+ /** Upgrade of an expiring `access_request` grant: `'kept'` (no new expiry asked), `'set'` (the new one applies). */
8751
+ expiry?: 'kept' | 'set';
8752
+ /** The approval also records the owner's opt-in to supervisor follow-ups (`notifyOwner`). */
8753
+ ownerNotify?: boolean;
8754
+ }
8755
+
8756
+ /** The supervision-grant fields an access request can add to. */
8757
+ declare interface SupervisionAccessGrantFields {
8758
+ actions: string[];
8759
+ releaseWorkflowIds?: string[];
8760
+ unattendedWorkflowIds?: string[];
8761
+ dataCollections?: string[];
8762
+ }
8763
+
8764
+ /** The live grant an upgrade request was filed against (stored on the request; never user ids). */
8765
+ declare interface SupervisionAccessGrantSnapshot extends SupervisionAccessGrantFields {
8766
+ grantId: string;
8767
+ source: 'pap' | 'access_request';
8768
+ /** ISO; only an `access_request` grant expires. */
8769
+ expiresAt?: string;
8770
+ }
8771
+
8772
+ /** lua `supervision_access_requests` row (owner U29). */
8773
+ declare interface SupervisionAccessRequest {
8774
+ requestId: string;
8775
+ orgId: string;
8776
+ requesterAgentId: string;
8777
+ targetAgentId: string;
8778
+ actions: ProvisionedSupervisionAction[];
8779
+ reason: string;
8780
+ approverKind: SupervisionAccessApproverKind;
8781
+ state: SupervisionAccessRequestState;
8782
+ /** The inbox `input_request` item the approver acts on. */
8783
+ inboxItemId?: string;
8784
+ /** Set on approval: the grant created with `createdByUserId = decidedByUserId`, `source: 'access_request'`. */
8785
+ grantId?: string;
8786
+ decidedByUserId?: string;
8787
+ /** ISO. */
8788
+ createdAt: string;
8789
+ expiresAt: string;
8790
+ grantExpiresAt?: string;
8791
+ decidedAt?: string;
8792
+ /** SV — bindings the request asked for (see {@link SupervisionAccessRequestInput}). */
8793
+ releaseWorkflowIds?: string[];
8794
+ unattendedWorkflowIds?: string[];
8795
+ dataCollections?: string[];
8796
+ notifyOwner?: boolean;
8797
+ /** SV — set when the request UPGRADES a live grant: that grant as it was when the request was filed. */
8798
+ upgradeOf?: SupervisionAccessGrantSnapshot;
8799
+ /** SV — exactly what approval adds to the supervisor's access (the approver's card lists this). */
8800
+ adds?: SupervisionAccessGrantDelta;
8801
+ }
8802
+
8803
+ /** `Agents.requestAccess(agentId, opts)`. */
8804
+ declare interface SupervisionAccessRequestInput {
8805
+ actions: ProvisionedSupervisionAction[];
8806
+ /** Shown to the approver; ≤ {@link SUPERVISION_ACCESS_REASON_MAX}. */
8807
+ reason: string;
8808
+ /** ISO; the GRANT's expiry once approved (absent ⇒ until revoked). */
8809
+ expiresAt?: string;
8810
+ /**
8811
+ * SV — the requester's OWN workflows whose code steps may release on the target (needs `release`).
8812
+ * `LUA_SUPERVISION_ACCESS_BINDINGS_ENABLED`; see `supervision-access-upgrade.types.ts`.
8813
+ */
8814
+ releaseWorkflowIds?: string[];
8815
+ /** SV — the requester's OWN workflows that may run unattended Job-tier plugin steps on the target. */
8816
+ unattendedWorkflowIds?: string[];
8817
+ /** SV — the target's custom-data collections the supervisor may read (needs `observe`). */
8818
+ dataCollections?: string[];
8819
+ /**
8820
+ * SV — ask the target's OWNER to opt in to follow-ups from this supervisor (`Agents.notifyOwner`). Recorded only
8821
+ * when the approver IS the target's owner (creator); an org admin approving a shared agent cannot opt its owner in.
8822
+ */
8823
+ notifyOwner?: boolean;
8824
+ }
8825
+
8826
+ declare type SupervisionAccessRequestState = (typeof SUPERVISION_ACCESS_REQUEST_STATES)[number];
8827
+
8828
+ /** Per-kind payloads — metadata only: never message bodies, user ids, run inputs or outputs. */
8829
+ export declare interface SupervisionEventDataByKind {
8830
+ 'governance.blocked': {
8831
+ stage: 'preprocess' | 'tool_call' | 'postprocess';
8832
+ /** `workflow` = a workflow agent step's owner-governance preflight (gate 2). */
8833
+ surface?: 'chat' | 'voice' | 'delegation' | 'workflow';
8834
+ ruleId?: string;
8835
+ reason?: string;
8836
+ channel?: string;
8837
+ };
8838
+ 'workflow.run_failed': {
8839
+ runId: string;
8840
+ workflowId?: string;
8841
+ reason?: string;
8842
+ stepId?: string;
8843
+ };
8844
+ 'workflow.run_gated': {
8845
+ runId: string;
8846
+ workflowId?: string;
8847
+ gate: 'billing' | 'quota';
8848
+ code?: string;
8849
+ stepId?: string;
8850
+ };
8851
+ 'connection.unhealthy': {
8852
+ connectionId: string;
8853
+ integrationType?: string;
8854
+ lastUnhealthyCode?: string;
8855
+ };
8856
+ /** A delivery was held for replay (`reason`: `inactive` / `paused`); one per trigger per hour (SV emitter). */
8857
+ 'trigger.held': {
8858
+ triggerName: string;
8859
+ reason?: string;
8860
+ };
8861
+ /** The agent was paused (SV emitter, lua-api). `pausedBy` is a coarse marker (`user`), never a user id. */
8862
+ 'agent.paused': {
8863
+ reason?: string;
8864
+ pausedBy?: string;
8865
+ };
8866
+ /**
8867
+ * Wave 2 extension point (U30): an owner-confirmed objective broke one of its guardrails
8868
+ * (`breach: 'guardrail'`) or drifted below its baseline (`breach: 'baseline'`). Metric values only.
8869
+ */
8870
+ 'objective.breached': {
8871
+ objectiveId: string;
8872
+ metric: string;
8873
+ breach: 'guardrail' | 'baseline';
8874
+ value: number;
8875
+ threshold: number;
8876
+ /** The evaluated window, e.g. `7d`. */
8877
+ window?: string;
8878
+ guardrailId?: string;
8879
+ };
8880
+ /**
8881
+ * Wave 2 extension point (U25c, DOC3 §4.9): a sampled completed run scored below its monitor's
8882
+ * threshold. `reasoning` respects the org's judge redaction tier and is absent when the tier strips it.
8883
+ * Flat on purpose: the outbox keeps only flat scalars (`sanitizeSupervisionEventData`), so DOC3's
8884
+ * `subject: { kind, id }` travels as `subjectKind` + `subjectId`.
8885
+ */
8886
+ 'judge.score_below_threshold': {
8887
+ monitorKey: string;
8888
+ subjectKind: 'workflow-run' | 'trigger' | 'job';
8889
+ subjectId: string;
8890
+ score: number;
8891
+ threshold: number;
8892
+ reasoning?: string;
8893
+ };
8894
+ /**
8895
+ * SV — a tool / integration call of the target failed with an AUTH error: HTTP 401 / 403, or an expired /
8896
+ * invalid token. Deduped per (target, tool) per window (`windowStart`, ISO). Metadata only: never the error text.
8897
+ */
8898
+ 'tool.auth_failed': {
8899
+ toolName: string;
8900
+ /** Where it ran: `skill`, `mcp`, `job`, `webhook`, … (the log row's `logSource`). */
8901
+ logSource?: string;
8902
+ primitiveName?: string;
8903
+ /** `unauthorized` (401), `forbidden` (403), `token_expired` (expired / invalid token or grant). */
8904
+ reason: 'unauthorized' | 'forbidden' | 'token_expired';
8905
+ windowStart: string;
8906
+ };
8907
+ /**
8908
+ * SV — the same tool / primitive of the target failed `count` times inside one window (`windowSeconds`), counted
8909
+ * across pods. Emitted once per (target, tool, window), when the count reaches the threshold.
8910
+ */
8911
+ 'tool.errors_repeated': {
8912
+ toolName: string;
8913
+ logSource?: string;
8914
+ primitiveName?: string;
8915
+ count: number;
8916
+ windowSeconds: number;
8917
+ windowStart: string;
8918
+ };
8919
+ /** Wave 2 extension point (U25c): a stored never-rule refused (or, log-only, would have refused) a call. */
8920
+ 'never_rule.violated': {
8921
+ ruleId: string;
8922
+ surface: 'passthrough' | 'mcp' | 'workflow-step' | 'tool';
8923
+ toolName?: string;
8924
+ operation?: string;
8925
+ /** `false` while `LUA_NEVER_RULES_ENFORCED` is off: the call was allowed and only recorded. */
8926
+ enforced: boolean;
8927
+ severity: 'severe';
8928
+ };
8929
+ }
8930
+
8931
+ /**
8932
+ * The trigger body a subscribed supervisor receives (`source: 'supervision'`). It is
8933
+ * delivered through the supervisor's own trigger, so that trigger's verify / filter /
8934
+ * transform slots run as for any other dispatch.
8935
+ */
8936
+ export declare interface SupervisionEventEnvelope {
8937
+ source: 'supervision';
8938
+ eventId: string;
8939
+ kind: SupervisionEventKind;
8940
+ targetAgentId: string;
8941
+ occurredAt: string;
8942
+ data: Record<string, unknown>;
8943
+ }
8944
+
8945
+ export declare type SupervisionEventKind = (typeof SUPERVISION_EVENT_KINDS)[number];
8946
+
8947
+ /**
8948
+ * `supervisorAgentId`'s trigger `triggerName` fires on `kinds` of `targetAgentId`.
8949
+ *
8950
+ * A subscription lives only as long as the grant behind it: when a delivery finds the
8951
+ * supervisor no longer holds `supervision:observe` on the target (revoked, or the two
8952
+ * agents are no longer in one org), the platform deletes the subscription, and a
8953
+ * re-granted supervisor subscribes again. Archiving either agent purges it too.
8954
+ */
8955
+ export declare interface SupervisionEventSubscription {
8956
+ supervisorAgentId: string;
8957
+ targetAgentId: string;
8958
+ kinds: SupervisionEventKind[];
8959
+ triggerName: string;
8960
+ createdAt?: string;
8961
+ updatedAt?: string;
8962
+ }
8963
+
6957
8964
  declare interface SupervisionLogRow {
6958
8965
  timestamp: string | number | Date;
6959
8966
  level?: string;
@@ -6962,6 +8969,32 @@ declare interface SupervisionLogRow {
6962
8969
  logSource?: string;
6963
8970
  primitiveName?: string;
6964
8971
  toolName?: string;
8972
+ /**
8973
+ * A non-identifying conversation key: the same value for every row of one conversation (thread) on this target,
8974
+ * never the thread id itself (which embeds the end user's id), and different on another target. Present on rows
8975
+ * written with a thread (a turn's `user_message` and `agent_response` rows, tool runtime logs, STT), so a
8976
+ * conversation's user turns and replies group under one key; absent otherwise.
8977
+ */
8978
+ threadKey?: string;
8979
+ }
8980
+
8981
+ declare interface SupervisionOwnerNotifyInput {
8982
+ message: string;
8983
+ /**
8984
+ * Optional dedupe key (1-256 characters, no control characters). A retried `notifyOwner` with the same key from
8985
+ * the same supervisor within 24 hours never posts twice: it answers the FIRST call's receipt (same `followUpId`,
8986
+ * same `threadId`). A concurrent duplicate still in flight is refused `thread_follow_up_in_progress` (retryable).
8987
+ * Scoped to `notifyOwner` — the same key on `Threads.followUp` is a different key. A key already used for another
8988
+ * target agent is refused `supervision_owner_notify_invalid`. Without a key every call posts.
8989
+ */
8990
+ idempotencyKey?: string;
8991
+ }
8992
+
8993
+ declare interface SupervisionOwnerNotifyReceipt {
8994
+ followUpId: string;
8995
+ /** The owner's home thread with the supervisor. */
8996
+ threadId: string;
8997
+ status: 'posted';
6965
8998
  }
6966
8999
 
6967
9000
  declare interface SupervisionRunSummary {
@@ -7111,6 +9144,90 @@ export declare const Templates: {
7111
9144
  };
7112
9145
  };
7113
9146
 
9147
+ /** Recorded effect kinds (DOC2 §7 seam table; `fetch` is sandbox egress record mode, §9.1). */
9148
+ declare const TEST_EFFECT_KINDS: readonly ["channel.send", "whatsapp.template", "whatsapp.reaction", "whatsapp.phone_request", "email.send", "inbox.push", "voice.call", "passthrough", "mcp.tool", "supervision.write", "user.update_name", "browser.action", "jobs.create", "fetch", "refused", "metrics.record", "threads.open", "threads.follow_up", "secrets.request", "connection_request.create", "connection_request.reconnect", "connection_request.cancel", "ai.generate"];
9149
+
9150
+ declare type TestEffectKind = (typeof TEST_EFFECT_KINDS)[number];
9151
+
9152
+ /** DOC2 §6.3 — Data: `shadow` (copy-on-write over live, default) or `isolated` (empty shadow only). */
9153
+ declare type TestSessionDataMode = 'shadow' | 'isolated';
9154
+
9155
+ /** One row of `lua.test_session_effects` (unique `{testSessionId, seq}`; TTL = the session's `expiresAt`). */
9156
+ declare interface TestSessionEffect {
9157
+ testSessionId: string;
9158
+ seq: number;
9159
+ kind: TestEffectKind;
9160
+ /** The execution site (`tool`, `job`, `trigger`, `workflow-step`, …). */
9161
+ site: string;
9162
+ primitiveId?: string;
9163
+ /** Redacted: secret-keyed values `[REDACTED]`, `Authorization` / `Cookie` / `X-Api-Key` dropped, body ≤ 16 KB. */
9164
+ request: unknown;
9165
+ syntheticResponse?: unknown;
9166
+ /** ISO. */
9167
+ at: string;
9168
+ }
9169
+
9170
+ /** DOC2 §6.1 — sandbox egress: `record` (default) or `live` (explicit OWNER opt-in; never for supervisors). */
9171
+ declare type TestSessionEgressMode = 'record' | 'live';
9172
+
9173
+ declare type TestSessionFireInput = TestSessionFireTarget & {
9174
+ payload?: unknown;
9175
+ };
9176
+
9177
+ declare type TestSessionFireTarget = {
9178
+ trigger: string;
9179
+ } | {
9180
+ job: string;
9181
+ } | {
9182
+ workflow: string;
9183
+ } | {
9184
+ webhook: string;
9185
+ };
9186
+
9187
+ /** DOC2 §6.1 — MCP mode: `doubles-only` (T13 default) or `read-live` (session default). */
9188
+ declare type TestSessionMcpMode = 'doubles-only' | 'read-live';
9189
+
9190
+ /** `Agents.versions(id).session(opts)` (DOC2 §6.1). `testTraffic: true` is a required literal. */
9191
+ declare interface TestSessionOpenInput {
9192
+ version: number;
9193
+ testTraffic: true;
9194
+ toolDoubles?: TestSessionToolDouble[];
9195
+ mcp?: TestSessionMcpMode;
9196
+ data?: TestSessionDataMode;
9197
+ egress?: TestSessionEgressMode;
9198
+ /** Hours; default {@link TEST_SESSION_TTL_HOURS_DEFAULT}, max {@link TEST_SESSION_TTL_HOURS_MAX}. */
9199
+ ttlHours?: number;
9200
+ }
9201
+
9202
+ /** The session record (`lua.test_sessions`). */
9203
+ declare interface TestSessionRecord {
9204
+ id: string;
9205
+ agentId: string;
9206
+ orgId: string;
9207
+ version: number;
9208
+ /** `user:<id>` / `apiKey:<id>` / `system:<agentId>` for a supervisor. */
9209
+ createdBy: string;
9210
+ mcp: TestSessionMcpMode;
9211
+ data: TestSessionDataMode;
9212
+ egress: TestSessionEgressMode;
9213
+ toolDoubles: TestSessionToolDouble[];
9214
+ status: TestSessionStatus;
9215
+ /** Turns plus fires so far (cap {@link TEST_SESSION_OPS_MAX}). */
9216
+ ops: number;
9217
+ /** ISO. */
9218
+ createdAt: string;
9219
+ expiresAt: string;
9220
+ }
9221
+
9222
+ declare type TestSessionStatus = 'open' | 'closed' | 'expired';
9223
+
9224
+ /** Same shape as `ChatRequest.toolDoubles` (lua-core `request.type.ts`). */
9225
+ declare interface TestSessionToolDouble {
9226
+ server?: string;
9227
+ tool: string;
9228
+ result: unknown;
9229
+ }
9230
+
7114
9231
  export declare interface TextMessage {
7115
9232
  type: 'text';
7116
9233
  text: string;
@@ -7121,6 +9238,88 @@ declare type TextMessage_2 = {
7121
9238
  text: string;
7122
9239
  };
7123
9240
 
9241
+ /**
9242
+ * `Threads.followUp(threadId, input)`: exactly one of `prompt` (a BACKGROUND agent turn on the thread,
9243
+ * like the workflow callback loopback) or `message` (post the text as the agent, no model turn).
9244
+ * Only the agent's OWN threads (its home threads and the threads of its turns).
9245
+ */
9246
+ export declare type ThreadFollowUpInput = ({
9247
+ prompt: string;
9248
+ message?: never;
9249
+ } | {
9250
+ message: string;
9251
+ prompt?: never;
9252
+ }) & {
9253
+ /**
9254
+ * Optional dedupe key (1-256 characters, no control characters). A retried call with the same key on the same
9255
+ * agent — within 24 hours (`FOLLOW_UP_IDEMPOTENCY_TTL_SECONDS`) — never delivers twice: it answers the FIRST call's
9256
+ * receipt (same `followUpId`) and posts / queues nothing. The key belongs to its first thread: reusing it on
9257
+ * another thread is refused `INPUT_INVALID`. Without a key every call delivers.
9258
+ */
9259
+ idempotencyKey?: string;
9260
+ };
9261
+
9262
+ export declare interface ThreadFollowUpReceipt {
9263
+ followUpId: string;
9264
+ mode: 'turn' | 'message';
9265
+ /** A turn is queued and delivered by the loopback; a message is posted immediately. */
9266
+ status: 'queued' | 'posted';
9267
+ }
9268
+
9269
+ /** `Threads.open(ownerUserId)`. The user must be one the agent may reach (same rules as `User.Inbox.push`). */
9270
+ export declare interface ThreadOpenResult {
9271
+ threadId: string;
9272
+ /** `true` the first time; the thread is otherwise reused. */
9273
+ created: boolean;
9274
+ }
9275
+
9276
+ export declare const Threads: ThreadsApi;
9277
+
9278
+ /**
9279
+ * Threads API — reach a person on a conversation your agent owns, from a job, trigger, webhook or supervision
9280
+ * handler. The platform decides every call: the feature flag, that the thread is this agent's own, that the person
9281
+ * is reachable (the run's own user, or — for an agent-level run — a member of the agent's notify list), a rate
9282
+ * limit (12 per thread and 120 per agent per hour) and an audit row on the agent's logs (never the text).
9283
+ *
9284
+ * Refusals throw an error with `name: 'ThreadFollowUpError'` and a `code` from `THREAD_FOLLOW_UP_ERRORS`
9285
+ * (`thread_follow_up_disabled`, `thread_not_owned_by_agent`, `thread_user_unreachable`,
9286
+ * `thread_follow_up_rate_limited`, `thread_follow_up_input_invalid`, `thread_follow_up_unavailable`, …).
9287
+ * `lua test` / `lua dev` never post into a real conversation: both members throw `thread_follow_up_unavailable`.
9288
+ *
9289
+ * @example
9290
+ * ```typescript
9291
+ * // In a job: open the user's home thread with this agent, then follow up there.
9292
+ * const { threadId } = await Threads.open(userId);
9293
+ * await Threads.followUp(threadId, { message: 'Your weekly report is ready.' }); // posted as the agent
9294
+ * await Threads.followUp(threadId, { prompt: 'Check whether order 1042 shipped and tell the user.' }); // a background turn
9295
+ *
9296
+ * // Safe to retry: the same idempotencyKey never delivers twice (the retry resolves the first receipt).
9297
+ * await Threads.followUp(threadId, { message: 'Order 1042 shipped.', idempotencyKey: 'order-1042-shipped' });
9298
+ * ```
9299
+ */
9300
+ export declare interface ThreadsApi {
9301
+ /**
9302
+ * The agent's HOME thread with `ownerUserId` (`{userId}-{agentId}:home`) — the same thread every time;
9303
+ * `created` is `true` only the first time.
9304
+ */
9305
+ open(ownerUserId: string): Promise<ThreadOpenResult>;
9306
+ /**
9307
+ * Follow up on one of the agent's own threads with EXACTLY one of:
9308
+ * - `{ prompt }` (≤ 8,000 chars) — start a background agent turn on the thread; the receipt is `queued`;
9309
+ * - `{ message }` (≤ 4,000 chars) — post the text as the agent with no model turn; the receipt is `posted`.
9310
+ *
9311
+ * Optional `idempotencyKey` (1-256 characters, no control characters): a retried call with the same key from this
9312
+ * agent within 24 hours delivers nothing and resolves the FIRST call's receipt (same `followUpId`) — use it when a
9313
+ * job, trigger or webhook may run twice. A duplicate sent while the first is still delivering waits for it, or is
9314
+ * refused `thread_follow_up_in_progress` (retry it). The key identifies the delivery: reusing it with different text
9315
+ * on the same thread still delivers nothing, and reusing it on ANOTHER thread is refused
9316
+ * `thread_follow_up_input_invalid` (as is reusing it for the other mode) — use one key per delivery. For
9317
+ * `{ prompt }` the key covers QUEUEING the turn, not its completion. At most once unless the platform's key store
9318
+ * fails mid-delivery. Without a key every call delivers.
9319
+ */
9320
+ followUp(threadId: string, input: ThreadFollowUpInput): Promise<ThreadFollowUpReceipt>;
9321
+ }
9322
+
7124
9323
  /**
7125
9324
  * Base interface for entities with timestamps.
7126
9325
  * Most database entities include these fields.
@@ -7215,7 +9414,7 @@ export declare interface TriggerContext<T = any> {
7215
9414
  /**
7216
9415
  * Context delivered to a trigger's verify / filter / transform slots.
7217
9416
  *
7218
- * Unlike a webhook event, `rawBody` carries the EXACT unparsed request bytes
9417
+ * As on a webhook event, `rawBody` carries the EXACT unparsed request bytes
7219
9418
  * (utf8) — HMAC signature schemes (Stripe `t=…,v1=…`, GitHub `sha256=…`, Slack
7220
9419
  * `v0:…`) are computed over the wire bytes, which `JSON.stringify(body)` does
7221
9420
  * not reproduce. `headers` keys arrive lowercased (Express), e.g.
@@ -7243,7 +9442,7 @@ export declare interface TriggerContext<T = any> {
7243
9442
  * `lua workflows describe <ref>` resolves); `correlationKey` accepts a literal or a
7244
9443
  * `'${input.<field>}'` template the trigger fills.
7245
9444
  */
7246
- declare interface TriggerStartWorkflow {
9445
+ export declare interface TriggerStartWorkflow {
7247
9446
  startWorkflow: {
7248
9447
  name: string;
7249
9448
  input?: unknown;
@@ -7276,6 +9475,8 @@ export { TypedRef }
7276
9475
  declare interface UpdateCustomDataResponse {
7277
9476
  status: string;
7278
9477
  message: string;
9478
+ /** Entry version after the write (LUA-963). */
9479
+ version?: number;
7279
9480
  }
7280
9481
 
7281
9482
  /**
@@ -7462,10 +9663,12 @@ export declare class UserDataInstance {
7462
9663
  unset(...fields: string[]): Promise<any>;
7463
9664
  /**
7464
9665
  * Clears all user data for the current user
7465
- * @returns Promise resolving to true if clearing was successful
9666
+ * @returns Promise resolving to `{ success: true }` if clearing was successful
7466
9667
  * @throws Error if the clear operation fails
7467
9668
  */
7468
- clear(): Promise<boolean>;
9669
+ clear(): Promise<{
9670
+ success: boolean;
9671
+ }>;
7469
9672
  /**
7470
9673
  * Saves the user's data
7471
9674
  * @returns Promise resolving to true if saving was successful
@@ -7475,21 +9678,41 @@ export declare class UserDataInstance {
7475
9678
  /**
7476
9679
  * Sends a message to a specific user conversation for the agent
7477
9680
  * @param messages - An array of messages to send (can be text, image, or file types)
7478
- * @returns Promise resolving to the response data from the server
7479
- * @throws Error if the message sending fails or the request is unsuccessful
9681
+ * @returns Promise resolving to true only when the platform confirmed delivery, false on a failure or an unconfirmed result. Never throws.
7480
9682
  */
7481
- send(messages: Message[]): Promise<any>;
9683
+ send(messages: Message[]): Promise<boolean>;
7482
9684
  getChatHistory(): Promise<ChatHistoryMessage[]>;
7483
9685
  }
7484
9686
 
9687
+ /** One channel id of a person, as that channel issued it. */
9688
+ declare interface UserIdentity {
9689
+ /** `whatsapp_bsuid`, `slack_user`, `slack_bot` or `teams_user`; more kinds arrive as channels move over. */
9690
+ kind: string;
9691
+ /** Who issued the value: the WhatsApp business portfolio, the Slack team or enterprise, or the Microsoft tenant. */
9692
+ scope: string;
9693
+ value: string;
9694
+ verifiedBy?: UserIdentityVerifiedBy;
9695
+ /** What the channel shows for the person. Never use it to identify them. */
9696
+ displayName?: string;
9697
+ username?: string;
9698
+ }
9699
+
9700
+ /** Which identity a message came from, as `Lua.request.sender` gives it. */
9701
+ declare type UserIdentityRef = Pick<UserIdentity, 'kind' | 'scope' | 'value'>;
9702
+
9703
+ /** How an identity was established. */
9704
+ declare type UserIdentityVerifiedBy = 'otp' | 'oauth' | 'receipt' | 'provider' | 'observed' | 'none';
9705
+
7485
9706
  /**
7486
- * Options for looking up a user by email or phone
9707
+ * Options for looking up a user by email, phone or channel identity
7487
9708
  */
7488
9709
  export declare interface UserLookupOptions {
7489
9710
  /** Email address to look up */
7490
9711
  email?: string;
7491
9712
  /** Phone number to look up (with or without + prefix) */
7492
9713
  phone?: string;
9714
+ /** A channel identity, e.g. `Lua.request.sender` or an entry of `_luaProfile.identities` */
9715
+ identity?: UserIdentityRef;
7493
9716
  }
7494
9717
 
7495
9718
  export declare const value: (v: unknown) => MapDescriptor;
@@ -7781,11 +10004,29 @@ declare interface WebRouteAuth {
7781
10004
 
7782
10005
  declare type WebRouteMethod = (typeof WEB_ROUTE_METHODS)[number];
7783
10006
 
10007
+ /**
10008
+ * Body of POST /developer/agents/:agentId/channels/whatsapp/phone-request.
10009
+ * Sends WhatsApp's "share your phone number" button. A user who taps it shares
10010
+ * their own number, which is saved on their Lua profile before their next turn
10011
+ * runs. Needs an open 24h customer-service window.
10012
+ */
10013
+ declare interface WhatsAppPhoneRequestInput {
10014
+ to: {
10015
+ userId?: string;
10016
+ phoneNumber?: string;
10017
+ identity?: UserIdentityRef;
10018
+ };
10019
+ /** Message shown above the button (max 1024 characters). */
10020
+ text: string;
10021
+ options?: ChannelSendOptions;
10022
+ }
10023
+
7784
10024
  /** Body of POST /developer/agents/:agentId/channels/whatsapp/reaction */
7785
10025
  export declare interface WhatsAppReactionSendInput {
7786
10026
  to: {
7787
10027
  userId?: string;
7788
10028
  phoneNumber?: string;
10029
+ identity?: UserIdentityRef;
7789
10030
  };
7790
10031
  /** Vendor id (`wamid...`) of the message to react to — e.g. an inbound
7791
10032
  * message's id from the conversation history, ≤30 days old per Meta. */
@@ -7876,6 +10117,7 @@ export declare interface WhatsAppTemplateSendInput {
7876
10117
  to: {
7877
10118
  userId?: string;
7878
10119
  phoneNumber?: string;
10120
+ identity?: UserIdentityRef;
7879
10121
  };
7880
10122
  templateName: string;
7881
10123
  languageCode?: string;
@@ -8182,7 +10424,16 @@ declare interface WorkflowRun {
8182
10424
  parentRunId?: string;
8183
10425
  correlationKey?: string;
8184
10426
  tags?: string[];
8185
- /** R4 `gate` (02 §2.4). LUA-788: a `kind:'billing'` gate names the wallet's refusal (`code`), the held step and its expiry. */
10427
+ /**
10428
+ * R3/R4 `gate` (02 §2.4) — what a `gated` run (and a gate-parked `suspended` one) waits on. LUA-788: a
10429
+ * `kind:'billing'` gate names the wallet's refusal (`code`), the held step and its expiry. A `kind:'budget'` gate
10430
+ * carries the run cap it met (`dimension`, `spent`, `cap`) and — item 10, newer servers — the refused step's
10431
+ * estimate (`reserve`). A `kind:'start-consent'` gate carries — item 10, newer servers — WHY the start asked a
10432
+ * person (`exceeded`: each crossed threshold and the estimate judged against it, e.g. credits 34 > maxAutoCredits
10433
+ * 20) and `rateLimited` when the autonomy envelope's hourly meter sent it back. Every member past `kind` is
10434
+ * optional: an older server sends none of the item-10 members, and the CLI then words the reason from the members
10435
+ * it does send.
10436
+ */
8186
10437
  gate?: {
8187
10438
  kind: string;
8188
10439
  reason?: string;
@@ -8190,7 +10441,21 @@ declare interface WorkflowRun {
8190
10441
  code?: string;
8191
10442
  stepId?: string;
8192
10443
  expiresAt?: number;
10444
+ dimension?: 'credits' | 'actions' | 'steps' | 'jobSeconds' | (string & {});
10445
+ spent?: number;
10446
+ cap?: number;
10447
+ reserve?: number;
10448
+ exceeded?: WorkflowStartConsentExceededDto[];
10449
+ rateLimited?: boolean;
8193
10450
  };
10451
+ /**
10452
+ * WHY a `suspended` / `waiting` run is parked (R3 list rows and R4; `WorkflowRunSuspendedFor` on the server) —
10453
+ * stamped by the engine at every park, dropped on every wake and terminal. Servers since LUA-816 send it for
10454
+ * approval / input / signal / billing parks; item-10 servers add budget and the waiting kinds. Absent on a run that
10455
+ * is not parked and on a run parked before its park site stamped one: read `gate` / `status` then.
10456
+ * `lua workflows status` renders it on the header line (`suspensionReason`).
10457
+ */
10458
+ suspendedFor?: WorkflowRunSuspendedForDto;
8194
10459
  /**
8195
10460
  * Server-decided (09 §9.6): `raise_budget` on a budget gate (LUA-665), `top_up` on a billing gate (LUA-788 — the
8196
10461
  * wallet clears it; the engine re-checks and resumes on its own), `cancel_again` / `force` under a pending cancel,
@@ -8339,9 +10604,52 @@ declare interface WorkflowRunModelUsageRow {
8339
10604
  fallbacks?: number;
8340
10605
  }
8341
10606
 
8342
- /** §02 §2.4 run statuses (one union across every section). */
10607
+ /**
10608
+ * §02 §2.4 run statuses (one union across every section). The three PARKED statuses hold no worker and say why on
10609
+ * the run: `gated` (read `gate` — consent, quota, billing, an archived workspace, a paused agent), `suspended`
10610
+ * (read `suspendedFor` — an approval / input / signal, the run's budget, a payment; `gate` for a step awaiting a
10611
+ * decision),
10612
+ * `waiting` (read `suspendedFor` — a sleep, a retry backoff, a child run). See `WorkflowRunSuspendedForDto`.
10613
+ */
8343
10614
  declare type WorkflowRunStatus = 'queued' | 'running' | 'cancellation_requested' | 'gated' | 'suspended' | 'waiting' | 'completed' | 'failed' | 'cancelled' | 'abandoned' | 'timed_out';
8344
10615
 
10616
+ /**
10617
+ * Item 10 — `WorkflowRun.suspendedFor`: what the engine parked the run FOR.
10618
+ *
10619
+ * `kind` is OPEN (an unknown kind from a newer server must render generically, never crash). A step parked for a
10620
+ * decision (an exception park) is read off `gate` (`kind:'exception'`, `stepId`, `code`), not this stamp.
10621
+ * - `approval` | `input` | `signal` — a person or a signal decides (`stepId`; `approvalId` / `escalatedHop` on an
10622
+ * approval; `signalName` on a signal wait; `deadlineAt` when the wait times out);
10623
+ * - `budget` — the run met its own cap before step `stepId` (`dimension`, `spent`, `cap`, the step's estimate
10624
+ * `reserve`, the gate's `expiresAt`) — `lua workflows raise-budget` resumes it;
10625
+ * - `billing` — the wallet refused (`code`: `insufficient_credits` | `out_of_actions`) — a top-up resumes it;
10626
+ * - `model_policy` | `gate` — a platform policy holds step `stepId`;
10627
+ * - `sleep` | `retry_backoff` — a `waiting` run the engine wakes at `wakeAt` on its own;
10628
+ * - `subrun` — a `waiting` run waits on child run `childRunId`.
10629
+ */
10630
+ declare interface WorkflowRunSuspendedForDto {
10631
+ kind: 'approval' | 'input' | 'signal' | 'budget' | 'billing' | 'model_policy' | 'gate' | 'sleep' | 'retry_backoff' | 'subrun' | (string & {});
10632
+ stepId?: string;
10633
+ attempt?: number;
10634
+ /** When the park began (epoch ms). */
10635
+ since?: number;
10636
+ code?: string;
10637
+ expiresAt?: number;
10638
+ operationId?: string;
10639
+ approvalId?: string;
10640
+ escalatedHop?: number;
10641
+ signalName?: string;
10642
+ /** HITL waits: when the wait times out (epoch ms). */
10643
+ deadlineAt?: number;
10644
+ /** `sleep` / `retry_backoff`: when the engine wakes the run (epoch ms). */
10645
+ wakeAt?: number;
10646
+ childRunId?: string;
10647
+ dimension?: 'credits' | 'actions' | 'steps' | 'jobSeconds' | (string & {});
10648
+ spent?: number;
10649
+ cap?: number;
10650
+ reserve?: number;
10651
+ }
10652
+
8345
10653
  /**
8346
10654
  * [WJB-B5] (BAC-671) — the four token figures the server sums per run and per step (`WorkflowRunTokens` in
8347
10655
  * `@lua/shared-types`). Every member optional: the CLI is a reader of whatever the server sends, and a figure
@@ -8381,6 +10689,9 @@ export declare const Workflows: WorkflowsApi;
8381
10689
  * - `get`/`list` honour output ACLs: a restricted run comes back with `restricted:true`
8382
10690
  * and no `output` — never an error.
8383
10691
  *
10692
+ * - `start` options are checked: an option key it does not know throws
10693
+ * `WorkflowApiError{ code:'VALIDATION_FAILED' }` naming it — never silently dropped.
10694
+ *
8384
10695
  * `startBatch`, `signalByKey`, `raiseBudget`, `setGoal` and `goals.*` are part of the
8385
10696
  * frozen member list and throw `WORKFLOWS_API_UNAVAILABLE` until their routes ship.
8386
10697
  */
@@ -8396,16 +10707,39 @@ export declare interface WorkflowsApi {
8396
10707
  initialState?: Record<string, unknown>;
8397
10708
  correlationKey?: string;
8398
10709
  tags?: string[];
10710
+ /** Deliver the terminal summary back on this channel thread (07 §7.4.5). */
8399
10711
  replyTo?: {
8400
10712
  channel: string;
8401
10713
  threadId: string;
8402
10714
  };
10715
+ /** Run on behalf of an end customer: `principalKind:'customer'` (reduced scope; never an approver). */
8403
10716
  onBehalfOf?: {
8404
- userId: string;
10717
+ kind: 'customer';
10718
+ externalId: string;
8405
10719
  };
10720
+ /**
10721
+ * Opt-in `workflow-callback`: on the terminal (completed | failed | timed_out) the agent takes one
10722
+ * background turn on `originThreadId` with the outcome. Needs an origin thread — from a tool it defaults
10723
+ * to the current chat thread; elsewhere a start without one throws `CALLBACK_THREAD_REQUIRED`.
10724
+ */
10725
+ callback?: boolean;
10726
+ /**
10727
+ * The chat thread the run's cards and callback land on. Defaults to `Lua.request.threadId` when called
10728
+ * from a chat turn (a tool / processor); must be the calling user's own thread on this agent
10729
+ * (`ORIGIN_THREAD_INVALID` otherwise).
10730
+ */
10731
+ originThreadId?: string;
10732
+ notify?: 'emailApp' | 'email' | 'app' | 'off';
8406
10733
  workflowVersionId?: string;
8407
10734
  }): Promise<StartWorkflowRunResult>;
10735
+ /**
10736
+ * One run (R4). A parked run says WHY: `status` is `gated` | `suspended` | `waiting`, `gate` carries a gated run's
10737
+ * reason (consent — with the crossed thresholds on newer servers —, quota, billing, budget …) and `suspendedFor`
10738
+ * a suspended / waiting run's (`approval` | `input` | `signal` | `budget` | `billing` | `sleep` |
10739
+ * `retry_backoff` | `subrun` …, with the step and the figures). Both are optional — absent on older servers.
10740
+ */
8408
10741
  get(runId: string): Promise<WorkflowRun>;
10742
+ /** Runs of this agent (R3); each row carries `gate` / `suspendedFor` exactly as `get` does. */
8409
10743
  list(opts?: {
8410
10744
  limit?: number;
8411
10745
  status?: WorkflowRunStatus | string;
@@ -8501,6 +10835,16 @@ export declare interface WorkflowSpecialistRole {
8501
10835
  tools: string[];
8502
10836
  }
8503
10837
 
10838
+ /** Item 10 — one crossed consent threshold on a `start-consent` gate (`WorkflowRun.gate.exceeded`). */
10839
+ declare interface WorkflowStartConsentExceededDto {
10840
+ /** `steps` | `credits` | `duration` (seconds) | `actions`. */
10841
+ dimension: 'steps' | 'credits' | 'duration' | 'actions' | (string & {});
10842
+ /** The threshold crossed — `maxAutoSteps` / `maxAutoCredits` / `maxAutoDurationSeconds` / the envelope's `maxActions`. */
10843
+ limit: number;
10844
+ /** The start's estimate on that dimension. */
10845
+ estimate: number;
10846
+ }
10847
+
8504
10848
  export declare interface WorkflowStepContext<TIn = unknown, TResume = unknown, TState = Record<string, unknown>> {
8505
10849
  runId: string;
8506
10850
  workflowId: string;
@@ -8705,6 +11049,7 @@ export declare type WorkspaceSpec = {
8705
11049
  ref?: string | TemplateBinding;
8706
11050
  credentialsRef?: string;
8707
11051
  sizeGb?: number;
11052
+ /** Hours a released or held volume is kept before expiry — default 72 h (24 h for a completed `keepArtefacts` volume), platform ceiling 168 h; once the platform enables `LUA_WF_WORKSPACE_TTL_CEILING_ENFORCE` a larger value is refused at push with `workspace-ttl-exceeds-cap` or clamped at run time. */
8708
11053
  ttlHours?: number;
8709
11054
  verify?: string;
8710
11055
  keepArtefacts?: boolean;
@@ -8712,9 +11057,10 @@ export declare type WorkspaceSpec = {
8712
11057
  } | {
8713
11058
  kind: 'empty';
8714
11059
  sizeGb?: number;
11060
+ /** Hours a released or held volume is kept before expiry — default 72 h (24 h for a completed `keepArtefacts` volume), platform ceiling 168 h; once the platform enables `LUA_WF_WORKSPACE_TTL_CEILING_ENFORCE` a larger value is refused at push with `workspace-ttl-exceeds-cap` or clamped at run time. */
8715
11061
  ttlHours?: number;
8716
11062
  /**
8717
- * Keep the volume after the run completes: held until `ttlHours` (24 h when undeclared), then expired. A kept
11063
+ * Keep the volume after the run completes: held until `ttlHours` (24 h when undeclared; the platform ceiling is 168 h once enforced), then expired. A kept
8718
11064
  * volume holds one of the organisation's workspace slots (`maxWorkspacesPerOrg`, 10 by default) until then.
8719
11065
  */
8720
11066
  keepArtefacts?: boolean;