esoul-sdk 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  Releases before 0.20.0 are recorded in the repository history only.
4
4
 
5
+ ## 0.21.0
6
+
7
+ ### Added
8
+
9
+ - **Model calls, billed: `llm` in `plugin.json` and `llm(ctx).generate(req)` in `esoul-sdk/server`.**
10
+ Declare `"llm": { "why", "dailyBudgetUsd"? (default 5, at most 100), "models"? }` and call
11
+ `llm(ctx).generate({ purpose, model?, system?, messages, tools?, schema?, maxOutputTokens?, temperature? })`
12
+ from an op or a route — or `ctx.llm.generate(…)` from a task. The app instance's workspace **owner**
13
+ pays from their AI credits; every call is recorded with the app, the instance and `purpose`; the
14
+ app's spend per owner per UTC day is capped by `dailyBudgetUsd`. `model` is a tier (`fast`,
15
+ `balanced`, `best`) or a gateway id on the platform's allowlist (DeepSeek, Claude, GPT mini/nano,
16
+ Gemini Flash) or in `llm.models`. `tools` are definitions: the model's calls come back in
17
+ `toolCalls`, never executed by the platform. `schema` (JSON Schema) returns the answer parsed in
18
+ `object`. A refusal throws `LlmUnavailable` (`isLlmUnavailable`) with `code` `not_declared` |
19
+ `not_allowed` | `no_credits` | `budget_exceeded` | `model_not_allowed` | `provider_unavailable`.
20
+ Schema: `PluginLlmSchema`. See `docs/19-model-calls.md`.
21
+ - **`scriptedModel(policy?)` in `esoul-sdk/testing`.** A deterministic stand-in for `llm(ctx)`: scripted
22
+ texts, objects and tool calls by matching the last user message (or a function), a short echo by
23
+ default, zero cost, every request in `.calls`. The Forge box answers every model call with one.
24
+
25
+ ### Changed
26
+
27
+ - **App files may not import a model SDK** (`ai`, `@ai-sdk/*`, `openai`, `@anthropic-ai/*`,
28
+ `@google/genai`, `@inngest/ai`) — the box check and the install inspection refuse it, tests
29
+ included. Apps call models through `llm(ctx)`.
30
+
5
31
  ## 0.20.0
6
32
 
7
33
  ### Added
package/README.md CHANGED
@@ -573,6 +573,7 @@ Exits 0 when the folder is a well-formed application package; otherwise prints e
573
573
  | [14. Your own tables](docs/14-database.md) | `db`, rules, scopes, sealed fields, indexes, migrations |
574
574
  | [15. Realtime](docs/15-realtime.md) | Topics, audiences, addressing |
575
575
  | [16. Bindings](docs/16-bindings.md) | Slots, contracts, reaching another application |
576
+ | [19. Model calls](docs/19-model-calls.md) | `llm(ctx)`: billed model calls, budgets, `scriptedModel()` for tests |
576
577
 
577
578
  ## Versions
578
579
 
package/api-reference.md CHANGED
@@ -7,11 +7,11 @@ the complete list it teaches from. In a Forge workbench the source itself is rea
7
7
  Regenerate: `npm run docs:api`.
8
8
 
9
9
  ==============================================================================
10
- ## `esoul-sdk` — 210 exports
10
+ ## `esoul-sdk` — 215 exports
11
11
 
12
12
  Manifest, events, tools, ops, bindings, contracts, charts, access words — what app.tsx and the shared modules import.
13
13
 
14
- ### Functions and values (126)
14
+ ### Functions and values (130)
15
15
 
16
16
  #### `ASSET_APP_MAX_BYTES` — const · src/assets.ts
17
17
 
@@ -549,6 +549,30 @@ const LABELME_VERSION: "5.5.0"
549
549
  function listPageSize(opts?: FileListOptions | null): number
550
550
  ```
551
551
 
552
+ #### `LLM_DEFAULT_DAILY_BUDGET_USD` — const · src/manifest.ts
553
+
554
+ `llm.dailyBudgetUsd` when the manifest does not set it.
555
+
556
+ ```ts
557
+ const LLM_DEFAULT_DAILY_BUDGET_USD: 5
558
+ ```
559
+
560
+ #### `LLM_MAX_DAILY_BUDGET_USD` — const · src/manifest.ts
561
+
562
+ The largest `llm.dailyBudgetUsd` a manifest may set.
563
+
564
+ ```ts
565
+ const LLM_MAX_DAILY_BUDGET_USD: 100
566
+ ```
567
+
568
+ #### `LLM_MODEL_ID_RE` — const · src/manifest.ts
569
+
570
+ A gateway model id: `provider/model` ("deepseek/deepseek-v3.2").
571
+
572
+ ```ts
573
+ const LLM_MODEL_ID_RE: RegExp
574
+ ```
575
+
552
576
  #### `makeOpTool` — function · src/ops.ts
553
577
 
554
578
  `opTool`, bound to a caller. The package binds its own `callPluginOp`; the platform binds the one that carries the acting viewer and targets this deployment — same tool, different wire, decided once at the index.
@@ -837,12 +861,20 @@ WHOSE ENVIRONMENT VARIABLE IS THIS.
837
861
  function pluginEnvPrefix(pluginId: string): string
838
862
  ```
