@elevasis/sdk 1.25.0 → 1.26.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.
Files changed (60) hide show
  1. package/dist/cli.cjs +18 -116
  2. package/dist/index.d.ts +165 -48
  3. package/dist/index.js +4 -435
  4. package/dist/node/index.d.ts +36 -36
  5. package/dist/test-utils/index.d.ts +99 -38
  6. package/dist/test-utils/index.js +27 -355
  7. package/dist/types/worker/adapters/clickup.d.ts +22 -0
  8. package/dist/types/worker/adapters/index.d.ts +1 -0
  9. package/dist/worker/index.js +32 -354
  10. package/package.json +2 -2
  11. package/reference/_navigation.md +11 -1
  12. package/reference/_reference-manifest.json +70 -0
  13. package/reference/claude-config/rules/organization-model.md +12 -1
  14. package/reference/claude-config/rules/organization-os.md +12 -1
  15. package/reference/claude-config/skills/om/SKILL.md +13 -5
  16. package/reference/claude-config/skills/om/operations/codify-level-a.md +109 -100
  17. package/reference/claude-config/skills/om/operations/customers.md +10 -6
  18. package/reference/claude-config/skills/om/operations/features.md +7 -3
  19. package/reference/claude-config/skills/om/operations/goals.md +10 -6
  20. package/reference/claude-config/skills/om/operations/identity.md +8 -5
  21. package/reference/claude-config/skills/om/operations/labels.md +17 -1
  22. package/reference/claude-config/skills/om/operations/offerings.md +11 -7
  23. package/reference/claude-config/skills/om/operations/roles.md +11 -7
  24. package/reference/claude-config/skills/om/operations/techStack.md +10 -2
  25. package/reference/claude-config/sync-notes/2026-05-20-om-define-helpers.md +32 -0
  26. package/reference/claude-config/sync-notes/2026-05-22-access-model-and-right-panel.md +43 -0
  27. package/reference/claude-config/sync-notes/2026-05-22-lead-gen-tenant-config.md +40 -0
  28. package/reference/claude-config/sync-notes/2026-05-22-org-model-multi-file-split.md +61 -0
  29. package/reference/cli-management.mdx +539 -0
  30. package/reference/cli.mdx +4 -532
  31. package/reference/concepts.mdx +134 -146
  32. package/reference/deployment/api.mdx +296 -297
  33. package/reference/deployment/command-center.mdx +208 -209
  34. package/reference/deployment/index.mdx +194 -195
  35. package/reference/deployment/provided-features.mdx +110 -107
  36. package/reference/deployment/ui-execution.mdx +249 -250
  37. package/reference/framework/index.mdx +111 -195
  38. package/reference/framework/resource-documentation.mdx +90 -0
  39. package/reference/framework/tutorial-system.mdx +135 -135
  40. package/reference/getting-started.mdx +141 -142
  41. package/reference/index.mdx +95 -106
  42. package/reference/packages/ui/src/auth/README.md +6 -6
  43. package/reference/platform-tools/adapters-integration.mdx +300 -301
  44. package/reference/platform-tools/adapters-platform.mdx +552 -553
  45. package/reference/platform-tools/index.mdx +216 -217
  46. package/reference/platform-tools/type-safety.mdx +82 -82
  47. package/reference/resources/index.mdx +348 -349
  48. package/reference/resources/patterns.mdx +446 -449
  49. package/reference/resources/types.mdx +115 -116
  50. package/reference/roadmap.mdx +164 -165
  51. package/reference/rules/organization-model.md +14 -0
  52. package/reference/runtime.mdx +172 -173
  53. package/reference/scaffold/operations/propagation-pipeline.md +1 -1
  54. package/reference/scaffold/recipes/extend-lead-gen.md +130 -77
  55. package/reference/scaffold/reference/contracts.md +376 -446
  56. package/reference/scaffold/reference/glossary.md +8 -6
  57. package/reference/scaffold/ui/feature-flags-and-gating.md +59 -46
  58. package/reference/scaffold/ui/feature-shell.mdx +11 -11
  59. package/reference/scaffold/ui/recipes.md +24 -24
  60. package/reference/troubleshooting.mdx +222 -223
