lua-cli 3.41.0 → 3.42.0-beta.2

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.
Files changed (40) hide show
  1. package/dist/api-exports.d.ts +2425 -126
  2. package/dist/api-exports.js +17963 -11393
  3. package/dist/api-exports.js.map +1 -1
  4. package/dist/index.js +11147 -1071
  5. package/dist/index.js.map +1 -1
  6. package/dist/voice/test/index.d.ts +72 -72
  7. package/dist/workflow-builder.d.ts +16 -2
  8. package/dist/workflow-builder.js +5666 -317
  9. package/dist/workflow-builder.js.map +1 -1
  10. package/docs/API_REFERENCE.md +7 -1
  11. package/docs/api/AI.md +3 -1
  12. package/docs/api/Agents.md +197 -12
  13. package/docs/api/Data.md +192 -61
  14. package/docs/api/Jobs.md +2 -0
  15. package/docs/api/LuaWebhook.md +128 -85
  16. package/docs/api/LuaWorkflow.md +15 -15
  17. package/docs/api/Orders.md +7 -5
  18. package/docs/api/Products.md +1 -1
  19. package/docs/api/Progress.md +57 -0
  20. package/docs/api/Threads.md +122 -0
  21. package/docs/api/User.md +2 -2
  22. package/docs/api/Workflows.md +22 -1
  23. package/docs/workflows/approvals.md +4 -0
  24. package/docs/workflows/coding-harness.md +27 -1
  25. package/docs/workflows/reply-channels.md +2 -2
  26. package/docs/workflows/workspaces-and-long-steps.md +3 -1
  27. package/package.json +2 -1
  28. package/scripts/generate-catalog.lib.ts +813 -0
  29. package/scripts/generate-catalog.ts +94 -0
  30. package/template/package.json +1 -1
  31. package/template/tsconfig.json +1 -1
  32. package/template-web-app/app.ts +29 -0
  33. package/template-web-app/web/index.html +12 -0
  34. package/template-web-app/web/package.json +27 -0
  35. package/template-web-app/web/src/App.tsx +28 -0
  36. package/template-web-app/web/src/index.css +3 -0
  37. package/template-web-app/web/src/lua/client.ts +264 -0
  38. package/template-web-app/web/src/main.tsx +16 -0
  39. package/template-web-app/web/tsconfig.json +14 -0
  40. package/template-web-app/web/vite.config.ts +9 -0
@@ -31,6 +31,159 @@ 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
+ /** U9 — `{ pendingFor }` secret requests to attach to the new agent (U9 owns the attach). */
115
+ pendingSecretRequestIds?: string[];
116
+ }
117
+
118
+ /** `Agents.create` second argument: exactly one of `consentId` or `approval`. */
119
+ declare interface AgentCreateOptions {
120
+ /** The member the agent is created for; must be a member of the caller's org. */
121
+ onBehalfOf: string;
122
+ /** Minted by that member's chat confirmation (`POST /developer/agent-provisioning/consents`). */
123
+ consentId?: string;
124
+ /**
125
+ * …or the member's decision on a workflow `approval` step whose payload carries
126
+ * `{ [AGENT_PROVISIONING_APPROVAL_PAYLOAD_KEY]: AgentProvisioningApprovalPayload }` describing this create.
127
+ */
128
+ approval?: AgentCreateApprovalRef;
129
+ }
130
+
131
+ declare interface AgentCreateResult {
132
+ agentId: string;
133
+ name: string;
134
+ isPrivate: true;
135
+ createdBy: string;
136
+ connectionPolicy: AgentConnectionPolicy;
137
+ /** The scaffold backup version seeded at create (always 1). */
138
+ backupVersion: 1;
139
+ mountedConnectionIds: string[];
140
+ /** The provisioner's grant on the new agent (absent when `supervise` was empty). */
141
+ grant?: {
142
+ grantId: string;
143
+ actions: ProvisionedSupervisionAction[];
144
+ };
145
+ /** U9 — env keys attached from pending secret requests (never values). */
146
+ attachedSecretKeys?: string[];
147
+ }
148
+
149
+ /** `Agents.lifecycle(id).delete({ confirmName })` — must equal the agent's current name exactly. */
150
+ declare interface AgentDeleteInput {
151
+ confirmName: string;
152
+ }
153
+
154
+ /** How the agent is built: from a source backup, in the dashboard, or from a repo (a `commitHash` on its versions). */
155
+ declare type AgentDirectoryBuildKind = 'backup-source' | 'dashboard' | 'repo';
156
+
157
+ /**
158
+ * One agent the turn's DELEGATED user can see (same visibility as the user's own agent list: private
159
+ * agents only for their creator / agent-grant holders; PDP-checked). Metadata only.
160
+ */
161
+ declare interface AgentDirectoryEntry {
162
+ agentId: string;
163
+ name?: string;
164
+ /** The creator's user id (never their email). */
165
+ ownerUserId?: string;
166
+ isPrivate: boolean;
167
+ buildKind: AgentDirectoryBuildKind;
168
+ /**
169
+ * ISO — the latest counted activity: the newest persisted chat turn or workflow run. Job / trigger / webhook
170
+ * executions are not counted (U29 v1). When the live chat read fails the directory falls back to the nightly
171
+ * evidence rollup, and the chat half is then the UTC day of the latest exchanges.
172
+ */
173
+ lastActivityAt?: string;
174
+ /**
175
+ * Chat turns + workflow runs over the last 30 days, read live. A chat turn is a row in `chats.messages`: one
176
+ * per user turn the platform persisted, on ANY channel — production and sandbox (`lua chat -e sandbox`, the
177
+ * `dev` channel) alike. Not counted: version previews and test-session / test-traffic turns (never persisted),
178
+ * and job / trigger / webhook executions (U29 v1). A sub-agent's turns count on its own entry. `lua logs`
179
+ * counts differently (one log row per user message AND per agent response, plus tool / runtime rows), so a
180
+ * log count is typically about twice this number.
181
+ */
182
+ volume30d: number;
183
+ /** The supervision actions the CALLER already holds on it. */
184
+ callerActions: string[];
185
+ }
186
+
34
187
  /**
35
188
  * Narrowed, wire-safe output for `Agents.invoke`. A slice of the internal
36
189
  * `FullOutput` shape — raw Mastra steps / tripwire payloads are intentionally
@@ -44,7 +197,7 @@ declare interface AgentInvocationEffects {
44
197
  blocker?: TaskRunBlocker;
45
198
  }
46
199
 
47
- declare interface AgentInvocationInput {
200
+ export declare interface AgentInvocationInput {
48
201
  /** Shortcut: plain-text prompt. Mutually exclusive with `messages`. */
49
202
  prompt?: string;
50
203
  /** AI SDK `UserContent` (text/image/file parts). Mutually exclusive with `prompt`. */
@@ -271,6 +424,79 @@ declare interface AgentInvocationOutput {
271
424
  threadId?: string;
272
425
  }
273
426
 
427
+ /**
428
+ * U4b (wave 2) — archive / delete with confirmation, the owner-departure policy, and non-secret config
429
+ * writes. Owner: U4b (the ONE owner-departure hook: pause agents, suspend grants, notify org admins; U1
430
+ * only suspends grants when a provisioning policy is revoked). Contract: docs/agent-builder/wave2-contracts.md §U4b.
431
+ */
432
+ /**
433
+ * What archive and delete do (U4b spec): unmount connections (never revoke them at the provider), delete
434
+ * the agent's secrets, cancel its runs, revoke grants on it, and keep external records.
435
+ */
436
+ declare interface AgentLifecycleResult {
437
+ agentId: string;
438
+ action: 'archive' | 'delete';
439
+ unmountedConnectionIds: string[];
440
+ deletedSecretKeys: number;
441
+ cancelledRunIds: string[];
442
+ /** The supervision grants revoked: every one ON the agent and every one it held on other agents. */
443
+ revokedGrantIds: string[];
444
+ /** Member access grants (roster and org-wide) the archive revoked or suspended; counted, not listed. */
445
+ memberGrantsRevoked?: number;
446
+ /** ISO. When the agent was archived (a re-archive keeps the first date). */
447
+ archivedAt?: string;
448
+ /**
449
+ * ISO. When the purge sweep may hard-delete the agent's Lua-held data. `archive` keeps the 30-day grace
450
+ * (`restore` works until then); `delete` sets it to now, so the agent cannot be restored.
451
+ */
452
+ purgeAfter?: string;
453
+ /** True when the agent was already archived (a race with another archive) and this call re-ran the teardown. */
454
+ resumed?: boolean;
455
+ /**
456
+ * Best-effort steps that did not complete (channel teardown, a run cancel, an unmount…). The call also revokes the
457
+ * caller's own grant on the agent, so a supervisor cannot re-run it: finishing a partial teardown (or deleting an
458
+ * already-archived agent) is a staff action.
459
+ */
460
+ warnings?: string[];
461
+ }
462
+
463
+ /** `Agents.metrics(id).query(...)` and the owners' REST twin. */
464
+ export declare interface AgentMetricQueryInput {
465
+ /** A recorded metric name, or … */
466
+ name?: string;
467
+ /** … an objective (its metric definition is resolved server-side). */
468
+ objectiveId?: string;
469
+ /** ISO. */
470
+ from: string;
471
+ /** ISO. */
472
+ to: string;
473
+ interval: '1h' | '1d';
474
+ /**
475
+ * How each bucket reduces (added by U30): default `sum` for a name, the objective's own aggregation for an
476
+ * `objectiveId`. Buckets show the mean for `p50` / `p95` (percentiles are window-level, see the evaluator).
477
+ */
478
+ aggregation?: AgentObjectiveAggregation;
479
+ }
480
+
481
+ export declare interface AgentMetricQueryResult {
482
+ name: string;
483
+ interval: '1h' | '1d';
484
+ series: Array<{
485
+ tags: Record<string, string>;
486
+ points: Array<{
487
+ t: string;
488
+ value: number;
489
+ count: number;
490
+ }>;
491
+ }>;
492
+ }
493
+
494
+ export declare interface AgentMetricRecordReceipt {
495
+ accepted: boolean;
496
+ /** Present when `accepted: false`. */
497
+ code?: string;
498
+ }
499
+
274
500
  /**
275
501
  * Per-agent LLM call settings PLUS normalized reasoning config. The
276
502
  * `CallSettings` leafs (`temperature`, `topP`, …) map directly onto Mastra's
@@ -320,6 +546,90 @@ export declare interface AgentModelSettings {
320
546
  };
321
547
  }
322
548
 
549
+ /** One objective (agents DB `agentObjectives`). Only `active` objectives are evaluated and can breach. */
550
+ export declare interface AgentObjective {
551
+ id: string;
552
+ agentId: string;
553
+ statement: string;
554
+ metric: AgentObjectiveMetric;
555
+ baseline?: number;
556
+ target?: number;
557
+ guardrails: AgentObjectiveGuardrail[];
558
+ confidence: 'low' | 'medium' | 'high';
559
+ status: AgentObjectiveStatus;
560
+ /** `user:<id>` or `service:agent:<id>` (a supervisor's proposal). */
561
+ proposedBy: string;
562
+ /** The OWNER who confirmed it (absent while `proposed`). */
563
+ confirmedBy?: string;
564
+ confirmedAt?: string;
565
+ lastEvaluatedAt?: string;
566
+ lastValue?: number;
567
+ /**
568
+ * A supervisor's `update` / `retire` proposal (U30): a separate `proposed` row that names the objective it
569
+ * would change. The target objective is untouched until the owner confirms this row; confirming applies
570
+ * `patch` (or retires the target) and marks this row `retired`. Absent on `create` proposals and owner rows.
571
+ */
572
+ pendingChange?: AgentObjectivePendingChange;
573
+ createdAt: string;
574
+ updatedAt: string;
575
+ }
576
+
577
+ /**
578
+ * How a window's points reduce to one value. `rate` is the mean of the recorded values (for 0/1 outcome
579
+ * metrics: the success rate); `p50` / `p95` are over at most the newest 10,000 points in the window.
580
+ */
581
+ declare type AgentObjectiveAggregation = 'count' | 'sum' | 'avg' | 'rate' | 'p50' | 'p95' | 'min' | 'max';
582
+
583
+ export declare interface AgentObjectiveGuardrail {
584
+ id: string;
585
+ metric: AgentObjectiveMetric;
586
+ op: 'lt' | 'lte' | 'gt' | 'gte';
587
+ value: number;
588
+ }
589
+
590
+ /**
591
+ * What an objective measures. `definition` is source-specific and validated server-side: `custom` = a
592
+ * `Metrics.record` name; `runs` = `{ workflowId?, status? }`; `logs` = `{ level?, logSource? }`; `evals` =
593
+ * `{ suiteKey | monitorKey }`; `data` = `{ collection, filter }` (read through the owner's Data).
594
+ */
595
+ export declare interface AgentObjectiveMetric {
596
+ source: AgentObjectiveMetricSource;
597
+ definition: Record<string, unknown> | string;
598
+ aggregation: AgentObjectiveAggregation;
599
+ window: AgentObjectiveWindow;
600
+ }
601
+
602
+ declare type AgentObjectiveMetricSource = 'logs' | 'runs' | 'evals' | 'data' | 'custom';
603
+
604
+ /** The fields an owner `PATCH` (or a confirmed `update` proposal) may change. */
605
+ declare type AgentObjectivePatch = Partial<Pick<AgentObjective, 'statement' | 'metric' | 'baseline' | 'target' | 'guardrails' | 'confidence'>>;
606
+
607
+ declare type AgentObjectivePendingChange = {
608
+ op: 'update';
609
+ objectiveId: string;
610
+ patch: AgentObjectivePatch;
611
+ } | {
612
+ op: 'retire';
613
+ objectiveId: string;
614
+ };
615
+
616
+ /** `objectives.propose` (supervisor, `act`): never effective until the owner confirms. */
617
+ export declare type AgentObjectiveProposal = {
618
+ op: 'create';
619
+ objective: Omit<AgentObjective, 'id' | 'agentId' | 'status' | 'proposedBy' | 'createdAt' | 'updatedAt'>;
620
+ } | {
621
+ op: 'update';
622
+ objectiveId: string;
623
+ patch: AgentObjectivePatch;
624
+ } | {
625
+ op: 'retire';
626
+ objectiveId: string;
627
+ };
628
+
629
+ export declare type AgentObjectiveStatus = (typeof AGENT_OBJECTIVE_STATUSES)[number];
630
+
631
+ declare type AgentObjectiveWindow = '1d' | '7d' | '30d';
632
+
323
633
  export declare const Agents: AgentsApi;
324
634
 
325
635
  /**
@@ -406,6 +716,79 @@ export declare interface AgentsApi {
406
716
  promote(version: number, opts: {
407
717
  expectActive: number | null;
408
718
  }): Promise<unknown>;
719
+ /**
720
+ * Soft-delete `version` (`supervision:release`; only from a named workflow step). Refused
721
+ * (409 `supervision_version_not_superseded`) unless the version is `superseded` — never the
722
+ * active version, never the last one.
723
+ */
724
+ delete(version: number): Promise<{
725
+ deleted: true;
726
+ version: number;
727
+ }>;
728
+ /**
729
+ * Open a TEST SESSION on staged `opts.version` (`supervision:preview`, U11 / DOC2 §6.1): multi-turn chat and
730
+ * fire against the staged version with side effects recorded instead of executed. A supervisor session runs
731
+ * with no tools (the preview posture) and never gets `egress: 'live'`.
732
+ */
733
+ session(opts: TestSessionOpenInput): Promise<{
734
+ sessionId: string;
735
+ version: number;
736
+ session: TestSessionRecord;
737
+ chat(input: string | {
738
+ prompt?: string;
739
+ messages?: unknown[];
740
+ threadId?: string;
741
+ }): Promise<{
742
+ sessionId: string;
743
+ threadId: string;
744
+ version: number;
745
+ text: string;
746
+ toolsUsed: string[];
747
+ }>;
748
+ fire(input: TestSessionFireInput): Promise<unknown>;
749
+ effects(): Promise<{
750
+ effects: TestSessionEffect[];
751
+ }>;
752
+ close(): Promise<{
753
+ id: string;
754
+ status: 'closed';
755
+ shadowPurged: boolean;
756
+ }>;
757
+ }>;
758
+ };
759
+ /** A workflow of the target: read it (`supervision:observe`), create and release it (`supervision:release`). */
760
+ workflows(agentId: string): {
761
+ /**
762
+ * The workflow's live `activeVersionId` (the value `deploy` takes as `expectActive`; null = none live) and
763
+ * its newest 20 versions — metadata only (`supervision:observe`).
764
+ */
765
+ get(workflowId: string): Promise<SupervisedWorkflow>;
766
+ /**
767
+ * Create workflow `name` on the target, or answer the one a previous `create` made (`created: false`), so a
768
+ * retried release step converges; a person's or a chat-composed workflow of that name is a 409
769
+ * `WORKFLOW_NAME_TAKEN`. INERT: inactive, no version; `push` then adds an inactive version and `deploy`
770
+ * (with `expectActive: null`) publishes it. It has no human author (what you write never runs as a person),
771
+ * so a SCHEDULED version on it is refused at deploy (`WORKFLOW_SCHEDULE_OWNER_UNKNOWN`); start it from a
772
+ * trigger or `Workflows.start` instead. Release-bound like `push` / `deploy` (`supervision:release`).
773
+ */
774
+ create(name: string, opts?: {
775
+ description?: string;
776
+ form?: 'graph' | 'script';
777
+ }): Promise<SupervisedWorkflowCreated>;
778
+ /**
779
+ * Push a new version of workflow `workflowId` (the same body `lua push workflow` sends). The version is
780
+ * NEVER activated: `activate` is forced to `false`. Deploy it with `deploy`.
781
+ */
782
+ push(workflowId: string, definition: Record<string, unknown>): Promise<unknown>;
783
+ /**
784
+ * Publish workflow `version` (a semver). Compare-and-swap: refused (409 `WORKFLOW_DEPLOY_CONFLICT`, the
785
+ * message names the live version) unless `expectActive` is the workflow's live version ID (null = none live).
786
+ * A deploy also records a new active agent version, so a later `versions.promote` needs a fresh
787
+ * `expectActive`.
788
+ */
789
+ deploy(workflowId: string, version: string, opts: {
790
+ expectActive: string | null;
791
+ }): Promise<unknown>;
409
792
  };
410
793
  persona(agentId: string): {
411
794
  versions(): Promise<unknown>;
@@ -433,6 +816,253 @@ export declare interface AgentsApi {
433
816
  keys: string[];
434
817
  }>;
435
818
  };
