@alvera-ai/platform-sdk 0.10.0-rc.8 → 0.11.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 (66) hide show
  1. package/.agent/AGENTS.md +499 -0
  2. package/.agent/account_management.md +456 -0
  3. package/.agent/action_status_updaters.md +264 -0
  4. package/.agent/ai_agents.md +462 -0
  5. package/.agent/ai_sandbox.md +265 -0
  6. package/.agent/async.md +112 -0
  7. package/.agent/connected_apps.md +408 -0
  8. package/.agent/cookbook/_fixtures/README.md +106 -0
  9. package/.agent/cookbook/_fixtures/accounts_receivable/_customers_accounts_receivable_customer.liquid +32 -0
  10. package/.agent/cookbook/_fixtures/accounts_receivable/_customers_accounts_receivable_mdm.liquid +20 -0
  11. package/.agent/cookbook/_fixtures/accounts_receivable/stripe_customers_batch1.csv +5 -0
  12. package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_generic_table.liquid +33 -0
  13. package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_legal_entity.liquid +88 -0
  14. package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_mdm.liquid +48 -0
  15. package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_appointment.liquid +47 -0
  16. package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_mdm.liquid +24 -0
  17. package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_patient.liquid +38 -0
  18. package/.agent/cookbook/_fixtures/healthcare/memorandum-of-association-01.png +0 -0
  19. package/.agent/cookbook/_fixtures/healthcare/sample_two_page.pdf +43 -0
  20. package/.agent/cookbook/_fixtures/payment_risk/_compliance_screenings_payment_risk_compliance_screening.liquid +59 -0
  21. package/.agent/cookbook/_fixtures/payment_risk/_compliance_screenings_payment_risk_mdm.liquid +36 -0
  22. package/.agent/cookbook/_fixtures/payment_risk/_payment_accounts_payment_risk_mdm.liquid +30 -0
  23. package/.agent/cookbook/_fixtures/payment_risk/_payment_accounts_payment_risk_payment_account.liquid +55 -0
  24. package/.agent/cookbook/_setup/accounts_receivable.md +282 -0
  25. package/.agent/cookbook/_setup/foundation.md +277 -0
  26. package/.agent/cookbook/_setup/healthcare.md +279 -0
  27. package/.agent/cookbook/_setup/payment_risk.md +283 -0
  28. package/.agent/cookbook/action-status-updaters.md +212 -0
  29. package/.agent/cookbook/ai-agent-invoke.md +243 -0
  30. package/.agent/cookbook/appointment-review-sms-workflow.md +761 -0
  31. package/.agent/cookbook/birthday-greeting-sms-trigger.md +656 -0
  32. package/.agent/cookbook/bulk-ingest.md +254 -0
  33. package/.agent/cookbook/contact-us-triage-with-llm.md +622 -0
  34. package/.agent/cookbook/custom-tables.md +201 -0
  35. package/.agent/cookbook/dunning-sms-for-delinquent.md +619 -0
  36. package/.agent/cookbook/invite-team.md +194 -0
  37. package/.agent/cookbook/kyc-notification-on-account-activation.md +619 -0
  38. package/.agent/cookbook/rest-fetch.md +246 -0
  39. package/.agent/cookbook/sanctions-screening-with-agent-review.md +733 -0
  40. package/.agent/cookbook/score-leads-with-llm-categorization.md +624 -0
  41. package/.agent/cookbook/system-templates.md +129 -0
  42. package/.agent/cookbook/triage-prospects-by-priority.md +533 -0
  43. package/.agent/cookbook/welcome-sms-for-customers.md +607 -0
  44. package/.agent/data_activation_clients.md +559 -0
  45. package/.agent/data_sources.md +235 -0
  46. package/.agent/datalakes.md +714 -0
  47. package/.agent/debugging.md +137 -0
  48. package/.agent/errors.md +190 -0
  49. package/.agent/generic_tables.md +351 -0
  50. package/.agent/interoperability_contracts.md +417 -0
  51. package/.agent/mdm.md +293 -0
  52. package/.agent/mutations.md +126 -0
  53. package/.agent/templates.md +98 -0
  54. package/.agent/tool-call-configs.md +90 -0
  55. package/.agent/tools.md +547 -0
  56. package/.agent/type_naming.md +129 -0
  57. package/.agent/workflows.md +617 -0
  58. package/README.md +178 -0
  59. package/dist/bin/platform-sdk.d.mts +1 -0
  60. package/dist/bin/platform-sdk.mjs +106 -0
  61. package/dist/bin/platform-sdk.mjs.map +1 -0
  62. package/dist/index.d.mts +1310 -44116
  63. package/dist/index.d.mts.map +1 -1
  64. package/dist/index.mjs +1194 -7344
  65. package/dist/index.mjs.map +1 -1
  66. package/package.json +19 -10