839
863
 
864
+ #### `PluginLlmSchema` — const · src/manifest.ts
865
+
866
+ The `llm` block (docs/19): the app makes model calls, billed to the workspace owner. Without it `llm(ctx)` answers `not_declared`.
867
+
868
+ ```ts
869
+ const PluginLlmSchema: z.ZodObject<{ why: z.ZodString; dailyBudgetUsd: z.ZodOptional<z.ZodNumber>; models: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { why?: string; dailyBudgetUsd?: number; models?: string[]; }, { why?: string; dailyBudgetUsd?: number; models?: string[]; }>
870
+ ```
871
+
840
872
  #### `PluginManifestSchema` — const · src/manifest.ts
841
873
 
842
874
  The zod schema `plugin.json` must satisfy — the sync and `check_app` refuse a manifest that fails it, with the path.
843
875
 
844
876
  ```ts
845
- const PluginManifestSchema: z.ZodEffects<z.ZodObject<{ manifestVersion: z.ZodLiteral<1>; id: z.ZodString; name: z.ZodString; version: z.ZodString; description: z.ZodString; applicationType: z.ZodString; entry: z.ZodString; icon: z.ZodOptional<z.ZodString>; author: z.ZodOptional<z.ZodObject<{ name: z.ZodString; email: z.ZodOptional<z.ZodString>; url: z.ZodOptional<z.ZodString>; }, "strip", z.ZodTypeAny, { email?: string; name?: string; url?: string; }, { email?: string; name?: string; url?: string; }>>; kickableTasks: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; webhooks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; ops: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; routes: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; pollTasks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{ task: z.ZodString; everyMinutes: z.ZodNumber; }, "strip", z.ZodTypeAny, { task?: string; everyMinutes?: number; }, { task?: string; everyMinutes?: number; }>, "many">>>; platformApi: z.ZodOptional<z.ZodObject<{ min: z.ZodString; max: z.ZodOptional<z.ZodString>; }, "strip", z.ZodTypeAny, { min?: string; max?: string; }, { min?: string; max?: string; }>>; scopes: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; roles: z.ZodOptional<z.ZodEffects<z.ZodObject<{ vocabulary: z.ZodArray<z.ZodString, "many">; default: z.ZodDefault<z.ZodOptional<z.ZodObject<{ owner: z.ZodOptional<z.ZodString>; "member-edit": z.ZodOptional<z.ZodString>; "member-readonly": z.ZodOptional<z.ZodString>; visitor: z.ZodOptional<z.ZodString>; anonymous: z.ZodOptional<z.ZodString>; agent: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }>>>; describe: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>; attributes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<["string", "int", "boolean"]>>>; custom: z.ZodOptional<z.ZodObject<{ attributes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; models: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ where: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; hide: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; update: z.ZodOptional<z.ZodObject<{ fields: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; transitions: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { fields?: string[]; transitions?: string; }, { fields?: string[]; transitions?: string; }>>; }, "strict", z.ZodTypeAny, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>>>; ops: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }, { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }>>; }, "strict", z.ZodTypeAny, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>>; workspaceTools: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; device: z.ZodOptional<z.ZodEffects<z.ZodObject<{ commands: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{ argv: z.ZodArray<z.ZodString, "many">; params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodEnum<["int", "number", "bool", "string"]>, z.ZodObject<{ type: z.ZodEnum<["int", "number"]>; min: z.ZodOptional<z.ZodNumber>; max: z.ZodOptional<z.ZodNumber>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "number" | "int"; min?: number; max?: number; describe?: string; }, { type?: "number" | "int"; min?: number; max?: number; describe?: string; }>, z.ZodObject<{ type: z.ZodLiteral<"string">; pattern: z.ZodOptional<z.ZodString>; maxLength: z.ZodOptional<z.ZodNumber>; allowDash: z.ZodOptional<z.ZodBoolean>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; }, { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; }>, z.ZodObject<{ type: z.ZodLiteral<"enum">; values: z.ZodArray<z.ZodString, "many">; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { values?: string[]; type?: "enum"; describe?: string; }, { values?: string[]; type?: "enum"; describe?: string; }>, z.ZodObject<{ type: z.ZodLiteral<"bool">; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "bool"; describe?: string; }, { type?: "bool"; describe?: string; }>]>>>; cwd: z.ZodOptional<z.ZodString>; env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>; config: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; timeoutSeconds: z.ZodOptional<z.ZodNumber>; onRestart: z.ZodOptional<z.ZodEnum<["report", "rerun"]>>; output: z.ZodOptional<z.ZodObject<{ mode: z.ZodOptional<z.ZodEnum<["live", "batched", "final"]>>; flushMs: z.ZodOptional<z.ZodNumber>; maxChunkKb: z.ZodOptional<z.ZodNumber>; keep: z.ZodOptional<z.ZodEnum<["head", "tail", "both"]>>; maxKb: z.ZodOptional<z.ZodNumber>; }, "strict", z.ZodTypeAny, { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }, { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }>>; result: z.ZodOptional<z.ZodEnum<["text", "json"]>>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>>>; program: z.ZodOptional<z.ZodObject<{ main: z.ZodString; resident: z.ZodOptional<z.ZodBoolean>; setup: z.ZodOptional<z.ZodArray<z.ZodObject<{ id: z.ZodString; describe: z.ZodString; run: z.ZodArray<z.ZodString, "many">; inputs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; timeoutSeconds: z.ZodOptional<z.ZodNumber>; }, "strict", z.ZodTypeAny, { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }, { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }>, "many">>; selfTest: z.ZodOptional<z.ZodObject<{ run: z.ZodArray<z.ZodString, "many">; timeoutSeconds: z.ZodOptional<z.ZodNumber>; }, "strict", z.ZodTypeAny, { timeoutSeconds?: number; run?: string[]; }, { timeoutSeconds?: number; run?: string[]; }>>; }, "strict", z.ZodTypeAny, { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }, { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }>>; config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ secret: z.ZodOptional<z.ZodBoolean>; required: z.ZodOptional<z.ZodBoolean>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { required?: boolean; describe?: string; secret?: boolean; }, { required?: boolean; describe?: string; secret?: boolean; }>>>; redact: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; onAppDeleted: z.ZodOptional<z.ZodEnum<["kill", "finish"]>>; }, "strict", z.ZodTypeAny, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }>, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }>>; connections: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodObject<{ key: z.ZodString; kind: z.ZodEnum<["oauth2", "apiKey"]>; label: z.ZodString; description: z.ZodOptional<z.ZodString>; authorizeUrl: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>; tokenUrl: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>; oauthScopes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; clientIdEnv: z.ZodOptional<z.ZodString>; clientSecretEnv: z.ZodOptional<z.ZodString>; headerNames: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }>, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }>, "many">>>; credentials: z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodObject<{ family: z.ZodLiteral<"google">; scopes: z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>; label: z.ZodOptional<z.ZodString>; why: z.ZodString; background: z.ZodOptional<z.ZodBoolean>; }, "strict", z.ZodTypeAny, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>>, Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>, Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>>>; fileSources: z.ZodOptional<z.ZodEffects<z.ZodObject<{ workspace: z.ZodOptional<z.ZodEnum<["read", "readwrite"]>>; providers: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; write: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }>, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }>>; fileProviders: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{ key: z.ZodString; connectionKey: z.ZodString; label: z.ZodString; }, "strict", z.ZodTypeAny, { key?: string; label?: string; connectionKey?: string; }, { key?: string; label?: string; connectionKey?: string; }>, "many">>>; uses: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ contract: z.ZodString; label: z.ZodOptional<z.ZodString>; optional: z.ZodOptional<z.ZodBoolean>; }, "strict", z.ZodTypeAny, { label?: string; contract?: string; optional?: boolean; }, { label?: string; contract?: string; optional?: boolean; }>>>; provides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; events: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; models: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { models?: string[]; tools?: string[]; events?: string[]; }, { models?: string[]; tools?: string[]; events?: string[]; }>>>; channel: z.ZodOptional<z.ZodObject<{ topics: z.ZodRecord<z.ZodString, z.ZodObject<{ audience: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"all">, z.ZodLiteral<"viewer">, z.ZodString]>>; mayAddress: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; description: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { description?: string; audience?: string; mayAddress?: string[]; }, { description?: string; audience?: string; mayAddress?: string[]; }>>; }, "strict", z.ZodTypeAny, { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }, { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }>>; db: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ scope: z.ZodOptional<z.ZodEnum<["instance", "workspace", "user"]>>; owner: z.ZodOptional<z.ZodLiteral<"creator">>; fields: z.ZodRecord<z.ZodString, z.ZodString>; sealed: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; unique: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodString, "many">, "many">>; indexes: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodObject<{ fields: z.ZodArray<z.ZodString, "many">; kind: z.ZodOptional<z.ZodEnum<["btree", "contains", "text"]>>; }, "strict", z.ZodTypeAny, { kind?: "text" | "btree" | "contains"; fields?: string[]; }, { kind?: "text" | "btree" | "contains"; fields?: string[]; }>]>, "many">>; rules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>; }, "strict", z.ZodTypeAny, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>>>; }, "strict", z.ZodTypeAny, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; scopes?: string[]; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { email?: string; name?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; workspaceTools?: string[]; device?: { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; credentials?: Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; scopes?: string[]; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { email?: string; name?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; workspaceTools?: string[]; device?: { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; credentials?: Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }>, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; scopes?: string[]; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { email?: string; name?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; workspaceTools?: string[]; device?: { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; credentials?: Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; scopes?: string[]; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { email?: string; name?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; workspaceTools?: string[]; device?: { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; credentials?: Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }>
877
+ const PluginManifestSchema: z.ZodEffects<z.ZodObject<{ manifestVersion: z.ZodLiteral<1>; id: z.ZodString; name: z.ZodString; version: z.ZodString; description: z.ZodString; applicationType: z.ZodString; entry: z.ZodString; icon: z.ZodOptional<z.ZodString>; author: z.ZodOptional<z.ZodObject<{ name: z.ZodString; email: z.ZodOptional<z.ZodString>; url: z.ZodOptional<z.ZodString>; }, "strip", z.ZodTypeAny, { email?: string; name?: string; url?: string; }, { email?: string; name?: string; url?: string; }>>; kickableTasks: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; webhooks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; ops: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; routes: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; pollTasks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{ task: z.ZodString; everyMinutes: z.ZodNumber; }, "strip", z.ZodTypeAny, { task?: string; everyMinutes?: number; }, { task?: string; everyMinutes?: number; }>, "many">>>; platformApi: z.ZodOptional<z.ZodObject<{ min: z.ZodString; max: z.ZodOptional<z.ZodString>; }, "strip", z.ZodTypeAny, { min?: string; max?: string; }, { min?: string; max?: string; }>>; scopes: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; roles: z.ZodOptional<z.ZodEffects<z.ZodObject<{ vocabulary: z.ZodArray<z.ZodString, "many">; default: z.ZodDefault<z.ZodOptional<z.ZodObject<{ owner: z.ZodOptional<z.ZodString>; "member-edit": z.ZodOptional<z.ZodString>; "member-readonly": z.ZodOptional<z.ZodString>; visitor: z.ZodOptional<z.ZodString>; anonymous: z.ZodOptional<z.ZodString>; agent: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }>>>; describe: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>; attributes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<["string", "int", "boolean"]>>>; custom: z.ZodOptional<z.ZodObject<{ attributes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; models: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ where: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; hide: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; update: z.ZodOptional<z.ZodObject<{ fields: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; transitions: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { fields?: string[]; transitions?: string; }, { fields?: string[]; transitions?: string; }>>; }, "strict", z.ZodTypeAny, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>>>; ops: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }, { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }>>; }, "strict", z.ZodTypeAny, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>>; workspaceTools: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; device: z.ZodOptional<z.ZodEffects<z.ZodObject<{ commands: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{ argv: z.ZodArray<z.ZodString, "many">; params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodEnum<["int", "number", "bool", "string"]>, z.ZodObject<{ type: z.ZodEnum<["int", "number"]>; min: z.ZodOptional<z.ZodNumber>; max: z.ZodOptional<z.ZodNumber>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "number" | "int"; min?: number; max?: number; describe?: string; }, { type?: "number" | "int"; min?: number; max?: number; describe?: string; }>, z.ZodObject<{ type: z.ZodLiteral<"string">; pattern: z.ZodOptional<z.ZodString>; maxLength: z.ZodOptional<z.ZodNumber>; allowDash: z.ZodOptional<z.ZodBoolean>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; }, { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; }>, z.ZodObject<{ type: z.ZodLiteral<"enum">; values: z.ZodArray<z.ZodString, "many">; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { values?: string[]; type?: "enum"; describe?: string; }, { values?: string[]; type?: "enum"; describe?: string; }>, z.ZodObject<{ type: z.ZodLiteral<"bool">; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "bool"; describe?: string; }, { type?: "bool"; describe?: string; }>]>>>; cwd: z.ZodOptional<z.ZodString>; env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>; config: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; timeoutSeconds: z.ZodOptional<z.ZodNumber>; onRestart: z.ZodOptional<z.ZodEnum<["report", "rerun"]>>; output: z.ZodOptional<z.ZodObject<{ mode: z.ZodOptional<z.ZodEnum<["live", "batched", "final"]>>; flushMs: z.ZodOptional<z.ZodNumber>; maxChunkKb: z.ZodOptional<z.ZodNumber>; keep: z.ZodOptional<z.ZodEnum<["head", "tail", "both"]>>; maxKb: z.ZodOptional<z.ZodNumber>; }, "strict", z.ZodTypeAny, { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }, { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }>>; result: z.ZodOptional<z.ZodEnum<["text", "json"]>>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>>>; program: z.ZodOptional<z.ZodObject<{ main: z.ZodString; resident: z.ZodOptional<z.ZodBoolean>; setup: z.ZodOptional<z.ZodArray<z.ZodObject<{ id: z.ZodString; describe: z.ZodString; run: z.ZodArray<z.ZodString, "many">; inputs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; timeoutSeconds: z.ZodOptional<z.ZodNumber>; }, "strict", z.ZodTypeAny, { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }, { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }>, "many">>; selfTest: z.ZodOptional<z.ZodObject<{ run: z.ZodArray<z.ZodString, "many">; timeoutSeconds: z.ZodOptional<z.ZodNumber>; }, "strict", z.ZodTypeAny, { timeoutSeconds?: number; run?: string[]; }, { timeoutSeconds?: number; run?: string[]; }>>; }, "strict", z.ZodTypeAny, { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }, { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }>>; config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ secret: z.ZodOptional<z.ZodBoolean>; required: z.ZodOptional<z.ZodBoolean>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { required?: boolean; describe?: string; secret?: boolean; }, { required?: boolean; describe?: string; secret?: boolean; }>>>; redact: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; onAppDeleted: z.ZodOptional<z.ZodEnum<["kill", "finish"]>>; }, "strict", z.ZodTypeAny, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }>, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }>>; connections: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodObject<{ key: z.ZodString; kind: z.ZodEnum<["oauth2", "apiKey"]>; label: z.ZodString; description: z.ZodOptional<z.ZodString>; authorizeUrl: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>; tokenUrl: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>; oauthScopes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; clientIdEnv: z.ZodOptional<z.ZodString>; clientSecretEnv: z.ZodOptional<z.ZodString>; headerNames: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }>, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }>, "many">>>; credentials: z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodObject<{ family: z.ZodLiteral<"google">; scopes: z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>; label: z.ZodOptional<z.ZodString>; why: z.ZodString; background: z.ZodOptional<z.ZodBoolean>; }, "strict", z.ZodTypeAny, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>>, Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>, Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>>>; llm: z.ZodOptional<z.ZodObject<{ why: z.ZodString; dailyBudgetUsd: z.ZodOptional<z.ZodNumber>; models: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { why?: string; dailyBudgetUsd?: number; models?: string[]; }, { why?: string; dailyBudgetUsd?: number; models?: string[]; }>>; fileSources: z.ZodOptional<z.ZodEffects<z.ZodObject<{ workspace: z.ZodOptional<z.ZodEnum<["read", "readwrite"]>>; providers: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; write: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }>, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }>>; fileProviders: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{ key: z.ZodString; connectionKey: z.ZodString; label: z.ZodString; }, "strict", z.ZodTypeAny, { key?: string; label?: string; connectionKey?: string; }, { key?: string; label?: string; connectionKey?: string; }>, "many">>>; uses: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ contract: z.ZodString; label: z.ZodOptional<z.ZodString>; optional: z.ZodOptional<z.ZodBoolean>; }, "strict", z.ZodTypeAny, { label?: string; contract?: string; optional?: boolean; }, { label?: string; contract?: string; optional?: boolean; }>>>; provides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; events: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; models: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { models?: string[]; tools?: string[]; events?: string[]; }, { models?: string[]; tools?: string[]; events?: string[]; }>>>; channel: z.ZodOptional<z.ZodObject<{ topics: z.ZodRecord<z.ZodString, z.ZodObject<{ audience: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"all">, z.ZodLiteral<"viewer">, z.ZodString]>>; mayAddress: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; description: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { description?: string; audience?: string; mayAddress?: string[]; }, { description?: string; audience?: string; mayAddress?: string[]; }>>; }, "strict", z.ZodTypeAny, { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }, { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }>>; db: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ scope: z.ZodOptional<z.ZodEnum<["instance", "workspace", "user"]>>; owner: z.ZodOptional<z.ZodLiteral<"creator">>; fields: z.ZodRecord<z.ZodString, z.ZodString>; sealed: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; unique: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodString, "many">, "many">>; indexes: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodObject<{ fields: z.ZodArray<z.ZodString, "many">; kind: z.ZodOptional<z.ZodEnum<["btree", "contains", "text"]>>; }, "strict", z.ZodTypeAny, { kind?: "text" | "btree" | "contains"; fields?: string[]; }, { kind?: "text" | "btree" | "contains"; fields?: string[]; }>]>, "many">>; rules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>; }, "strict", z.ZodTypeAny, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>>>; }, "strict", z.ZodTypeAny, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; scopes?: string[]; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { email?: string; name?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; workspaceTools?: string[]; device?: { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; credentials?: Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>; llm?: { why?: string; dailyBudgetUsd?: number; models?: string[]; }; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; scopes?: string[]; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { email?: string; name?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; workspaceTools?: string[]; device?: { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; credentials?: Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>; llm?: { why?: string; dailyBudgetUsd?: number; models?: string[]; }; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }>, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; scopes?: string[]; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { email?: string; name?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; workspaceTools?: string[]; device?: { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; credentials?: Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>; llm?: { why?: string; dailyBudgetUsd?: number; models?: string[]; }; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; scopes?: string[]; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { email?: string; name?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; workspaceTools?: string[]; device?: { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; credentials?: Record<string, { label?: string; family?: "google"; scopes?: string[]; why?: string; background?: boolean; }>; llm?: { why?: string; dailyBudgetUsd?: number; models?: string[]; }; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }>
846
878
  ```