@@ -1,217 +1,216 @@
1
- ---
2
- title: Platform Tools
3
- description: Access 70+ tools across integration adapters and platform services from your SDK workflows -- typed adapters, credential security model, and working code examples
4
- loadWhen: "Connecting to external services"
5
- ---
6
-
7
- Your SDK workflows have access to 70+ tools -- Gmail, Stripe, Google Sheets, PDF generation, human-in-the-loop approvals, storage, scheduling, and more. Credentials are managed server-side and never appear in your code.
8
-
9
- **Typed adapters** are the recommended way to call tools. They provide full TypeScript autocomplete, compile-time method checking, and eliminate boilerplate. Use `platform.call()` only for tools that don't have an adapter yet.
10
-
11
- ## Usage
12
-
13
- **Preferred: Typed adapters** (available for all integration tools + key platform services)
14
-
15
- ```typescript
16
- import { createResendAdapter, scheduler, llm } from '@elevasis/sdk/worker'
17
-
18
- // Integration tools: factory pattern (credential bound once)
19
- const resend = createResendAdapter('my-resend')
20
- await resend.sendEmail({ from: 'hi@app.com', to: 'user@example.com', subject: '...' })
21
-
22
- // Platform services: singleton (no credential needed)
23
- await scheduler.createSchedule({ ... })
24
- const result = await llm.generate({ messages: [...] })
25
- ```
26
-
27
- **Fallback: `platform.call()`** (for tools without typed adapters)
28
-
29
- ```typescript
30
- import { platform } from '@elevasis/sdk/worker'
31
-
32
- const result = await platform.call({
33
- tool: 'acqDb', // tool name
34
- method: 'upsertDeal', // method exposed by that tool
35
- params: { ... }, // method-specific parameters
36
- })
37
- ```
38
-
39
- Both patterns return a Promise that resolves with the tool result or rejects with a `PlatformToolError` containing a message, error code, and a `retryable` flag.
40
-
41
- ## Integration Adapters
42
-
43
- Ten integration adapters give you access to 50+ tool methods covering third-party APIs. Pass the credential name once at adapter creation. Supabase is listed separately under [Database Access](#database-access) below.
44
-
45
- | Adapter | Tools | Credential Shape |
46
- | ------------- | ----------------------------- | ------------------------ |
47
- | Attio | 12 (CRUD + schema + notes) | `{ apiKey }` |
48
- | Google Sheets | 13 (read/write/filter/upsert) | OAuth2 / service account |
49
- | Stripe | 6 (payment links + checkout) | `{ secretKey }` |
50
- | Instantly | 5 (email campaigns) | `{ apiKey }` |
51
- | SignatureAPI | 4 (envelopes) | `{ apiKey }` |
52
- | Tomba | 3 (email discovery) | `api-key-secret` |
53
- | Gmail | 2 (send email) | OAuth2 / service account |
54
- | Resend | 2 (send/get email) | `{ apiKey }` |
55
- | Dropbox | 2 (upload/folder) | `{ accessToken }` |
56
- | Apify | 1 (run actor) | `{ token }` |
57
-
58
- ## Credential Security
59
-
60
- Integration credentials are never stored in `.env` and never available via `process.env` inside worker threads. Credentials live in the platform credential system and are accessed through three controlled channels.
61
-
62
- ### Layer 1: Platform Tools (Default)
63
-
64
- All platform tools resolve credentials server-side. The credential value never crosses the postMessage boundary into the worker.
65
-
66
- ```typescript
67
- // Credential 'my-gmail' is resolved server-side -- value never enters worker memory
68
- const result = await platform.call({
69
- tool: 'gmail',
70
- method: 'sendEmail',
71
- credential: 'my-gmail',
72
- params: { to: '...', subject: '...', body: '...' },
73
- })
74
- ```
75
-
76
- ### Layer 2: HTTP Platform Tool
77
-
78
- For APIs without a dedicated adapter, use the `http` platform tool. Credentials are injected server-side before the outgoing request.
79
-
80
- ```typescript
81
- const result = await platform.call({
82
- tool: 'http',
83
- method: 'request',
84
- credential: 'my-custom-api',
85
- params: {
86
- url: 'https://api.example.com/v1/data',
87
- method: 'GET',
88
- headers: { 'Content-Type': 'application/json' },
89
- },
90
- })
91
- ```
92
-
93
- **Supported injection patterns:**
94
-
95
- | Pattern | Credential Config | How Injected |
96
- | --------------- | ---------------------------------------------------------------- | ---------------------------------------- |
97
- | Bearer token | `{ type: 'bearer', token: 'sk_...' }` | `Authorization: Bearer sk_...` header |
98
- | API key header | `{ type: 'api-key-header', header: 'X-API-Key', key: 'ak_...' }` | Custom header |
99
- | Basic auth | `{ type: 'basic', username: '...', password: '...' }` | `Authorization: Basic base64(user:pass)` |
100
- | Query parameter | `{ type: 'query-param', param: 'api_key', value: 'ak_...' }` | Appended to URL |
101
- | Body field | `{ type: 'body-field', field: 'apiKey', value: 'ak_...' }` | Merged into JSON body |
102
- | Custom header | `{ type: 'custom-header', header: 'X-Custom', value: '...' }` | Arbitrary header |
103
-
104
- ### Layer 3: getCredential() (Explicit Opt-In)
105
-
106
- For third-party SDKs that require a raw key (e.g., `new Stripe(key)`), use `platform.getCredential()`. This explicitly causes the credential value to enter worker memory.
107
-
108
- ```typescript
109
- import { platform } from '@elevasis/sdk/worker'
110
-
111
- const cred = await platform.getCredential('my-stripe-key')
112
- const stripe = new Stripe(cred.credentials.secretKey)
113
- ```
114
-
115
- All `getCredential()` calls are logged. Use `platform.call()` with the `http` tool when possible.
116
-
117
- ### Credential Setup
118
-
119
- Credentials are created in the command center UI: navigate to Credentials -> Add Credential -> select type -> enter values -> save. The name you give the credential is what you pass as `credential: 'my-cred-name'` in `platform.call()`. Credential names are case-sensitive -- a mismatch causes `PlatformToolError: credential not found`.
120
-
121
- ### Choosing a Pattern
122
-
123
- | Situation | Pattern |
124
- | ------------------------------------------------------ | --------------------------------------- |
125
- | Using a supported adapter (Gmail, Attio, Stripe, etc.) | `platform.call()` with the adapter tool |
126
- | Calling an API not in the catalog | `platform.call()` with `tool: 'http'` |
127
- | Third-party SDK that requires a raw key | `platform.getCredential()` |
128
-
129
- `.env` contains only `ELEVASIS_PLATFORM_KEY` for CLI authentication -- never integration credentials.
130
-
131
- ---
132
-
133
- ## Platform Services
134
-
135
- Nine built-in platform services are available without a `credential` field. All have typed singleton adapters imported from `@elevasis/sdk/worker`.
136
-
137
- | Tool Key | Methods | Purpose |
138
- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
139
- | `acqDb` | 35 methods (CRUD + sync) | Acquisition database -- `acqDb` adapter |
140
- | `email` | `send` | Send email to org members -- `email` adapter |
141
- | `storage` | `upload`, `download`, `createSignedUrl`, `delete`, `list` | File storage -- `storage` adapter |
142
- | `pdf` | `render`, `renderToBuffer` | PDF rendering -- `pdf` adapter |
143
- | `notification` | `create` | In-app notifications -- `notifications` adapter |
144
- | `approval` | `create`, `deleteByMetadata` | HITL approval gates -- `approval` adapter |
145
- | `scheduler` | `createSchedule`, `updateAnchor`, `deleteSchedule`, `findByIdempotencyKey`, `deleteScheduleByIdempotencyKey`, `listSchedules`, `getSchedule`, `cancelSchedule`, `cancelSchedulesByMetadata` | Task scheduling -- `scheduler` adapter |
146
- | `llm` | `generate` | LLM inference -- `llm` adapter |
147
- | `execution` | `trigger` | Nested child execution -- `execution` adapter |
148
-
149
- ## LLM Tool
150
-
151
- Call any supported LLM from your workflow with no API keys required. Keys are resolved server-side from environment variables.
152
-
153
- **Supported models:**
154
-
155
- | Provider | Models |
156
- | ------------ | -------------------------------------------------------------------------------------------------------------- |
157
- | `google` | `gemini-3-flash-preview` |
158
- | `openai` | `gpt-5`, `gpt-5-mini` |
159
- | `anthropic` | `claude-opus-4-5`, `claude-sonnet-4-5`, `claude-haiku-4-5` |
160
- | `openrouter` | `openrouter/anthropic/claude-sonnet-4.5`, `openrouter/deepseek/deepseek-v3.2`, `openrouter/x-ai/grok-4.1-fast` |
161
-
162
- **Key params:** `provider`, `model`, `messages` (`{ role, content }[]`), `responseSchema` (optional JSON Schema), `temperature` (optional).
163
-
164
- See [Platform Adapters](adapters-platform.mdx#llm-adapter) for full typed usage with structured output.
165
-
166
- ## Execution Tool
167
-
168
- Trigger another resource as a nested child of the current execution. The child runs synchronously and its result is returned. Maximum depth: 5 levels. The invoked resource must belong to the same organization.
169
-
170
- See [Platform Adapters](adapters-platform.mdx#execution-adapter) for usage.
171
-
172
- ## Database Access
173
-
174
- Supabase is a first-class integration adapter for persistent storage. Pass the `credential` field with your stored Supabase credential name.
175
-
176
- **Methods:** `insert`, `select`, `update`, `delete`, `upsert`, `rpc`, `count`
177
-
178
- ```typescript
179
- const qualified = await platform.call({
180
- tool: 'supabase',
181
- credential: 'my-database',
182
- method: 'select',
183
- params: {
184
- table: 'leads',
185
- filter: { status: 'eq.qualified', score: 'gte.80' },
186
- order: { column: 'score', ascending: false },
187
- limit: 50,
188
- },
189
- })
190
- ```
191
-
192
- **Filter syntax** uses PostgREST format (`operator.value`):
193
-
194
- | Filter | Example | Meaning |
195
- | ------------------------ | ---------------------------------- | ------------- |
196
- | `eq` | `{ status: 'eq.qualified' }` | Equals |
197
- | `neq` | `{ status: 'neq.lost' }` | Not equals |
198
- | `gt`, `gte`, `lt`, `lte` | `{ score: 'gte.80' }` | Comparisons |
199
- | `like`, `ilike` | `{ name: 'ilike.%jane%' }` | Pattern match |
200
- | `in` | `{ status: 'in.(new,contacted)' }` | In set |
201
- | `is` | `{ deleted_at: 'is.null' }` | Null check |
202
-
203
- **Credential setup:** Create a credential with provider `supabase` -- config fields are `url` and `serviceRoleKey`. Workflows always use the service role key (server-side, no RLS).
204
-
205
- **`/database init`:** Guided setup that stores your Supabase credential, generates `data/schema.ts`, and creates `docs/database.mdx`.
206
-
207
- ---
208
-
209
- ## Documentation
210
-
211
- - [Integration Adapters](adapters-integration.mdx) - All 10 integration adapters with method tables and code examples
212
- - [Platform Adapters](adapters-platform.mdx) - All 9 platform service adapters with method tables and code examples
213
- - [Adapter Type Safety](type-safety.mdx) - Required fields, discriminated unions, and intentionally loose adapter types
214
-
215
- ---
216
-
217
- **Last Updated:** 2026-03-06
1
+ ---
2
+ title: Platform Tools
3
+ description: Access 70+ tools across integration adapters and platform services from your SDK workflows -- typed adapters, credential security model, and working code examples
4
+ ---
5
+
6
+ Your SDK workflows have access to 70+ tools -- Gmail, Stripe, Google Sheets, PDF generation, human-in-the-loop approvals, storage, scheduling, and more. Credentials are managed server-side and never appear in your code.
7
+
8
+ **Typed adapters** are the recommended way to call tools. They provide full TypeScript autocomplete, compile-time method checking, and eliminate boilerplate. Use `platform.call()` only for tools that don't have an adapter yet.
9
+
10
+ ## Usage
11
+
12
+ **Preferred: Typed adapters** (available for all integration tools + key platform services)
13
+
14
+ ```typescript
15
+ import { createResendAdapter, scheduler, llm } from '@elevasis/sdk/worker'
16
+
17
+ // Integration tools: factory pattern (credential bound once)
18
+ const resend = createResendAdapter('my-resend')
19
+ await resend.sendEmail({ from: 'hi@app.com', to: 'user@example.com', subject: '...' })
20
+
21
+ // Platform services: singleton (no credential needed)
22
+ await scheduler.createSchedule({ ... })
23
+ const result = await llm.generate({ messages: [...] })
24
+ ```
25
+
26
+ **Fallback: `platform.call()`** (for tools without typed adapters)
27
+
28
+ ```typescript
29
+ import { platform } from '@elevasis/sdk/worker'
30
+
31
+ const result = await platform.call({
32
+ tool: 'acqDb', // tool name
33
+ method: 'upsertDeal', // method exposed by that tool
34
+ params: { ... }, // method-specific parameters
35
+ })
36
+ ```
37
+
38
+ Both patterns return a Promise that resolves with the tool result or rejects with a `PlatformToolError` containing a message, error code, and a `retryable` flag.
39
+
40
+ ## Integration Adapters
41
+
42
+ Ten integration adapters give you access to 50+ tool methods covering third-party APIs. Pass the credential name once at adapter creation. Supabase is listed separately under [Database Access](#database-access) below.
43
+
44
+ | Adapter | Tools | Credential Shape |
45
+ | ------------- | ----------------------------- | ------------------------ |
46
+ | Attio | 12 (CRUD + schema + notes) | `{ apiKey }` |
47
+ | Google Sheets | 13 (read/write/filter/upsert) | OAuth2 / service account |
48
+ | Stripe | 6 (payment links + checkout) | `{ secretKey }` |
49
+ | Instantly | 5 (email campaigns) | `{ apiKey }` |
50
+ | SignatureAPI | 4 (envelopes) | `{ apiKey }` |
51
+ | Tomba | 3 (email discovery) | `api-key-secret` |
52
+ | Gmail | 2 (send email) | OAuth2 / service account |
53
+ | Resend | 2 (send/get email) | `{ apiKey }` |
54
+ | Dropbox | 2 (upload/folder) | `{ accessToken }` |
55
+ | Apify | 1 (run actor) | `{ token }` |
56
+
57
+ ## Credential Security
58
+
59
+ Integration credentials are never stored in `.env` and never available via `process.env` inside worker threads. Credentials live in the platform credential system and are accessed through three controlled channels.
60
+
61
+ ### Layer 1: Platform Tools (Default)
62
+
63
+ All platform tools resolve credentials server-side. The credential value never crosses the postMessage boundary into the worker.
64
+
65
+ ```typescript
66
+ // Credential 'my-gmail' is resolved server-side -- value never enters worker memory
67
+ const result = await platform.call({
68
+ tool: 'gmail',
69
+ method: 'sendEmail',
70
+ credential: 'my-gmail',
71
+ params: { to: '...', subject: '...', body: '...' },
72
+ })
73
+ ```
74
+
75
+ ### Layer 2: HTTP Platform Tool
76
+
77
+ For APIs without a dedicated adapter, use the `http` platform tool. Credentials are injected server-side before the outgoing request.
78
+
79
+ ```typescript
80
+ const result = await platform.call({
81
+ tool: 'http',
82
+ method: 'request',
83
+ credential: 'my-custom-api',
84
+ params: {
85
+ url: 'https://api.example.com/v1/data',
86
+ method: 'GET',
87
+ headers: { 'Content-Type': 'application/json' },
88
+ },
89
+ })
90
+ ```
91
+
92
+ **Supported injection patterns:**
93
+
94
+ | Pattern | Credential Config | How Injected |
95
+ | --------------- | ---------------------------------------------------------------- | ---------------------------------------- |
96
+ | Bearer token | `{ type: 'bearer', token: 'sk_...' }` | `Authorization: Bearer sk_...` header |
97
+ | API key header | `{ type: 'api-key-header', header: 'X-API-Key', key: 'ak_...' }` | Custom header |
98
+ | Basic auth | `{ type: 'basic', username: '...', password: '...' }` | `Authorization: Basic base64(user:pass)` |
99
+ | Query parameter | `{ type: 'query-param', param: 'api_key', value: 'ak_...' }` | Appended to URL |
100
+ | Body field | `{ type: 'body-field', field: 'apiKey', value: 'ak_...' }` | Merged into JSON body |
101
+ | Custom header | `{ type: 'custom-header', header: 'X-Custom', value: '...' }` | Arbitrary header |
102
+
103
+ ### Layer 3: getCredential() (Explicit Opt-In)
104
+
105
+ For third-party SDKs that require a raw key (e.g., `new Stripe(key)`), use `platform.getCredential()`. This explicitly causes the credential value to enter worker memory.
106
+
107
+ ```typescript
108
+ import { platform } from '@elevasis/sdk/worker'
109
+
110
+ const cred = await platform.getCredential('my-stripe-key')
111
+ const stripe = new Stripe(cred.credentials.secretKey)
112
+ ```
113
+
114
+ All `getCredential()` calls are logged. Use `platform.call()` with the `http` tool when possible.
115
+
116
+ ### Credential Setup
117
+
118
+ Credentials are created in the command center UI: navigate to Credentials -> Add Credential -> select type -> enter values -> save. The name you give the credential is what you pass as `credential: 'my-cred-name'` in `platform.call()`. Credential names are case-sensitive -- a mismatch causes `PlatformToolError: credential not found`.
119
+
120
+ ### Choosing a Pattern
121
+
122
+ | Situation | Pattern |
123
+ | ------------------------------------------------------ | --------------------------------------- |
124
+ | Using a supported adapter (Gmail, Attio, Stripe, etc.) | `platform.call()` with the adapter tool |
125
+ | Calling an API not in the catalog | `platform.call()` with `tool: 'http'` |
126
+ | Third-party SDK that requires a raw key | `platform.getCredential()` |
127
+
128
+ `.env` contains only `ELEVASIS_PLATFORM_KEY` for CLI authentication -- never integration credentials.
129
+
130
+ ---
131
+
132
+ ## Platform Services
133
+
134
+ Nine built-in platform services are available without a `credential` field. All have typed singleton adapters imported from `@elevasis/sdk/worker`.
135
+
136
+ | Tool Key | Methods | Purpose |
137
+ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
138
+ | `acqDb` | 35 methods (CRUD + sync) | Acquisition database -- `acqDb` adapter |
139
+ | `email` | `send` | Send email to org members -- `email` adapter |
140
+ | `storage` | `upload`, `download`, `createSignedUrl`, `delete`, `list` | File storage -- `storage` adapter |
141
+ | `pdf` | `render`, `renderToBuffer` | PDF rendering -- `pdf` adapter |
142
+ | `notification` | `create` | In-app notifications -- `notifications` adapter |
143
+ | `approval` | `create`, `deleteByMetadata` | HITL approval gates -- `approval` adapter |
144
+ | `scheduler` | `createSchedule`, `updateAnchor`, `deleteSchedule`, `findByIdempotencyKey`, `deleteScheduleByIdempotencyKey`, `listSchedules`, `getSchedule`, `cancelSchedule`, `cancelSchedulesByMetadata` | Task scheduling -- `scheduler` adapter |
145
+ | `llm` | `generate` | LLM inference -- `llm` adapter |
146
+ | `execution` | `trigger` | Nested child execution -- `execution` adapter |
147
+
148
+ ## LLM Tool
149
+
150
+ Call any supported LLM from your workflow with no API keys required. Keys are resolved server-side from environment variables.
151
+
152
+ **Supported models:**
153
+
154
+ | Provider | Models |
155
+ | ------------ | -------------------------------------------------------------------------------------------------------------- |
156
+ | `google` | `gemini-3-flash-preview` |
157
+ | `openai` | `gpt-5`, `gpt-5-mini` |
158
+ | `anthropic` | `claude-opus-4-5`, `claude-sonnet-4-5`, `claude-haiku-4-5` |
159
+ | `openrouter` | `openrouter/anthropic/claude-sonnet-4.5`, `openrouter/deepseek/deepseek-v3.2`, `openrouter/x-ai/grok-4.1-fast` |
160
+
161
+ **Key params:** `provider`, `model`, `messages` (`{ role, content }[]`), `responseSchema` (optional JSON Schema), `temperature` (optional).
162
+
163
+ See [Platform Adapters](adapters-platform.mdx#llm-adapter) for full typed usage with structured output.
164
+
165
+ ## Execution Tool
166
+
167
+ Trigger another resource as a nested child of the current execution. The child runs synchronously and its result is returned. Maximum depth: 5 levels. The invoked resource must belong to the same organization.
168
+
169
+ See [Platform Adapters](adapters-platform.mdx#execution-adapter) for usage.
170
+
171
+ ## Database Access
172
+
173
+ Supabase is a first-class integration adapter for persistent storage. Pass the `credential` field with your stored Supabase credential name.
174
+
175
+ **Methods:** `insert`, `select`, `update`, `delete`, `upsert`, `rpc`, `count`
176
+
177
+ ```typescript
178
+ const qualified = await platform.call({
179
+ tool: 'supabase',
180
+ credential: 'my-database',
181
+ method: 'select',
182
+ params: {
183
+ table: 'leads',
184
+ filter: { status: 'eq.qualified', score: 'gte.80' },
185
+ order: { column: 'score', ascending: false },
186
+ limit: 50,
187
+ },
188
+ })
189
+ ```
190
+
191
+ **Filter syntax** uses PostgREST format (`operator.value`):
192
+
193
+ | Filter | Example | Meaning |
194
+ | ------------------------ | ---------------------------------- | ------------- |
195
+ | `eq` | `{ status: 'eq.qualified' }` | Equals |
196
+ | `neq` | `{ status: 'neq.lost' }` | Not equals |
197
+ | `gt`, `gte`, `lt`, `lte` | `{ score: 'gte.80' }` | Comparisons |
198
+ | `like`, `ilike` | `{ name: 'ilike.%jane%' }` | Pattern match |
199
+ | `in` | `{ status: 'in.(new,contacted)' }` | In set |
200
+ | `is` | `{ deleted_at: 'is.null' }` | Null check |
201
+
202
+ **Credential setup:** Create a credential with provider `supabase` -- config fields are `url` and `serviceRoleKey`. Workflows always use the service role key (server-side, no RLS).
203
+
204
+ **`/database init`:** Guided setup that stores your Supabase credential, generates `data/schema.ts`, and creates `docs/database.mdx`.
205
+
206
+ ---
207
+
208
+ ## Documentation
209
+
210
+ - [Integration Adapters](adapters-integration.mdx) - All 10 integration adapters with method tables and code examples
211
+ - [Platform Adapters](adapters-platform.mdx) - All 9 platform service adapters with method tables and code examples
212
+ - [Adapter Type Safety](type-safety.mdx) - Required fields, discriminated unions, and intentionally loose adapter types
213
+
214
+ ---
215
+
216
+ **Last Updated:** 2026-03-06
@@ -1,82 +1,82 @@
1
- ---
2
- title: Adapter Type Safety
3
- description: SDK worker adapter type safety patterns - required fields, discriminated unions, and intentionally loose types
4
- ---
5
-
6
- SDK worker adapters enforce correctness at compile time via TypeScript, not at deploy time. Misconfigured adapters fail in the IDE before a file is even saved no runtime surprises, no silent failures in production.
7
-
8
- The approach: tighten types where misconfiguration is a realistic foot-gun, and leave types intentionally loose where flexibility is a design requirement.
9
-
10
- ---
11
-
12
- ## Required Field Enforcement
13
-
14
- ### LLM Adapter `provider` and `model`
15
-
16
- `provider` and `model` are required on `SDKLLMGenerateParams` in `packages/sdk/src/worker/adapters/llm.ts`. They were previously optional because the server-side `modelConfig` fallback in `tool-dispatcher.ts` would fill them in but that fallback is a foot-gun, not a feature. Omitting them silently selects a default model that may not be appropriate for the call site.
17
-
18
- ```typescript
19
- // Required both fields must be specified inline
20
- await llm.generate({
21
- provider: 'anthropic',
22
- model: 'claude-sonnet-4-5',
23
- messages: [...],
24
- responseSchema: {...},
25
- })
26
- ```
27
-
28
- ### Tomba Adapter `domain` and `email`
29
-
30
- `domain` is required on `TombaDomainSearchParams` and `TombaEmailFinderParams`. `email` is required on `TombaEmailVerifierParams`. Previously all params were optional, allowing calls to compile but fail at runtime. The type change enforces the fields that are always necessary for email discovery and verification.
31
-
32
- ---
33
-
34
- ## Discriminated Unions
35
-
36
- ### Email Targeting mutually exclusive modes
37
-
38
- `EmailToolMap.send.params` uses a discriminated union with `never` to enforce that exactly one targeting mode is provided. You cannot pass zero modes or combine multiple modes.
39
-
40
- ```typescript
41
- type EmailTargeting =
42
- | { userIds: string[]; targetRole?: never; targetAll?: never }
43
- | { targetRole: string; userIds?: never; targetAll?: never }
44
- | { targetAll: true; userIds?: never; targetRole?: never }
45
- ```
46
-
47
- The `never` pattern on sibling fields causes TypeScript to error if you pass two targeting fields simultaneously. Passing none also fails because none of the union members match.
48
-
49
- ---
50
-
51
- ## Strict Object Types
52
-
53
- ### Approval Adapter typed context
54
-
55
- `ApprovalToolMap.create.params` uses `context: Record<string, unknown>` instead of `context: unknown`. This prevents passing primitives (strings, numbers) as context approval tasks always expect a structured key-value object.
56
-
57
- ```typescript
58
- // Correct
59
- await approval.create({
60
- context: { dealId: 'deal-123', proposalUrl: 'https://...' },
61
- ...
62
- })
63
-
64
- // TypeScript error primitives not assignable to Record<string, unknown>
65
- await approval.create({ context: 'deal-123', ... })
66
- ```
67
-
68
- ---
69
-
70
- ## Intentionally Loose Types
71
-
72
- Some adapters were audited and deliberately left with flexible types. Do not tighten these the looseness is a design requirement.
73
-
74
- | Adapter | Field | Type | Reason |
75
- | ------- | ---------- | --------------------------- | -------------------------------------------------------------------------------------------------------------- |
76
- | Attio | `object` | `string` | Supports custom user-defined object slugs; a union would be too restrictive for orgs with custom Attio objects |
77
- | Attio | `values` | `Record<string, unknown>` | Dynamic per-object schemas vary by org configuration |
78
- | PDF | `document` | `Record<string, unknown>` | Renderer accepts flexible document structures by design; schema is enforced server-side |
79
-
80
- ---
81
-
82
- **Source:** `packages/sdk/src/worker/adapters/llm.ts`, `packages/core/src/execution/engine/tools/tool-maps.ts`
1
+ ---
2
+ title: Adapter Type Safety
3
+ description: SDK worker adapter type safety patterns - required fields, discriminated unions, and intentionally loose types
4
+ ---
5
+
6
+ SDK worker adapters enforce correctness at compile time via TypeScript, not at deploy time. Misconfigured adapters fail in the IDE before a file is even saved -- no runtime surprises, no silent failures in production.
7
+
8
+ The approach: tighten types where misconfiguration is a realistic foot-gun, and leave types intentionally loose where flexibility is a design requirement.
9
+
10
+ ---
11
+
12
+ ## Required Field Enforcement
13
+
14
+ ### LLM Adapter -- `provider` and `model`
15
+
16
+ `provider` and `model` are required on `SDKLLMGenerateParams` in `packages/sdk/src/worker/adapters/llm.ts`. They were previously optional because the server-side `modelConfig` fallback in `tool-dispatcher.ts` would fill them in -- but that fallback is a foot-gun, not a feature. Omitting them silently selects a default model that may not be appropriate for the call site.
17
+
18
+ ```typescript
19
+ // Required -- both fields must be specified inline
20
+ await llm.generate({
21
+ provider: 'anthropic',
22
+ model: 'claude-sonnet-4-5',
23
+ messages: [...],
24
+ responseSchema: {...},
25
+ })
26
+ ```
27
+
28
+ ### Tomba Adapter -- `domain` and `email`
29
+
30
+ `domain` is required on `TombaDomainSearchParams` and `TombaEmailFinderParams`. `email` is required on `TombaEmailVerifierParams`. Previously all params were optional, allowing calls to compile but fail at runtime. The type change enforces the fields that are always necessary for email discovery and verification.
31
+
32
+ ---
33
+
34
+ ## Discriminated Unions
35
+
36
+ ### Email Targeting -- mutually exclusive modes
37
+
38
+ `EmailToolMap.send.params` uses a discriminated union with `never` to enforce that exactly one targeting mode is provided. You cannot pass zero modes or combine multiple modes.
39
+
40
+ ```typescript
41
+ type EmailTargeting =
42
+ | { userIds: string[]; targetRole?: never; targetAll?: never }
43
+ | { targetRole: string; userIds?: never; targetAll?: never }
44
+ | { targetAll: true; userIds?: never; targetRole?: never }
45
+ ```
46
+
47
+ The `never` pattern on sibling fields causes TypeScript to error if you pass two targeting fields simultaneously. Passing none also fails because none of the union members match.
48
+
49
+ ---
50
+
51
+ ## Strict Object Types
52
+
53
+ ### Approval Adapter -- typed context
54
+
55
+ `ApprovalToolMap.create.params` uses `context: Record<string, unknown>` instead of `context: unknown`. This prevents passing primitives (strings, numbers) as context -- approval tasks always expect a structured key-value object.
56
+
57
+ ```typescript
58
+ // Correct
59
+ await approval.create({
60
+ context: { dealId: 'deal-123', proposalUrl: 'https://...' },
61
+ ...
62
+ })
63
+
64
+ // TypeScript error -- primitives not assignable to Record<string, unknown>
65
+ await approval.create({ context: 'deal-123', ... })
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Intentionally Loose Types
71
+
72
+ Some adapters were audited and deliberately left with flexible types. Do not tighten these -- the looseness is a design requirement.
73
+
74
+ | Adapter | Field | Type | Reason |
75
+ | ------- | ---------- | --------------------------- | -------------------------------------------------------------------------------------------------------------- |
76
+ | Attio | `object` | `string` | Supports custom user-defined object slugs; a union would be too restrictive for orgs with custom Attio objects |
77
+ | Attio | `values` | `Record<string, unknown>` | Dynamic per-object schemas vary by org configuration |
78
+ | PDF | `document` | `Record<string, unknown>` | Renderer accepts flexible document structures by design; schema is enforced server-side |
79
+
80
+ ---
81
+
82
+ **Source:** `packages/sdk/src/worker/adapters/llm.ts`, `packages/core/src/execution/engine/tools/tool-maps.ts`