@elevasis/sdk 1.24.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.
- package/dist/cli.cjs +875 -834
- package/dist/index.d.ts +4857 -4547
- package/dist/index.js +564 -2338
- package/dist/node/index.d.ts +693 -1356
- package/dist/node/index.js +1 -1
- package/dist/test-utils/index.d.ts +4186 -4139
- package/dist/test-utils/index.js +694 -2769
- package/dist/types/worker/adapters/clickup.d.ts +22 -0
- package/dist/types/worker/adapters/index.d.ts +1 -0
- package/dist/types/worker/index.d.ts +3 -2
- package/dist/types/worker/platform.d.ts +2 -2
- package/dist/worker/index.js +427 -2803
- package/package.json +2 -2
- package/reference/_navigation.md +11 -1
- package/reference/_reference-manifest.json +70 -0
- package/reference/claude-config/rules/organization-model.md +12 -1
- package/reference/claude-config/rules/organization-os.md +12 -1
- package/reference/claude-config/skills/om/SKILL.md +13 -5
- package/reference/claude-config/skills/om/operations/codify-level-a.md +109 -100
- package/reference/claude-config/skills/om/operations/customers.md +10 -6
- package/reference/claude-config/skills/om/operations/features.md +7 -3
- package/reference/claude-config/skills/om/operations/goals.md +10 -6
- package/reference/claude-config/skills/om/operations/identity.md +8 -5
- package/reference/claude-config/skills/om/operations/labels.md +17 -1
- package/reference/claude-config/skills/om/operations/offerings.md +11 -7
- package/reference/claude-config/skills/om/operations/roles.md +11 -7
- package/reference/claude-config/skills/om/operations/techStack.md +10 -2
- package/reference/claude-config/sync-notes/2026-05-20-om-define-helpers.md +32 -0
- package/reference/claude-config/sync-notes/2026-05-22-access-model-and-right-panel.md +43 -0
- package/reference/claude-config/sync-notes/2026-05-22-lead-gen-tenant-config.md +40 -0
- package/reference/claude-config/sync-notes/2026-05-22-org-model-multi-file-split.md +61 -0
- package/reference/cli-management.mdx +539 -0
- package/reference/cli.mdx +579 -808
- package/reference/concepts.mdx +134 -146
- package/reference/deployment/api.mdx +296 -297
- package/reference/deployment/command-center.mdx +208 -209
- package/reference/deployment/index.mdx +194 -195
- package/reference/deployment/provided-features.mdx +110 -107
- package/reference/deployment/ui-execution.mdx +249 -250
- package/reference/framework/index.mdx +111 -195
- package/reference/framework/resource-documentation.mdx +90 -0
- package/reference/framework/tutorial-system.mdx +135 -135
- package/reference/getting-started.mdx +141 -142
- package/reference/index.mdx +95 -106
- package/reference/packages/ui/src/auth/README.md +6 -6
- package/reference/platform-tools/adapters-integration.mdx +300 -301
- package/reference/platform-tools/adapters-platform.mdx +552 -553
- package/reference/platform-tools/index.mdx +216 -217
- package/reference/platform-tools/type-safety.mdx +82 -82
- package/reference/resources/index.mdx +348 -349
- package/reference/resources/patterns.mdx +446 -449
- package/reference/resources/types.mdx +115 -116
- package/reference/roadmap.mdx +164 -165
- package/reference/rules/organization-model.md +14 -0
- package/reference/runtime.mdx +172 -173
- package/reference/scaffold/operations/propagation-pipeline.md +1 -1
- package/reference/scaffold/recipes/customize-crm-actions.md +45 -46
- package/reference/scaffold/recipes/extend-crm.md +253 -255
- package/reference/scaffold/recipes/extend-lead-gen.md +130 -77
- package/reference/scaffold/recipes/index.md +43 -44
- package/reference/scaffold/reference/contracts.md +1275 -1432
- package/reference/scaffold/reference/glossary.md +8 -6
- package/reference/scaffold/ui/feature-flags-and-gating.md +59 -46
- package/reference/scaffold/ui/feature-shell.mdx +11 -11
- package/reference/scaffold/ui/recipes.md +24 -24
- 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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
await
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
|
96
|
-
|
|
|
97
|
-
|
|
|
98
|
-
|
|
|
99
|
-
|
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
|
124
|
-
|
|
|
125
|
-
|
|
|
126
|
-
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
|
138
|
-
|
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
|
156
|
-
|
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
|
195
|
-
|
|
|
196
|
-
| `
|
|
197
|
-
| `
|
|
198
|
-
| `
|
|
199
|
-
| `
|
|
200
|
-
| `
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
- [
|
|
212
|
-
- [
|
|
213
|
-
|
|
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
|
|
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
|
|
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
|
|
17
|
-
|
|
18
|
-
```typescript
|
|
19
|
-
// Required
|
|
20
|
-
await llm.generate({
|
|
21
|
-
provider: 'anthropic',
|
|
22
|
-
model: 'claude-sonnet-4-5',
|
|
23
|
-
messages: [...],
|
|
24
|
-
responseSchema: {...},
|
|
25
|
-
})
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### Tomba Adapter
|
|
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
|
|
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
|
|
54
|
-
|
|
55
|
-
`ApprovalToolMap.create.params` uses `context: Record<string, unknown>` instead of `context: unknown`. This prevents passing primitives (strings, numbers) as context
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
// Correct
|
|
59
|
-
await approval.create({
|
|
60
|
-
context: { dealId: 'deal-123', proposalUrl: 'https://...' },
|
|
61
|
-
...
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
// TypeScript error
|
|
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
|
|
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`
|