847
879
 
848
880
  #### `PluginRolesSchema` — const · src/manifest.ts
@@ -850,7 +882,7 @@ const PluginManifestSchema: z.ZodEffects<z.ZodObject<{ manifestVersion: z.ZodLit
850
882
  WHAT THE APP CALLS ITS PEOPLE.
851
883
 
852
884
  ```ts
853
- const PluginRolesSchema: z.ZodEffects<z.ZodObject<{ vocabulary: z.ZodArray<z.ZodString, "many">; default: z.ZodDefault<z.ZodOptional<z.ZodObject<{ owner: z.ZodOptional<z.ZodString>; "member-edit": z.ZodOptional<z.ZodString>; "member-readonly": z.ZodOptional<z.ZodString>; visitor: z.ZodOptional<z.ZodString>; anonymous: z.ZodOptional<z.ZodString>; agent: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }>>>; describe: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>; attributes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<["string", "int", "boolean"]>>>; custom: z.ZodOptional<z.ZodObject<{ attributes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; models: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ where: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; hide: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; update: z.ZodOptional<z.ZodObject<{ fields: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; transitions: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { fields?: string[]; transitions?: string; }, { fields?: string[]; transitions?: string; }>>; }, "strict", z.ZodTypeAny, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>>>; ops: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }, { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }>>; }, "strict", z.ZodTypeAny, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>
885
+ const PluginRolesSchema: z.ZodEffects<z.ZodObject<{ vocabulary: z.ZodArray<z.ZodString, "many">; default: z.ZodDefault<z.ZodOptional<z.ZodObject<{ owner: z.ZodOptional<z.ZodString>; "member-edit": z.ZodOptional<z.ZodString>; "member-readonly": z.ZodOptional<z.ZodString>; visitor: z.ZodOptional<z.ZodString>; anonymous: z.ZodOptional<z.ZodString>; agent: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }>>>; describe: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>; attributes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<["string", "int", "boolean"]>>>; custom: z.ZodOptional<z.ZodObject<{ attributes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; models: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ where: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; hide: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; update: z.ZodOptional<z.ZodObject<{ fields: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; transitions: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { fields?: string[]; transitions?: string; }, { fields?: string[]; transitions?: string; }>>; }, "strict", z.ZodTypeAny, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>>>; ops: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }, { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }>>; }, "strict", z.ZodTypeAny, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; ops?: string[]; attributes?: string[]; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>
854
886
  ```
855
887
 
856
888
  #### `pluginRouteUrl` — function · src/helpers.ts
@@ -1021,7 +1053,7 @@ A manifest with one entry removed (the bytes stay; they may be shared). Pure.
1021
1053
  function withoutAsset(assets: AssetsManifest | null | undefined, pluginId: string, name: string): AssetsManifest
1022
1054
  ```
1023
1055
 
1024
- ### Types (84)
1056
+ ### Types (85)
1025
1057
 
1026
1058
  #### `AgentRunToolContext` — interface · src/types.ts
1027
1059
 
@@ -1140,6 +1172,7 @@ interface AppTaskContext<TState extends ApplicationIdentifier> {
1140
1172
  dispatchEvent(eventName: string, eventData: any): Promise<void>;
1141
1173
  notify(topic: string, data: any, opts?: { to?: { viewerIds: string[] } | { role: string } }): Promise<void>;
1142
1174
  credentials(slot: string): CredentialSlot;
1175
+ llm: Llm;
1143
1176
  }
1144
1177
  ```
1145
1178
 
@@ -1867,6 +1900,12 @@ type PluginConnectionDecl = z.infer<typeof PluginConnectionSchema>;
1867
1900
  type PluginCredentialSlot = z.infer<typeof PluginCredentialSlotSchema>;
1868
1901
  ```
1869
1902
 
1903
+ #### `PluginLlm` — type · src/manifest.ts
1904
+
1905
+ ```ts
1906
+ type PluginLlm = z.infer<typeof PluginLlmSchema>;
1907
+ ```
1908
+
1870
1909
  #### `PluginManifest` — type · src/manifest.ts
1871
1910
 
1872
1911
  ```ts
@@ -2034,11 +2073,11 @@ interface UsesDecl {
2034
2073
  ```
2035
2074
 
2036
2075
  ==============================================================================
2037
- ## `esoul-sdk/server` — 86 exports
2076
+ ## `esoul-sdk/server` — 97 exports
2038
2077
 
2039
2078
  Server code only (server.ts, ops, routes, tasks): the viewer, the app's database, files, connections, machines, charts, route tokens.
2040
2079
 
2041
- ### Functions and values (32)
2080
+ ### Functions and values (35)
2042
2081
 
2043
2082
  #### `APPROVAL_WAIT` — const · src/computer.ts
2044
2083
 
@@ -2144,6 +2183,14 @@ True for a `CredentialUnavailable`, also across bundle boundaries where `instanc
2144
2183
  function isCredentialUnavailable(err: unknown): err is CredentialUnavailable
2145
2184
  ```
2146
2185
 
2186
+ #### `isLlmUnavailable` — function · src/server.ts
2187
+
2188
+ True for an `LlmUnavailable`, also across bundle boundaries where `instanceof` fails.
2189
+
2190
+ ```ts
2191
+ function isLlmUnavailable(err: unknown): err is LlmUnavailable
2192
+ ```
2193
+
2147
2194
  #### `isTerminal` — const · src/computer.ts
2148
2195
 
2149
2196
  Whether a command has finished for good (`done`, `failed`, `denied`) — anything else is worth waiting on.
@@ -2160,6 +2207,22 @@ Everyone the owner has given a role in THIS instance, the words the app declared
2160
2207
  function listAppRoles( _ctx: { pluginId: string; workspaceId: string; nodeId: string; viewer: PluginViewer }, ): Promise<AppRolesListing>
2161
2208
  ```
2162
2209
 
2210
+ #### `llm` — function · src/server.ts
2211
+
2212
+ MODEL CALLS, BILLED. Hand it the context your op, route or task was called with (that object, not a copy). The workspace owner pays, from their AI credits, within your manifest's `llm.dailyBudgetUsd`; every call is recorded with your app, instance and `purpose`.
2213
+
2214
+ ```ts
2215
+ function llm(_ctx: object): Llm
2216
+ ```
2217
+
2218
+ #### `LlmUnavailable` — class · src/server.ts
2219
+
2220
+ A model call the platform refused or could not make. The message is a sentence a tool can relay to a person. `code` is what a program branches on; a refusal never charges anyone.
2221
+
2222
+ ```ts
2223
+ class LlmUnavailable extends Error { … }
2224
+ ```
2225
+
2163
2226
  #### `makeComputer` — function · src/computer.ts
2164
2227
 
2165
2228
  Bind the client to a side's `callWorkspaceTool`. Authors use `computer(...)`, never this.
@@ -2296,7 +2359,7 @@ WHO IS THIS, IN WORDS. The caller's own name and email, for an app with a reason
2296
2359
  function viewerProfile(_viewer: PluginViewer): Promise<ViewerProfile | null>
2297
2360
  ```
2298
2361
 
2299
- ### Types (54)
2362
+ ### Types (62)
2300
2363
 
2301
2364
  #### `AppRolePerson` — interface · src/server.ts
2302
2365
 
@@ -2515,6 +2578,8 @@ interface CredentialStatus {
2515
2578
  missingScopes?: string[];
2516
2579
  connectUrl?: string;
2517
2580
  reason?: string;
2581
+ candidates?: { storeId: string; email: string | null }[];
2582
+ connectAssignUrl?: string;
2518
2583
  }
2519
2584
  ```
2520
2585
 
@@ -2781,6 +2846,96 @@ interface JsonOutcome<T = unknown> {
2781
2846
  }
2782
2847
  ```
2783
2848
 
2849
+ #### `Llm` — interface · src/server.ts
2850
+
2851
+ ```ts
2852
+ interface Llm {
2853
+ generate(req: LlmRequest): Promise<LlmResult>;
2854
+ }
2855
+ ```
2856
+
2857
+ #### `LlmMessage` — interface · src/server.ts
2858
+
2859
+ One turn of the conversation the model reads.
2860
+
2861
+ ```ts
2862
+ interface LlmMessage {
2863
+ role: "user" | "assistant";
2864
+ content: string;
2865
+ }
2866
+ ```
2867
+
2868
+ #### `LlmRequest` — interface · src/server.ts
2869
+
2870
+ ```ts
2871
+ interface LlmRequest {
2872
+ purpose: string;
2873
+ model?: LlmTier | (string & {});
2874
+ system?: string;
2875
+ messages: LlmMessage[];
2876
+ tools?: Record<string, LlmToolDefinition>;
2877
+ schema?: object;
2878
+ maxOutputTokens?: number;
2879
+ temperature?: number;
2880
+ }
2881
+ ```
2882
+
2883
+ #### `LlmResult` — interface · src/server.ts
2884
+
2885
+ ```ts
2886
+ interface LlmResult {
2887
+ text: string;
2888
+ object?: unknown;
2889
+ toolCalls: LlmToolCall[];
2890
+ finishReason: string;
2891
+ model: string;
2892
+ usage: { inputTokens: number; outputTokens: number; costUsd?: number };
2893
+ }
2894
+ ```
2895
+
2896
+ #### `LlmTier` — type · src/server.ts
2897
+
2898
+ A model tier: the platform picks the model (docs/19).
2899
+
2900
+ ```ts
2901
+ type LlmTier = "fast" | "balanced" | "best";
2902
+ ```
2903
+
2904
+ #### `LlmToolCall` — interface · src/server.ts
2905
+
2906
+ ```ts
2907
+ interface LlmToolCall {
2908
+ id: string;
2909
+ name: string;
2910
+ args: unknown;
2911
+ }
2912
+ ```
2913
+
2914
+ #### `LlmToolDefinition` — interface · src/server.ts
2915
+
2916
+ A tool the model may ask to call. The platform never runs it: the call comes back in `toolCalls`.
2917
+
2918
+ ```ts
2919
+ interface LlmToolDefinition {
2920
+ description: string;
2921
+ parameters: object;
2922
+ }
2923
+ ```
2924
+
2925
+ #### `LlmUnavailableCode` — type · src/server.ts
2926
+
2927
+ Why a model call was refused.
2928
+
2929
+ ```ts
2930
+ type LlmUnavailableCode =
2931
+ | "not_declared"
2932
+ | "not_allowed"
2933
+ | "no_credits"
2934
+ | "budget_exceeded"
2935
+ | "model_not_allowed"
2936
+ | "provider_unavailable";
2937
+ ```
2938
+
2784
2939
  #### `PluginConnectionCredentials` — type · src/server.ts
2785
2940
 
2786
2941
  ```ts
@@ -3773,11 +3928,11 @@ interface WorkspaceTools {
3773
3928
  ```
3774
3929
 
3775
3930
  ==============================================================================
3776
- ## `esoul-sdk/testing` — 48 exports
3931
+ ## `esoul-sdk/testing` — 53 exports
3777
3932
 
3778
3933
  Tests: run an op as a persona, an in-memory database with the real rules, recorders.
3779
3934
 
3780
- ### Functions and values (11)
3935
+ ### Functions and values (13)
3781
3936
 
3782
3937
  #### `capture` — function · src/testing/ops.ts
3783
3938
 
@@ -3803,6 +3958,14 @@ The account a sim has when `accounts` is not given (RFC 2606 reserved domain —
3803
3958
  const DEFAULT_SIM_ACCOUNT: "owner@sim.mail.example"
3804
3959
  ```
3805
3960
 
3961
+ #### `defaultScriptedText` — function · src/testing/llm.ts
3962
+
3963
+ The default answer's text: `scripted: ` and the first 120 characters of the last user message.
3964
+
3965
+ ```ts
3966
+ function defaultScriptedText(req: LlmRequest): string
3967
+ ```
3968
+
3806
3969
  #### `fakeApps` — function · src/testing/ops.ts
3807
3970
 
3808
3971
  Fill a `uses` slot with a stand-in provider, so a consumer's op can be tested without the other app existing. Calls to a tool the fixture does not define come back as a refusal, which is what an unbound slot really does.
@@ -3851,6 +4014,14 @@ Call `pluginServer.ops[name]` with a context shaped like the platform's. Throws
3851
4014
  async function runOp<T = unknown>( server: ServerModuleLike, opName: string, options: RunOpOptions, ): Promise<RunOpResult<T>>
3852
4015
  ```
3853
4016
 
4017
+ #### `scriptedModel` — function · src/testing/llm.ts
4018
+
4019
+ A deterministic fake model: scripted replies by matching the last user message, or a function.
4020
+
4021
+ ```ts
4022
+ function scriptedModel(policy?: ScriptedPolicy): ScriptedLlm
4023
+ ```
4024
+
3854
4025
  #### `simGmail` — function · src/testing/sim-gmail/index.ts
3855
4026
 
3856
4027
  A fake Gmail at the HTTP level. `sim.fetch` answers the Gmail REST endpoints the platform's mail code calls (profile, messages list/get/send/modify/trash/delete/attachments, threads, labels, history, watch/stop) and Google's OAuth token endpoints, with Gmail's field names, types and units; mailboxes deliver to each other and thread like Gmail; `addPersona`/`crowd` script counterparties; `faults` injects 429/5xx/401/403/network errors deterministically; `corpus` seeds a production-shaped synthetic mailbox; `snapshot()` / `{ restore }` persist the world. No Node built-ins.
@@ -3867,7 +4038,7 @@ A real (tiny) OAuth2 provider for exercising the plugin-connection flow: /author
3867
4038
  function startMockOAuth(opts?: { port?: number; clientId?: string; accessTtlMs?: number; }): Promise<MockOAuthServer>
3868
4039
  ```
3869
4040
 
3870
- ### Types (37)
4041
+ ### Types (40)
3871
4042
 
3872
4043
  #### `BoundAppFixture` — interface · src/testing/ops.ts
3873
4044
 
@@ -4157,6 +4328,35 @@ interface RunOpResult<T = unknown> {
4157
4328
  }
4158
4329
  ```
4159
4330
 
4331
+ #### `ScriptedLlm` — interface · src/testing/llm.ts
4332
+
4333
+ ```ts
4334
+ interface ScriptedLlm extends Llm {
4335
+ readonly calls: LlmRequest[];
4336
+ }
4337
+ ```
4338
+
4339
+ #### `ScriptedPolicy` — type · src/testing/llm.ts
4340
+
4341
+ ```ts
4342
+ type ScriptedPolicy =
4343
+ | ((req: LlmRequest, callIndex: number) => Partial<LlmResult> | string | Promise<Partial<LlmResult> | string>)
4344
+ | { replies?: ScriptedReply[]; fallback?: (req: LlmRequest, callIndex: number) => Partial<LlmResult> | string };
4345
+ ```
4346
+
4347
+ #### `ScriptedReply` — interface · src/testing/llm.ts
4348
+
4349
+ ```ts
4350
+ interface ScriptedReply {
4351
+ match?: string | RegExp;
4352
+ text?: string;
4353
+ object?: unknown;
4354
+ toolCalls?: { name: string; args?: unknown }[];
4355
+ finishReason?: string;
4356
+ once?: boolean;
4357
+ }
4358
+ ```
4359
+
4160
4360
  #### `SimAccountSpec` — interface · src/testing/sim-gmail/types.ts
4161
4361
 
4162
4362
  One simulated Google account = one Gmail mailbox.