819
+ /**
820
+ * Supervision events of the target (`supervision:observe`). Each event of a subscribed kind
821
+ * (`governance.blocked`, `workflow.run_failed`, `workflow.run_gated`, `connection.unhealthy`, …)
822
+ * starts one of YOUR agent's triggers, `triggerName`, with a
823
+ * `SupervisionEventEnvelope` body (`source: 'supervision'`). The grant is re-checked on every
824
+ * delivery: a revoked grant stops the events. Not available offline.
825
+ */
826
+ events(agentId: string): {
827
+ /** Upsert by `triggerName` (one of your own triggers); at most 10 per supervised agent. */
828
+ subscribe(opts: {
829
+ kinds: SupervisionEventKind[];
830
+ triggerName: string;
831
+ }): Promise<SupervisionEventSubscription>;
832
+ unsubscribe(triggerName: string): Promise<{
833
+ removed: boolean;
834
+ }>;
835
+ /** Your own subscriptions on this agent. */
836
+ list(): Promise<SupervisionEventSubscription[]>;
837
+ };
838
+ /**
839
+ * Create a PRIVATE agent for a member of your organization (`onBehalfOf`), owned by them. Needs the org's
840
+ * agent-provisioning policy to name your agent, and the member's consent — exactly one of:
841
+ * - `consentId`: from their chat confirmation (single use, 10 minutes);
842
+ * - `approval: { runId, stepId }`: the member approved an `approval` step of YOUR workflow run. The step before
843
+ * the approval outputs EXACTLY `{ agentProvisioning: { name, model, supervise, connections, releaseWorkflowIds,
844
+ * pendingSecretRequestIds } }` (the approval's payload; no other key — the platform renders the card from it),
845
+ * the approval is `approver: 'creator'` and is not editable, and a later code step calls `Agents.create` with
846
+ * exactly that input, `runId: ctx.runId` and `stepId` = the approval step's id as stored (`confirm`; inside a
847
+ * loop / foreach `confirm#n` / `confirm[i]`), or `approvalId` when you hold the `wfa_…` id. The run must have
848
+ * been started by the member and still be running, and the member must have approved in their own signed-in
849
+ * session (Lua Desktop / the inbox — not a chat card, a channel reply or an API key) within the last 10
850
+ * minutes; each approval creates one agent. Set no `details` on the approval, or details equal in shape to the
851
+ * payload. Call it from a regular code step (not `tier: 'job'`); graph workflows only.
852
+ * The policy bounds the model, how many agents a member may hold and the supervision actions (`supervise`) your
853
+ * agent gets on the new one. Refused offline (`supervision_offline_unsupported`) and while the platform has
854
+ * provisioning disabled (`agent_provisioning_disabled`).
855
+ *
856
+ * @example
857
+ * ```typescript
858
+ * const created = await Agents.create(
859
+ * { name: 'Inbox helper', model: 'google/gemini-2.5-flash', supervise: ['observe'] },
860
+ * { onBehalfOf: userId, consentId }
861
+ * );
862
+ * ```
863
+ *
864
+ * @example
865
+ * ```typescript
866
+ * // A workflow the member starts (e.g. from chat): plan → confirm (the member approves) → create.
867
+ * const plan = { name: 'Inbox helper', model: 'google/gemini-2.5-flash', supervise: ['observe' as const] };
868
+ * const propose = createStep({
869
+ * id: 'propose', inputSchema: z.object({ memberId: z.string() }), outputSchema: z.any(),
870
+ * execute: async () => ({ agentProvisioning: plan }), // the approval's payload: what the member sees
871
+ * });
872
+ * const create = createStep({
873
+ * id: 'create', inputSchema: z.any(), outputSchema: z.any(),
874
+ * execute: async (ctx) => {
875
+ * if (!ctx.inputData.approved) return { created: false };
876
+ * return Agents.create(plan, {
877
+ * onBehalfOf: ctx.getInitData<{ memberId: string }>().memberId, // must be the run's creator
878
+ * approval: { runId: ctx.runId, stepId: 'confirm' },
879
+ * });
880
+ * },
881
+ * });
882
+ * createWorkflow({ ... })
883
+ * .then(propose)
884
+ * .approval('confirm', { title: 'Create “Inbox helper” for you?', approver: 'creator' })
885
+ * .then(create)
886
+ * .commit();
887
+ * ```
888
+ */
889
+ create(input: AgentCreateInput, opts: AgentCreateOptions): Promise<AgentCreateResult>;
890
+ /**
891
+ * The supervised agent's connections (`supervision:observe`): what `Integrations.list()` shows, without
892
+ * any person's identity (no owner user ids; no account identity on personal connections), and READ
893
+ * catalogue checks only — a check that writes is refused.
894
+ */
895
+ integrations(agentId: string): {
896
+ list(): Promise<IntegrationConnectionSummary[]>;
897
+ check(connectionId: string, check: ConnectionCheckName): Promise<ConnectionCheckOutcome>;
898
+ };
899
+ /**
900
+ * Metrics the target recorded with `Metrics.record` (`supervision:observe`): one `name` (or the metric of one
901
+ * `objectiveId`), bucketed by `1h` (≤ 7 days) or `1d` (≤ 400 days).
902
+ */
903
+ metrics(agentId: string): {
904
+ query(q: AgentMetricQueryInput): Promise<AgentMetricQueryResult>;
905
+ };
906
+ /**
907
+ * The target's objectives. `list` (`supervision:observe`) shows confirmed and proposed ones; `propose`
908
+ * (`supervision:act`) adds a `proposed` create / update / retire that takes effect ONLY when the agent's owner
909
+ * confirms it. Offline, `list` reads with your developer credential and `propose` is refused.
910
+ */
911
+ objectives(agentId: string): {
912
+ list(opts?: {
913
+ status?: AgentObjectiveStatus;
914
+ }): Promise<AgentObjective[]>;
915
+ propose(proposal: AgentObjectiveProposal): Promise<AgentObjective>;
916
+ };
917
+ /**
918
+ * The target's advisory change lease. A lease never blocks anyone's push: the agent's humans see it
919
+ * (`lua push` / `lua status` print a warning, and the dashboard shows it) and another supervisor cannot take
920
+ * it while it is live. Use it to say "I am working on this agent until …".
921
+ *
922
+ * @example
923
+ * ```typescript
924
+ * const { lease, lastHumanChangeAt } = await Agents.lease(agentId).get();
925
+ * // Back off while a person changed the agent in the last hour.
926
+ * if (lastHumanChangeAt && Date.now() - Date.parse(lastHumanChangeAt) < 3_600_000) return;
927
+ * await Agents.lease(agentId).acquire({ ttlMinutes: 30, reason: 'Tuning the refund skill' });
928
+ * // ... change the agent ...
929
+ * await Agents.lease(agentId).release();
930
+ * ```
931
+ */
932
+ lease(agentId: string): {
933
+ /**
934
+ * The live lease (null when none, or expired) and when a human (`lastHumanChangeAt`) or a supervisor agent
935
+ * (`lastAgentChangeAt`) last created or promoted a version or pushed the source (`supervision:observe`).
936
+ */
937
+ get(): Promise<AgentChangeActivity>;
938
+ /**
939
+ * Take the lease for YOUR agent, or renew the one you hold (`supervision:act`). `ttlMinutes` is 1-240,
940
+ * `reason` (at most 300 characters) is shown to the agent's humans. Refused (409 `change_lease_held`) while
941
+ * another agent's lease is live. Not available offline.
942
+ */
943
+ acquire(opts: {
944
+ ttlMinutes: number;
945
+ reason: string;
946
+ }): Promise<AgentChangeLease>;
947
+ /** Drop the lease you hold (`supervision:act`); `released: false` when you hold none. Not available offline. */
948
+ release(): Promise<{
949
+ released: boolean;
950
+ }>;
951
+ };
952
+ /**
953
+ * Archive or delete a supervised agent (`supervision:act`, on a grant written by an org owner or by the agent's
954
+ * creator). Both remove its connections from the agent without revoking them at the provider, delete its
955
+ * secrets (env), cancel its workflow runs and revoke every grant on it, yours included (so you cannot call it twice
956
+ * on the same agent: archive OR delete, and `warnings` lists anything staff must finish); records outside Lua are
957
+ * kept. Archive is reversible by staff for 30 days; `delete` needs the agent's exact current name and cannot be
958
+ * undone.
959
+ * Refused offline and while the platform has it disabled (`supervised_lifecycle_disabled`).
960
+ *
961
+ * @example
962
+ * ```typescript
963
+ * await Agents.lifecycle(agentId).delete({ confirmName: 'Old intake bot' });
964
+ * ```
965
+ */
966
+ lifecycle(agentId: string): {
967
+ archive(): Promise<AgentLifecycleResult>;
968
+ delete(opts: AgentDeleteInput): Promise<AgentLifecycleResult>;
969
+ };
970
+ /**
971
+ * Change a supervised agent's settings (`supervision:act`): its model, its name, or NON-secret env keys (merged;
972
+ * other keys untouched). A key ending SECRET, TOKEN, KEY or PASSWORD refuses the whole call
973
+ * (`agent_config_secret_key_refused`): secrets are set by the agent's owner. Refused offline.
974
+ */
975
+ config(agentId: string): {
976
+ set(input: AgentConfigSetInput): Promise<AgentConfigSetResult>;
977
+ };
978
+ /**
979
+ * Agents the DELEGATED user of the current turn can see (private agents only for their owner or agent-grant
980
+ * holders), with owner, privacy, build kind, last activity, 30-day volume and the actions you hold on each.
981
+ * Refused with `agent_directory_requires_user` on a turn with no user (or a user outside your org), a turn
982
+ * whose user an invoking agent chose, code in a Job or workflow run, and any turn invoked onward from those.
983
+ */
984
+ directory(): Promise<AgentDirectoryEntry[]>;
985
+ /**
986
+ * Ask for supervision actions on `agentId`. The request goes to the owner of a private agent, or to the org
987
+ * admins / agent builders of a shared one, as an inbox card; approving creates the grant (expiring at
988
+ * `expiresAt`, when given). One pending request per agent; a pending request lapses after 7 days. Refused
989
+ * with `supervision_access_no_approver` when nobody can approve (a departed owner, no admin / builder).
990
+ *
991
+ * Where the platform enables them, a request may also name `releaseWorkflowIds` / `unattendedWorkflowIds` (YOUR
992
+ * own workflows: release only ever happens in those workflows' code steps) and `dataCollections`
993
+ * (`supervision_access_bindings_disabled` otherwise), and `notifyOwner: true` (the owner opts in to `notifyOwner` by
994
+ * approving it). When you already hold a grant on the agent, the request UPGRADES it: the approver sees exactly
995
+ * what is added (`adds`), nothing is ever removed, and approval is refused (`supervision_access_grant_changed`) if
996
+ * your access changed after you asked (`supervision_access_upgrades_disabled` / `_grant_exists` where off).
997
+ */
998
+ requestAccess(agentId: string, opts: SupervisionAccessRequestInput): Promise<SupervisionAccessRequest>;
999
+ /** Your own access requests, newest first (at most 50). */
1000
+ accessRequests(): Promise<SupervisionAccessRequest[]>;
1001
+ /** Withdraw one of your own pending requests. */
1002
+ cancelAccessRequest(requestId: string): Promise<SupervisionAccessRequest>;
1003
+ /**
1004
+ * Eval suites of a supervised agent (U12). Reads need `supervision:observe`; `run` and `cancel` need
1005
+ * `supervision:preview`. `run` executes a STAGED (unpromoted) version — or `'active'` — against a suite the agent's
1006
+ * owner defined, isolated from live tools unless the owner opted some in. Bounded by the suite budget, the agent's
1007
+ * monthly eval allowance and a per-day cap of supervised runs per agent (`supervision_eval_runs_rate_limited`).
1008
+ * Per-check `detail`, the judge's `reasoning` and transcripts need `observe-content`. `cancel` stops only runs you
1009
+ * started, and works even after the platform turns evals or preview off. Suites are written by the owner
1010
+ * (`lua evals push`), never by a supervisor. Off until the platform enables evals (`agent_evals_disabled`).
1011
+ * Offline (`lua test`): reads use your developer credential; `run` / `cancel` are refused.
1012
+ *
1013
+ * @example
1014
+ * ```typescript
1015
+ * const { runId } = await Agents.evals(agentId).run({ suite: 'release-gate', version: staged });
1016
+ * const run = await Agents.evals(agentId).getRun(runId); // poll (or wait in a workflow step) until it finishes
1017
+ * if (run.passed === false) { ... }
1018
+ * ```
1019
+ */
1020
+ evals(agentId: string): {
1021
+ suites(): Promise<Array<{
1022
+ key: string;
1023
+ revision: number;
1024
+ caseCount: number;
1025
+ minPassRate: number;
1026
+ updatedAt?: string;
1027
+ }>>;
1028
+ suite(key: string): Promise<EvalSuite>;
1029
+ run(opts: {
1030
+ suite: string;
1031
+ version: number | 'active';
1032
+ maxCredits?: number;
1033
+ caseIds?: string[];
1034
+ }): Promise<EvalRunReceipt>;
1035
+ runs(opts?: {
1036
+ suite?: string;
1037
+ version?: number;
1038
+ status?: string;
1039
+ limit?: number;
1040
+ before?: string;
1041
+ }): Promise<EvalSuiteRunSummary[]>;
1042
+ getRun(runId: string): Promise<EvalSuiteRunSummary>;
1043
+ transcript(runId: string, caseId: string): Promise<EvalCaseTranscript>;
1044
+ cancel(runId: string): Promise<EvalSuiteRunSummary>;
1045
+ };
1046
+ /**
1047
+ * Message the OWNER of a supervised agent: a plain message (no model turn) in their home thread with YOUR agent,
1048
+ * from any run — a schedule or an event trigger included, not only your own notify list. Needs `supervision:observe`
1049
+ * and the owner's opt-in on your grant (they approved a `requestAccess({ notifyOwner: true })` themselves, or turned
1050
+ * it on from the agent's supervisors list). Refused `supervision_owner_notify_not_opted_in` otherwise, and when the
1051
+ * agent changed owner or the owner left. Shares `Threads.followUp`'s rate limits. Off until the platform enables it
1052
+ * (`supervision_owner_notify_disabled`); not available offline.
1053
+ *
1054
+ * Pass an optional `idempotencyKey` (1-256 characters) to make retries safe: a second call from your agent with the
1055
+ * same key within 24 hours posts nothing and resolves the FIRST call's receipt (same `followUpId` and `threadId`).
1056
+ * A duplicate sent while the first is still posting waits for it, or is refused `thread_follow_up_in_progress`
1057
+ * (retry it). A key already used for ANOTHER target agent is refused `supervision_owner_notify_invalid`. At most
1058
+ * once unless the platform's key store fails mid-delivery. Without a key every call posts.
1059
+ *
1060
+ * @example
1061
+ * ```typescript
1062
+ * await Agents.notifyOwner(targetId, { message: 'Lead Desk is failing', idempotencyKey: `incident-${incidentId}` });
1063
+ * ```
1064
+ */
1065
+ notifyOwner(agentId: string, input: SupervisionOwnerNotifyInput): Promise<SupervisionOwnerNotifyReceipt>;
436
1066
  }
437
1067
 
