@alvera-ai/platform-sdk 0.10.0-rc.2 → 0.10.0-rc.21
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/.agent/AGENTS.md +440 -0
- package/.agent/account_management.md +455 -0
- package/.agent/action_status_updaters.md +262 -0
- package/.agent/ai_agents.md +423 -0
- package/.agent/ai_sandbox.md +265 -0
- package/.agent/async.md +111 -0
- package/.agent/connected_apps.md +407 -0
- package/.agent/cookbook/_fixtures/README.md +99 -0
- package/.agent/cookbook/_fixtures/accounts_receivable/_customers_accounts_receivable_customer.liquid +32 -0
- package/.agent/cookbook/_fixtures/accounts_receivable/_customers_accounts_receivable_mdm.liquid +20 -0
- package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_generic_table.liquid +33 -0
- package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_legal_entity.liquid +88 -0
- package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_mdm.liquid +48 -0
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_appointment.liquid +47 -0
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_mdm.liquid +24 -0
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_patient.liquid +38 -0
- package/.agent/cookbook/_fixtures/payment_risk/_compliance_screenings_payment_risk_compliance_screening.liquid +59 -0
- package/.agent/cookbook/_fixtures/payment_risk/_compliance_screenings_payment_risk_mdm.liquid +36 -0
- package/.agent/cookbook/_fixtures/payment_risk/_payment_accounts_payment_risk_mdm.liquid +30 -0
- package/.agent/cookbook/_fixtures/payment_risk/_payment_accounts_payment_risk_payment_account.liquid +55 -0
- package/.agent/cookbook/_setup/accounts_receivable.md +282 -0
- package/.agent/cookbook/_setup/foundation.md +277 -0
- package/.agent/cookbook/_setup/healthcare.md +279 -0
- package/.agent/cookbook/_setup/payment_risk.md +283 -0
- package/.agent/cookbook/appointment-review-sms-workflow.md +761 -0
- package/.agent/cookbook/birthday-greeting-sms-trigger.md +656 -0
- package/.agent/cookbook/contact-us-triage-with-llm.md +603 -0
- package/.agent/cookbook/dunning-sms-for-delinquent.md +619 -0
- package/.agent/cookbook/kyc-notification-on-account-activation.md +619 -0
- package/.agent/cookbook/sanctions-screening-with-agent-review.md +711 -0
- package/.agent/cookbook/score-leads-with-llm-categorization.md +602 -0
- package/.agent/cookbook/welcome-sms-for-customers.md +607 -0
- package/.agent/data_activation_clients.md +557 -0
- package/.agent/data_sources.md +234 -0
- package/.agent/datalakes.md +712 -0
- package/.agent/debugging.md +137 -0
- package/.agent/errors.md +196 -0
- package/.agent/generic_tables.md +351 -0
- package/.agent/interoperability_contracts.md +351 -0
- package/.agent/mdm.md +293 -0
- package/.agent/mutations.md +152 -0
- package/.agent/templates.md +98 -0
- package/.agent/tool-call-configs.md +90 -0
- package/.agent/tools.md +546 -0
- package/.agent/type_naming.md +131 -0
- package/.agent/workflows.md +601 -0
- package/README.md +46 -0
- package/dist/bin/platform-sdk.d.mts +1 -0
- package/dist/bin/platform-sdk.mjs +106 -0
- package/dist/bin/platform-sdk.mjs.map +1 -0
- package/dist/index.d.mts +1200 -43201
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1859 -7319
- package/dist/index.mjs.map +1 -1
- package/package.json +19 -10
package/.agent/tools.md
ADDED
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
# `tools` — block authoring reference
|
|
2
|
+
|
|
3
|
+
Family: **INFRA** (anchor for `intent = data_exchange`) +
|
|
4
|
+
**WORKFLOWS** (tagged for `intent ∈ {sms, email, voice, export}`).
|
|
5
|
+
|
|
6
|
+
A tool is an authenticated connection to an external system that
|
|
7
|
+
the platform invokes to **execute actions**. Two orthogonal
|
|
8
|
+
dimensions:
|
|
9
|
+
|
|
10
|
+
- **intent** classifies what the tool DOES (move data, send a
|
|
11
|
+
message, render a report)
|
|
12
|
+
- **body type** declares HOW the tool connects (S3, SFTP, SQL,
|
|
13
|
+
REST, AWS Lambda, …) via a polymorphic discriminator
|
|
14
|
+
|
|
15
|
+
A datalake can own many tools. Some tools nest under a data source
|
|
16
|
+
(`data_source_id` populated — typical for ingestion-receiving
|
|
17
|
+
tools like `manual_upload`); others are standalone and reachable
|
|
18
|
+
to any workflow on the datalake.
|
|
19
|
+
|
|
20
|
+
## 1. Wire shape
|
|
21
|
+
|
|
22
|
+
SDK TypeScript type (request shape; server-derived fields excluded):
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
import type { ToolRequestWritable }
|
|
26
|
+
from '@alvera-ai/platform-sdk'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
No runtime validator is exported — validation is server-authoritative
|
|
30
|
+
(a bad body returns a 422 `AlveraApiError`; see `errors.md`).
|
|
31
|
+
|
|
32
|
+
Intent enum (typed):
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
import { ToolIntent } from '@alvera-ai/platform-sdk'
|
|
36
|
+
|
|
37
|
+
ToolIntent.DATA_EXCHANGE // fetch / push payloads
|
|
38
|
+
ToolIntent.SMS // outbound text messages
|
|
39
|
+
ToolIntent.EMAIL // outbound email
|
|
40
|
+
ToolIntent.VOICE // outbound voice / voicemail
|
|
41
|
+
ToolIntent.EXPORT // report / extract generation
|
|
42
|
+
ToolIntent.STATUS_POLLER // polls external systems for
|
|
43
|
+
// delivery/action status; paired
|
|
44
|
+
// with action status updaters
|
|
45
|
+
// (see action_status_updaters.md)
|
|
46
|
+
ToolIntent.CHAT_COMPLETION // OpenAI-compatible chat-completion
|
|
47
|
+
// endpoint; paired with AI agents
|
|
48
|
+
// (see ai_agents.md)
|
|
49
|
+
ToolIntent.CONTEXT_EXTRACTION
|
|
50
|
+
// LLM-backed enrichment that extracts
|
|
51
|
+
// structured context from raw rows;
|
|
52
|
+
// paired with AI agents (see
|
|
53
|
+
// ai_agents.md). Like CHAT_COMPLETION,
|
|
54
|
+
// pairs with rest_api body against an
|
|
55
|
+
// OpenAI-compatible endpoint.
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Polymorphic body dispatch — the `body.tool_body_type` field is
|
|
59
|
+
the discriminator. Each branch is its own TypeScript type:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
tool_body_type = 'manual_upload' → manual-upload receiver
|
|
63
|
+
(presigned-URL upload path)
|
|
64
|
+
tool_body_type = 's3' → AWS S3 / R2 / custom-endpoint
|
|
65
|
+
object storage
|
|
66
|
+
tool_body_type = 'sftp' → SFTP file transfer
|
|
67
|
+
tool_body_type = 'sql_database' → SQL (Postgres, MySQL, …)
|
|
68
|
+
tool_body_type = 'rest_api' → generic REST endpoint
|
|
69
|
+
tool_body_type = 'sns' → AWS SNS topic (used for
|
|
70
|
+
SMS / push notifications)
|
|
71
|
+
tool_body_type = 'sharepoint' → Microsoft Graph SharePoint
|
|
72
|
+
tool_body_type = 'aws_lambda' → invoke a Lambda function
|
|
73
|
+
tool_body_type = 'sqs' → AWS SQS queue
|
|
74
|
+
tool_body_type = 'cloud_watch_log_group'
|
|
75
|
+
→ AWS CloudWatch Logs poller
|
|
76
|
+
(paired with
|
|
77
|
+
ToolIntent.STATUS_POLLER)
|
|
78
|
+
tool_body_type = 'email' → dedicated email-provider body
|
|
79
|
+
(SendGrid, SES, SMTP-bridge)
|
|
80
|
+
— alternative to using
|
|
81
|
+
rest_api for email intents
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The authoritative enum lives in the generated `ToolBodyTypeEnum`
|
|
85
|
+
export from `@alvera-ai/platform-sdk` — consult the type for the
|
|
86
|
+
complete set, since new body types land independently of doc
|
|
87
|
+
revisions.
|
|
88
|
+
|
|
89
|
+
## 2. Rules the type cannot encode
|
|
90
|
+
|
|
91
|
+
### `intent` and `tool_body_type` are loosely coupled
|
|
92
|
+
|
|
93
|
+
The TypeScript type lets you combine any intent with any body
|
|
94
|
+
type, but the platform validates the pairing semantically at
|
|
95
|
+
create time:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
data_exchange → s3, sftp, sql_database, rest_api,
|
|
99
|
+
manual_upload, aws_lambda, sharepoint, sqs
|
|
100
|
+
sms → sns, rest_api (provider-specific)
|
|
101
|
+
email → email (dedicated body), rest_api,
|
|
102
|
+
aws_lambda (custom dispatchers)
|
|
103
|
+
voice → rest_api (Twilio Voice, etc.)
|
|
104
|
+
export → s3, aws_lambda
|
|
105
|
+
status_poller → cloud_watch_log_group, rest_api
|
|
106
|
+
llm_enrichment → rest_api (against an OpenAI-compatible LLM
|
|
107
|
+
endpoint; the platform appends
|
|
108
|
+
/chat/completions to base_url; the
|
|
109
|
+
tool is the complete LLM provider
|
|
110
|
+
adapter and AI agents bind it for
|
|
111
|
+
structured row enrichment)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
A misaligned pair (e.g. `intent: sms` + `tool_body_type: sftp`)
|
|
115
|
+
returns a `422` with `body.tool_body_type` in `errors`.
|
|
116
|
+
|
|
117
|
+
### `data_source_id` is optional but discriminator-aware
|
|
118
|
+
|
|
119
|
+
When set, the tool is **embedded under a data source** — its
|
|
120
|
+
lifecycle is tied to the parent data source, and ingestion paths
|
|
121
|
+
expect it at that scope. When omitted, the tool is **standalone**
|
|
122
|
+
on the datalake — available to any workflow that names it.
|
|
123
|
+
|
|
124
|
+
The body type itself signals the typical pattern: `manual_upload`
|
|
125
|
+
is almost always embedded (the data source IS the upload sink);
|
|
126
|
+
`sns`, `rest_api`, `sql_database` are typically standalone.
|
|
127
|
+
|
|
128
|
+
### Body-type sub-fields are validated against the matching discriminator branch (server-side)
|
|
129
|
+
|
|
130
|
+
Each branch has its own required-list. Common patterns:
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
sns body region, auth_method, plus EITHER
|
|
134
|
+
(access_key_id + secret_access_key
|
|
135
|
+
+ optional endpoint_url)
|
|
136
|
+
OR (iam_role)
|
|
137
|
+
|
|
138
|
+
sql_database body db_type, db_host, db_port, db_name,
|
|
139
|
+
auth_method, db_username,
|
|
140
|
+
db_password (or iam_role)
|
|
141
|
+
|
|
142
|
+
s3 body region, bucket, auth_method,
|
|
143
|
+
access_key_id, secret_access_key
|
|
144
|
+
(or iam_role), optional base_path
|
|
145
|
+
|
|
146
|
+
sftp body hostname, port, username, auth_method,
|
|
147
|
+
password (or private_key)
|
|
148
|
+
|
|
149
|
+
rest_api body base_url, auth_method (oauth2 /
|
|
150
|
+
oidc / api_key / basic), plus the
|
|
151
|
+
corresponding credential block
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The full per-branch shape lives in
|
|
155
|
+
`packages/sdk/src/generated/types.gen.ts` under the matching
|
|
156
|
+
`Tool<Type>BodyWritable` types.
|
|
157
|
+
|
|
158
|
+
### `status` field gates whether the tool can be invoked
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
active tool is invocable; test-invocation + workflow steps work
|
|
162
|
+
inactive tool exists but invocations short-circuit with
|
|
163
|
+
an explanatory error envelope
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Most callers set `status: 'active'` on create; flipping to
|
|
167
|
+
`inactive` is the soft-delete / pause pattern.
|
|
168
|
+
|
|
169
|
+
### `aws_lambda` body has a second discriminator: `type`
|
|
170
|
+
|
|
171
|
+
Inside the `aws_lambda` body (selected by the outer
|
|
172
|
+
`tool_body_type: "aws_lambda"`), the wire carries a second
|
|
173
|
+
discriminator field literally named `type`:
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
body.type = "managed" → the platform owns the function;
|
|
177
|
+
create + deploy + delete go through
|
|
178
|
+
the platform's CloudFormation stack
|
|
179
|
+
body.type = "external" → the function is operator-managed in
|
|
180
|
+
an AWS account; the platform only
|
|
181
|
+
invokes it
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The two paths require disjoint field sets:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
type: "managed"
|
|
188
|
+
required: ssm_config_key (string — names the config
|
|
189
|
+
partition in SSM Parameter Store
|
|
190
|
+
the function reads at runtime)
|
|
191
|
+
accepted: secrets[] (array of { key, value } — material
|
|
192
|
+
the function reads as runtime
|
|
193
|
+
secrets; values are sensitive,
|
|
194
|
+
treat as write-only on the manifest
|
|
195
|
+
side via `<%= name %>` per §6 gotcha 10)
|
|
196
|
+
env_vars[] (array of { key, value } — passed
|
|
197
|
+
to the function as plain environment
|
|
198
|
+
variables; non-sensitive)
|
|
199
|
+
server-set: function_arn (populated after deploy succeeds)
|
|
200
|
+
stack_id, stack_name, stack_status
|
|
201
|
+
(CloudFormation tracking; see
|
|
202
|
+
§2 "aws_lambda tools have an
|
|
203
|
+
async deployment lifecycle")
|
|
204
|
+
|
|
205
|
+
type: "external"
|
|
206
|
+
required: function_arn (the existing AWS function to invoke)
|
|
207
|
+
auth_method ("access_key" or "iam_role")
|
|
208
|
+
access_key: access_key_id required;
|
|
209
|
+
secret_access_key write-only at create
|
|
210
|
+
iam_role: no AWS credentials required; the platform
|
|
211
|
+
assumes the role at invocation time
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### `aws_lambda` tools have an async deployment lifecycle
|
|
215
|
+
|
|
216
|
+
For `type: "managed"`, creating the tool registers the row but
|
|
217
|
+
DOES NOT deploy. An out-of-band deployment step packages and
|
|
218
|
+
uploads the function; poll the tool's `deployment_status` field:
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
pending POST returned; deployment job enqueued
|
|
222
|
+
deploying code being uploaded to AWS
|
|
223
|
+
deployed function is invocable; testInvocation will route to it
|
|
224
|
+
failed deployment error; check `deployment_error` field
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Two consumer-relevant consequences:
|
|
228
|
+
|
|
229
|
+
- **Managed tools cannot be created with `status: "active"`.**
|
|
230
|
+
The platform rejects with `/status: "cannot be set to active
|
|
231
|
+
until Lambda deployment is complete"`. Create with
|
|
232
|
+
`status: "draft"` (the typical pattern for managed lambdas),
|
|
233
|
+
trigger deployment, poll until `deployment_status: "deployed"`,
|
|
234
|
+
then PUT to flip `status` to `"active"`.
|
|
235
|
+
- **`function_arn` is server-populated for managed tools.** Do
|
|
236
|
+
not supply it on POST/PUT for `type: "managed"` — the platform
|
|
237
|
+
writes it after the CloudFormation stack reaches a
|
|
238
|
+
create-complete state.
|
|
239
|
+
|
|
240
|
+
For `type: "external"`, there is no deployment phase — the row
|
|
241
|
+
is invocable as soon as the create returns, and `function_arn`
|
|
242
|
+
is caller-supplied. Other body types (`s3`, `sns`, `rest_api`,
|
|
243
|
+
…) likewise have no deployment phase.
|
|
244
|
+
|
|
245
|
+
### `rest_api` body with `auth_method: "oidc"` probes the token endpoint at create
|
|
246
|
+
|
|
247
|
+
For `auth_method: "oidc"`, the platform fetches an access token
|
|
248
|
+
from the configured `oidc_issuer_url` using
|
|
249
|
+
`oidc_client_id` + `oidc_client_secret` **before** the row is
|
|
250
|
+
written. The probe surfaces in field-level rejections:
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
401 from token endpoint → /oidc_client_id:
|
|
254
|
+
"invalid credentials — token
|
|
255
|
+
endpoint returned 401"
|
|
256
|
+
other non-200 → /oidc_issuer_url:
|
|
257
|
+
"token endpoint returned HTTP {status}"
|
|
258
|
+
network unreachable → /oidc_issuer_url:
|
|
259
|
+
"cannot reach token endpoint: {reason}"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The probe is skipped when any of the required OIDC fields
|
|
263
|
+
(`oidc_issuer_url`, `oidc_client_id`, `oidc_client_secret`) are
|
|
264
|
+
missing — in that case the request fails on the missing-field
|
|
265
|
+
check before any HTTP call. Other `auth_method` values
|
|
266
|
+
(`oauth2`, `api_key`, `basic`, `none`) do not probe — only the
|
|
267
|
+
OIDC path runs the token-endpoint reachability check.
|
|
268
|
+
|
|
269
|
+
The probe runs on PUT too; an update that re-supplies any of
|
|
270
|
+
the three OIDC fields re-validates the token endpoint, so a
|
|
271
|
+
silent OIDC-provider outage can fail an otherwise-cosmetic
|
|
272
|
+
PUT.
|
|
273
|
+
|
|
274
|
+
## 3. Field ownership conventions
|
|
275
|
+
|
|
276
|
+
### Caller-supplied
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
identification + metadata
|
|
280
|
+
name human-readable label (unique per datalake)
|
|
281
|
+
description (nullable) free text
|
|
282
|
+
intent ToolIntent enum value
|
|
283
|
+
status "draft" | "active" | "inactive" | "error" | "marked_for_deletion"
|
|
284
|
+
'draft' — created but unconfigured (typical for
|
|
285
|
+
lambda tools awaiting deployment)
|
|
286
|
+
'active' — invocable; the steady state
|
|
287
|
+
'inactive' — paused / soft-deleted; invocations
|
|
288
|
+
short-circuit (see §2)
|
|
289
|
+
'error' — failure state; surfaces via UI banners
|
|
290
|
+
and gates re-invocation until resolved
|
|
291
|
+
'marked_for_deletion' — cleanup in flight (lambda undeploy etc.);
|
|
292
|
+
transient before DB row removal
|
|
293
|
+
|
|
294
|
+
scoping
|
|
295
|
+
datalake_id parent datalake (UUID)
|
|
296
|
+
data_source_id (optional) parent data source for embedded
|
|
297
|
+
tools; omit for standalone
|
|
298
|
+
|
|
299
|
+
body (polymorphic — required keys depend on tool_body_type)
|
|
300
|
+
tool_body_type discriminator — names which branch shape
|
|
301
|
+
the rest of `body` must satisfy
|
|
302
|
+
<branch-specific> auth + endpoint + credential fields
|
|
303
|
+
(use `<%= name %>` Eta refs for credentials;
|
|
304
|
+
never literal values)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Server-derived
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
id UUID
|
|
311
|
+
slug derived from name (lowercase + hyphen)
|
|
312
|
+
created_at ISO timestamp
|
|
313
|
+
updated_at ISO timestamp
|
|
314
|
+
deployment_status lambda tools only
|
|
315
|
+
deployment_error lambda tools only, when status="failed"
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
The slug, like every other resource, is the canonical handle for
|
|
319
|
+
downstream references after create — never pre-compute it
|
|
320
|
+
client-side.
|
|
321
|
+
|
|
322
|
+
## 4. Error envelopes
|
|
323
|
+
|
|
324
|
+
A `422` from `POST` / `PUT` returns:
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
{
|
|
328
|
+
"errors": {
|
|
329
|
+
"field.path": ["check message", …],
|
|
330
|
+
"body.tool_body_type": ["is invalid"],
|
|
331
|
+
…
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Walking each entry:
|
|
337
|
+
|
|
338
|
+
1. Look up the field on `ToolRequestWritable` (or the relevant
|
|
339
|
+
`Tool<Type>BodyWritable` branch when the path starts with
|
|
340
|
+
`body.`). The TS type's JSDoc names the semantic role.
|
|
341
|
+
2. Read the 422 `detail` for the precise constraint that fired
|
|
342
|
+
(the field tables in this MD list each branch's required-list).
|
|
343
|
+
3. For `body.<...>` failures, the FIRST diagnostic is usually
|
|
344
|
+
`tool_body_type` — fix the discriminator before chasing other
|
|
345
|
+
fields, because the wrong branch's required-list will fire
|
|
346
|
+
spuriously when the discriminator is wrong.
|
|
347
|
+
|
|
348
|
+
Common rejections:
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
field check cause
|
|
352
|
+
───────────────────────────── ─────────────────────────────
|
|
353
|
+
"is invalid" on intent value not in ToolIntent enum
|
|
354
|
+
"is invalid" on tool_body_type value not in
|
|
355
|
+
ToolBodyTypeEnum
|
|
356
|
+
"is invalid" on body intent ↔ body_type pairing
|
|
357
|
+
rejected at platform level
|
|
358
|
+
"can't be blank" on a body sub-field branch-specific required
|
|
359
|
+
field omitted
|
|
360
|
+
"must match auth_method" on credentials e.g. `iam_role` set but
|
|
361
|
+
`access_key_id` also supplied
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## 5. Lifecycle
|
|
365
|
+
|
|
366
|
+
### Create
|
|
367
|
+
|
|
368
|
+
`POST /tenants/:tenant_slug/datalakes/:datalake_slug/tools`
|
|
369
|
+
returns `201` with the full tool shape including server-derived
|
|
370
|
+
fields. For non-lambda body types the tool is invocable
|
|
371
|
+
immediately; for `aws_lambda` the deployment is async (see §2).
|
|
372
|
+
|
|
373
|
+
### Test invocation
|
|
374
|
+
|
|
375
|
+
`POST /tenants/:tenant/datalakes/:datalake/tools/:id/test-
|
|
376
|
+
invocation` exercises the tool end-to-end against the live
|
|
377
|
+
external system.
|
|
378
|
+
|
|
379
|
+
The request body wraps the call payload under `tool_call`, whose
|
|
380
|
+
own polymorphic `tool_call_type` discriminator selects the call
|
|
381
|
+
shape:
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
await api.tools.testInvocation(
|
|
385
|
+
tenantSlug, datalakeSlug, toolId,
|
|
386
|
+
{
|
|
387
|
+
tool_call: {
|
|
388
|
+
tool_call_type: 'sms_request', // 'email_request' | ...
|
|
389
|
+
to: { type: 'custom', body: '+15551234567' },
|
|
390
|
+
body: { type: 'custom', body: 'Hello' },
|
|
391
|
+
sms_type: 'transactional', // sms_request-specific
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
)
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
`to` and `body` are each `{ type, body }` embeds — `type: 'custom'`
|
|
398
|
+
inlines the value verbatim; `type: 'system'` references a
|
|
399
|
+
platform-shipped template (see `templates.md`). Variant-specific
|
|
400
|
+
fields carry their own enums and constraints; the per-branch
|
|
401
|
+
required-list:
|
|
402
|
+
|
|
403
|
+
```
|
|
404
|
+
tool_call_type: 'sms_request'
|
|
405
|
+
required: to, body, sms_type
|
|
406
|
+
enums: sms_type ∈ { 'transactional' (default), 'promotional' }
|
|
407
|
+
|
|
408
|
+
tool_call_type: 'email_request'
|
|
409
|
+
required: to, subject, body
|
|
410
|
+
embeds: TemplateConfig variants accepted on each ({ type:
|
|
411
|
+
'custom', body } or { type: 'identity' } or
|
|
412
|
+
{ type: 'system', path }); 'null' is not valid here
|
|
413
|
+
|
|
414
|
+
tool_call_type: 'rest_api_request'
|
|
415
|
+
required: path, method, pagination_context_template
|
|
416
|
+
enums: method ∈ HTTP methods (GET, POST, PUT, PATCH, DELETE,
|
|
417
|
+
HEAD, OPTIONS)
|
|
418
|
+
optional: body, params (each TemplateConfig — 'identity' or
|
|
419
|
+
'custom' both accepted)
|
|
420
|
+
|
|
421
|
+
tool_call_type: 'sql_query'
|
|
422
|
+
required: query (TemplateConfig — Liquid template producing
|
|
423
|
+
the SQL string)
|
|
424
|
+
|
|
425
|
+
tool_call_type: 'aws_lambda_request'
|
|
426
|
+
required: payload (TemplateConfig — 'identity' acceptable)
|
|
427
|
+
constraints: timeout_ms in inclusive range [1000, 900_000]
|
|
428
|
+
(defaults to 30_000 ms when omitted)
|
|
429
|
+
|
|
430
|
+
tool_call_type: 'sftp_request'
|
|
431
|
+
required: path, content_type
|
|
432
|
+
enums: content_type ∈ closed set (json, ndjson, csv, ...);
|
|
433
|
+
the SDK type names the live set per branch
|
|
434
|
+
format: path validated against an absolute-path pattern
|
|
435
|
+
and a maximum length
|
|
436
|
+
|
|
437
|
+
tool_call_type: 'microsoft_share_point_excel_request'
|
|
438
|
+
required: every field of the branch
|
|
439
|
+
constraints: sheet_number >= 0 (0-indexed; negative values are
|
|
440
|
+
rejected with a "greater than -1" message)
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
Liquid template bodies (`query`, `payload`, body/params on
|
|
444
|
+
`rest_api_request`, `sms_request` body, `email_request` body) are
|
|
445
|
+
parsed at create time — invalid Liquid syntax surfaces as a field
|
|
446
|
+
rejection on the corresponding TemplateConfig path, not on the
|
|
447
|
+
outer request.
|
|
448
|
+
|
|
449
|
+
The response shape:
|
|
450
|
+
|
|
451
|
+
```
|
|
452
|
+
{
|
|
453
|
+
id: UUID of the recorded invocation
|
|
454
|
+
status: "success" | "error"
|
|
455
|
+
error_message: string | null
|
|
456
|
+
tool_call: the input echoed back, with provider metadata
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
This endpoint **never returns a 5xx for tool-side failures** —
|
|
461
|
+
provider errors (bad credentials, network refused, misconfigured
|
|
462
|
+
auth) surface as `status: "error"` with `error_message` populated.
|
|
463
|
+
Only platform-internal failures (DB unreachable, etc.) produce
|
|
464
|
+
5xx. Treat 5xx as infra noise; treat `200 + status:"error"` as a
|
|
465
|
+
real (and handleable) configuration problem.
|
|
466
|
+
|
|
467
|
+
### Update
|
|
468
|
+
|
|
469
|
+
`PUT /tenants/:tenant/datalakes/:datalake/tools/:id` replays the
|
|
470
|
+
full body — no PATCH. The polymorphic discriminator MUST match
|
|
471
|
+
the existing row's `tool_body_type`; changing body type requires
|
|
472
|
+
delete + recreate.
|
|
473
|
+
|
|
474
|
+
### Delete
|
|
475
|
+
|
|
476
|
+
`DELETE /tenants/:tenant/datalakes/:datalake/tools/:id` removes
|
|
477
|
+
the row. For `aws_lambda` tools, this also enqueues a
|
|
478
|
+
`trigger_lambda_deletion` job — poll until the AWS function is
|
|
479
|
+
gone. Other body types delete synchronously.
|
|
480
|
+
|
|
481
|
+
### Ordering
|
|
482
|
+
|
|
483
|
+
A tool MUST be created AFTER its parent datalake reaches
|
|
484
|
+
`status: "ready"`, and (if embedded) AFTER its parent data source
|
|
485
|
+
exists. Workflows and data activation clients reference tools by id, so any
|
|
486
|
+
downstream resource that names a tool must apply AFTER it.
|
|
487
|
+
|
|
488
|
+
## 6. Gotchas
|
|
489
|
+
|
|
490
|
+
1. **Discriminator wire name is `tool_body_type`** — not `type`,
|
|
491
|
+
not `kind`, not `__type__`. Always use the wire name on the
|
|
492
|
+
request body.
|
|
493
|
+
|
|
494
|
+
2. **`manual_upload` body is the only branch with no auth /
|
|
495
|
+
endpoint fields** — its presigned URLs are issued by the
|
|
496
|
+
platform per-upload. `body: { tool_body_type: 'manual_upload' }`
|
|
497
|
+
with no other body fields is the full create body.
|
|
498
|
+
|
|
499
|
+
3. **`sns` tools with `iam_role` auth + no `endpoint_url` MUST be
|
|
500
|
+
tested against real AWS** — `ExAws.Config.AuthCache` refreshes
|
|
501
|
+
SSO credentials at invocation time. In dev / E2E, use
|
|
502
|
+
`auth_method: 'access_key'` + `endpoint_url:
|
|
503
|
+
'http://localhost:4566'` for LocalStack routing.
|
|
504
|
+
|
|
505
|
+
4. **Test-invocation graceful-error contract is load-bearing** —
|
|
506
|
+
any code path that crashes the test-invocation route into a 500
|
|
507
|
+
is a regression. Misconfigured tools must surface
|
|
508
|
+
`status: "error"` + non-empty `error_message`. If you see a
|
|
509
|
+
5xx, file a platform bug, do not retry.
|
|
510
|
+
|
|
511
|
+
5. **Standalone vs embedded tool routing differs at list time**
|
|
512
|
+
— `tools.list(tenant, datalake)` returns ALL tools on the
|
|
513
|
+
datalake (standalone + embedded). To find tools owned by a
|
|
514
|
+
specific data source, filter the list client-side on
|
|
515
|
+
`data_source_id`.
|
|
516
|
+
|
|
517
|
+
6. **Tool slug uniqueness is per-datalake, not per-tenant** —
|
|
518
|
+
two datalakes on the same tenant can have tools with the same
|
|
519
|
+
slug. Always scope tool references via the datalake slug,
|
|
520
|
+
never just the tool slug.
|
|
521
|
+
|
|
522
|
+
7. **`tools.metadata(tenant, datalake)` returns a Markdown
|
|
523
|
+
catalog** — useful as a discovery surface for downstream
|
|
524
|
+
tooling. `tools.metadataDetails(tenant, datalake, toolId)`
|
|
525
|
+
returns Markdown for a single tool including the body
|
|
526
|
+
discriminator + per-branch fields.
|
|
527
|
+
|
|
528
|
+
8. **`PUT` replays the full body** — to flip `status` from
|
|
529
|
+
`active` to `inactive`, resubmit the entire body including all
|
|
530
|
+
credential / endpoint fields. Forgetting the body branch
|
|
531
|
+
discriminator on PUT triggers the "tool_body_type required"
|
|
532
|
+
rejection.
|
|
533
|
+
|
|
534
|
+
9. **Lambda deployment_status is the readiness signal, not
|
|
535
|
+
`status`** — for `aws_lambda` tools, `status: "active"` only
|
|
536
|
+
means "row exists and is invocation-eligible if deployed".
|
|
537
|
+
The actual readiness is `deployment_status: "deployed"`.
|
|
538
|
+
|
|
539
|
+
10. **Credentials in the body MUST go through `<%= name %>`
|
|
540
|
+
Eta references** when the tool is authored via a manifest — never
|
|
541
|
+
literal strings on disk. The flat top-level identifier form is the
|
|
542
|
+
safe shape (`<%= secrets.name %>` nested under a `secrets` object
|
|
543
|
+
silently renders the string `"undefined"` if the key is missing).
|
|
544
|
+
The SDK does not enforce this (it accepts literals), but secret
|
|
545
|
+
references are the required operating mode for any non-test
|
|
546
|
+
environment.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Type naming
|
|
2
|
+
|
|
3
|
+
The SDK's TypeScript codegen emits two type variants per
|
|
4
|
+
resource — a request shape (for POST/PUT bodies) and a response
|
|
5
|
+
shape (for GET output). They differ in which fields they
|
|
6
|
+
include.
|
|
7
|
+
|
|
8
|
+
## Writable suffix for request shapes
|
|
9
|
+
|
|
10
|
+
Request types carry a `Writable` suffix. The codegen
|
|
11
|
+
auto-excludes any field marked `readOnly` in the OpenAPI spec —
|
|
12
|
+
these are the server-derived fields (`id`, `slug`, `created_at`,
|
|
13
|
+
`updated_at`, `status`, etc. — enumerated in the next section).
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import type {
|
|
17
|
+
DatalakeRequestWritable, // POST/PUT body
|
|
18
|
+
DatalakeResponse, // GET output
|
|
19
|
+
} from '@alvera-ai/platform-sdk'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Same convention for every resource:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
<Resource>RequestWritable POST/PUT body (request shape)
|
|
26
|
+
<Resource>Response GET output (response shape with
|
|
27
|
+
server-derived fields included)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Server-derived fields auto-excluded from Writable
|
|
31
|
+
|
|
32
|
+
Every resource carries a consistent set of fields the platform
|
|
33
|
+
server derives on create. These appear in `<Resource>Response`
|
|
34
|
+
types but are NEVER part of `<Resource>RequestWritable` types —
|
|
35
|
+
the codegen auto-excludes them based on `readOnly` markers in
|
|
36
|
+
the OpenAPI spec:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
id UUID, allocated on create
|
|
40
|
+
slug derived from `name` via the platform's
|
|
41
|
+
slug-generation (lowercase + hyphenate +
|
|
42
|
+
de-duplicate within scope)
|
|
43
|
+
created_at ISO 8601 timestamp
|
|
44
|
+
updated_at ISO 8601 timestamp
|
|
45
|
+
status resource-specific lifecycle enum
|
|
46
|
+
(e.g. "new" → "ready" → ... per the
|
|
47
|
+
resource's MD §5)
|
|
48
|
+
status_reason nullable; populated when status enters a
|
|
49
|
+
terminal-failure state
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Including any of these in a POST/PUT body triggers a layer-1
|
|
53
|
+
422 with an "unknown key" detail. The typed `*RequestWritable`
|
|
54
|
+
doesn't expose these fields, so TypeScript prevents it at
|
|
55
|
+
compile time when consumers use the typed methods.
|
|
56
|
+
|
|
57
|
+
### Never pre-compute the slug client-side
|
|
58
|
+
|
|
59
|
+
Slugs are derived from `name` server-side and de-duplicated
|
|
60
|
+
within scope (per-resource — usually datalake-scoped for
|
|
61
|
+
datalake-owned resources, tenant-scoped for tenant-level
|
|
62
|
+
resources). A client-computed slug that conflicts with an
|
|
63
|
+
existing row gets a different suffix server-side, leaving the
|
|
64
|
+
client's local state out of sync.
|
|
65
|
+
|
|
66
|
+
The canonical pattern:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// 1. create — slug returned in the response
|
|
70
|
+
const { data: created } = await api.tools.create(
|
|
71
|
+
tenantSlug, datalakeSlug, body,
|
|
72
|
+
)
|
|
73
|
+
const toolSlug = created.slug // <-- canonical
|
|
74
|
+
|
|
75
|
+
// 2. downstream references use the returned slug
|
|
76
|
+
await api.tools.get(tenantSlug, datalakeSlug, toolSlug)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Never:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// ❌ wrong — client-computed slug can drift from server-side
|
|
83
|
+
const toolSlug = body.name.toLowerCase().replace(/\s+/g, '-')
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Per-resource extras
|
|
87
|
+
|
|
88
|
+
Some resources have additional server-derived fields beyond
|
|
89
|
+
the universal set (e.g. AWS Lambda tools' `deployment_status`
|
|
90
|
+
+ `deployment_error`; data-activation-client `last_run_at`).
|
|
91
|
+
Each resource's MD §3 (Field ownership) lists its full
|
|
92
|
+
server-derived set.
|
|
93
|
+
|
|
94
|
+
## No client-side validators
|
|
95
|
+
|
|
96
|
+
The SDK ships **types only** — there is no paired runtime validator to
|
|
97
|
+
import (`v<Resource>RequestWritable` no longer exists). Validation is
|
|
98
|
+
server-authoritative: submit the body and handle the server's 422
|
|
99
|
+
`AlveraApiError` if it's malformed (see `errors.md`). If you author config
|
|
100
|
+
through the `alvera` CLI, `alvera plan` validates locally against the spec
|
|
101
|
+
before any HTTP call.
|
|
102
|
+
|
|
103
|
+
## Enum types
|
|
104
|
+
|
|
105
|
+
Enums are exported as TypeScript const-style values (per the
|
|
106
|
+
SDK's strict-TS conventions — no TypeScript-native `enum`
|
|
107
|
+
keyword):
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { ToolIntent } from '@alvera-ai/platform-sdk'
|
|
111
|
+
|
|
112
|
+
ToolIntent.DATA_EXCHANGE // wire value: "data_exchange"
|
|
113
|
+
ToolIntent.SMS // wire value: "sms"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The wire value is always snake_case; the TS-side identifier is
|
|
117
|
+
UPPER_SNAKE for readability. Each resource's MD names its
|
|
118
|
+
relevant enum types.
|
|
119
|
+
|
|
120
|
+
## List response types
|
|
121
|
+
|
|
122
|
+
List endpoints return a typed envelope: `<Resource>List-
|
|
123
|
+
Response` with `data: <Resource>Response[]` and `meta:
|
|
124
|
+
PaginationMeta`:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import type { ToolListResponse } from '@alvera-ai/platform-sdk'
|
|
128
|
+
|
|
129
|
+
const { data } = await api.tools.list(tenantSlug, datalakeSlug)
|
|
130
|
+
// data is ToolListResponse: { data: ToolResponse[], meta: PaginationMeta }
|
|
131
|
+
```
|