@@ -0,0 +1,462 @@
1
+ # AI agents
2
+
3
+ An **AI agent** is a registered LLM caller — a configured pairing
4
+ of a chat-completion tool, a model identifier, a system prompt
5
+ template, and JSON Schemas declaring the agent's input shape and
6
+ the LLM's required output shape. Workflows attach agents at
7
+ their enrichment stage; the agent's structured output then feeds
8
+ the workflow's decision template.
9
+
10
+ SDK namespace: `api.aiAgents`.
11
+
12
+ AI agents are **Datalake-DB-resident** — the parent datalake
13
+ must be `status: 'ready'` and the bound tool must exist before
14
+ you `create()`.
15
+
16
+ ## 1. Wire shape
17
+
18
+ ```typescript
19
+ import type {
20
+ AiAgentRequestWritable,
21
+ AiAgentResponse,
22
+ } from '@alvera-ai/platform-sdk'
23
+
24
+ const { data: created } = await api.aiAgents.create(
25
+ tenantSlug,
26
+ datalakeSlug,
27
+ {
28
+ name: 'Contact Us Triage Categorizer',
29
+ description: 'Triages inbound submissions into appointment / job / spam',
30
+
31
+ tool_id: chatCompletionToolId, // see §2 — must be a tool with intent: 'llm_enrichment'
32
+
33
+ model: 'llama3.2:3b', // provider-specific model identifier
34
+ data_access: 'unregulated', // 'unregulated' | 'regulated' (compliance gate)
35
+ temperature: 0.0,
36
+ max_tokens: 2048,
37
+ enabled: true,
38
+
39
+ input_schema: { // JSON Schema — fields the prompt receives
40
+ type: 'object',
41
+ properties: {
42
+ msg: { type: 'string' },
43
+ submission_id: { type: 'string' },
44
+ },
45
+ required: ['msg', 'submission_id'],
46
+ },
47
+
48
+ llm_response_schema: { // JSON Schema — what the LLM MUST return
49
+ type: 'object',
50
+ properties: {
51
+ category: {
52
+ type: 'string',
53
+ enum: ['appointment_request', 'job_inquiry', 'flag_spam'],
54
+ },
55
+ },
56
+ required: ['category'],
57
+ additionalProperties: false,
58
+ },
59
+
60
+ prompt_config: {
61
+ type: 'custom',
62
+ body: `You are a triage assistant. Categorize this submission ...
63
+
64
+ Submission ID: {{ submission_id }}
65
+ Message: {{ msg }}
66
+
67
+ Respond with JSON: {"category": "..."}`,
68
+ },
69
+ },
70
+ )
71
+ // created.id, created.slug — server-derived
72
+ // created.name === body.name
73
+ ```
74
+
75
+ ## 2. Rules the type cannot encode
76
+
77
+ ### `tool_id` must point to a chat-completion tool
78
+
79
+ The bound tool's `intent` MUST be `llm_enrichment`. Tools with
80
+ any other intent (`sms`, `data_exchange`, `status_poller`, …)
81
+ are rejected at create time as a 422 on `/tool_id`.
82
+
83
+ The chat-completion tool is typically a `tool_body_type:
84
+ 'rest_api'` configured against an OpenAI-compatible endpoint
85
+ (OpenAI itself, Ollama, vLLM, etc.). The platform appends
86
+ `/chat/completions` to the tool's `base_url`, so:
87
+
88
+ ```
89
+ tool.base_url = 'http://localhost:11434/v1'
90
+ → actual request URL = 'http://localhost:11434/v1/chat/completions'
91
+ ```
92
+
93
+ A tool whose `base_url` already contains `/chat/completions`
94
+ will produce a doubled path and 404.
95
+
96
+ ### `llm_response_schema` is REQUIRED and load-bearing
97
+
98
+ The schema is mandatory at create time — a body omitting it
99
+ returns a 422 on `/llm_response_schema`. The schema serves two
100
+ roles:
101
+
102
+ 1. **Provider-side decoding constraint**: the platform forwards
103
+ the schema in the chat-completion request as
104
+ `response_format: json_schema`, instructing the provider to
105
+ constrain decoding so the LLM cannot return prose, markdown
106
+ code fences, or chat preamble around the JSON. Without this
107
+ constraint, small models often wrap output in fences and the
108
+ platform's JSON parse step fails with `json_decode_failed`.
109
+ 2. **Output binding**: the parsed LLM output is exposed in the
110
+ workflow's `additional_context` under the agent's slug, with
111
+ property paths matching the schema (see §3 below).
112
+
113
+ ### Prompt receives Liquid-rendered fields from `input_schema`
114
+
115
+ The agent's `prompt_config.body` is a Liquid template that
116
+ references the agent's `input_schema` fields via `{{ <field> }}`.
117
+ At workflow runtime, the workflow's `context_mapping_config`
118
+ populates these fields from the inbound dataset row (see §3).
119
+
120
+ The platform validates at create time that every `{{ <field> }}`
121
+ referenced by the prompt body resolves to a property declared in
122
+ `input_schema`. Drift between the two surfaces as a 422 on
123
+ `/prompt_config/body`.
124
+
125
+ ### `data_access` is the compliance gate
126
+
127
+ ```
128
+ data_access: 'unregulated' — the LLM call receives tokenized,
129
+ redacted data; safe for any LLM
130
+ (third-party, on-prem, …).
131
+ Default for triage / categorization
132
+ / lead-scoring workflows.
133
+ data_access: 'regulated' — the LLM call receives raw values;
134
+ MUST be paired with an LLM the
135
+ operator trusts with this tier
136
+ (typically an on-prem deployment).
137
+ Use for compliance workflows that
138
+ need raw values — sanctions
139
+ screening, manual review, KYC.
140
+ ```
141
+
142
+ The setting is **immutable post-create**. Flipping the access
143
+ tier requires recreating the agent (delete + create).
144
+
145
+ ### `enabled` gates whether workflows can invoke the agent
146
+
147
+ A workflow that references a `disabled` agent fails at run time
148
+ with `error_code: 'ai_agent_disabled'` on the workflow execution
149
+ log. `enabled: false` is the operator's kill switch for an agent
150
+ without removing it from the workflow's `ai_agents` array.
151
+
152
+ ### Numeric clamps on `temperature` and `max_tokens`
153
+
154
+ The platform validates the numeric ranges at create / update time
155
+ — BEFORE any chat-completion call to the bound tool. Out-of-range
156
+ values surface as field-level rejections, not as runtime
157
+ provider errors:
158
+
159
+ ```
160
+ temperature required number ∈ [0.0, 2.0] inclusive on both ends
161
+ max_tokens required integer ∈ [1, 100_000] inclusive on both ends
162
+ ```
163
+
164
+ These bounds are the platform's, not the provider's. Picking a
165
+ value the provider doesn't support (e.g. `temperature: 1.5` on
166
+ a model that caps at 1.0) surfaces later as a provider error in
167
+ the workflow execution log, not at create.
168
+
169
+ ### Name uniqueness is per-tenant, not per-datalake
170
+
171
+ The agent's `name` (and the server-derived `slug`) must be
172
+ unique within the tenant — collisions across **different
173
+ datalakes of the same tenant** are rejected with a 422 on
174
+ `/name` or `/slug`. This is unusual: most other resources scoped
175
+ under a datalake (tools, data sources, interoperability
176
+ contracts) carry per-datalake uniqueness. AI agents are the
177
+ exception because their `slug` is the workflow-template
178
+ reference key (`additional_context.<slug>`) and the platform
179
+ needs a stable cross-datalake namespace for it.
180
+
181
+ Practical consequence: if you want the same logical agent in
182
+ two datalakes (e.g. dev + prod inside one tenant), give them
183
+ distinct names. A naming convention like `"<purpose>-<env>"` or
184
+ including the datalake slug in the agent name keeps the
185
+ namespace clean.
186
+
187
+ ## 3. Workflow & contract nesting
188
+
189
+ An agent runs as an **enrichment** step on a workflow or an
190
+ interoperability contract. The agent is **nested directly on the
191
+ parent body** — workflow and interoperability-contract
192
+ create/update bodies accept a `workflow_ai_agents` /
193
+ `interoperability_contract_ai_agents` array. There is
194
+ no separate attach/detach endpoint, and **no per-join checksum**: the
195
+ nested agents fold into the parent's own checksum.
196
+
197
+ ```typescript
198
+ // Nest on create. `position` is REQUIRED.
199
+ const { data: workflow } = await api.workflows.create(
200
+ tenantSlug, datalakeSlug,
201
+ {
202
+ name: 'Contact-Us Triage',
203
+ dataset_type: 'generic_table',
204
+ // …other workflow fields…
205
+ workflow_ai_agents: [
206
+ {
207
+ ai_agent_id: createdAgentId,
208
+ position: 0, // ordering when multiple agents fire; REQUIRED
209
+ context_mapping_config: {
210
+ type: 'custom',
211
+ // Liquid renders to a JSON object whose keys match the agent's
212
+ // input_schema. Values reference the inbound row via `event_dataset.<field>`.
213
+ body: JSON.stringify({
214
+ msg: '{{ event_dataset.message }}',
215
+ submission_id: '{{ event_dataset.submission_id }}',
216
+ }),
217
+ // Workflow joins OMIT output_schema — the server pins it from
218
+ // the agent's input_schema. Interop joins author it (below).
219
+ },
220
+ },
221
+ ],
222
+ },
223
+ )
224
+ workflow.checksum // the PARENT checksum — the nested agents fold into it
225
+ ```
226
+
227
+ Interoperability contracts nest the same way, via the
228
+ `interoperability_contract_ai_agents` array on the contract
229
+ create/update body. The one difference: a contract join's
230
+ `context_mapping_config` **does** carry `output_schema` (the server
231
+ does not pin it there).
232
+
233
+ Adding, repositioning, and removing agents are all expressed by
234
+ re-supplying the full set on the parent's `update()` — `update()`
235
+ replaces the whole array, and any item you omit is removed:
236
+
237
+ | Operation | How | Result |
238
+ |------------|------------------------------------------------------|--------|
239
+ | add / nest | include in `*_ai_agents` on create or update | parent checksum reflects the agents |
240
+ | reposition | `update()` with the same agent at a new `position` | full-set replace |
241
+ | detach | `update()` omitting that agent (or `[]` to clear all)| the omitted agent is removed |
242
+ | drift | parent `checksum()` endpoint over the full body | the would-be parent checksum (no persist) |
243
+
244
+ The parent surfaces its nested agents on read: a workflow `get()`
245
+ returns `workflow_ai_agents: [...]` and a contract `get()` returns
246
+ `interoperability_contract_ai_agents: [...]`. Both arrays are writable
247
+ on the parent body (create + update).
248
+
249
+ The workflow's own `decision_config` reads the agent's parsed output
250
+ at `additional_context.<agent_slug>.<field>` (property paths match the
251
+ agent's `llm_response_schema`):
252
+
253
+ ```typescript
254
+ decision_config: {
255
+ type: 'custom',
256
+ body: '["{{ additional_context.contact-us-triage-categorizer.category }}"]',
257
+ output_schema: '{"type":"array","items":{"type":"string"}}',
258
+ }
259
+ ```
260
+
261
+ The flow at run time:
262
+
263
+ ```
264
+ inbound row
265
+ │
266
+ ▼
267
+ workflow filter
268
+ │
269
+ ▼
270
+ for each ai_agents[i] (ordered by position):
271
+ • render context_mapping_config.body with Liquid (event_dataset.*, etc.)
272
+ • parse rendered output as JSON
273
+ • check it conforms to agent.input_schema
274
+ • forward to the bound tool as a chat completion
275
+ • parse the LLM response per agent.llm_response_schema
276
+ • merge under additional_context[agent.slug]
277
+ │
278
+ ▼
279
+ workflow decision (reads additional_context.<agent_slug>.<field>)
280
+ │
281
+ ▼
282
+ workflow action(s)
283
+ ```
284
+
285
+ ## 4. Field ownership
286
+
287
+ **Server-derived (Response-only).** Universal set from
288
+ `type_naming.md`. The `slug` is what workflow templates
289
+ reference via `additional_context.<slug>`.
290
+
291
+ **Caller-supplied (round-trip).**
292
+
293
+ ```
294
+ name required string
295
+ description optional string
296
+ tool_id required UUID — must be intent: llm_enrichment
297
+ model required string — provider-specific identifier
298
+ data_access required enum — 'unregulated' | 'regulated'
299
+ temperature required number
300
+ max_tokens required number
301
+ enabled required bool
302
+ input_schema required JSON Schema object
303
+ llm_response_schema required JSON Schema object — see §2
304
+ prompt_config required embed — { type, body }
305
+ ```
306
+
307
+ **Write-only (Request-only).** None.
308
+
309
+ ## 5. Error envelopes
310
+
311
+ Standard JSON:API envelopes per `errors.md`. Common rejections:
312
+
313
+ | `source.pointer` | Cause |
314
+ |---------------------------------|----------------------------------------------------|
315
+ | `/tool_id` | tool's intent isn't `llm_enrichment` |
316
+ | `/llm_response_schema` | missing or not a valid JSON Schema object |
317
+ | `/input_schema` | missing or not a valid JSON Schema object |
318
+ | `/prompt_config/body` | references a field absent from `input_schema` |
319
+ | `/data_access` | value not in enum |
320
+ | `/temperature` | outside the inclusive range [0.0, 2.0] |
321
+ | `/max_tokens` | outside the inclusive range [1, 100_000] |
322
+ | `/name` or `/slug` | uniqueness collision — scope is per-tenant |
323
+
324
+ ## 6. Lifecycle
325
+
326
+ ### Create
327
+
328
+ Synchronous. The agent is immediately invocable by workflows
329
+ once `enabled: true`.
330
+
331
+ ### Read shapes
332
+
333
+ ```
334
+ .list(tenantSlug, datalakeSlug) Paged: { data, meta }
335
+ .get(tenantSlug, datalakeSlug, id) One row, BY ID (UUID — not slug)
336
+ .metadata(tenantSlug, datalakeSlug) Markdown catalog
337
+ .metadataDetails(tenantSlug, datalakeSlug, Markdown for one agent;
338
+ id) section headings: Model,
339
+ Bound tool, Prompt config
340
+ ```
341
+
342
+ `.get` and `.metadataDetails` accept the agent's UUID `id` as
343
+ the path key — NOT the slug. The slug is only used as a
344
+ runtime reference key (`additional_context.<slug>` in workflow
345
+ templates).
346
+
347
+ ### Update
348
+
349
+ `update()` replaces the whole resource — resupply the full
350
+ body; there's no partial update. That means all required
351
+ fields must be re-supplied verbatim, including
352
+ `input_schema`, `llm_response_schema`, and `prompt_config`.
353
+ Omitting any returns a 422.
354
+
355
+ ### Delete
356
+
357
+ `delete()` removes the row. Workflows that still reference the
358
+ agent in their `ai_agents` array fail at run time with
359
+ `error_code: 'ai_agent_not_found'`; clean up workflow
360
+ references first.
361
+
362
+ ## 7. Run-time failure modes
363
+
364
+ When a workflow run's enrichment stage fails, the per-execution
365
+ `error.json` artifact carries a structured failure record (see
366
+ `workflows.md` §6 for the artifact convention). The
367
+ agent-specific codes:
368
+
369
+ ```
370
+ tool_execution_failed — the bound chat-completion tool's
371
+ HTTP call failed (404, refused,
372
+ timeout). error.json carries the
373
+ rich detail (URL, status); the
374
+ workflow execution log carries
375
+ a coarse error_message of the
376
+ form "AI enrichment failed: <agent_name>"
377
+ json_decode_failed — provider returned a response that
378
+ didn't parse as JSON (typically
379
+ when llm_response_schema wasn't
380
+ wired through to the provider's
381
+ structured-output mode)
382
+ context_mapping_failed — context_mapping_config.body
383
+ rendered output that didn't
384
+ validate against the agent's
385
+ input_schema
386
+ ai_agent_disabled — agent's enabled flag is false
387
+ ai_agent_not_found — agent was deleted but workflow
388
+ still references it
389
+ ```
390
+
391
+ The `error.json` shape:
392
+
393
+ ```
394
+ {
395
+ error_code: string — one of the codes above
396
+ stage: string — 'enrichment' for agent-related failures
397
+ ai_agent_slug: string — slug of the failing agent
398
+ error_message: string — coarse copy of the workflow execution log's message
399
+ detail: string — rich provider context (URL, HTTP status, etc.);
400
+ ONLY present in error.json, NOT mirrored to the
401
+ workflow execution log row
402
+ }
403
+ ```
404
+
405
+ The `enrichment.json` artifact (success branch) carries the
406
+ parsed agent outputs:
407
+
408
+ ```
409
+ {
410
+ status: 'completed' | 'failed' | 'skipped',
411
+ <agent_slug_1>: {
412
+ status: 'completed',
413
+ output: { /* matches llm_response_schema */ },
414
+ },
415
+ <agent_slug_2>: { /* ... */ },
416
+ }
417
+ ```
418
+
419
+ For workflows without any `ai_agents`, `enrichment.json` lands
420
+ with `{ status: 'skipped' }` and no per-agent entries.
421
+
422
+ ## 8. Gotchas
423
+
424
+ 1. **`llm_response_schema` is REQUIRED**, not optional. Omitting
425
+ it returns 422 on `/llm_response_schema`. The platform uses
426
+ it both as a provider-side decoding constraint and as the
427
+ output-binding shape for `additional_context.<slug>`. Missing
428
+ the schema means no structured output and downstream decision
429
+ templates can't reference the agent's fields.
430
+
431
+ 2. **`tool_id` must reference an `intent: 'llm_enrichment'`
432
+ tool.** Other intents are rejected at create. The chat
433
+ completion tool is typically `tool_body_type: 'rest_api'`
434
+ against an OpenAI-compatible endpoint; the platform appends
435
+ `/chat/completions` to its `base_url`.
436
+
437
+ 3. **`additional_context.<slug>` is the workflow accessor.**
438
+ The agent's `slug` (server-derived from `name`) is what
439
+ workflow decision and action templates reference. Capture it
440
+ from the create response — don't pre-compute.
441
+
442
+ 4. **`.get` takes UUID `id`, not slug.** The single-row read
443
+ route is `/ai-agents/:id`. The slug is only a runtime template key.
444
+
445
+ 5. **`update()` replaces the whole resource.** Update bodies
446
+ must re-supply `input_schema`, `llm_response_schema`,
447
+ `prompt_config` verbatim — there's no partial update. A
448
+ partial body silently drops fields and returns 422 on the
449
+ missing required field.
450
+
451
+ 6. **`data_access` is immutable post-create.** Flipping the
452
+ compliance tier requires delete + recreate.
453
+
454
+ 7. **`prompt_config.body` field references must resolve in
455
+ `input_schema`.** A `{{ field }}` that isn't declared in
456
+ `input_schema` returns 422 on `/prompt_config/body` at
457
+ create time.
458
+
459
+ 8. **The chat-completion tool's `base_url` should NOT include
460
+ `/chat/completions`.** The platform appends the path; a
461
+ doubled path 404s. Use the API root (e.g. `/v1` for OpenAI
462
+ or Ollama).