438
1068
  export declare interface AgentStepOptions {
@@ -557,16 +1187,30 @@ export declare interface AiApi {
557
1187
  generate(prompt: string, content?: UserContent): Promise<string>;
558
1188
  /**
559
1189
  * Generate text with full options — a serializable subset of `generateText`
560
- * (`model`, `system`, `prompt`, `messages`, `temperature`, `maxOutputTokens`).
1190
+ * (`model`, `system`, `prompt`, `messages`, `temperature`, `maxOutputTokens`,
1191
+ * `structuredOutput`, `reasoning`).
561
1192
  * Returns the full AI SDK–aligned result including `text`, `finishReason`, `usage`,
562
1193
  * `sources` (Google Search grounding), `reasoning`, `warnings`, and more.
563
1194
  *
1195
+ * `reasoning` takes the same `{ effort?, show? }` as an agent's `modelSettings.reasoning`:
1196
+ * `effort` (`'off' | 'minimal' | 'low' | 'medium' | 'high' | 'max'`) is translated for the
1197
+ * model's provider and clamped to the levels that model supports; `show: false` omits
1198
+ * `reasoning` / `reasoningText` from the result (the count stays on `usage.reasoningTokens`).
1199
+ * The call's `reasoning` outranks the model's catalog default. The agent's own
1200
+ * `modelSettings.reasoning` is not applied to `AI.generate`.
1201
+ *
564
1202
  * @example
565
1203
  * ```typescript
566
1204
  * const { text, finishReason, usage, sources } = await AI.generate({
567
1205
  * system: 'You are concise.',
568
1206
  * prompt: 'Say hi.',
569
1207
  * });
1208
+ *
1209
+ * // Think harder, but keep the trace out of the result.
1210
+ * const { text: plan } = await AI.generate({
1211
+ * prompt: 'Plan the migration in five steps.',
1212
+ * reasoning: { effort: 'high', show: false },
1213
+ * });
570
1214
  * ```
571
1215
  */
572
1216
  generate(options: AiGenerateInput): Promise<AiGenerateOutput>;
@@ -584,6 +1228,11 @@ export declare interface AiGenerateInput {
584
1228
  messages?: ModelMessage[];
585
1229
  temperature?: number;
586
1230
  maxOutputTokens?: number;
1231
+ /**
1232
+ * Reasoning effort / visibility — the same shape and semantics as an agent's
1233
+ * `modelSettings.reasoning` (see {@link AiGenerateReasoningOptions}).
1234
+ */
1235
+ reasoning?: AiGenerateReasoningOptions;
587
1236
  /**
588
1237
  * When set, constrains the response to match the JSON Schema. The parsed result
589
1238
  * lands on `AiGenerateOutput.output`. Mirrors AI SDK `Output.object({ schema })`.
@@ -599,6 +1248,19 @@ export declare interface AiGenerateInput {
599
1248
  */
600
1249
  export declare type AiGenerateJsonSchema = Record<string, unknown>;
601
1250
 
1251
+ /**
1252
+ * Why the served model differs from the requested one:
1253
+ * - `not-approved`: the resolved model (the agent's own pin, when the call named none) is not in the model
1254
+ * catalogue, so the platform default ran. A model the CALLER names is never swapped this way on
1255
+ * `AI.generate` — it is refused with a 400 `MODEL_NOT_AVAILABLE` instead.
1256
+ * - `provider-unavailable`: the requested model's provider failed transiently and a fallback leg served.
1257
+ */
1258
+ declare interface AiGenerateModelFallback {
1259
+ requestedModel: string;
1260
+ servedModel: string;
1261
+ reason: 'not-approved' | 'provider-unavailable';
1262
+ }
1263
+
602
1264
  /**
603
1265
  * Wire-format output from `AI.generate` / `POST .../generate`.
604
1266
  * Fields mirror AI SDK `GenerateTextResult` — uses AI SDK types where exported.
@@ -627,8 +1289,29 @@ export declare interface AiGenerateOutput {
627
1289
  output?: unknown;
628
1290
  /** Provider warnings (e.g. unsupported settings) — AI SDK `CallWarning[]` */
629
1291
  warnings?: CallWarning[];
1292
+ /**
1293
+ * The model that actually produced `text` (`provider/model`). Present on every response from builds that
1294
+ * report it; absent only from older servers.
1295
+ */
1296
+ model?: string;
1297
+ /** Present only when `model` is NOT the model the call resolved to — see {@link AiGenerateModelFallback}. */
1298
+ modelFallback?: AiGenerateModelFallback;
630
1299
  }
631
1300
 
1301
+ /**
1302
+ * Reasoning options for `AI.generate` — the same shape and semantics as an agent's
1303
+ * `modelSettings.reasoning` (and the chat request's `options.reasoning`):
1304
+ *
1305
+ * - `effort` — `'off' | 'minimal' | 'low' | 'medium' | 'high' | 'max'`, translated per
1306
+ * provider (Anthropic `thinking`, OpenAI `reasoningEffort`, Gemini `thinkingConfig`, …)
1307
+ * and clamped to the levels the served model supports, exactly as on an agent turn.
1308
+ * Unset = the model's catalog default.
1309
+ * - `show` — whether the reasoning trace is returned. `false` asks the provider to omit
1310
+ * its summaries AND drops `reasoning` / `reasoningText` from the response (the token
1311
+ * count stays on `usage.reasoningTokens`). Default `true`.
1312
+ */
1313
+ export declare type AiGenerateReasoningOptions = ModelReasoningOptions;
1314
+
632
1315
  /**
633
1316
  * URL source from Google Search grounding.
634
1317
  * Mirrors `LanguageModelV2Source` (AI SDK `Source` type — not exported from `ai` as of v5).
@@ -751,6 +1434,14 @@ export declare interface ApprovalOptions {
751
1434
  fourEyes?: WorkflowFourEyes;
752
1435
  /** default 168; a binding is resolved at suspend time and must yield 1..720 */
753
1436
  timeoutHours?: number | TemplateBinding;
1437
+ /**
1438
+ * Re-send the approval push to the approvers who have not decided yet, every `remindAfterHours` hours while the
1439
+ * approval is pending — at most 3 reminders per ask (an escalation hop starts a new ask), and never after the
1440
+ * deadline. A plain number in 1..720 (no binding); a value at or above a numeric `timeoutHours` never fires (a
1441
+ * push warning). Absent ⇒ no reminder. Reminders ride the approval push, so they reach the approvers an agent's
1442
+ * approval routing names (Settings → Approvals); they are sent on the platform's sweep cadence.
1443
+ */
1444
+ remindAfterHours?: number;
754
1445
  /** 'deny' (default) | 'cancel-run' | 'fail' | a chain of ≤ 3 hops ending in one terminal member */
755
1446
  onTimeout?: WorkflowSuspendTimeoutChain;
756
1447
  /** default 'continue' (denial is data unless 'fail') */
@@ -1060,7 +1751,7 @@ export declare enum BasketStatus {
1060
1751
  * Per-agent message batching/debounce configuration.
1061
1752
  * Overrides platform-wide env var defaults for this specific agent.
1062
1753
  */
1063
- declare interface BatchingConfig {
1754
+ export declare interface BatchingConfig {
1064
1755
  /** Hold first message N ms before processing, to allow rapid follow-ups to batch together. 0 = disabled. */
1065
1756
  firstMessageDelayMs?: number;
1066
1757
  /** Window to collect subsequent messages while one is in-flight (ms). 0 = batching disabled. */
@@ -1089,7 +1780,7 @@ declare interface BatchingConfig {
1089
1780
  * local browser (desktop) or the Browser-Use cloud fallback. The object form
1090
1781
  * adds optional policy.
1091
1782
  */
1092
- declare interface BrowserSwitchConfig {
1783
+ export declare interface BrowserSwitchConfig {
1093
1784
  /** Preferred engine; 'auto' lets the platform pick local (desktop) vs cloud. */
1094
1785
  engine?: 'auto' | 'browser-use' | 'agent-browser';
1095
1786
  /** Egress allowlist — domains the browser may navigate/sub-request. */
@@ -1175,10 +1866,6 @@ export declare const CDN: {
1175
1866
  get(fileId: string): Promise<File>;
1176
1867
  };
1177
1868
 
1178
- /**
1179
- * Lua Runtime Interfaces
1180
- * Request-level runtime information available in the execution sandbox
1181
- */
1182
1869
  /**
1183
1870
  * Channel type.
1184
1871
  * Represents the communication channel through which a request originated.
@@ -1188,7 +1875,7 @@ export declare type Channel = 'web' | 'whatsapp' | 'facebook' | 'instagram' | 's
1188
1875
 
1189
1876
  /** Channels accepted by the v1 unified send. Warm-only channels (teams,
1190
1877
  * instagram, messenger) require a prior inbound conversation. */
1191
- export declare const CHANNEL_SEND_CHANNELS: readonly ["whatsapp", "sms", "email", "webchat", "teams", "instagram", "messenger"];
1878
+ export declare const CHANNEL_SEND_CHANNELS: readonly ["whatsapp", "sms", "email", "webchat", "teams", "instagram", "messenger", "slack"];
1192
1879
 
1193
1880
  export declare const Channels: ChannelsApi;
1194
1881
 
@@ -1238,6 +1925,16 @@ export declare const Channels: ChannelsApi;
1238
1925
  * to: { conversationId: '19:9495c339...@thread.v2' },
1239
1926
  * text: 'Sample LOT-4471 is missing origin and cupping score.',
1240
1927
  * });
1928
+ *
1929
+ * // Reply in a Slack thread through the agent's own bot (the bot must be in the channel)
1930
+ * await Channels.send({
1931
+ * channel: 'slack',
1932
+ * to: { conversationId: 'C0123ABCDEF:1712345678.000100' },
1933
+ * text: 'The overnight load finished with 3 warnings.',
1934
+ * });
1935
+ *
1936
+ * // DM a person on Slack, found by their email in the bot's workspace
1937
+ * await Channels.send({ channel: 'slack', to: { email: 'pat@acme.co' }, text: 'Your report is ready.' });
1241
1938
  * ```
1242
1939
  */
1243
1940
  export declare interface ChannelsApi {
@@ -1246,9 +1943,15 @@ export declare interface ChannelsApi {
1246
1943
  * Returns `ChannelSendOutput` — check `persisted` if memory durability matters.
1247
1944
  *
1248
1945
  * Address a person with `userId` (any channel), `phoneNumber` (whatsapp/sms)
1249
- * or `email`. Address a shared conversation with `conversationId` (teams
1250
- * only) — everyone in it receives the message, and because there is no single
1251
- * recipient the send returns `persisted: false`.
1946
+ * or `email` (email, slack). Address a conversation with `conversationId`
1947
+ * (teams, slack) — everyone in it receives the message. It is recorded in the
1948
+ * room that mirrors the conversation when the agent has one; otherwise the send
1949
+ * returns `persisted: false`.
1950
+ *
1951
+ * Slack `conversationId` forms: `Lua.request.conversation.externalId`, a channel
1952
+ * id (`C…`, top level), `C…:threadTs` (a reply in that thread), a member id
1953
+ * (`U…`, their DM with the bot) or 2–8 member ids (`U…,U…`, a group DM). With
1954
+ * more than one Slack connection, pass `options.channelIdentifier` (`T…-A…`).
1252
1955
  *
1253
1956
  * @example
1254
1957
  * ```typescript
@@ -1294,6 +1997,25 @@ export declare interface ChannelsApi {
1294
1997
  * ```
1295
1998
  */
1296
1999
  sendReaction(input: WhatsAppReactionSendInput): Promise<ChannelSendOutput>;
2000
+ /**
2001
+ * Ask a WhatsApp user to share their phone number. WhatsApp shows `text`
2002
+ * with a share button. If they tap it, their own number is saved on their
2003
+ * profile (when it has none) and is in `user._luaProfile.mobileNumbers`
2004
+ * on that same turn. Users who hide their number behind a WhatsApp
2005
+ * username otherwise reach you without one.
2006
+ *
2007
+ * Needs an open 24h window (the user wrote in the last 24 hours); a
2008
+ * closed window throws. Declining sends nothing back.
2009
+ *
2010
+ * @example
2011
+ * ```typescript
2012
+ * await Channels.whatsapp.requestPhoneNumber({
2013
+ * to: { userId: user._luaProfile.userId },
2014
+ * text: 'Please share your phone number so we can confirm you are registered.',
2015
+ * });
2016
+ * ```
2017
+ */
2018
+ requestPhoneNumber(input: WhatsAppPhoneRequestInput): Promise<ChannelSendOutput>;
1297
2019
  };
1298
2020
  /** Email-specific send operations. */
1299
2021
  email: {
@@ -1353,6 +2075,11 @@ export declare interface ChannelSendInput {
1353
2075
  export declare interface ChannelSendOptions {
1354
2076
  /** Pin a specific channel config (must belong to the sending agent). */
1355
2077
  channelIdentifier?: string;
2078
+ /**
2079
+ * Send even while a staff member holds the conversation. By default a held
2080
+ * conversation refuses proactive sends with 409 `CONVERSATION_HELD`.
2081
+ */
2082
+ ignoreHold?: boolean;
1356
2083
  /** WhatsApp-specific send options. */
1357
2084
  whatsapp?: {
1358
2085
  /**
@@ -1386,8 +2113,10 @@ export declare interface ChannelSendOutput {
1386
2113
  */
1387
2114
  status: DeliveryStatus;
1388
2115
  delivered: boolean;
1389
- /** False for conversation-scoped sends: a shared conversation has no single
1390
- * user to attribute the message to, so nothing is written to agent memory. */
2116
+ /** Whether agent memory recorded the message. A conversation-scoped send is
2117
+ * recorded in the room that mirrors the conversation when the agent has one
2118
+ * (and a Slack DM in the conversation of the post's own thread); otherwise it
2119
+ * is delivered but not recorded (`persisted: false` with a `warning`). */
1391
2120
  persisted: boolean;
1392
2121
  /**
1393
2122
  * True when the send was deferred to the WhatsApp message-request queue
@@ -1405,16 +2134,25 @@ export declare interface ChannelSendOutput {
1405
2134
  }
1406
2135
 
1407
2136
  /** Recipient — exactly one of the fields must be set. userId works on every
1408
- * channel (resolved via the user's channel history); raw identifiers only on
1409
- * cold-start-capable channels (whatsapp/sms → phoneNumber, email → email).
1410
- * `conversationId` addresses a shared conversation rather than a person —
1411
- * everyone in it receives the message. Teams only, and warm-only: the agent
1412
- * must already be part of that conversation. */
2137
+ * channel (resolved via the user's channel history; on Slack, via the user's
2138
+ * email to the workspace member); raw identifiers only on cold-start-capable
2139
+ * channels (whatsapp/sms → phoneNumber, email and slack → email).
2140
+ * `conversationId` addresses a conversation rather than a person — everyone in
2141
+ * it receives the message:
2142
+ * - teams: a group chat or channel the agent is already part of;
2143
+ * - slack: `Lua.request.conversation.externalId` (`T…:A…:C…[:threadTs]`), a
2144
+ * channel id (`C…`, top level), `C…:threadTs` (a reply in that thread), a
2145
+ * member id (`U…`, their DM with the bot) or 2–8 member ids (`U…,U…`, a group
2146
+ * DM). The bot must be in the channel.
2147
+ *
2148
+ * `identity` names one of the agent's users by a channel id, as `Lua.request.sender`
2149
+ * gives it: a `whatsapp_bsuid` on whatsapp, a `slack_user` on slack. */
1413
2150
  export declare interface ChannelSendTarget {
1414
2151
  userId?: string;
1415
2152
  phoneNumber?: string;
1416
2153
  email?: string;
1417
2154
  conversationId?: string;
2155
+ identity?: UserIdentityRef;
1418
2156
  }
1419
2157
 
1420
2158
  /**
@@ -1519,6 +2257,98 @@ export declare interface ChatHistoryMessage {
1519
2257
  */
1520
2258
  export declare type ChatMessage = TextMessage | ImageMessage | FileMessage;
1521
2259
 
2260
+ /** wave 2 U33 — the typed refusal `Integrations.checkAsUser` raises outside a live chat turn. */
2261
+ export declare function checkAsUserRequiresUser(): Error;
2262
+
2263
+ /**
2264
+ * U6 (wave 2) — connection inspection, account pinning and capability checks; U33 — the same checks run
2265
+ * with the CONVERSATION USER's principal. Owner: U6 (catalogue, list, pin, check, cleanup); U33 owns only
2266
+ * `checkAsUser`. Contract: docs/agent-builder/wave2-contracts.md §U6, §U33.
2267
+ *
2268
+ * The check catalogue is SERVER-OWNED (lua-api `services/connection-checks/`): a caller can only NAME a
2269
+ * check; the probe, its request and its interpretation live on the server. Results are a fixed enum
2270
+ * plus SAFE metadata (account identity, counts) — never a provider body.
2271
+ */
2272
+ declare const CONNECTION_CHECK_RESULTS: readonly ["ok", "unauthorized", "insufficient_scope", "not_found", "unreachable", "unsupported"];
2273
+
2274
+ /** u21 doc §5.1 — the request row's state machine (transition table in §6.3). */
2275
+ declare const CONNECTION_REQUEST_STATES: readonly ["pending", "opened", "authorizing", "remote_created", "finalizing", "connected", "identity_mismatch", "declined", "expired", "cancelled", "exhausted", "manual_review"];
2276
+
2277
+ /**
2278
+ * A check id. `identity` exists for every catalogued integration; the rest are per integration
2279
+ * ({@link CONNECTION_CHECK_CATALOGUE_V1}). An uncatalogued pair answers `unsupported`, never an error.
2280
+ */
2281
+ declare type ConnectionCheckName = 'identity' | (string & {});
2282
+
2283
+ declare interface ConnectionCheckOptions {
2284
+ /** Required (`true`) for a `reversible-write` catalogue entry; refused otherwise. */
2285
+ allowWrite?: boolean;
2286
+ }
2287
+
2288
+ declare interface ConnectionCheckOutcome {
2289
+ connectionId: string;
2290
+ integrationType: string;
2291
+ check: ConnectionCheckName;
2292
+ result: ConnectionCheckResult;
2293
+ /** ISO. */
2294
+ checkedAt: string;
2295
+ metadata?: ConnectionCheckSafeMetadata;
2296
+ /** Present only for a `reversible-write` check: `pending` ⇒ a leftover is queued for cleanup retry. */
2297
+ cleanup?: 'done' | 'pending';
2298
+ }
2299
+
2300
+ declare type ConnectionCheckResult = (typeof CONNECTION_CHECK_RESULTS)[number];
2301
+
2302
+ /** The ONLY metadata a check may return (allow-listed fields; no provider body, ever). */
2303
+ declare interface ConnectionCheckSafeMetadata {
2304
+ accountEmail?: string;
2305
+ accountId?: string;
2306
+ accountName?: string;
2307
+ /** Small named counts, e.g. `{ teams: 3 }`. */
2308
+ counts?: Record<string, number>;
2309
+ /** Unified scope names the probe found missing (`insufficient_scope`). */
2310
+ missingScopes?: string[];
2311
+ }
2312
+
2313
+ /** `Integrations.requestConnection(...)` (u21 doc §15.2). The agent id comes from the runtime credential. */
2314
+ export declare interface ConnectionRequestCreateInput {
2315
+ integrationType: string;
2316
+ invitee: {
2317
+ email: string;
2318
+ };
2319
+ scopes?: string[];
2320
+ /** Default false. */
2321
+ unattended?: boolean;
2322
+ /** Default 72, max 168. */
2323
+ expiresInHours?: number;
2324
+ }
2325
+
2326
+ declare type ConnectionRequestHolderClass = 'member' | 'nonmember';
2327
+
2328
+ declare type ConnectionRequestKind = 'connect' | 'reconnect';
2329
+
2330
+ export declare type ConnectionRequestState = (typeof CONNECTION_REQUEST_STATES)[number];
2331
+
2332
+ /** What the requester (SDK, CLI, Desktop card) may read — never the token, never the hosted URL. */
2333
+ export declare interface ConnectionRequestStatus {
2334
+ requestId: string;
2335
+ kind: ConnectionRequestKind;
2336
+ agentId: string;
2337
+ integrationType: string;
2338
+ state: ConnectionRequestState;
2339
+ /** A display label for the invitee (name, else the email's local part). */
2340
+ inviteeLabel: string;
2341
+ holderClass: ConnectionRequestHolderClass;
2342
+ unattended: boolean;
2343
+ /** ISO. */
2344
+ expiresAt: string;
2345
+ /** Present once `connected`. */
2346
+ connectionId?: string;
2347
+ /** Present once `connected`: the remote identity the holder signed in with. */
2348
+ connectedAs?: string;
2349
+ lastErrorCode?: string;
2350
+ }
2351
+
1522
2352
  /**
1523
2353
  * A container arm: a `StepRef` — a `createStep` object, or a string naming an entry declared elsewhere in the chain
1524
2354
  * (`agentStep` / `specialistStep` / `toolStep` / `workflow`, and since LUA-684 `approval` / `waitForSignal`, so an
@@ -1565,16 +2395,16 @@ export declare interface ConversationParticipant {
1565
2395
  }
1566
2396
 
1567
2397
  /**
1568
- * The conversation a turn runs in. Present on group turns (a desktop room or a
1569
- * Teams group chat); undefined on 1:1 chats, jobs, webhooks, triggers and
1570
- * workflow steps.
2398
+ * The conversation a turn runs in. Present on group turns (a desktop room, a
2399
+ * Teams group chat, a Slack channel thread or group DM); undefined on 1:1 chats,
2400
+ * jobs, webhooks, triggers and workflow steps.
1571
2401
  */
1572
2402
  export declare interface ConversationRef {
1573
2403
  /** The room conversation id (`room:<id>`). */
1574
2404
  id: string;
1575
2405
  kind: ConversationKind;
1576
2406
  channel: Channel;
1577
- /** The provider's conversation id; pass it to `Channels.send({ to: { conversationId } })` to reply proactively. */
2407
+ /** The provider's conversation id (Teams chat id, Slack `T…:A…:C…:threadTs`); pass it to `Channels.send({ to: { conversationId } })` to reply proactively. */
1578
2408
  externalId?: string;
1579
2409
  currentSpeakerId?: string;
1580
2410
  /** Capped at 50 entries, current speaker first; see `participantCount` and `truncated`. */
@@ -1690,12 +2520,25 @@ declare interface CustomDataAPI {
1690
2520
  * @returns Promise resolving to update response
1691
2521
  */
1692
2522
  update(collectionName: string, entryId: string, data: Record<string, any>, optionsOrSearchText?: string | CreateCustomDataOptions): Promise<UpdateCustomDataResponse>;
1693
- /** Atomically sets and removes top-level entry fields and optionally changes search text. */
2523
+ /**
2524
+ * Atomically sets and removes top-level entry fields and optionally changes search text.
2525
+ * `options.ifVersion` makes it a compare-and-swap: a stale version rejects with
2526
+ * `code === 'data_version_conflict'` (409) and writes nothing.
2527
+ */
1694
2528
  patch(collectionName: string, entryId: string, mutation: {
1695
2529
  set?: Record<string, any>;
1696
2530
  unset?: string[];
1697
2531
  searchText?: string | null;
2532
+ }, options?: {
2533
+ ifVersion?: number;
1698
2534
  }): Promise<UpdateCustomDataResponse>;
2535
+ /**
2536
+ * Atomically adds `by` (default 1) to a top-level numeric field and resolves the new value.
2537
+ * A missing field starts at 0; `options.upsert` creates a missing entry under `entryId`.
2538
+ */
2539
+ increment(collectionName: string, entryId: string, field: string, by?: number, options?: {
2540
+ upsert?: boolean;
2541
+ }): Promise<number>;
1699
2542
  /**
1700
2543
  * Performs vector search on a collection.
1701
2544
  * @param collectionName - Collection name
@@ -1735,6 +2578,12 @@ declare interface CustomDataEntry extends IdentifiedEntity, TimestampedEntity {
1735
2578
  createdAt: number;
1736
2579
  updatedAt: number;
1737
2580
  searchText?: string;
2581
+ /**
2582
+ * Write counter for compare-and-swap (LUA-963): pass it back as
2583
+ * `Data.patch(c, id, mutation, { ifVersion })`. Every write bumps it;
2584
+ * entries not written since versioning was introduced report 0.
2585
+ */
2586
+ version?: number;
1738
2587
  }
1739
2588
 
1740
2589
  /**
@@ -1840,6 +2689,74 @@ export declare const Data: {
1840
2689
  * @returns Promise resolving to update response
1841
2690
  */
1842
2691
  update(collectionName: string, entryId: string, data: Record<string, any>, optionsOrSearchText?: string | CreateCustomDataOptions): Promise<UpdateCustomDataResponse>;
2692
+ /**
2693
+ * Atomically sets and removes top-level fields of an entry in ONE write (no
2694
+ * read-merge), optionally changing its search text.
2695
+ *
2696
+ * Compare-and-swap: pass `{ ifVersion }` to apply the patch only if nobody
2697
+ * wrote the entry since you read it. Every entry carries a `version`
2698
+ * (`entry.version` from `Data.get`, `entry._version` on the instance from
2699
+ * `Data.getEntry` / `Data.create`) that every write bumps. On a mismatch
2700
+ * nothing is written and the call rejects with an error whose
2701
+ * `code === 'data_version_conflict'` (`status` 409, plus `currentVersion`
2702
+ * and `expectedVersion`): re-read and retry. A present `ifVersion` that is
2703
+ * not a non-negative integer (even `undefined`) throws a TypeError and
2704
+ * sends nothing; omit the key for an unconditional patch. A CAS patch is
2705
+ * sent once (not retried), so after a network error re-read the entry to
2706
+ * see whether it landed.
2707
+ *
2708
+ * ```typescript
2709
+ * const entry = await Data.getEntry('seats', seatId);
2710
+ * if (entry.data.heldBy) return 'taken';
2711
+ * try {
2712
+ * await Data.patch('seats', seatId, { set: { heldBy: userId } }, { ifVersion: entry._version });
2713
+ * } catch (error: any) {
2714
+ * if (error?.code === 'data_version_conflict') return 'taken'; // someone else won
2715
+ * throw error;
2716
+ * }
2717
+ * ```
2718
+ *
2719
+ * @param collectionName - Name of the collection
2720
+ * @param entryId - ID of the entry
2721
+ * @param mutation - `{ set?, unset?, searchText? }` (`searchText: null` clears it)
2722
+ * @param options - `{ ifVersion? }` for compare-and-swap
2723
+ * @returns Promise resolving to `{ status, message, version }` (`version` = the entry's new version)
2724
+ */
2725
+ patch(collectionName: string, entryId: string, mutation: {
2726
+ set?: Record<string, any>;
2727
+ unset?: string[];
2728
+ searchText?: string | null;
2729
+ }, options?: PatchCustomDataOptions): Promise<UpdateCustomDataResponse>;
2730
+ /**
2731
+ * Atomically adds `by` (default 1; negative and fractional amounts allowed)
2732
+ * to a top-level numeric field and resolves the field's NEW value. Safe
2733
+ * under concurrency: unlike `get` + `update`, simultaneous increments
2734
+ * never lose a count. A missing field starts at 0.
2735
+ *
2736
+ * ```typescript
2737
+ * const views = await Data.increment('stats', 'homepage', 'views');
2738
+ * await Data.increment('stock', sku, 'available', -1);
2739
+ * // Daily counter: one long-lived entry, one field per day (a missing field starts at 0).
2740
+ * await Data.increment('stats', 'calls', `day-${today}`);
2741
+ * ```
2742
+ *
2743
+ * Errors: 404 when the entry does not exist (unless `upsert`), 400 when the
2744
+ * field holds a non-number. `upsert` is NOT safe for an entry many
2745
+ * conversations may create at once: concurrent first-time upserts of the
2746
+ * same new id can create duplicate entries, and the count in one of them is
2747
+ * lost. Do not upsert a fresh id per day or per event under load; create the
2748
+ * entry once from a non-concurrent path, then increment it.
2749
+ * The SDK sends the request once and does not retry it, so a network
2750
+ * failure means the increment may or may not have been applied.
2751
+ *
2752
+ * @param collectionName - Name of the collection
2753
+ * @param entryId - ID of the entry (the id to create under when upserting)
2754
+ * @param field - Top-level field name (no dots, no `$` prefix)
2755
+ * @param by - Amount to add (default 1)
2756
+ * @param options - `{ upsert? }`
2757
+ * @returns Promise resolving to the field's value after the increment
2758
+ */
2759
+ increment(collectionName: string, entryId: string, field: string, by?: number, options?: IncrementCustomDataOptions): Promise<number>;
1843
2760
  /**
1844
2761
  * Performs vector search on a collection.
1845
2762
  *
@@ -1870,6 +2787,12 @@ export declare class DataEntryInstance {
1870
2787
  id: string;
1871
2788
  collectionName: string;
1872
2789
  score?: number;
2790
+ /**
2791
+ * The entry's write version for compare-and-swap (LUA-963):
2792
+ * `entry.patch(m, { ifVersion: entry._version })`. Underscored so it never
2793
+ * shadows a user `data.version` field through the property proxy.
2794
+ */
2795
+ _version: number;
1873
2796
  private customDataAPI;
1874
2797
  [key: string]: any;
1875
2798
  /**
@@ -1893,10 +2816,18 @@ export declare class DataEntryInstance {
1893
2816
  * @throws Error if the update fails
1894
2817
  */
1895
2818
  update(data: Record<string, any>, searchText?: string): Promise<Record<string, any>>;
2819
+ /**
2820
+ * Atomically sets/unsets fields. `options.ifVersion` makes it a
2821
+ * compare-and-swap (pass `entry._version`); a stale version rejects with
2822
+ * `code === 'data_version_conflict'` (status 409) and leaves the entry (and
2823
+ * this instance) unchanged.
2824
+ */
1896
2825
  patch(mutation: {
1897
2826
  set?: Record<string, any>;
1898
2827
  unset?: string[];
1899
2828
  searchText?: string | null;
2829
+ }, options?: {
2830
+ ifVersion?: number;
1900
2831
  }): Promise<Record<string, any>>;
1901
2832
  unset(...fields: string[]): Promise<Record<string, any>>;
1902
2833
  /**
@@ -2298,9 +3229,222 @@ export declare const env: ((key: string, opts?: {
2298
3229
  };
2299
3230
  };
2300
3231
 
2301
- export { EnvRefBinding }
3232
+ export { EnvRefBinding }
3233
+
3234
+ export declare const eq: <T>(l: TypedRef<T>, r: TypedRef<T> | Literal<T>) => LuaPredicate;
3235
+
3236
+ /** DOC3 §4.3 — deterministic check kinds (`side_effect` / `no_side_effect` / `no_log_errors` are Phase 2). */
3237
+ 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"];
3238
+
3239
+ declare const EVAL_SUITE_RUN_STATUSES: readonly ["queued", "running", "completed", "failed", "cancelled", "budget_exhausted"];
3240
+
3241
+ declare type EvalCase = EvalConversationCase | EvalEventCase;
3242
+
3243
+ declare interface EvalCaseResult {
3244
+ caseId: string;
3245
+ status: EvalCaseStatus;
3246
+ checks: Array<{
3247
+ kind: string;
3248
+ passed: boolean;
3249
+ detail?: string;
3250
+ }>;
3251
+ judge?: {
3252
+ score: number;
3253
+ passed: boolean;
3254
+ reasoning?: string;
3255
+ };
3256
+ turns: number;
3257
+ durationMs?: number;
3258
+ credits?: number;
3259
+ holdout?: boolean;
3260
+ }
3261
+
3262
+ declare type EvalCaseStatus = 'pending' | 'passed' | 'failed' | 'error' | 'skipped';
3263
+
3264
+ /** `evalCaseTranscripts` (agents DB, 30-day TTL) — what the transcript route returns. */
3265
+ declare interface EvalCaseTranscript {
3266
+ runId: string;
3267
+ caseId: string;
3268
+ agentId: string;
3269
+ turns: EvalTranscriptTurn[];
3270
+ judge?: {
3271
+ score: number;
3272
+ passed: boolean;
3273
+ reasoning?: string;
3274
+ };
3275
+ error?: string;
3276
+ holdout?: boolean;
3277
+ /** Always true until the U19 scrubber lands: bodies are stored through `redactTranscript` (DOC3 §4.6). */
3278
+ redacted: boolean;
3279
+ }
3280
+
3281
+ /** One check. Fields beyond `kind` are per kind (DOC3 §4.2 examples); the parser validates them. */
3282
+ declare interface EvalCheck {
3283
+ kind: EvalCheckKind;
3284
+ [field: string]: unknown;
3285
+ }
3286
+
3287
+ declare type EvalCheckKind = (typeof EVAL_CHECK_KINDS)[number];
3288
+
3289
+ declare interface EvalConversationCase {
3290
+ id: string;
3291
+ kind: 'conversation';
3292
+ turns?: Array<{
3293
+ role: 'user' | 'assistant';
3294
+ content: string;
3295
+ }>;
3296
+ simulatedUser?: {
3297
+ persona: string;
3298
+ goal: string;
3299
+ stopWhen: string;
3300
+ maxTurns: number;
3301
+ };
3302
+ checks: EvalCheck[];
3303
+ rubric?: EvalRubric;
3304
+ toolDoubles?: EvalToolDouble[];
3305
+ tags?: string[];
3306
+ }
3307
+
3308
+ declare interface EvalEventCase {
3309
+ id: string;
3310
+ kind: 'event';
3311
+ fire: {
3312
+ trigger: string;
3313
+ } | {
3314
+ job: string;
3315
+ } | {
3316
+ workflow: string;
3317
+ } | {
3318
+ webhook: string;
3319
+ };
3320
+ payload: unknown;
3321
+ checks: EvalCheck[];
3322
+ rubric?: EvalRubric;
3323
+ toolDoubles?: EvalToolDouble[];
3324
+ }
3325
+
3326
+ declare interface EvalRubric {
3327
+ text: string;
3328
+ /** 0..1; default the suite's judge threshold (default 0.7). */
3329
+ threshold?: number;
3330
+ }
3331
+
3332
+ declare interface EvalRunReceipt {
3333
+ runId: string;
3334
+ estimate: {
3335
+ credits: number;
3336
+ cases: number;
3337
+ };
3338
+ }
3339
+
3340
+ /** `evalSuites` (agents DB), one per `(agentId, key)`. Only the OWNER writes the `live*` lists. */
3341
+ declare interface EvalSuite {
3342
+ id: string;
3343
+ agentId: string;
3344
+ key: string;
3345
+ revision: number;
3346
+ source: EvalSuiteSource;
3347
+ minPassRate: number;
3348
+ judge: {
3349
+ model?: string;
3350
+ threshold: number;
3351
+ };
3352
+ budget: {
3353
+ maxCredits: number;
3354
+ maxTurnsPerCase: number;
3355
+ maxCases: number;
3356
+ };
3357
+ toolDoubles: EvalToolDouble[];
3358
+ liveSkills: string[];
3359
+ liveBuiltins: string[];
3360
+ liveAgentTools: string[];
3361
+ monitors: EvalSuiteMonitor[];
3362
+ cases: EvalCase[];
3363
+ updatedBy: string;
3364
+ }
3365
+
3366
+ /** DOC3 §4.9 — a suite monitor (template `EvalSetMonitor` + `appliesTo` / `threshold`). */
3367
+ declare interface EvalSuiteMonitor {
3368
+ key: string;
3369
+ title: string;
3370
+ rubric: string;
3371
+ samplingRate: number;
3372
+ appliesTo: Array<'chat' | 'workflow' | 'trigger' | 'job'>;
3373
+ threshold: number;
3374
+ }
3375
+
3376
+ declare type EvalSuiteRunStatus = (typeof EVAL_SUITE_RUN_STATUSES)[number];
3377
+
3378
+ /** `evalSuiteRuns` (agents DB) — what `Evals.runs(id).get` returns (no transcripts). */
3379
+ declare interface EvalSuiteRunSummary {
3380
+ id: string;
3381
+ agentId: string;
3382
+ suiteKey: string;
3383
+ suiteRevision: number;
3384
+ version: number;
3385
+ sourceDigest?: string;
3386
+ /** U11 session, when the run used one. */
3387
+ testSessionId?: string;
3388
+ /** `user:<id>` | `apiKey:<id>` | `service:agent:<id>`. */
3389
+ initiatedBy: string;
3390
+ status: EvalSuiteRunStatus;
3391
+ budget: {
3392
+ maxCredits: number;
3393
+ reserved: number;
3394
+ spent: {
3395
+ credits: number;
3396
+ agentCredits: number;
3397
+ judgeCredits: number;
3398
+ simulatorCredits: number;
3399
+ };
3400
+ };
3401
+ cases: EvalCaseResult[];
3402
+ passRate?: number;
3403
+ passed?: boolean;
3404
+ /**
3405
+ * Why a run stopped early when it was not the run budget: `EVAL_MONTHLY_CAP_REACHED` (the agent's
3406
+ * monthly allowance ran out mid-run) or `EVAL_CAP_UNAVAILABLE` (the cap store was down; fail closed).
3407
+ * Absent for plain per-run `budget_exhausted`.
3408
+ */
3409
+ error?: string;
3410
+ startedAt?: string;
3411
+ finishedAt?: string;
3412
+ }
3413
+
3414
+ declare type EvalSuiteSource = {
3415
+ kind: 'agent';
3416
+ } | {
3417
+ kind: 'template';
3418
+ templateId: string;
3419
+ evalSetRevision: number;
3420
+ } | {
3421
+ kind: 'builder';
3422
+ projectId: string;
3423
+ };
3424
+
3425
+ /** Shape of `agent-template.eval-set.schema.ts` `EvalSetToolDouble` (reused, not redefined). */
3426
+ declare interface EvalToolDouble {
3427
+ tool: string;
3428
+ server?: string;
3429
+ kind?: 'mcp' | 'skill' | 'builtin';
3430
+ result: unknown;
3431
+ /** When set, the double returns an isError result with this text (template `EvalSetToolDouble.error`). */
3432
+ error?: string;
3433
+ }
2302
3434
 
2303
- export declare const eq: <T>(l: TypedRef<T>, r: TypedRef<T> | Literal<T>) => LuaPredicate;
3435
+ /** One recorded turn of a case transcript. */
3436
+ declare interface EvalTranscriptTurn {
3437
+ role: 'user' | 'assistant';
3438
+ content: string;
3439
+ /** `script` for a scripted turn, `simulator` for a simulated-user message, `agent` for a reply. */
3440
+ source: 'script' | 'simulator' | 'agent';
3441
+ toolCalls?: Array<{
3442
+ name: string;
3443
+ input?: string;
3444
+ }>;
3445
+ latencyMs?: number;
3446
+ finishReason?: string;
3447
+ }
2304
3448
 
2305
3449
  export declare const exists: (ref: TypedRef<unknown>) => LuaPredicate;
2306
3450
 
@@ -2387,7 +3531,7 @@ declare interface GetJobsResponseData {
2387
3531
  * platform resolves it from the `GOVERNANCE_API_KEY` env var. This
2388
3532
  * keeps secrets out of MongoDB, support logs, and backups.
2389
3533
  */
2390
- declare interface GovernanceConfig {
3534
+ export declare interface GovernanceConfig {
2391
3535
  mode: 'sdk' | 'api';
2392
3536
  /**
2393
3537
  * SDK mode — a named governance-sdk preset composed as the base rule set. The platform builder
@@ -2561,6 +3705,15 @@ declare abstract class HttpClient {
2561
3705
  * @protected
2562
3706
  */
2563
3707
  protected httpPatch<T>(url: string, data?: any, headers?: Record<string, string>): Promise<ApiResponse<T>>;
3708
+ /**
3709
+ * Performs one HTTP PATCH attempt (no client retry).
3710
+ *
3711
+ * For a conditional write whose retry is not safe: a compare-and-swap PATCH
3712
+ * (`Data.patch(..., { ifVersion })`, LUA-963) that landed but lost its
3713
+ * response would, on retry, find the version already bumped and report a
3714
+ * false conflict. An ambiguous failure surfaces instead.
3715
+ */
3716
+ protected httpPatchOnce<T>(url: string, data?: any, headers?: Record<string, string>): Promise<ApiResponse<T>>;
2564
3717
  /**
2565
3718
  * Opens a Server-Sent Events stream (WF-204 — 03 §3.10 `watch`; 09 §9.10 `watchEvents`).
2566
3719
  *
@@ -2610,6 +3763,8 @@ declare interface ImmutableUserProfile {
2610
3763
  fullName: string;
2611
3764
  mobileNumbers: string[];
2612
3765
  emailAddresses: string[];
3766
+ /** The person's channel ids (WhatsApp, Slack, ...). Absent when they could not be loaded. */
3767
+ identities?: UserIdentity[];
2613
3768
  }
2614
3769
 
2615
3770
  /**
@@ -2678,6 +3833,12 @@ declare interface InboxPushReceipt {
2678
3833
  reason?: string;
2679
3834
  }
2680
3835
 
3836
+ /** Options for `Data.increment` (LUA-963). */
3837
+ export declare interface IncrementCustomDataOptions {
3838
+ /** Create the entry (`data: { [field]: by }`) under the given id if it does not exist. Default false. */
3839
+ upsert?: boolean;
3840
+ }
3841
+
2681
3842
  export declare const init: <T = unknown>(path: string) => TypedRef<T>;
2682
3843
 
2683
3844
  export declare const inSet: <T extends string | number | boolean | null>(v: TypedRef<T>, set: T[]) => LuaPredicate;
@@ -2685,8 +3846,91 @@ export declare const inSet: <T extends string | number | boolean | null>(v: Type
2685
3846
  /** HTTP methods the passthrough relay accepts. */
2686
3847
  declare const INTEGRATION_PASSTHROUGH_METHODS: readonly ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"];
2687
3848
 
3849
+ declare type IntegrationConnectionStatus = 'active' | 'paused' | 'unhealthy' | 'needs_reconnect';
3850
+
3851
+ /** One row of `Integrations.list()` / `Agents.integrations(id).list()`: a connection VISIBLE to the agent. */
3852
+ declare interface IntegrationConnectionSummary {
3853
+ connectionId: string;
3854
+ integrationType: string;
3855
+ displayName?: string;
3856
+ /** Remote account identity as captured at finalize or by the last `identity` check. */
3857
+ account?: {
3858
+ email?: string;
3859
+ id?: string;
3860
+ name?: string;
3861
+ };
3862
+ /** Provider-granted unified scopes (`grantedScopes`), else the requested filter. */
3863
+ scopes: string[];
3864
+ status: IntegrationConnectionStatus;
3865
+ owner: {
3866
+ type: 'agent' | 'user' | 'org';
3867
+ userId?: string;
3868
+ };
3869
+ /** Agents the connection is mounted on that the CALLER may know about (same org). */
3870
+ agentIds: string[];
3871
+ /** U2 (d): `check-only` mounts are listed but not usable as tools. */
3872
+ mount?: 'tools' | 'check-only';
3873
+ }
3874
+
3875
+ /**
3876
+ * LUA-860 — the typed members `IntegrationPassthroughError` carries beside `message`: the fields lua-api serves on a
3877
+ * route-level refusal of `Integrations.passthrough` (`ApiResponse.error`), copied APPEND-ONLY — a member absent on the
3878
+ * wire is absent on the error, never `undefined`-valued — so skill code branches on `code` (and, for one release,
3879
+ * `legacyCode`) on the in-process path (`lua test`, `lua dev`, the api-exports `Integrations` namespace) exactly as it
3880
+ * does on the production runtime. Parity is complete (LUA-862, #2737, commit 90f05540b — in the lua-cli@3.33.0 tree;
3881
+ * this comment corrected under BAC-551): every production hop relays the same members append-only — lua-core's
3882
+ * `callInternalUnifiedPassthrough` (`unified-passthrough.tool.ts`, via `pickVendorFaultRelayFields` in
3883
+ * `vendor-fault-relay.ts`), the seam envelope (`InternalSandboxSeamController.run` on the fast / worker planes and
3884
+ * `sandbox-passthrough.controller.ts` on the Job tier), the remote-runner bridge (`lua-sandbox-runner/src/executor/
3885
+ * bridge-deps.ts`, the `seamFetch` rebuild) and the Job pod (`lua-workflow-job/src/protocol-client.ts` +
3886
+ * `code-step-ipc.ts`) — so `retryAfterSeconds` / `vendor` / `vendorStatus` / `requestId` are identical on the
3887
+ * in-process path and the production routing, and "absent on the wire ⇒ absent on the error" holds at every hop (a
3888
+ * withheld `retryAfterSeconds` is lua-api's unsafe-to-retry marker, never defaulted). The class is not on the public
3889
+ * `lua-cli` surface — skill code duck-types on `name === 'IntegrationPassthroughError'` and `code`. Before this, the
3890
+ * in-process path threw a bare `Error(message)`: no `code` could reach skill code, so a shipped 3.32.x client could
3891
+ * only be steered server-side through the message text (the LUA-826 `(503 Service Unavailable)` suffix — the shim
3892
+ * this replaces).
3893
+ */
3894
+ export declare interface IntegrationPassthroughErrorFields {
3895
+ /**
3896
+ * The server's discriminator — `VENDOR_UNAVAILABLE` (503, the vendor behind the relay failed: transient) ·
3897
+ * `VENDOR_REJECTED` (422, the vendor refused the request as sent: deterministic) · `passthrough_disabled` ·
3898
+ * `passthrough_no_connection` · `passthrough_rate_limited` · `passthrough_invalid_request` · … Absent when the
3899
+ * server served none, or the request never reached it.
3900
+ */
3901
+ code?: string;
3902
+ /** lua-api's own HTTP status; `0` for a transport failure (no answer / timeout). Never the vendor's: that is `vendorStatus`. */
3903
+ statusCode?: number;
3904
+ /** Alias of `statusCode` — the member lua-core's production `IntegrationPassthroughError` exposes under that name. */
3905
+ status?: number;
3906
+ /**
3907
+ * LUA-826, ONE release: the code a vendor-fault site served before it moved to `VENDOR_UNAVAILABLE`
3908
+ * (`passthrough_upstream_error`) and the line it served under it. Branch on `code`; these exist for skill code that
3909
+ * still greps the old string, and go away the release after.
3910
+ */
3911
+ legacyCode?: string;
3912
+ legacyMessage?: string;
3913
+ /**
3914
+ * Seconds to wait before retrying. On a 503 `VENDOR_UNAVAILABLE`: present ONLY when the server says a blind retry is
3915
+ * safe — a read, or a write whose duplicate is inert. On a 429 `passthrough_rate_limited` (LUA-968): always present —
3916
+ * the seconds left in the caller's shared per-minute window (also served as the `Retry-After` header).
3917
+ */
3918
+ retryAfterSeconds?: number;
3919
+ /** The third-party vendor behind the fault (`unified` | `github` | `google` | …) and its own status when it answered. */
3920
+ vendor?: string;
3921
+ vendorStatus?: number;
3922
+ /** The id on the server's matching error log line — the one to quote. */
3923
+ requestId?: string;
3924
+ }
3925
+
2688
3926
  export declare type IntegrationPassthroughMethod = (typeof INTEGRATION_PASSTHROUGH_METHODS)[number];
2689
3927
 
3928
+ /** `Integrations.passthrough(type, request, options)` — the third argument (U6 pin). */
3929
+ declare interface IntegrationPassthroughPinOptions {
3930
+ /** Use exactly this connection (it must be visible to the agent); the server pin in `pickConnection`. */
3931
+ connectionId?: string;
3932
+ }
3933
+
2690
3934
  /**
2691
3935
  * One raw provider API call, relative to the provider's API base URL
2692
3936
  * (e.g. `repos/{owner}/{repo}/pulls/42/files` against GitHub).
@@ -2763,7 +4007,86 @@ export declare interface IntegrationsApi {
2763
4007
  * });
2764
4008
  * ```
2765
4009
  */
2766
- passthrough(integrationType: string, request: IntegrationPassthroughRequest): Promise<IntegrationPassthroughResponse>;
4010
+ passthrough(integrationType: string, request: IntegrationPassthroughRequest,
4011
+ /**
4012
+ * `{ connectionId }` pins one connection (from {@link IntegrationsApi.list}) when the agent has several of
4013
+ * the same type. The pin must be a connection this agent may use: it narrows the choice, never widens it.
4014
+ */
4015
+ options?: IntegrationPassthroughPinOptions): Promise<IntegrationPassthroughResponse>;
4016
+ /**
4017
+ * The connections visible to this agent: integration type, remote account identity, scopes, status,
4018
+ * owner and the agents (of your organization) each one is mounted on. A personal connection is listed
4019
+ * only for the person it belongs to.
4020
+ *
4021
+ * @example
4022
+ * ```typescript
4023
+ * const gmail = (await Integrations.list()).filter((c) => c.integrationType === 'googlemail');
4024
+ * ```
4025
+ */
4026
+ list(): Promise<IntegrationConnectionSummary[]>;
4027
+ /**
4028
+ * Run one platform-owned check on a visible connection: `identity` exists for every catalogued
4029
+ * integration; others are per integration (`mail.list`, `teams.list`, `issue.create-permission`,
4030
+ * `refund.calculate`, …). The answer is a fixed `result` (`ok` | `unauthorized` | `insufficient_scope`
4031
+ * | `not_found` | `unreachable` | `unsupported`) plus safe metadata (account email/id, counts) — never a
4032
+ * provider body. A check that writes and then undoes (`mail.draft-create-delete`) runs only with
4033
+ * `{ allowWrite: true }`.
4034
+ *
4035
+ * @example
4036
+ * ```typescript
4037
+ * const { result, metadata } = await Integrations.check(gmail.connectionId, 'identity');
4038
+ * ```
4039
+ */
4040
+ check(connectionId: string, check: ConnectionCheckName, options?: ConnectionCheckOptions): Promise<ConnectionCheckOutcome>;
4041
+ /**
4042
+ * Run one server-owned catalogue check (`identity`, `mail.list`, …) on a connection the CONVERSATION USER
4043
+ * owns, with that user as the principal. The answer is a fixed result enum (`ok`, `unauthorized`,
4044
+ * `insufficient_scope`, `not_found`, `unreachable`, `unsupported`) plus safe metadata — never a provider body.
4045
+ *
4046
+ * Only during a chat turn with a live user: jobs, triggers, webhooks, workflows and background turns throw
4047
+ * `connection_check_requires_user`; a connection the user does not own throws `connection_check_not_owner`.
4048
+ * Read checks only. Every call is audited on the agent's logs. Off unless the platform enables
4049
+ * `LUA_CONNECTION_CHECK_AS_USER_ENABLED` (`connection_checks_disabled`).
4050
+ *
4051
+ * Offline (`lua test`) there is no live user, so it always throws `connection_check_requires_user`.
4052
+ *
4053
+ * @example
4054
+ * ```typescript
4055
+ * const outcome = await Integrations.checkAsUser(connectionId, 'identity');
4056
+ * if (outcome.result !== 'ok') return `Your connection needs attention: ${outcome.result}`;
4057
+ * ```
4058
+ */
4059
+ checkAsUser(connectionId: string, check: string): Promise<ConnectionCheckOutcome>;
4060
+ /**
4061
+ * Ask someone else to connect their account to THIS agent. The invitee gets the link from Lua (never from
4062
+ * your code): this returns the request's id, state and expiry only — never a token or URL. Refused off a
4063
+ * user's own turn (a job, webhook, trigger, workflow or `Agents.invoke` call) with `REQUESTER_UNAUTHORIZED`.
4064
+ * Failures throw an `Error` with `name === 'ConnectionRequestError'` and the server's `code`.
4065
+ *
4066
+ * @example
4067
+ * ```typescript
4068
+ * const { requestId } = await Integrations.requestConnection({
4069
+ * integrationType: 'googlemail',
4070
+ * invitee: { email: 'ceo@acme.io' },
4071
+ * expiresInHours: 72, // 1..168, default 72
4072
+ * });
4073
+ * ```
4074
+ */
4075
+ requestConnection(input: ConnectionRequestCreateInput): Promise<{
4076
+ requestId: string;
4077
+ state: ConnectionRequestState;
4078
+ expiresAt: string;
4079
+ }>;
4080
+ /** Ask the holder of a delegated connection to reconnect it (e.g. after its token was revoked). */
4081
+ requestReconnect(connectionId: string): Promise<{
4082
+ requestId: string;
4083
+ state: ConnectionRequestState;
4084
+ expiresAt: string;
4085
+ }>;
4086
+ /** Read one of this agent's connection requests. Never carries a token or URL. */
4087
+ connectionRequest(requestId: string): Promise<ConnectionRequestStatus>;
4088
+ /** Cancel a pending connection request. */
4089
+ cancelConnectionRequest(requestId: string): Promise<void>;
2767
4090
  }
2768
4091
 
2769
4092
  /**
@@ -2782,7 +4105,10 @@ export declare interface InvokedBy {
2782
4105
  supervisor: boolean;
2783
4106
  /** The caller's supervision scopes on this agent (e.g. `supervision:act`); `[]` on preview turns. */
2784
4107
  scopes: string[];
2785
- /** Set when the caller passed `input.userId` to `Agents.invoke` (a delegated turn). */
4108
+ /**
4109
+ * Set when the caller passed `input.userId` to `Agents.invoke` (a delegated turn), and when the caller's own
4110
+ * turn had such a user or ran in a Job / workflow run (the platform did not pick the user).
4111
+ */
2786
4112
  delegatedUserId?: string;
2787
4113
  }
2788
4114
 
@@ -3020,6 +4346,17 @@ export declare class JobInstance {
3020
4346
  /** The active version of the job (if one exists) */
3021
4347
  readonly activeVersion?: JobVersion;
3022
4348
  metadata: Record<string, any>;
4349
+ /**
4350
+ * Per-run execution identity, set by the platform when the job runs. `occurrenceId` is the stable
4351
+ * dedupe key across retries of the same fire; `scheduledTime` is set on scheduled fires only.
4352
+ * Undefined when the platform did not supply it, so read it as `job.execution?.occurrenceId`.
4353
+ */
4354
+ execution?: {
4355
+ executionId: string;
4356
+ attempt: number;
4357
+ occurrenceId: string;
4358
+ scheduledTime?: string;
4359
+ };
3023
4360
  private userApi?;
3024
4361
  constructor(jobApi: JobApi, jobData: Job);
3025
4362
  /**
@@ -3986,6 +5323,11 @@ export declare interface LuaRequest {
3986
5323
  userId?: string;
3987
5324
  /** The id of the agent handling this turn. */
3988
5325
  agentId?: string;
5326
+ /**
5327
+ * The organization the agent belongs to. Present on deployed runtimes that know it (absent offline in `lua test`
5328
+ * and on older runtimes) — read it defensively.
5329
+ */
5330
+ orgId?: string;
3989
5331
  /**
3990
5332
  * The group conversation this turn belongs to, with its participants and the
3991
5333
  * current speaker. Undefined on 1:1 turns and on non-chat executions.
@@ -3997,6 +5339,12 @@ export declare interface LuaRequest {
3997
5339
  * `lua test`). Read it defensively — older runtimes do not set it.
3998
5340
  */
3999
5341
  invokedBy?: InvokedBy;
5342
+ /**
5343
+ * The channel identity that sent this message, e.g. `{ kind: 'whatsapp_bsuid', scope, value }` or a
5344
+ * `slack_user`. Present only when Lua confirmed it belongs to this turn's user on this channel;
5345
+ * absent on other channels, voice, jobs and webhooks. Match it against `user._luaProfile.identities`.
5346
+ */
5347
+ sender?: UserIdentityRef;
4000
5348
  }
4001
5349
 
4002
5350
  /**
@@ -4099,7 +5447,7 @@ export declare class LuaSkill {
4099
5447
  * Lua Skill configuration.
4100
5448
  * Used to initialize a new LuaSkill instance.
4101
5449
  */
4102
- declare interface LuaSkillConfig {
5450
+ export declare interface LuaSkillConfig {
4103
5451
  /** Skill name (required; used as the server-side identifier). */
4104
5452
  name: string;
4105
5453
  /** Short description of the skill (1-2 sentences) */
@@ -4156,7 +5504,7 @@ export declare interface LuaTool<TInput extends ZodType = ZodType> {
4156
5504
  * voice: { say } }`. Tools that want to act differently inside a voice
4157
5505
  * call check for `ctx?.voice` and use the typed surface.
4158
5506
  */
4159
- declare interface LuaToolCtx {
5507
+ export declare interface LuaToolCtx {
4160
5508
  /** LiveKit's tool-call id (voice only). */
4161
5509
  toolCallId?: string;
4162
5510
  /** Voice-runtime delegates. Only set when the tool runs over voice. */
@@ -4388,13 +5736,13 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4388
5736
  }, "strip", z.ZodTypeAny, {
4389
5737
  voice?: string;
4390
5738
  kind?: "inference";
4391
- options?: Record<string, unknown>;
4392
5739
  model?: string;
5740
+ options?: Record<string, unknown>;
4393
5741
  }, {
4394
5742
  voice?: string;
4395
5743
  kind?: "inference";
4396
- options?: Record<string, unknown>;
4397
5744
  model?: string;
5745
+ options?: Record<string, unknown>;
4398
5746
  }>, z.ZodObject<{
4399
5747
  kind: z.ZodLiteral<"plugin">;
4400
5748
  provider: z.ZodEnum<["deepgram", "elevenlabs"]>;
@@ -4407,14 +5755,14 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4407
5755
  */
4408
5756
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4409
5757
  }, "strip", z.ZodTypeAny, {
4410
- provider?: "deepgram" | "elevenlabs";
4411
- kind?: "plugin";
4412
5758
  class?: "LLM" | "STT" | "STTv2" | "TTS";
5759
+ kind?: "plugin";
5760
+ provider?: "deepgram" | "elevenlabs";
4413
5761
  options?: Record<string, unknown>;
4414
5762
  }, {
4415
- provider?: "deepgram" | "elevenlabs";
4416
- kind?: "plugin";
4417
5763
  class?: "LLM" | "STT" | "STTv2" | "TTS";
5764
+ kind?: "plugin";
5765
+ provider?: "deepgram" | "elevenlabs";
4418
5766
  options?: Record<string, unknown>;
4419
5767
  }>, z.ZodObject<{
4420
5768
  kind: z.ZodLiteral<"realtime">;
@@ -4427,12 +5775,12 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4427
5775
  */
4428
5776
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4429
5777
  }, "strip", z.ZodTypeAny, {
4430
- provider?: "google" | "xai" | "openai";
4431
5778
  kind?: "realtime";
5779
+ provider?: "openai" | "google" | "xai";
4432
5780
  options?: Record<string, unknown>;
4433
5781
  }, {
4434
- provider?: "google" | "xai" | "openai";
4435
5782
  kind?: "realtime";
5783
+ provider?: "openai" | "google" | "xai";
4436
5784
  options?: Record<string, unknown>;
4437
5785
  }>]>;
4438
5786
  stt: z.ZodOptional<z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
@@ -4454,13 +5802,13 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4454
5802
  }, "strip", z.ZodTypeAny, {
4455
5803
  voice?: string;
4456
5804
  kind?: "inference";
4457
- options?: Record<string, unknown>;
4458
5805
  model?: string;
5806
+ options?: Record<string, unknown>;
4459
5807
  }, {
4460
5808
  voice?: string;
4461
5809
  kind?: "inference";
4462
- options?: Record<string, unknown>;
4463
5810
  model?: string;
5811
+ options?: Record<string, unknown>;
4464
5812
  }>, z.ZodObject<{
4465
5813
  kind: z.ZodLiteral<"plugin">;
4466
5814
  provider: z.ZodEnum<["deepgram", "elevenlabs"]>;
@@ -4473,14 +5821,14 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4473
5821
  */
4474
5822
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4475
5823
  }, "strip", z.ZodTypeAny, {
4476
- provider?: "deepgram" | "elevenlabs";
4477
- kind?: "plugin";
4478
5824
  class?: "LLM" | "STT" | "STTv2" | "TTS";
5825
+ kind?: "plugin";
5826
+ provider?: "deepgram" | "elevenlabs";
4479
5827
  options?: Record<string, unknown>;
4480
5828
  }, {
4481
- provider?: "deepgram" | "elevenlabs";
4482
- kind?: "plugin";
4483
5829
  class?: "LLM" | "STT" | "STTv2" | "TTS";
5830
+ kind?: "plugin";
5831
+ provider?: "deepgram" | "elevenlabs";
4484
5832
  options?: Record<string, unknown>;
4485
5833
  }>, z.ZodObject<{
4486
5834
  kind: z.ZodLiteral<"realtime">;
@@ -4493,12 +5841,12 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4493
5841
  */
4494
5842
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4495
5843
  }, "strip", z.ZodTypeAny, {
4496
- provider?: "google" | "xai" | "openai";
4497
5844
  kind?: "realtime";
5845
+ provider?: "openai" | "google" | "xai";
4498
5846
  options?: Record<string, unknown>;
4499
5847
  }, {
4500
- provider?: "google" | "xai" | "openai";
4501
5848
  kind?: "realtime";
5849
+ provider?: "openai" | "google" | "xai";
4502
5850
  options?: Record<string, unknown>;
4503
5851
  }>]>>;
4504
5852
  tts: z.ZodOptional<z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
@@ -4520,13 +5868,13 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4520
5868
  }, "strip", z.ZodTypeAny, {
4521
5869
  voice?: string;
4522
5870
  kind?: "inference";
4523
- options?: Record<string, unknown>;
4524
5871
  model?: string;
5872
+ options?: Record<string, unknown>;
4525
5873
  }, {
4526
5874
  voice?: string;
4527
5875
  kind?: "inference";
4528
- options?: Record<string, unknown>;
4529
5876
  model?: string;
5877
+ options?: Record<string, unknown>;
4530
5878
  }>, z.ZodObject<{
4531
5879
  kind: z.ZodLiteral<"plugin">;
4532
5880
  provider: z.ZodEnum<["deepgram", "elevenlabs"]>;
@@ -4539,14 +5887,14 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4539
5887
  */
4540
5888
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4541
5889
  }, "strip", z.ZodTypeAny, {
4542
- provider?: "deepgram" | "elevenlabs";
4543
- kind?: "plugin";
4544
5890
  class?: "LLM" | "STT" | "STTv2" | "TTS";
5891
+ kind?: "plugin";
5892
+ provider?: "deepgram" | "elevenlabs";
4545
5893
  options?: Record<string, unknown>;
4546
5894
  }, {
4547
- provider?: "deepgram" | "elevenlabs";
4548
- kind?: "plugin";
4549
5895
  class?: "LLM" | "STT" | "STTv2" | "TTS";
5896
+ kind?: "plugin";
5897
+ provider?: "deepgram" | "elevenlabs";
4550
5898
  options?: Record<string, unknown>;
4551
5899
  }>, z.ZodObject<{
4552
5900
  kind: z.ZodLiteral<"realtime">;
@@ -4559,12 +5907,12 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4559
5907
  */
4560
5908
  options: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4561
5909
  }, "strip", z.ZodTypeAny, {
4562
- provider?: "google" | "xai" | "openai";
4563
5910
  kind?: "realtime";
5911
+ provider?: "openai" | "google" | "xai";
4564
5912
  options?: Record<string, unknown>;
4565
5913
  }, {
4566
- provider?: "google" | "xai" | "openai";
4567
5914
  kind?: "realtime";
5915
+ provider?: "openai" | "google" | "xai";
4568
5916
  options?: Record<string, unknown>;
4569
5917
  }>]>>;
4570
5918
  vad: z.ZodOptional<z.ZodString>;
@@ -4728,47 +6076,47 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4728
6076
  stt?: {
4729
6077
  voice?: string;
4730
6078
  kind?: "inference";
4731
- options?: Record<string, unknown>;
4732
6079
  model?: string;
6080
+ options?: Record<string, unknown>;
4733
6081
  } | {
4734
- provider?: "deepgram" | "elevenlabs";
4735
- kind?: "plugin";
4736
6082
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6083
+ kind?: "plugin";
6084
+ provider?: "deepgram" | "elevenlabs";
4737
6085
  options?: Record<string, unknown>;
4738
6086
  } | {
4739
- provider?: "google" | "xai" | "openai";
4740
6087
  kind?: "realtime";
6088
+ provider?: "openai" | "google" | "xai";
4741
6089
  options?: Record<string, unknown>;
4742
6090
  };
4743
6091
  volume?: number;
4744
6092
  llm?: {
4745
6093
  voice?: string;
4746
6094
  kind?: "inference";
4747
- options?: Record<string, unknown>;
4748
6095
  model?: string;
6096
+ options?: Record<string, unknown>;
4749
6097
  } | {
4750
- provider?: "deepgram" | "elevenlabs";
4751
- kind?: "plugin";
4752
6098
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6099
+ kind?: "plugin";
6100
+ provider?: "deepgram" | "elevenlabs";
4753
6101
  options?: Record<string, unknown>;
4754
6102
  } | {
4755
- provider?: "google" | "xai" | "openai";
4756
6103
  kind?: "realtime";
6104
+ provider?: "openai" | "google" | "xai";
4757
6105
  options?: Record<string, unknown>;
4758
6106
  };
4759
6107
  tts?: {
4760
6108
  voice?: string;
4761
6109
  kind?: "inference";
4762
- options?: Record<string, unknown>;
4763
6110
  model?: string;
6111
+ options?: Record<string, unknown>;
4764
6112
  } | {
4765
- provider?: "deepgram" | "elevenlabs";
4766
- kind?: "plugin";
4767
6113
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6114
+ kind?: "plugin";
6115
+ provider?: "deepgram" | "elevenlabs";
4768
6116
  options?: Record<string, unknown>;
4769
6117
  } | {
4770
- provider?: "google" | "xai" | "openai";
4771
6118
  kind?: "realtime";
6119
+ provider?: "openai" | "google" | "xai";
4772
6120
  options?: Record<string, unknown>;
4773
6121
  };
4774
6122
  vadOptions?: {
@@ -4822,47 +6170,47 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4822
6170
  stt?: {
4823
6171
  voice?: string;
4824
6172
  kind?: "inference";
4825
- options?: Record<string, unknown>;
4826
6173
  model?: string;
6174
+ options?: Record<string, unknown>;
4827
6175
  } | {
4828
- provider?: "deepgram" | "elevenlabs";
4829
- kind?: "plugin";
4830
6176
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6177
+ kind?: "plugin";
6178
+ provider?: "deepgram" | "elevenlabs";
4831
6179
  options?: Record<string, unknown>;
4832
6180
  } | {
4833
- provider?: "google" | "xai" | "openai";
4834
6181
  kind?: "realtime";
6182
+ provider?: "openai" | "google" | "xai";
4835
6183
  options?: Record<string, unknown>;
4836
6184
  };
4837
6185
  volume?: number;
4838
6186
  llm?: {
4839
6187
  voice?: string;
4840
6188
  kind?: "inference";
4841
- options?: Record<string, unknown>;
4842
6189
  model?: string;
6190
+ options?: Record<string, unknown>;
4843
6191
  } | {
4844
- provider?: "deepgram" | "elevenlabs";
4845
- kind?: "plugin";
4846
6192
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6193
+ kind?: "plugin";
6194
+ provider?: "deepgram" | "elevenlabs";
4847
6195
  options?: Record<string, unknown>;
4848
6196
  } | {
4849
- provider?: "google" | "xai" | "openai";
4850
6197
  kind?: "realtime";
6198
+ provider?: "openai" | "google" | "xai";
4851
6199
  options?: Record<string, unknown>;
4852
6200
  };
4853
6201
  tts?: {
4854
6202
  voice?: string;
4855
6203
  kind?: "inference";
4856
- options?: Record<string, unknown>;
4857
6204
  model?: string;
6205
+ options?: Record<string, unknown>;
4858
6206
  } | {
4859
- provider?: "deepgram" | "elevenlabs";
4860
- kind?: "plugin";
4861
6207
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6208
+ kind?: "plugin";
6209
+ provider?: "deepgram" | "elevenlabs";
4862
6210
  options?: Record<string, unknown>;
4863
6211
  } | {
4864
- provider?: "google" | "xai" | "openai";
4865
6212
  kind?: "realtime";
6213
+ provider?: "openai" | "google" | "xai";
4866
6214
  options?: Record<string, unknown>;
4867
6215
  };
4868
6216
  vadOptions?: {
@@ -4916,47 +6264,47 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
4916
6264
  stt?: {
4917
6265
  voice?: string;
4918
6266
  kind?: "inference";
4919
- options?: Record<string, unknown>;
4920
6267
  model?: string;
6268
+ options?: Record<string, unknown>;
4921
6269
  } | {
4922
- provider?: "deepgram" | "elevenlabs";
4923
- kind?: "plugin";
4924
6270
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6271
+ kind?: "plugin";
6272
+ provider?: "deepgram" | "elevenlabs";
4925
6273
  options?: Record<string, unknown>;
4926
6274
  } | {
4927
- provider?: "google" | "xai" | "openai";
4928
6275
  kind?: "realtime";
6276
+ provider?: "openai" | "google" | "xai";
4929
6277
  options?: Record<string, unknown>;
4930
6278
  };
4931
6279
  volume?: number;
4932
6280
  llm?: {
4933
6281
  voice?: string;
4934
6282
  kind?: "inference";
4935
- options?: Record<string, unknown>;
4936
6283
  model?: string;
6284
+ options?: Record<string, unknown>;
4937
6285
  } | {
4938
- provider?: "deepgram" | "elevenlabs";
4939
- kind?: "plugin";
4940
6286
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6287
+ kind?: "plugin";
6288
+ provider?: "deepgram" | "elevenlabs";
4941
6289
  options?: Record<string, unknown>;
4942
6290
  } | {
4943
- provider?: "google" | "xai" | "openai";
4944
6291
  kind?: "realtime";
6292
+ provider?: "openai" | "google" | "xai";
4945
6293
  options?: Record<string, unknown>;
4946
6294
  };
4947
6295
  tts?: {
4948
6296
  voice?: string;
4949
6297
  kind?: "inference";
4950
- options?: Record<string, unknown>;
4951
6298
  model?: string;
6299
+ options?: Record<string, unknown>;
4952
6300
  } | {
4953
- provider?: "deepgram" | "elevenlabs";
4954
- kind?: "plugin";
4955
6301
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6302
+ kind?: "plugin";
6303
+ provider?: "deepgram" | "elevenlabs";
4956
6304
  options?: Record<string, unknown>;
4957
6305
  } | {
4958
- provider?: "google" | "xai" | "openai";
4959
6306
  kind?: "realtime";
6307
+ provider?: "openai" | "google" | "xai";
4960
6308
  options?: Record<string, unknown>;
4961
6309
  };
4962
6310
  vadOptions?: {
@@ -5010,47 +6358,47 @@ declare const LuaVoiceConfigSchema: z.ZodEffects<z.ZodObject<{
5010
6358
  stt?: {
5011
6359
  voice?: string;
5012
6360
  kind?: "inference";
5013
- options?: Record<string, unknown>;
5014
6361
  model?: string;
6362
+ options?: Record<string, unknown>;
5015
6363
  } | {
5016
- provider?: "deepgram" | "elevenlabs";
5017
- kind?: "plugin";
5018
6364
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6365
+ kind?: "plugin";
6366
+ provider?: "deepgram" | "elevenlabs";
5019
6367
  options?: Record<string, unknown>;
5020
6368
  } | {
5021
- provider?: "google" | "xai" | "openai";
5022
6369
  kind?: "realtime";
6370
+ provider?: "openai" | "google" | "xai";
5023
6371
  options?: Record<string, unknown>;
5024
6372
  };
5025
6373
  volume?: number;
5026
6374
  llm?: {
5027
6375
  voice?: string;
5028
6376
  kind?: "inference";
5029
- options?: Record<string, unknown>;
5030
6377
  model?: string;
6378
+ options?: Record<string, unknown>;
5031
6379
  } | {
5032
- provider?: "deepgram" | "elevenlabs";
5033
- kind?: "plugin";
5034
6380
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6381
+ kind?: "plugin";
6382
+ provider?: "deepgram" | "elevenlabs";
5035
6383
  options?: Record<string, unknown>;
5036
6384
  } | {
5037
- provider?: "google" | "xai" | "openai";
5038
6385
  kind?: "realtime";
6386
+ provider?: "openai" | "google" | "xai";
5039
6387
  options?: Record<string, unknown>;
5040
6388
  };
5041
6389
  tts?: {
5042
6390
  voice?: string;
5043
6391
  kind?: "inference";
5044
- options?: Record<string, unknown>;
5045
6392
  model?: string;
6393
+ options?: Record<string, unknown>;
5046
6394
  } | {
5047
- provider?: "deepgram" | "elevenlabs";
5048
- kind?: "plugin";
5049
6395
  class?: "LLM" | "STT" | "STTv2" | "TTS";
6396
+ kind?: "plugin";
6397
+ provider?: "deepgram" | "elevenlabs";
5050
6398
  options?: Record<string, unknown>;
5051
6399
  } | {
5052
- provider?: "google" | "xai" | "openai";
5053
6400
  kind?: "realtime";
6401
+ provider?: "openai" | "google" | "xai";
5054
6402
  options?: Record<string, unknown>;
5055
6403
  };
5056
6404
  vadOptions?: {
@@ -5137,7 +6485,7 @@ export declare interface LuaVoiceHookContext {
5137
6485
  * The constructor below stores the raw input as-is — the runtime classes
5138
6486
  * never execute as part of the push pipeline.
5139
6487
  */
5140
- declare type LuaVoiceModelInput = string | object;
6488
+ export declare type LuaVoiceModelInput = string | object;
5141
6489
 
5142
6490
  export declare class LuaVoiceTool<TInput extends ZodType = ZodType> implements LuaTool<TInput> {
5143
6491
  readonly name: string;
@@ -5389,6 +6737,7 @@ export declare class LuaWebhook {
5389
6737
  * @param query - Query parameters object
5390
6738
  * @param headers - Headers object
5391
6739
  * @param body - Request body
6740
+ * @param rawBody - Exact request bytes (utf8), delivered as `event.rawBody` when given
5392
6741
  * @returns Promise resolving to webhook execution result
5393
6742
  * @throws Error if validation fails for any input
5394
6743
  *
@@ -5401,7 +6750,7 @@ export declare class LuaWebhook {
5401
6750
  * );
5402
6751
  * ```
5403
6752
  */
5404
- execute(query?: Record<string, any>, headers?: Record<string, any>, body?: any): Promise<any>;
6753
+ execute(query?: Record<string, any>, headers?: Record<string, any>, body?: any, rawBody?: string): Promise<any>;
5405
6754
  }
5406
6755
 
5407
6756
  /**
@@ -5434,13 +6783,23 @@ export declare interface LuaWebhookConfig {
5434
6783
  /**
5435
6784
  * Event payload delivered to webhook execute functions.
5436
6785
  */
5437
- declare interface LuaWebhookEvent {
6786
+ export declare interface LuaWebhookEvent {
5438
6787
  /** Parsed query parameters */
5439
6788
  query?: Record<string, any>;
5440
6789
  /** Request headers */
5441
6790
  headers?: Record<string, any>;
5442
6791
  /** Request body (JSON or raw data) */
5443
6792
  body?: any;
6793
+ /**
6794
+ * The EXACT unparsed request bytes, as a utf8 string. Use it to verify a
6795
+ * vendor's own signature scheme (Stripe `t=…,v1=…`, GitHub `sha256=…`, Slack
6796
+ * `v0:…`) in `execute` — those HMACs cover the wire bytes, which
6797
+ * `JSON.stringify(body)` does not reproduce. Present for JSON requests
6798
+ * (`''` for an empty body); absent for form-encoded / text bodies and for
6799
+ * webhooks fired by platform events. Header keys arrive lowercased, e.g.
6800
+ * `event.headers['x-hub-signature-256']`.
6801
+ */
6802
+ rawBody?: string;
5444
6803
  /** ISO timestamp when the webhook was received */
5445
6804
  timestamp: string;
5446
6805
  }
@@ -5480,7 +6839,9 @@ export declare type LuaWorkflowBuildCode = 'duplicate-step-id' | 'unknown-step-r
5480
6839
  * chain — the code is `node-type-unsupported-in-container`. Kept for one minor so a consumer switching on the
5481
6840
  * union still compiles; removed in the next.
5482
6841
  */
5483
- | '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';
6842
+ | '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'
6843
+ /** LUA-973: `remindAfterHours` is not a number of hours in 1..720 (`validateApprovalReminder`). */
6844
+ | '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';
5484
6845
 
5485
6846
  export declare interface LuaWorkflowBuilder {
5486
6847
  then(step: StepRef): this;
@@ -5662,6 +7023,12 @@ export declare interface MCPServerBaseConfig {
5662
7023
  description?: string;
5663
7024
  /** Optional timeout in milliseconds (default: 60000) */
5664
7025
  timeout?: number;
7026
+ /**
7027
+ * Optional tool allow/deny list, applied by the platform when it discovers
7028
+ * this server's tools. Use it to expose only the tools the agent needs.
7029
+ * See {@link MCPToolFilter}.
7030
+ */
7031
+ tools?: MCPToolFilter;
5665
7032
  }
5666
7033
 
5667
7034
  /**
@@ -5753,6 +7120,29 @@ export declare interface MCPStreamableHttpServerConfig extends MCPServerBaseConf
5753
7120
  headers?: Record<string, string> | HeadersResolverFunction;
5754
7121
  }
5755
7122
 
7123
+ /**
7124
+ * Per-server tool allow/deny list for an MCP server.
7125
+ *
7126
+ * Entries are the server's own (raw) tool names — not the namespaced
7127
+ * `${serverName}_${tool}` id the agent sees — matched exactly, or as a prefix
7128
+ * when the entry ends in `*` (e.g. `'read_*'`).
7129
+ *
7130
+ * - `deny` always wins over `allow`.
7131
+ * - `allow` omitted ⇒ every tool the server lists (minus `deny`).
7132
+ * - `allow: []` ⇒ no tools from this server.
7133
+ *
7134
+ * @example
7135
+ * ```typescript
7136
+ * tools: { allow: ['search', 'read_*'], deny: ['read_secrets'] }
7137
+ * ```
7138
+ */
7139
+ export declare interface MCPToolFilter {
7140
+ /** Only these tools are exposed to the agent. */
7141
+ allow?: string[];
7142
+ /** These tools are never exposed to the agent (wins over `allow`). */
7143
+ deny?: string[];
7144
+ }
7145
+
5756
7146
  /**
5757
7147
  * MCP Server transport type - determines how to connect to the server.
5758
7148
  *
@@ -5765,6 +7155,35 @@ export declare type MCPTransport = 'sse' | 'streamable-http';
5765
7155
 
5766
7156
  declare type Message = TextMessage_2 | ImageMessage_2 | FileMessage_2;
5767
7157
 
7158
+ export declare const Metrics: MetricsApi;
7159
+
7160
+ /**
7161
+ * Record a number your agent cares about (orders completed, a latency, a 0/1 outcome) so its owner's objectives
7162
+ * — and supervisor agents holding `supervision:observe` — can track it.
7163
+ */
7164
+ export declare interface MetricsApi {
7165
+ /**
7166
+ * Record one point. `name`: lower-case, dotted / underscored, ≤ 64 chars. `tags`: at most 4 short string pairs
7167
+ * (each distinct tag set is a series; an agent keeps at most 200 live series). Rate-limited per agent.
7168
+ *
7169
+ * Never throws: the receipt says whether the point was stored (`accepted`) or why not (`code`, e.g.
7170
+ * `agent_metrics_disabled`, `agent_metric_rate_limited`). In `lua test` / `lua dev` the point is checked but
7171
+ * recorded nowhere (`agent_metrics_offline`).
7172
+ *
7173
+ * @example
7174
+ * ```typescript
7175
+ * await Metrics.record('orders.completed', 1, { channel: Lua.request.channel });
7176
+ * ```
7177
+ */
7178
+ record(name: string, value: number, tags?: Record<string, string>): Promise<AgentMetricRecordReceipt>;
7179
+ }
7180
+
7181
+ declare interface ModelReasoningOptions {
7182
+ effort?: ReasoningEffort;
7183
+ /** Whether to surface the reasoning trace to the caller. Default true. */
7184
+ show?: boolean;
7185
+ }
7186
+
5768
7187
  export declare const ne: <T>(l: TypedRef<T>, r: TypedRef<T> | Literal<T>) => LuaPredicate;
5769
7188
 
5770
7189
  /** `.workflow(id, ref, input?, opts?)` — a nested run (a `subrun` row). */
@@ -5838,7 +7257,7 @@ declare class OrderApi extends HttpClient implements OrderAPI {
5838
7257
  create(orderData: CreateOrderRequest): Promise<OrderInstance>;
5839
7258
  /**
5840
7259
  * Updates the status of an existing order
5841
- * @param status - The new order status (e.g., 'pending', 'processing', 'shipped', 'delivered', 'cancelled')
7260
+ * @param status - The new order status (e.g., 'pending', 'confirmed', 'fulfilled', 'cancelled'). `OrderStatus.FULFILLED` is sent as the platform value `fullfilled`.
5842
7261
  * @param orderId - The unique identifier of the order to update
5843
7262
  * @returns Promise resolving to the updated OrderResponse
5844
7263
  * @throws Error if the order is not found or the status update fails
@@ -5854,7 +7273,7 @@ declare class OrderApi extends HttpClient implements OrderAPI {
5854
7273
  updateData(data: Record<string, any>, orderId: string): Promise<OrderResponse>;
5855
7274
  /**
5856
7275
  * Retrieves all user orders with optional status filtering
5857
- * @param status - Optional order status to filter by (e.g., 'pending', 'processing', 'shipped', 'delivered', 'cancelled')
7276
+ * @param status - Optional order status to filter by (e.g., 'pending', 'confirmed', 'fulfilled', 'cancelled'). `OrderStatus.FULFILLED` is sent as the platform value `fullfilled`.
5858
7277
  * @returns Promise resolving to an array of OrderInstance objects
5859
7278
  * @throws Error if the request fails or orders cannot be retrieved
5860
7279
  */
@@ -5873,7 +7292,8 @@ declare class OrderApi extends HttpClient implements OrderAPI {
5873
7292
  * Calculated/derived properties maintained by the system.
5874
7293
  */
5875
7294
  declare interface OrderCommon {
5876
- status: 'pending' | 'confirmed' | 'fulfilled' | 'cancelled';
7295
+ /** The platform stores and returns the misspelt 'fullfilled'. */
7296
+ status: 'pending' | 'confirmed' | 'fulfilled' | 'fullfilled' | 'cancelled';
5877
7297
  totalAmount: string | number;
5878
7298
  currency: string;
5879
7299
  itemCount: number;
@@ -6039,6 +7459,17 @@ declare interface Pagination {
6039
7459
  prevPage: number | null;
6040
7460
  }
6041
7461
 
7462
+ /** Options for `Data.patch` (LUA-963). */
7463
+ export declare interface PatchCustomDataOptions {
7464
+ /**
7465
+ * Compare-and-swap: apply the patch only if the entry is still at this
7466
+ * version (`entry.version` from `Data.get`, `entry._version` on a
7467
+ * `DataEntryInstance`). A mismatch writes nothing and rejects with
7468
+ * `code === 'data_version_conflict'`.
7469
+ */
7470
+ ifVersion?: number;
7471
+ }
7472
+
6042
7473
  export { PathOrLiteral }
6043
7474
 
6044
7475
  /** P split on '.' walked into T; `unknown` past depth 4 or through an index. */
@@ -6293,9 +7724,10 @@ declare interface ProductAPI {
6293
7724
  /**
6294
7725
  * Searches products.
6295
7726
  * @param query - Search query
7727
+ * @param limit - Max products to return (default 5)
6296
7728
  * @returns Promise resolving to search results
6297
7729
  */
6298
- search(query: string): Promise<any>;
7730
+ search(query: string, limit?: number): Promise<any>;
6299
7731
  }
6300
7732
 
6301
7733
  /**
@@ -6510,9 +7942,10 @@ export declare const Products: {
6510
7942
  * Searches products by query string.
6511
7943
  *
6512
7944
  * @param query - Search query
7945
+ * @param limit - Max products to return (default 5)
6513
7946
  * @returns Promise resolving to search results
6514
7947
  */
6515
- search(query: string): Promise<ProductSearchInstance>;
7948
+ search(query: string, limit?: number): Promise<ProductSearchInstance>;
6516
7949
  /**
6517
7950
  * Retrieves a specific product by ID.
6518
7951
  *
@@ -6633,6 +8066,87 @@ export declare interface ProfileResponse {
6633
8066
  };
6634
8067
  }
6635
8068
 
8069
+ /**
8070
+ * Progress API — show live progress for a long-running tool in the chat that called it.
8071
+ *
8072
+ * Each call updates ONE progress card for the current tool call; the card closes on its own when the tool
8073
+ * returns. It is best-effort: it never throws, and resolves `{ emitted: false }` when the chat surface cannot
8074
+ * show it (no live stream, a text-only channel, or offline in `lua test`).
8075
+ *
8076
+ * @example
8077
+ * ```typescript
8078
+ * import { Progress } from 'lua-cli';
8079
+ *
8080
+ * for (let i = 0; i < files.length; i++) {
8081
+ * await Progress.update({ label: 'Importing files', fraction: i / files.length, phase: files[i].name });
8082
+ * await importFile(files[i]);
8083
+ * }
8084
+ * ```
8085
+ */
8086
+ export declare const Progress: ProgressApi;
8087
+
8088
+ /**
8089
+ * wave 2 U15 — `Progress.update(...)` outside a deployed agent.
8090
+ *
8091
+ * In a deployed agent the `lua-cli` import is stripped at compile time and the sandbox's own `Progress` global
8092
+ * serves the call, putting a live progress card on the chat turn. Offline (`lua test`, `lua dev`, or a plain
8093
+ * Node import) there is no live chat stream to show it on, so every call is a no-op answering
8094
+ * `{ emitted: false }`. It never throws.
8095
+ */
8096
+ export declare interface ProgressApi {
8097
+ /**
8098
+ * Show or update this tool's progress card in the chat that called it.
8099
+ *
8100
+ * - `label`: card title; the first call's label (or the tool's name) is kept when you leave it out.
8101
+ * - `fraction`: 0..1 (clamped); leave it out for an indeterminate bar.
8102
+ * - `phase`: what the tool is doing now, e.g. "Reading sources (3/12)".
8103
+ *
8104
+ * Resolves `{ emitted: true }` when the card was (or, for a burst of calls, will be) shown, and
8105
+ * `{ emitted: false }` when there is nothing to show it on. It never throws.
8106
+ */
8107
+ update(input?: ProgressUpdateInput): Promise<ProgressUpdateReceipt>;
8108
+ }
8109
+
8110
+ /**
8111
+ * U15 (wave 2) — run cards for SDK-started runs and `Progress.update`. Owner: U15.
8112
+ * Contract: docs/agent-builder/wave2-contracts.md §U15.
8113
+ *
8114
+ * - An SDK-started workflow run (`Workflows.start`) carrying `originThreadId` emits the EXISTING
8115
+ * `data-lua-workflow-run` parts into that thread (lua-core `workflow-part-emitter.ts`), so Desktop shows
8116
+ * the live run card. No new part type.
8117
+ * - `Progress.update(...)` from a long custom tool emits the EXISTING `data-lua-job-progress` part
8118
+ * (`LuaJobProgressData`, `source: 'sdk-job'`) through lua-core `job-progress-emitter.ts` — only when a
8119
+ * live stream writer exists and the surface declared the `jobs` client capability; otherwise a no-op.
8120
+ */
8121
+ /** `Progress.update(input)`. */
8122
+ export declare interface ProgressUpdateInput {
8123
+ /** Card label; the first call's label (or the tool's name) is kept when absent. */
8124
+ label?: string;
8125
+ /** Determinate progress 0..1 (clamped); absent ⇒ indeterminate. */
8126
+ fraction?: number;
8127
+ /** Current phase text, e.g. "Reading sources (3/12)". */
8128
+ phase?: string;
8129
+ }
8130
+
8131
+ export declare interface ProgressUpdateReceipt {
8132
+ /** `false` when there is no live stream to show it on (a no-op, never an error). */
8133
+ emitted: boolean;
8134
+ }
8135
+
8136
+ /**
8137
+ * U1 (wave 2) — provision agents for a user: `Agents.create(input, { onBehalfOf, consentId })` under an
8138
+ * org provisioning policy. Owner: U1. Consumers: U17 (one-per-member instances), U9 (pending secrets
8139
+ * attach on create), U4b (suspension reasons). Contract: docs/agent-builder/wave2-contracts.md §U1.
8140
+ *
8141
+ * What a create does (U1 spec): a PRIVATE agent with `createdBy = onBehalfOf` (an org member), an empty
8142
+ * scaffold backup v1 (shared-source-sync) so restore works, `connectionPolicy: 'explicit'` (U2), and a
8143
+ * supervision grant for the CALLING agent on the new agent with `createdByUserId = onBehalfOf`,
8144
+ * `source: 'provisioning'`, `consentId`, its actions bounded by the policy.
8145
+ */
8146
+
8147
+ /** Supervision actions a provisioning grant may carry (`@lua/authz` `SUPERVISION_ACTIONS`). */
8148
+ declare type ProvisionedSupervisionAction = 'observe' | 'observe-content' | 'preview' | 'release' | 'act';
8149
+
6636
8150
  declare interface PushJobVersionDTO {
6637
8151
  name: string;
6638
8152
  version: string;
@@ -6802,6 +8316,175 @@ declare interface SearchProductsResponse {
6802
8316
  data: Product[];
6803
8317
  }
6804
8318
 
8319
+ /** Datadog's validate host is per region; the caller picks only from this enum. */
8320
+ declare const SECRET_DATADOG_REGIONS: readonly ["us1", "eu1"];
8321
+
8322
+ declare const SECRET_REQUEST_STATES: readonly ["pending", "submitted", "stored", "attached", "expired", "cancelled"];
8323
+
8324
+ /**
8325
+ * U9 (wave 2) — secret requests tested on the server. Owner: U9 (SDK `Secrets.*`, lua-api secrets service,
8326
+ * provider test catalogue, hosted-page token routes, the lua-core `requestSecret` echo tool). Consumers:
8327
+ * U9D (lua-desktop masked card), U1 (calls U9's attach for pending secrets at provisioning).
8328
+ * Contract: docs/agent-builder/wave2-contracts.md §U9.
8329
+ *
8330
+ * Values are stored through the EXISTING agent env path (lua-agents `agentenvs`). That path stores `data` as
8331
+ * plain text in the document, so an agent-target value is encrypted at rest only by the storage layer (the
8332
+ * database's own encryption), not by the application; a pending-target value is a KMS envelope until it is
8333
+ * attached. Values are never returned by any route, SDK call, log or outcome turn. The provider test catalogue is
8334
+ * SERVER-OWNED: a caller can only name a provider; the request, host and interpretation are fixed.
8335
+ */
8336
+ declare const SECRET_TEST_RESULTS: readonly ["ok", "unauthorized", "wrong_key_type", "insufficient_permission", "unreachable", "unverified"];
8337
+
8338
+ declare type SecretDatadogRegion = (typeof SECRET_DATADOG_REGIONS)[number];
8339
+
8340
+ /**
8341
+ * `Secrets.request(...)` input. `key` is the env key a single-field secret is stored under; a bundle
8342
+ * stores each field under `fields[i].envKey`. Env keys match {@link SECRET_ENV_KEY_PATTERN}.
8343
+ */
8344
+ export declare interface SecretRequestInput {
8345
+ provider: string;
8346
+ key: string;
8347
+ target?: SecretRequestTarget;
8348
+ fields?: Array<{
8349
+ name: string;
8350
+ envKey: string;
8351
+ label?: string;
8352
+ }>;
8353
+ region?: SecretDatadogRegion;
8354
+ /** One line shown on the card / hosted page. */
8355
+ reason?: string;
8356
+ }
8357
+
8358
+ export declare interface SecretRequestReceipt {
8359
+ requestId: string;
8360
+ key: string;
8361
+ state: SecretRequestState;
8362
+ /** ISO. */
8363
+ expiresAt: string;
8364
+ /**
8365
+ * The one-time hosted-page token (`/secret-requests/:token`). Returned ONCE, to the creator only, at
8366
+ * creation; the server stores only its sha256 and stops resolving it once the request is done (stored,
8367
+ * cancelled, or out of attempts). Absent on every later read.
8368
+ *
8369
+ * It is a bearer CREDENTIAL: whoever holds it can write a value into the target agent's env. Hand it only
8370
+ * to the person who should enter the secret (as the hosted-page link); never return it to the model as a
8371
+ * tool result, put it in chat history, or log it.
8372
+ */
8373
+ pageToken?: string;
8374
+ }
8375
+
8376
+ declare type SecretRequestState = (typeof SECRET_REQUEST_STATES)[number];
8377
+
8378
+ /**
8379
+ * `Secrets.requestStatus(requestId)` — one request THIS agent created (including a `{ pendingFor }` request for
8380
+ * an agent that does not exist yet), in the caller's org. Any other id answers `secret_request_not_found`.
8381
+ * Never the value, the hosted-page token, or the person it was for.
8382
+ */
8383
+ export declare interface SecretRequestStatus {
8384
+ requestId: string;
8385
+ key: string;
8386
+ provider: string;
8387
+ /** `expired` once a `pending` / `submitted` request is past `expiresAt`. A failed test leaves it `pending`. */
8388
+ state: SecretRequestState;
8389
+ /** The last server-side test of a submitted value (absent until the person submits). */
8390
+ lastTest?: {
8391
+ result: SecretTestResult; /** ISO. */
8392
+ at: string;
8393
+ };
8394
+ /** ISO. */
8395
+ expiresAt: string;
8396
+ /**
8397
+ * The agent a `{ pendingFor }` request's value was attached to (U1 provisioning), once `attached`. Omitted (with
8398
+ * `state` still `attached`) when that agent is not in the caller's org.
8399
+ */
8400
+ attachedAgentId?: string;
8401
+ }
8402
+
8403
+ /**
8404
+ * Where the secret goes. `'self'` = the calling agent; a string = that agent id (must be one the caller
8405
+ * may configure); `{ pendingFor }` = a not-yet-created agent: the value is held (encrypted) on the
8406
+ * request row and attached when U1 provisioning creates the agent with that request id.
8407
+ */
8408
+ export declare type SecretRequestTarget = 'self' | string | {
8409
+ pendingFor: string;
8410
+ };
8411
+
8412
+ export declare const Secrets: SecretsApi;
8413
+
8414
+ /**
8415
+ * Secrets API — ask a person for a credential this agent needs, tested by Lua on the server before it is
8416
+ * stored in the agent's env. Values never pass through your code: they are entered on the masked Desktop
8417
+ * card or the hosted secret page, and no call here ever returns one.
8418
+ *
8419
+ * Off unless the platform enables secret requests (`secret_requests_disabled` otherwise).
8420
+ */
8421
+ export declare interface SecretsApi {
8422
+ /**
8423
+ * Open a request for a provider credential. `target` defaults to this agent (`'self'`); `{ pendingFor }`
8424
+ * holds the value for an agent that is provisioned later on the requesting person's behalf.
8425
+ * The receipt's `pageToken` (returned once) opens the hosted secret page.
8426
+ *
8427
+ * **`pageToken` is a credential**: anyone holding it can write a value into this agent's env until the
8428
+ * request is done. Send it only to the person who should enter the secret (as the hosted-page link). Never
8429
+ * return the receipt (or the token) from a tool as-is, put it in a message to the model, or log it; return
8430
+ * `requestId` / `key` / `state` instead.
8431
+ *
8432
+ * @example
8433
+ * ```typescript
8434
+ * const { requestId, key, state } = await Secrets.request({
8435
+ * provider: 'stripe',
8436
+ * key: 'STRIPE_SECRET_KEY',
8437
+ * reason: 'Issue refunds for support tickets',
8438
+ * });
8439
+ * return { requestId, key, state }; // never the pageToken
8440
+ * ```
8441
+ */
8442
+ request(input: SecretRequestInput): Promise<SecretRequestReceipt>;
8443
+ /** Whether `key` is set, its provider, the last test result and any open request — never the value. */
8444
+ status(key: string): Promise<SecretStatus>;
8445
+ /** Re-test the stored value against the provider's fixed probe. `result` is a fixed enum. */
8446
+ test(key: string): Promise<SecretTestOutcome>;
8447
+ /**
8448
+ * The state of ONE request this agent created — notably a `{ pendingFor }` request for an agent that does not
8449
+ * exist yet, which `status(key)` cannot see. Answers `{ requestId, key, provider, state, lastTest?: { result, at },
8450
+ * expiresAt, attachedAgentId? }`: `state` `stored` means the person submitted and the server test passed
8451
+ * (`lastTest.result` `ok`, or `unverified` for an uncatalogued provider); a failed test leaves it `pending` with
8452
+ * `lastTest` set; `attached` (with `attachedAgentId`) once provisioning attached it. Never the value or the token.
8453
+ * A request another agent created, or from another org, answers `secret_request_not_found` like an unknown id.
8454
+ * Platform only: refused offline (`secrets_unavailable`).
8455
+ *
8456
+ * @example
8457
+ * ```typescript
8458
+ * const s = await Secrets.requestStatus(requestId);
8459
+ * if (s.state === 'stored' && s.lastTest?.result === 'ok') { ... }
8460
+ * ```
8461
+ */
8462
+ requestStatus(requestId: string): Promise<SecretRequestStatus>;
8463
+ }
8464
+
8465
+ /** `Secrets.status(key)` — never the value. */
8466
+ export declare interface SecretStatus {
8467
+ key: string;
8468
+ present: boolean;
8469
+ provider?: string;
8470
+ lastTest?: {
8471
+ result: SecretTestResult;
8472
+ testedAt: string;
8473
+ };
8474
+ pendingRequestId?: string;
8475
+ }
8476
+
8477
+ /** `Secrets.test(key)`. */
8478
+ export declare interface SecretTestOutcome {
8479
+ key: string;
8480
+ provider: string;
8481
+ result: SecretTestResult;
8482
+ /** ISO. */
8483
+ testedAt: string;
8484
+ }
8485
+
8486
+ export declare type SecretTestResult = (typeof SECRET_TEST_RESULTS)[number];
8487
+
6805
8488
  declare interface SendTemplateButtonValue {
6806
8489
  sub_type: WhatsAppTemplateButtonType;
6807
8490
  index: string;
@@ -6815,12 +8498,19 @@ export declare interface SendTemplateData {
6815
8498
  }
6816
8499
 
6817
8500
  export declare interface SendTemplateResponse {
6818
- results: any[];
8501
+ results: SendTemplateResult[];
6819
8502
  errors: any[];
6820
8503
  totalProcessed: number;
6821
8504
  totalErrors: number;
6822
8505
  }
6823
8506
 
8507
+ export declare interface SendTemplateResult {
8508
+ phoneNumber: string;
8509
+ ok: boolean;
8510
+ messageId?: string;
8511
+ error?: string;
8512
+ }
8513
+
6824
8514
  export declare interface SendTemplateValues {
6825
8515
  header?: Record<string, string> & {
6826
8516
  image_url?: string;
@@ -6852,7 +8542,7 @@ declare interface SignalRunResult {
6852
8542
  * and agent `persona` play different semantic roles. Sharing the structural
6853
8543
  * shape today keeps the runtime lean; future divergence is a one-line change.
6854
8544
  */
6855
- declare type SkillContextText = string | {
8545
+ export declare type SkillContextText = string | {
6856
8546
  base?: string;
6857
8547
  voice?: string;
6858
8548
  text?: string;
@@ -6931,6 +8621,275 @@ declare interface SupervisedAgentSummary {
6931
8621
  actions: string[];
6932
8622
  }
6933
8623
 
8624
+ /** `workflows.get` — metadata only: never the graph, script, code or tools. */
8625
+ declare interface SupervisedWorkflow {
8626
+ workflowId: string;
8627
+ name?: string;
8628
+ /** The value `workflows.deploy` takes as `expectActive` (null = nothing live). */
8629
+ activeVersionId: string | null;
8630
+ /** Newest first, at most {@link SUPERVISED_WORKFLOW_VERSIONS_MAX}. */
8631
+ versions: SupervisedWorkflowVersion[];
8632
+ }
8633
+
8634
+ /** `workflows.create` — the workflow `push` / `deploy` take as `workflowId`. `created: false` = it already existed. */
8635
+ declare interface SupervisedWorkflowCreated {
8636
+ workflowId: string;
8637
+ name: string;
8638
+ created: boolean;
8639
+ }
8640
+
8641
+ declare interface SupervisedWorkflowVersion {
8642
+ versionId: string;
8643
+ version: string;
8644
+ /** `active` = the workflow's `activeVersionId`; `sandbox` = a mutable `-sandbox` version; else `inactive`. */
8645
+ status: 'active' | 'inactive' | 'sandbox';
8646
+ createdAt?: string;
8647
+ }
8648
+
8649
+ declare const SUPERVISION_ACCESS_REQUEST_STATES: readonly ["pending", "approved", "denied", "cancelled", "expired", "revoked"];
8650
+
8651
+ /**
8652
+ * U25 (LUA-959) — the supervision event kinds. An emitter writes one outbox row
8653
+ * per event of a target agent that some supervisor subscribed to; lua-core then
8654
+ * starts each subscribed supervisor's trigger, re-checking the `supervision:observe`
8655
+ * grant at delivery time.
8656
+ *
8657
+ * `trigger.held` and `agent.paused` were typed extension points; SV (supervisor platform) gave them their
8658
+ * emitters: lua-core's trigger dispatch emits `trigger.held` when a delivery to an inactive or paused trigger
8659
+ * is held (one per trigger per hour), lua-api's agent pause emits `agent.paused`.
8660
+ *
8661
+ * Wave 2 adds three more extension points the same way (no emitter until the owning item lands):
8662
+ * `objective.breached` (U30), `judge.score_below_threshold` (U25c, DOC3 §4.9) and
8663
+ * `never_rule.violated` (U25c). Only the owning item writes an emitter for its kind.
8664
+ */
8665
+ 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"];
8666
+
8667
+ /**
8668
+ * The approver: the OWNER (creator) for a private agent; org admins / agent builders (holders of
8669
+ * `members:assign-role` or `agents:manage` on the agent) for a shared one.
8670
+ */
8671
+ declare type SupervisionAccessApproverKind = 'owner' | 'org_admin';
8672
+
8673
+ /** What approving the request adds (empty lists omitted). `expiry` says how the grant's expiry changes. */
8674
+ declare interface SupervisionAccessGrantDelta {
8675
+ actions?: string[];
8676
+ releaseWorkflowIds?: string[];
8677
+ unattendedWorkflowIds?: string[];
8678
+ dataCollections?: string[];
8679
+ /** Upgrade of an expiring `access_request` grant: `'kept'` (no new expiry asked), `'set'` (the new one applies). */
8680
+ expiry?: 'kept' | 'set';
8681
+ /** The approval also records the owner's opt-in to supervisor follow-ups (`notifyOwner`). */
8682
+ ownerNotify?: boolean;
8683
+ }
8684
+
8685
+ /** The supervision-grant fields an access request can add to. */
8686
+ declare interface SupervisionAccessGrantFields {
8687
+ actions: string[];
8688
+ releaseWorkflowIds?: string[];
8689
+ unattendedWorkflowIds?: string[];
8690
+ dataCollections?: string[];
8691
+ }
8692
+
8693
+ /** The live grant an upgrade request was filed against (stored on the request; never user ids). */
8694
+ declare interface SupervisionAccessGrantSnapshot extends SupervisionAccessGrantFields {
8695
+ grantId: string;
8696
+ source: 'pap' | 'access_request';
8697
+ /** ISO; only an `access_request` grant expires. */
8698
+ expiresAt?: string;
8699
+ }
8700
+
8701
+ /** lua `supervision_access_requests` row (owner U29). */
8702
+ declare interface SupervisionAccessRequest {
8703
+ requestId: string;
8704
+ orgId: string;
8705
+ requesterAgentId: string;
8706
+ targetAgentId: string;
8707
+ actions: ProvisionedSupervisionAction[];
8708
+ reason: string;
8709
+ approverKind: SupervisionAccessApproverKind;
8710
+ state: SupervisionAccessRequestState;
8711
+ /** The inbox `input_request` item the approver acts on. */
8712
+ inboxItemId?: string;
8713
+ /** Set on approval: the grant created with `createdByUserId = decidedByUserId`, `source: 'access_request'`. */
8714
+ grantId?: string;
8715
+ decidedByUserId?: string;
8716
+ /** ISO. */
8717
+ createdAt: string;
8718
+ expiresAt: string;
8719
+ grantExpiresAt?: string;
8720
+ decidedAt?: string;
8721
+ /** SV — bindings the request asked for (see {@link SupervisionAccessRequestInput}). */
8722
+ releaseWorkflowIds?: string[];
8723
+ unattendedWorkflowIds?: string[];
8724
+ dataCollections?: string[];
8725
+ notifyOwner?: boolean;
8726
+ /** SV — set when the request UPGRADES a live grant: that grant as it was when the request was filed. */
8727
+ upgradeOf?: SupervisionAccessGrantSnapshot;
8728
+ /** SV — exactly what approval adds to the supervisor's access (the approver's card lists this). */
8729
+ adds?: SupervisionAccessGrantDelta;
8730
+ }
8731
+
8732
+ /** `Agents.requestAccess(agentId, opts)`. */
8733
+ declare interface SupervisionAccessRequestInput {
8734
+ actions: ProvisionedSupervisionAction[];
8735
+ /** Shown to the approver; ≤ {@link SUPERVISION_ACCESS_REASON_MAX}. */
8736
+ reason: string;
8737
+ /** ISO; the GRANT's expiry once approved (absent ⇒ until revoked). */
8738
+ expiresAt?: string;
8739
+ /**
8740
+ * SV — the requester's OWN workflows whose code steps may release on the target (needs `release`).
8741
+ * `LUA_SUPERVISION_ACCESS_BINDINGS_ENABLED`; see `supervision-access-upgrade.types.ts`.
8742
+ */
8743
+ releaseWorkflowIds?: string[];
8744
+ /** SV — the requester's OWN workflows that may run unattended Job-tier plugin steps on the target. */
8745
+ unattendedWorkflowIds?: string[];
8746
+ /** SV — the target's custom-data collections the supervisor may read (needs `observe`). */
8747
+ dataCollections?: string[];
8748
+ /**
8749
+ * SV — ask the target's OWNER to opt in to follow-ups from this supervisor (`Agents.notifyOwner`). Recorded only
8750
+ * when the approver IS the target's owner (creator); an org admin approving a shared agent cannot opt its owner in.
8751
+ */
8752
+ notifyOwner?: boolean;
8753
+ }
8754
+
8755
+ declare type SupervisionAccessRequestState = (typeof SUPERVISION_ACCESS_REQUEST_STATES)[number];
8756
+
8757
+ /** Per-kind payloads — metadata only: never message bodies, user ids, run inputs or outputs. */
8758
+ export declare interface SupervisionEventDataByKind {
8759
+ 'governance.blocked': {
8760
+ stage: 'preprocess' | 'tool_call' | 'postprocess';
8761
+ /** `workflow` = a workflow agent step's owner-governance preflight (gate 2). */
8762
+ surface?: 'chat' | 'voice' | 'delegation' | 'workflow';
8763
+ ruleId?: string;
8764
+ reason?: string;
8765
+ channel?: string;
8766
+ };
8767
+ 'workflow.run_failed': {
8768
+ runId: string;
8769
+ workflowId?: string;
8770
+ reason?: string;
8771
+ stepId?: string;
8772
+ };
8773
+ 'workflow.run_gated': {
8774
+ runId: string;
8775
+ workflowId?: string;
8776
+ gate: 'billing' | 'quota';
8777
+ code?: string;
8778
+ stepId?: string;
8779
+ };
8780
+ 'connection.unhealthy': {
8781
+ connectionId: string;
8782
+ integrationType?: string;
8783
+ lastUnhealthyCode?: string;
8784
+ };
8785
+ /** A delivery was held for replay (`reason`: `inactive` / `paused`); one per trigger per hour (SV emitter). */
8786
+ 'trigger.held': {
8787
+ triggerName: string;
8788
+ reason?: string;
8789
+ };
8790
+ /** The agent was paused (SV emitter, lua-api). `pausedBy` is a coarse marker (`user`), never a user id. */
8791
+ 'agent.paused': {
8792
+ reason?: string;
8793
+ pausedBy?: string;
8794
+ };
8795
+ /**
8796
+ * Wave 2 extension point (U30): an owner-confirmed objective broke one of its guardrails
8797
+ * (`breach: 'guardrail'`) or drifted below its baseline (`breach: 'baseline'`). Metric values only.
8798
+ */
8799
+ 'objective.breached': {
8800
+ objectiveId: string;
8801
+ metric: string;
8802
+ breach: 'guardrail' | 'baseline';
8803
+ value: number;
8804
+ threshold: number;
8805
+ /** The evaluated window, e.g. `7d`. */
8806
+ window?: string;
8807
+ guardrailId?: string;
8808
+ };
8809
+ /**
8810
+ * Wave 2 extension point (U25c, DOC3 §4.9): a sampled completed run scored below its monitor's
8811
+ * threshold. `reasoning` respects the org's judge redaction tier and is absent when the tier strips it.
8812
+ * Flat on purpose: the outbox keeps only flat scalars (`sanitizeSupervisionEventData`), so DOC3's
8813
+ * `subject: { kind, id }` travels as `subjectKind` + `subjectId`.
8814
+ */
8815
+ 'judge.score_below_threshold': {
8816
+ monitorKey: string;
8817
+ subjectKind: 'workflow-run' | 'trigger' | 'job';
8818
+ subjectId: string;
8819
+ score: number;
8820
+ threshold: number;
8821
+ reasoning?: string;
8822
+ };
8823
+ /**
8824
+ * SV — a tool / integration call of the target failed with an AUTH error: HTTP 401 / 403, or an expired /
8825
+ * invalid token. Deduped per (target, tool) per window (`windowStart`, ISO). Metadata only: never the error text.
8826
+ */
8827
+ 'tool.auth_failed': {
8828
+ toolName: string;
8829
+ /** Where it ran: `skill`, `mcp`, `job`, `webhook`, … (the log row's `logSource`). */
8830
+ logSource?: string;
8831
+ primitiveName?: string;
8832
+ /** `unauthorized` (401), `forbidden` (403), `token_expired` (expired / invalid token or grant). */
8833
+ reason: 'unauthorized' | 'forbidden' | 'token_expired';
8834
+ windowStart: string;
8835
+ };
8836
+ /**
8837
+ * SV — the same tool / primitive of the target failed `count` times inside one window (`windowSeconds`), counted
8838
+ * across pods. Emitted once per (target, tool, window), when the count reaches the threshold.
8839
+ */
8840
+ 'tool.errors_repeated': {
8841
+ toolName: string;
8842
+ logSource?: string;
8843
+ primitiveName?: string;
8844
+ count: number;
8845
+ windowSeconds: number;
8846
+ windowStart: string;
8847
+ };
8848
+ /** Wave 2 extension point (U25c): a stored never-rule refused (or, log-only, would have refused) a call. */
8849
+ 'never_rule.violated': {
8850
+ ruleId: string;
8851
+ surface: 'passthrough' | 'mcp' | 'workflow-step' | 'tool';
8852
+ toolName?: string;
8853
+ operation?: string;
8854
+ /** `false` while `LUA_NEVER_RULES_ENFORCED` is off: the call was allowed and only recorded. */
8855
+ enforced: boolean;
8856
+ severity: 'severe';
8857
+ };
8858
+ }
8859
+
8860
+ /**
8861
+ * The trigger body a subscribed supervisor receives (`source: 'supervision'`). It is
8862
+ * delivered through the supervisor's own trigger, so that trigger's verify / filter /
8863
+ * transform slots run as for any other dispatch.
8864
+ */
8865
+ export declare interface SupervisionEventEnvelope {
8866
+ source: 'supervision';
8867
+ eventId: string;
8868
+ kind: SupervisionEventKind;
8869
+ targetAgentId: string;
8870
+ occurredAt: string;
8871
+ data: Record<string, unknown>;
8872
+ }
8873
+
8874
+ export declare type SupervisionEventKind = (typeof SUPERVISION_EVENT_KINDS)[number];
8875
+
8876
+ /**
8877
+ * `supervisorAgentId`'s trigger `triggerName` fires on `kinds` of `targetAgentId`.
8878
+ *
8879
+ * A subscription lives only as long as the grant behind it: when a delivery finds the
8880
+ * supervisor no longer holds `supervision:observe` on the target (revoked, or the two
8881
+ * agents are no longer in one org), the platform deletes the subscription, and a
8882
+ * re-granted supervisor subscribes again. Archiving either agent purges it too.
8883
+ */
8884
+ export declare interface SupervisionEventSubscription {
8885
+ supervisorAgentId: string;
8886
+ targetAgentId: string;
8887
+ kinds: SupervisionEventKind[];
8888
+ triggerName: string;
8889
+ createdAt?: string;
8890
+ updatedAt?: string;
8891
+ }
8892
+
6934
8893
  declare interface SupervisionLogRow {
6935
8894
  timestamp: string | number | Date;
6936
8895
  level?: string;
@@ -6939,6 +8898,32 @@ declare interface SupervisionLogRow {
6939
8898
  logSource?: string;
6940
8899
  primitiveName?: string;
6941
8900
  toolName?: string;
8901
+ /**
8902
+ * A non-identifying conversation key: the same value for every row of one conversation (thread) on this target,
8903
+ * never the thread id itself (which embeds the end user's id), and different on another target. Present on rows
8904
+ * written with a thread (a turn's `user_message` and `agent_response` rows, tool runtime logs, STT), so a
8905
+ * conversation's user turns and replies group under one key; absent otherwise.
8906
+ */
8907
+ threadKey?: string;
8908
+ }
8909
+
8910
+ declare interface SupervisionOwnerNotifyInput {
8911
+ message: string;
8912
+ /**
8913
+ * Optional dedupe key (1-256 characters, no control characters). A retried `notifyOwner` with the same key from
8914
+ * the same supervisor within 24 hours never posts twice: it answers the FIRST call's receipt (same `followUpId`,
8915
+ * same `threadId`). A concurrent duplicate still in flight is refused `thread_follow_up_in_progress` (retryable).
8916
+ * Scoped to `notifyOwner` — the same key on `Threads.followUp` is a different key. A key already used for another
8917
+ * target agent is refused `supervision_owner_notify_invalid`. Without a key every call posts.
8918
+ */
8919
+ idempotencyKey?: string;
8920
+ }
8921
+
8922
+ declare interface SupervisionOwnerNotifyReceipt {
8923
+ followUpId: string;
8924
+ /** The owner's home thread with the supervisor. */
8925
+ threadId: string;
8926
+ status: 'posted';
6942
8927
  }
6943
8928
 
6944
8929
  declare interface SupervisionRunSummary {
@@ -7088,6 +9073,90 @@ export declare const Templates: {
7088
9073
  };
7089
9074
  };
7090
9075
 
9076
+ /** Recorded effect kinds (DOC2 §7 seam table; `fetch` is sandbox egress record mode, §9.1). */
9077
+ 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"];
9078
+
9079
+ declare type TestEffectKind = (typeof TEST_EFFECT_KINDS)[number];
9080
+
9081
+ /** DOC2 §6.3 — Data: `shadow` (copy-on-write over live, default) or `isolated` (empty shadow only). */
9082
+ declare type TestSessionDataMode = 'shadow' | 'isolated';
9083
+
9084
+ /** One row of `lua.test_session_effects` (unique `{testSessionId, seq}`; TTL = the session's `expiresAt`). */
9085
+ declare interface TestSessionEffect {
9086
+ testSessionId: string;
9087
+ seq: number;
9088
+ kind: TestEffectKind;
9089
+ /** The execution site (`tool`, `job`, `trigger`, `workflow-step`, …). */
9090
+ site: string;
9091
+ primitiveId?: string;
9092
+ /** Redacted: secret-keyed values `[REDACTED]`, `Authorization` / `Cookie` / `X-Api-Key` dropped, body ≤ 16 KB. */
9093
+ request: unknown;
9094
+ syntheticResponse?: unknown;
9095
+ /** ISO. */
9096
+ at: string;
9097
+ }
9098
+
9099
+ /** DOC2 §6.1 — sandbox egress: `record` (default) or `live` (explicit OWNER opt-in; never for supervisors). */
9100
+ declare type TestSessionEgressMode = 'record' | 'live';
9101
+
9102
+ declare type TestSessionFireInput = TestSessionFireTarget & {
9103
+ payload?: unknown;
9104
+ };
9105
+
9106
+ declare type TestSessionFireTarget = {
9107
+ trigger: string;
9108
+ } | {
9109
+ job: string;
9110
+ } | {
9111
+ workflow: string;
9112
+ } | {
9113
+ webhook: string;
9114
+ };
9115
+
9116
+ /** DOC2 §6.1 — MCP mode: `doubles-only` (T13 default) or `read-live` (session default). */
9117
+ declare type TestSessionMcpMode = 'doubles-only' | 'read-live';
9118
+
9119
+ /** `Agents.versions(id).session(opts)` (DOC2 §6.1). `testTraffic: true` is a required literal. */
9120
+ declare interface TestSessionOpenInput {
9121
+ version: number;
9122
+ testTraffic: true;
9123
+ toolDoubles?: TestSessionToolDouble[];
9124
+ mcp?: TestSessionMcpMode;
9125
+ data?: TestSessionDataMode;
9126
+ egress?: TestSessionEgressMode;
9127
+ /** Hours; default {@link TEST_SESSION_TTL_HOURS_DEFAULT}, max {@link TEST_SESSION_TTL_HOURS_MAX}. */
9128
+ ttlHours?: number;
9129
+ }
9130
+
9131
+ /** The session record (`lua.test_sessions`). */
9132
+ declare interface TestSessionRecord {
9133
+ id: string;
9134
+ agentId: string;
9135
+ orgId: string;
9136
+ version: number;
9137
+ /** `user:<id>` / `apiKey:<id>` / `system:<agentId>` for a supervisor. */
9138
+ createdBy: string;
9139
+ mcp: TestSessionMcpMode;
9140
+ data: TestSessionDataMode;
9141
+ egress: TestSessionEgressMode;
9142
+ toolDoubles: TestSessionToolDouble[];
9143
+ status: TestSessionStatus;
9144
+ /** Turns plus fires so far (cap {@link TEST_SESSION_OPS_MAX}). */
9145
+ ops: number;
9146
+ /** ISO. */
9147
+ createdAt: string;
9148
+ expiresAt: string;
9149
+ }
9150
+
9151
+ declare type TestSessionStatus = 'open' | 'closed' | 'expired';
9152
+
9153
+ /** Same shape as `ChatRequest.toolDoubles` (lua-core `request.type.ts`). */
9154
+ declare interface TestSessionToolDouble {
9155
+ server?: string;
9156
+ tool: string;
9157
+ result: unknown;
9158
+ }
9159
+
7091
9160
  export declare interface TextMessage {
7092
9161
  type: 'text';
7093
9162
  text: string;
@@ -7098,6 +9167,88 @@ declare type TextMessage_2 = {
7098
9167
  text: string;
7099
9168
  };
7100
9169
 
9170
+ /**
9171
+ * `Threads.followUp(threadId, input)`: exactly one of `prompt` (a BACKGROUND agent turn on the thread,
9172
+ * like the workflow callback loopback) or `message` (post the text as the agent, no model turn).
9173
+ * Only the agent's OWN threads (its home threads and the threads of its turns).
9174
+ */
9175
+ export declare type ThreadFollowUpInput = ({
9176
+ prompt: string;
9177
+ message?: never;
9178
+ } | {
9179
+ message: string;
9180
+ prompt?: never;
9181
+ }) & {
9182
+ /**
9183
+ * Optional dedupe key (1-256 characters, no control characters). A retried call with the same key on the same
9184
+ * agent — within 24 hours (`FOLLOW_UP_IDEMPOTENCY_TTL_SECONDS`) — never delivers twice: it answers the FIRST call's
9185
+ * receipt (same `followUpId`) and posts / queues nothing. The key belongs to its first thread: reusing it on
9186
+ * another thread is refused `INPUT_INVALID`. Without a key every call delivers.
9187
+ */
9188
+ idempotencyKey?: string;
9189
+ };
9190
+
9191
+ export declare interface ThreadFollowUpReceipt {
9192
+ followUpId: string;
9193
+ mode: 'turn' | 'message';
9194
+ /** A turn is queued and delivered by the loopback; a message is posted immediately. */
9195
+ status: 'queued' | 'posted';
9196
+ }
9197
+
9198
+ /** `Threads.open(ownerUserId)`. The user must be one the agent may reach (same rules as `User.Inbox.push`). */
9199
+ export declare interface ThreadOpenResult {
9200
+ threadId: string;
9201
+ /** `true` the first time; the thread is otherwise reused. */
9202
+ created: boolean;
9203
+ }
9204
+
9205
+ export declare const Threads: ThreadsApi;
9206
+
9207
+ /**
9208
+ * Threads API — reach a person on a conversation your agent owns, from a job, trigger, webhook or supervision
9209
+ * handler. The platform decides every call: the feature flag, that the thread is this agent's own, that the person
9210
+ * is reachable (the run's own user, or — for an agent-level run — a member of the agent's notify list), a rate
9211
+ * limit (12 per thread and 120 per agent per hour) and an audit row on the agent's logs (never the text).
9212
+ *
9213
+ * Refusals throw an error with `name: 'ThreadFollowUpError'` and a `code` from `THREAD_FOLLOW_UP_ERRORS`
9214
+ * (`thread_follow_up_disabled`, `thread_not_owned_by_agent`, `thread_user_unreachable`,
9215
+ * `thread_follow_up_rate_limited`, `thread_follow_up_input_invalid`, `thread_follow_up_unavailable`, …).
9216
+ * `lua test` / `lua dev` never post into a real conversation: both members throw `thread_follow_up_unavailable`.
9217
+ *
9218
+ * @example
9219
+ * ```typescript
9220
+ * // In a job: open the user's home thread with this agent, then follow up there.
9221
+ * const { threadId } = await Threads.open(userId);
9222
+ * await Threads.followUp(threadId, { message: 'Your weekly report is ready.' }); // posted as the agent
9223
+ * await Threads.followUp(threadId, { prompt: 'Check whether order 1042 shipped and tell the user.' }); // a background turn
9224
+ *
9225
+ * // Safe to retry: the same idempotencyKey never delivers twice (the retry resolves the first receipt).
9226
+ * await Threads.followUp(threadId, { message: 'Order 1042 shipped.', idempotencyKey: 'order-1042-shipped' });
9227
+ * ```
9228
+ */
9229
+ export declare interface ThreadsApi {
9230
+ /**
9231
+ * The agent's HOME thread with `ownerUserId` (`{userId}-{agentId}:home`) — the same thread every time;
9232
+ * `created` is `true` only the first time.
9233
+ */
9234
+ open(ownerUserId: string): Promise<ThreadOpenResult>;
9235
+ /**
9236
+ * Follow up on one of the agent's own threads with EXACTLY one of:
9237
+ * - `{ prompt }` (≤ 8,000 chars) — start a background agent turn on the thread; the receipt is `queued`;
9238
+ * - `{ message }` (≤ 4,000 chars) — post the text as the agent with no model turn; the receipt is `posted`.
9239
+ *
9240
+ * Optional `idempotencyKey` (1-256 characters, no control characters): a retried call with the same key from this
9241
+ * agent within 24 hours delivers nothing and resolves the FIRST call's receipt (same `followUpId`) — use it when a
9242
+ * job, trigger or webhook may run twice. A duplicate sent while the first is still delivering waits for it, or is
9243
+ * refused `thread_follow_up_in_progress` (retry it). The key identifies the delivery: reusing it with different text
9244
+ * on the same thread still delivers nothing, and reusing it on ANOTHER thread is refused
9245
+ * `thread_follow_up_input_invalid` (as is reusing it for the other mode) — use one key per delivery. For
9246
+ * `{ prompt }` the key covers QUEUEING the turn, not its completion. At most once unless the platform's key store
9247
+ * fails mid-delivery. Without a key every call delivers.
9248
+ */
9249
+ followUp(threadId: string, input: ThreadFollowUpInput): Promise<ThreadFollowUpReceipt>;
9250
+ }
9251
+
7101
9252
  /**
7102
9253
  * Base interface for entities with timestamps.
7103
9254
  * Most database entities include these fields.
@@ -7192,7 +9343,7 @@ export declare interface TriggerContext<T = any> {
7192
9343
  /**
7193
9344
  * Context delivered to a trigger's verify / filter / transform slots.
7194
9345
  *
7195
- * Unlike a webhook event, `rawBody` carries the EXACT unparsed request bytes
9346
+ * As on a webhook event, `rawBody` carries the EXACT unparsed request bytes
7196
9347
  * (utf8) — HMAC signature schemes (Stripe `t=…,v1=…`, GitHub `sha256=…`, Slack
7197
9348
  * `v0:…`) are computed over the wire bytes, which `JSON.stringify(body)` does
7198
9349
  * not reproduce. `headers` keys arrive lowercased (Express), e.g.
@@ -7220,7 +9371,7 @@ export declare interface TriggerContext<T = any> {
7220
9371
  * `lua workflows describe <ref>` resolves); `correlationKey` accepts a literal or a
7221
9372
  * `'${input.<field>}'` template the trigger fills.
7222
9373
  */
7223
- declare interface TriggerStartWorkflow {
9374
+ export declare interface TriggerStartWorkflow {
7224
9375
  startWorkflow: {
7225
9376
  name: string;
7226
9377
  input?: unknown;
@@ -7253,6 +9404,8 @@ export { TypedRef }
7253
9404
  declare interface UpdateCustomDataResponse {
7254
9405
  status: string;
7255
9406
  message: string;
9407
+ /** Entry version after the write (LUA-963). */
9408
+ version?: number;
7256
9409
  }
7257
9410
 
7258
9411
  /**
@@ -7439,10 +9592,12 @@ export declare class UserDataInstance {
7439
9592
  unset(...fields: string[]): Promise<any>;
7440
9593
  /**
7441
9594
  * Clears all user data for the current user
7442
- * @returns Promise resolving to true if clearing was successful
9595
+ * @returns Promise resolving to `{ success: true }` if clearing was successful
7443
9596
  * @throws Error if the clear operation fails
7444
9597
  */
7445
- clear(): Promise<boolean>;
9598
+ clear(): Promise<{
9599
+ success: boolean;
9600
+ }>;
7446
9601
  /**
7447
9602
  * Saves the user's data
7448
9603
  * @returns Promise resolving to true if saving was successful
@@ -7452,21 +9607,41 @@ export declare class UserDataInstance {
7452
9607
  /**
7453
9608
  * Sends a message to a specific user conversation for the agent
7454
9609
  * @param messages - An array of messages to send (can be text, image, or file types)
7455
- * @returns Promise resolving to the response data from the server
7456
- * @throws Error if the message sending fails or the request is unsuccessful
9610
+ * @returns Promise resolving to true only when the platform confirmed delivery, false on a failure or an unconfirmed result. Never throws.
7457
9611
  */
7458
- send(messages: Message[]): Promise<any>;
9612
+ send(messages: Message[]): Promise<boolean>;
7459
9613
  getChatHistory(): Promise<ChatHistoryMessage[]>;
7460
9614
  }
7461
9615
 
9616
+ /** One channel id of a person, as that channel issued it. */
9617
+ declare interface UserIdentity {
9618
+ /** `whatsapp_bsuid`, `slack_user`, `slack_bot` or `teams_user`; more kinds arrive as channels move over. */
9619
+ kind: string;
9620
+ /** Who issued the value: the WhatsApp business portfolio, the Slack team or enterprise, or the Microsoft tenant. */
9621
+ scope: string;
9622
+ value: string;
9623
+ verifiedBy?: UserIdentityVerifiedBy;
9624
+ /** What the channel shows for the person. Never use it to identify them. */
9625
+ displayName?: string;
9626
+ username?: string;
9627
+ }
9628
+
9629
+ /** Which identity a message came from, as `Lua.request.sender` gives it. */
9630
+ declare type UserIdentityRef = Pick<UserIdentity, 'kind' | 'scope' | 'value'>;
9631
+
9632
+ /** How an identity was established. */
9633
+ declare type UserIdentityVerifiedBy = 'otp' | 'oauth' | 'receipt' | 'provider' | 'observed' | 'none';
9634
+
7462
9635
  /**
7463
- * Options for looking up a user by email or phone
9636
+ * Options for looking up a user by email, phone or channel identity
7464
9637
  */
7465
9638
  export declare interface UserLookupOptions {
7466
9639
  /** Email address to look up */
7467
9640
  email?: string;
7468
9641
  /** Phone number to look up (with or without + prefix) */
7469
9642
  phone?: string;
9643
+ /** A channel identity, e.g. `Lua.request.sender` or an entry of `_luaProfile.identities` */
9644
+ identity?: UserIdentityRef;
7470
9645
  }
7471
9646
 
7472
9647
  export declare const value: (v: unknown) => MapDescriptor;
@@ -7669,6 +9844,7 @@ export declare interface WaitForSignalOptions {
7669
9844
  */
7670
9845
  declare const WEB_APP_CSP_KEYS: readonly ["scriptSrc", "styleSrc", "imgSrc", "connectSrc", "fontSrc", "frameSrc", "workerSrc"];
7671
9846
 
9847
+ /** `defineWebApp({ name })`: the name leads the app's host label, so a DNS-safe subset. */
7672
9848
  export declare const WEB_APP_NAME_PATTERN: RegExp;
7673
9849
 
7674
9850
  declare const WEB_ROUTE_METHODS: readonly ["GET", "POST", "PUT", "PATCH", "DELETE"];
@@ -7757,11 +9933,29 @@ declare interface WebRouteAuth {
7757
9933
 
7758
9934
  declare type WebRouteMethod = (typeof WEB_ROUTE_METHODS)[number];
7759
9935
 
9936
+ /**
9937
+ * Body of POST /developer/agents/:agentId/channels/whatsapp/phone-request.
9938
+ * Sends WhatsApp's "share your phone number" button. A user who taps it shares
9939
+ * their own number, which is saved on their Lua profile before their next turn
9940
+ * runs. Needs an open 24h customer-service window.
9941
+ */
9942
+ declare interface WhatsAppPhoneRequestInput {
9943
+ to: {
9944
+ userId?: string;
9945
+ phoneNumber?: string;
9946
+ identity?: UserIdentityRef;
9947
+ };
9948
+ /** Message shown above the button (max 1024 characters). */
9949
+ text: string;
9950
+ options?: ChannelSendOptions;
9951
+ }
9952
+
7760
9953
  /** Body of POST /developer/agents/:agentId/channels/whatsapp/reaction */
7761
9954
  export declare interface WhatsAppReactionSendInput {
7762
9955
  to: {
7763
9956
  userId?: string;
7764
9957
  phoneNumber?: string;
9958
+ identity?: UserIdentityRef;
7765
9959
  };
7766
9960
  /** Vendor id (`wamid...`) of the message to react to — e.g. an inbound
7767
9961
  * message's id from the conversation history, ≤30 days old per Meta. */
@@ -7852,6 +10046,7 @@ export declare interface WhatsAppTemplateSendInput {
7852
10046
  to: {
7853
10047
  userId?: string;
7854
10048
  phoneNumber?: string;
10049
+ identity?: UserIdentityRef;
7855
10050
  };
7856
10051
  templateName: string;
7857
10052
  languageCode?: string;
@@ -8158,7 +10353,16 @@ declare interface WorkflowRun {
8158
10353
  parentRunId?: string;
8159
10354
  correlationKey?: string;
8160
10355
  tags?: string[];
8161
- /** R4 `gate` (02 §2.4). LUA-788: a `kind:'billing'` gate names the wallet's refusal (`code`), the held step and its expiry. */
10356
+ /**
10357
+ * R3/R4 `gate` (02 §2.4) — what a `gated` run (and a gate-parked `suspended` one) waits on. LUA-788: a
10358
+ * `kind:'billing'` gate names the wallet's refusal (`code`), the held step and its expiry. A `kind:'budget'` gate
10359
+ * carries the run cap it met (`dimension`, `spent`, `cap`) and — item 10, newer servers — the refused step's
10360
+ * estimate (`reserve`). A `kind:'start-consent'` gate carries — item 10, newer servers — WHY the start asked a
10361
+ * person (`exceeded`: each crossed threshold and the estimate judged against it, e.g. credits 34 > maxAutoCredits
10362
+ * 20) and `rateLimited` when the autonomy envelope's hourly meter sent it back. Every member past `kind` is
10363
+ * optional: an older server sends none of the item-10 members, and the CLI then words the reason from the members
10364
+ * it does send.
10365
+ */
8162
10366
  gate?: {
8163
10367
  kind: string;
8164
10368
  reason?: string;
@@ -8166,7 +10370,21 @@ declare interface WorkflowRun {
8166
10370
  code?: string;
8167
10371
  stepId?: string;
8168
10372
  expiresAt?: number;
10373
+ dimension?: 'credits' | 'actions' | 'steps' | 'jobSeconds' | (string & {});
10374
+ spent?: number;
10375
+ cap?: number;
10376
+ reserve?: number;
10377
+ exceeded?: WorkflowStartConsentExceededDto[];
10378
+ rateLimited?: boolean;
8169
10379
  };
10380
+ /**
10381
+ * WHY a `suspended` / `waiting` run is parked (R3 list rows and R4; `WorkflowRunSuspendedFor` on the server) —
10382
+ * stamped by the engine at every park, dropped on every wake and terminal. Servers since LUA-816 send it for
10383
+ * approval / input / signal / billing parks; item-10 servers add budget and the waiting kinds. Absent on a run that
10384
+ * is not parked and on a run parked before its park site stamped one: read `gate` / `status` then.
10385
+ * `lua workflows status` renders it on the header line (`suspensionReason`).
10386
+ */
10387
+ suspendedFor?: WorkflowRunSuspendedForDto;
8170
10388
  /**
8171
10389
  * Server-decided (09 §9.6): `raise_budget` on a budget gate (LUA-665), `top_up` on a billing gate (LUA-788 — the
8172
10390
  * wallet clears it; the engine re-checks and resumes on its own), `cancel_again` / `force` under a pending cancel,
@@ -8315,9 +10533,52 @@ declare interface WorkflowRunModelUsageRow {
8315
10533
  fallbacks?: number;
8316
10534
  }
8317
10535
 
8318
- /** §02 §2.4 run statuses (one union across every section). */
10536
+ /**
10537
+ * §02 §2.4 run statuses (one union across every section). The three PARKED statuses hold no worker and say why on
10538
+ * the run: `gated` (read `gate` — consent, quota, billing, an archived workspace, a paused agent), `suspended`
10539
+ * (read `suspendedFor` — an approval / input / signal, the run's budget, a payment; `gate` for a step awaiting a
10540
+ * decision),
10541
+ * `waiting` (read `suspendedFor` — a sleep, a retry backoff, a child run). See `WorkflowRunSuspendedForDto`.
10542
+ */
8319
10543
  declare type WorkflowRunStatus = 'queued' | 'running' | 'cancellation_requested' | 'gated' | 'suspended' | 'waiting' | 'completed' | 'failed' | 'cancelled' | 'abandoned' | 'timed_out';
8320
10544
 
10545
+ /**
10546
+ * Item 10 — `WorkflowRun.suspendedFor`: what the engine parked the run FOR.
10547
+ *
10548
+ * `kind` is OPEN (an unknown kind from a newer server must render generically, never crash). A step parked for a
10549
+ * decision (an exception park) is read off `gate` (`kind:'exception'`, `stepId`, `code`), not this stamp.
10550
+ * - `approval` | `input` | `signal` — a person or a signal decides (`stepId`; `approvalId` / `escalatedHop` on an
10551
+ * approval; `signalName` on a signal wait; `deadlineAt` when the wait times out);
10552
+ * - `budget` — the run met its own cap before step `stepId` (`dimension`, `spent`, `cap`, the step's estimate
10553
+ * `reserve`, the gate's `expiresAt`) — `lua workflows raise-budget` resumes it;
10554
+ * - `billing` — the wallet refused (`code`: `insufficient_credits` | `out_of_actions`) — a top-up resumes it;
10555
+ * - `model_policy` | `gate` — a platform policy holds step `stepId`;
10556
+ * - `sleep` | `retry_backoff` — a `waiting` run the engine wakes at `wakeAt` on its own;
10557
+ * - `subrun` — a `waiting` run waits on child run `childRunId`.
10558
+ */
10559
+ declare interface WorkflowRunSuspendedForDto {
10560
+ kind: 'approval' | 'input' | 'signal' | 'budget' | 'billing' | 'model_policy' | 'gate' | 'sleep' | 'retry_backoff' | 'subrun' | (string & {});
10561
+ stepId?: string;
10562
+ attempt?: number;
10563
+ /** When the park began (epoch ms). */
10564
+ since?: number;
10565
+ code?: string;
10566
+ expiresAt?: number;
10567
+ operationId?: string;
10568
+ approvalId?: string;
10569
+ escalatedHop?: number;
10570
+ signalName?: string;
10571
+ /** HITL waits: when the wait times out (epoch ms). */
10572
+ deadlineAt?: number;
10573
+ /** `sleep` / `retry_backoff`: when the engine wakes the run (epoch ms). */
10574
+ wakeAt?: number;
10575
+ childRunId?: string;
10576
+ dimension?: 'credits' | 'actions' | 'steps' | 'jobSeconds' | (string & {});
10577
+ spent?: number;
10578
+ cap?: number;
10579
+ reserve?: number;
10580
+ }
10581
+
8321
10582
  /**
8322
10583
  * [WJB-B5] (BAC-671) — the four token figures the server sums per run and per step (`WorkflowRunTokens` in
8323
10584
  * `@lua/shared-types`). Every member optional: the CLI is a reader of whatever the server sends, and a figure
@@ -8357,6 +10618,9 @@ export declare const Workflows: WorkflowsApi;
8357
10618
  * - `get`/`list` honour output ACLs: a restricted run comes back with `restricted:true`
8358
10619
  * and no `output` — never an error.
8359
10620
  *
10621
+ * - `start` options are checked: an option key it does not know throws
10622
+ * `WorkflowApiError{ code:'VALIDATION_FAILED' }` naming it — never silently dropped.
10623
+ *
8360
10624
  * `startBatch`, `signalByKey`, `raiseBudget`, `setGoal` and `goals.*` are part of the
8361
10625
  * frozen member list and throw `WORKFLOWS_API_UNAVAILABLE` until their routes ship.
8362
10626
  */
@@ -8372,16 +10636,39 @@ export declare interface WorkflowsApi {
8372
10636
  initialState?: Record<string, unknown>;
8373
10637
  correlationKey?: string;
8374
10638
  tags?: string[];
10639
+ /** Deliver the terminal summary back on this channel thread (07 §7.4.5). */
8375
10640
  replyTo?: {
8376
10641
  channel: string;
8377
10642
  threadId: string;
8378
10643
  };
10644
+ /** Run on behalf of an end customer: `principalKind:'customer'` (reduced scope; never an approver). */
8379
10645
  onBehalfOf?: {
8380
- userId: string;
10646
+ kind: 'customer';
10647
+ externalId: string;
8381
10648
  };
10649
+ /**
10650
+ * Opt-in `workflow-callback`: on the terminal (completed | failed | timed_out) the agent takes one
10651
+ * background turn on `originThreadId` with the outcome. Needs an origin thread — from a tool it defaults
10652
+ * to the current chat thread; elsewhere a start without one throws `CALLBACK_THREAD_REQUIRED`.
10653
+ */
10654
+ callback?: boolean;
10655
+ /**
10656
+ * The chat thread the run's cards and callback land on. Defaults to `Lua.request.threadId` when called
10657
+ * from a chat turn (a tool / processor); must be the calling user's own thread on this agent
10658
+ * (`ORIGIN_THREAD_INVALID` otherwise).
10659
+ */
10660
+ originThreadId?: string;
10661
+ notify?: 'emailApp' | 'email' | 'app' | 'off';
8382
10662
  workflowVersionId?: string;
8383
10663
  }): Promise<StartWorkflowRunResult>;
10664
+ /**
10665
+ * One run (R4). A parked run says WHY: `status` is `gated` | `suspended` | `waiting`, `gate` carries a gated run's
10666
+ * reason (consent — with the crossed thresholds on newer servers —, quota, billing, budget …) and `suspendedFor`
10667
+ * a suspended / waiting run's (`approval` | `input` | `signal` | `budget` | `billing` | `sleep` |
10668
+ * `retry_backoff` | `subrun` …, with the step and the figures). Both are optional — absent on older servers.
10669
+ */
8384
10670
  get(runId: string): Promise<WorkflowRun>;
10671
+ /** Runs of this agent (R3); each row carries `gate` / `suspendedFor` exactly as `get` does. */
8385
10672
  list(opts?: {
8386
10673
  limit?: number;
8387
10674
  status?: WorkflowRunStatus | string;
@@ -8477,6 +10764,16 @@ export declare interface WorkflowSpecialistRole {
8477
10764
  tools: string[];
8478
10765
  }
8479
10766
 
10767
+ /** Item 10 — one crossed consent threshold on a `start-consent` gate (`WorkflowRun.gate.exceeded`). */
10768
+ declare interface WorkflowStartConsentExceededDto {
10769
+ /** `steps` | `credits` | `duration` (seconds) | `actions`. */
10770
+ dimension: 'steps' | 'credits' | 'duration' | 'actions' | (string & {});
10771
+ /** The threshold crossed — `maxAutoSteps` / `maxAutoCredits` / `maxAutoDurationSeconds` / the envelope's `maxActions`. */
10772
+ limit: number;
10773
+ /** The start's estimate on that dimension. */
10774
+ estimate: number;
10775
+ }
10776
+
8480
10777
  export declare interface WorkflowStepContext<TIn = unknown, TResume = unknown, TState = Record<string, unknown>> {
8481
10778
  runId: string;
8482
10779
  workflowId: string;
@@ -8681,6 +10978,7 @@ export declare type WorkspaceSpec = {
8681
10978
  ref?: string | TemplateBinding;
8682
10979
  credentialsRef?: string;
8683
10980
  sizeGb?: number;
10981
+ /** 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. */
8684
10982
  ttlHours?: number;
8685
10983
  verify?: string;
8686
10984
  keepArtefacts?: boolean;
@@ -8688,9 +10986,10 @@ export declare type WorkspaceSpec = {
8688
10986
  } | {
8689
10987
  kind: 'empty';
8690
10988
  sizeGb?: number;
10989
+ /** 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. */
8691
10990
  ttlHours?: number;
8692
10991
  /**
8693
- * Keep the volume after the run completes: held until `ttlHours` (24 h when undeclared), then expired. A kept
10992
+ * 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
8694
10993
  * volume holds one of the organisation's workspace slots (`maxWorkspacesPerOrg`, 10 by default) until then.
8695
10994
  */
8696
10995
  keepArtefacts?: boolean;