@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
package/.agent/mdm.md ADDED
@@ -0,0 +1,293 @@
1
+ # MDM — entity resolution + identity verification
2
+
3
+ Master Data Management is the platform's entity-resolution layer.
4
+ It binds every inbound row to a canonical **subject** record (the
5
+ domain's primary entity — e.g. `patient` for healthcare-domain
6
+ datalakes, `legal_entity` for foundation-domain datalakes) so
7
+ that downstream datasets, workflows, and agent prompts reference
8
+ a single, deduplicated identity rather than the raw inbound
9
+ identifiers each upstream system carries.
10
+
11
+ SDK namespace: `api.mdm`. Today the wire exposes a single verb:
12
+
13
+ ```
14
+ api.mdm.verify(tenantSlug, datalakeSlug, body)
15
+ ```
16
+
17
+ Other MDM operations (subject resolution during ingestion,
18
+ record merging, conflict reconciliation) run inside the platform
19
+ on consumer-supplied inputs but are not directly SDK-callable —
20
+ see §5 Lifecycle.
21
+
22
+ MDM is **Datalake-DB-resident** — the parent datalake must be
23
+ `status: 'ready'` before any MDM verb is called, since
24
+ resolution / verification both look up against the datalake's
25
+ regulated master records.
26
+
27
+ ## 1. Wire shape — `.verify`
28
+
29
+ Verify that a person on the other end of a workflow action or a
30
+ connected-app form submission matches an existing subject in the
31
+ datalake. Used at action time (workflows confirming an SMS
32
+ recipient) and at runtime (connected apps confirming the form
33
+ submitter before posting tracking updates).
34
+
35
+ ```typescript
36
+ import type {
37
+ MDMVerifyRequest,
38
+ MDMVerifyResponse,
39
+ } from '@alvera-ai/platform-sdk'
40
+
41
+ const { data: result } = await api.mdm.verify(
42
+ tenantSlug,
43
+ datalakeSlug,
44
+ {
45
+ subject_id: subjectUuid, // required
46
+ family_name: 'Garcia', // optional
47
+ given_name: 'Maria', // optional
48
+ birth_date: '1978-11-03', // optional; ISO 8601 date
49
+ identifiers: [ // optional
50
+ { system: 'http://hospital.org/mrn', value: 'MRN12345' },
51
+ ],
52
+ },
53
+ )
54
+ // result.status === 'verified' | 'not_verified'
55
+ // result.subject_id === body.subject_id
56
+ // result.verified_at — ISO 8601 timestamp
57
+ // when status === 'not_verified':
58
+ // result.errors — { <field_name>: [reason, ...] } per-field failure detail
59
+ ```
60
+
61
+ The response is **polymorphic on `status`**:
62
+
63
+ ```
64
+ status === 'verified' → { subject_id, verified_at }
65
+ status === 'not_verified' → { subject_id, verified_at, errors }
66
+ ```
67
+
68
+ A `not_verified` response is NOT an error — it's a successful
69
+ identity check that returned a negative result. Distinguish from
70
+ 402-level rejections (404 for missing subject, 401 for missing
71
+ auth, 422 for malformed body).
72
+
73
+ ### Subject per data domain
74
+
75
+ Every datalake has a single canonical **subject entity** — the
76
+ domain's primary identity that all other rows attribute to. The
77
+ verify call resolves against that subject. The subject's wire
78
+ name follows the dataset's `resource_type` (see
79
+ `interoperability_contracts.md` §2 `resource_type`):
80
+
81
+ ```
82
+ data_domain subject resource_type
83
+ ─────────── ─────────────────────
84
+ healthcare patient
85
+ core_banking party
86
+ payment_risk legal_entity
87
+ accounts_receivable customer
88
+ service_commerce consumer
89
+ trading trading_account
90
+ foundation legal_entity
91
+ ```
92
+
93
+ (`legal_entity` is the subject for both `payment_risk` and
94
+ `foundation` — different domain context, same canonical entity
95
+ shape.)
96
+
97
+ Generic tables in a datalake automatically carry a foreign-key
98
+ column to their subject (e.g. `patient_id` in a healthcare-
99
+ domain generic table). Querying that column scopes any custom
100
+ dataset to subjects the verify call has confirmed.
101
+
102
+ ## 2. Rules the type cannot encode
103
+
104
+ ### `subject_id` is required; the identity fields are not
105
+
106
+ `subject_id` (the master record to verify against) is the only
107
+ required field. The identity fields (`family_name`, `given_name`,
108
+ `birth_date`, `identifiers`) are individually optional, but the
109
+ platform requires **at least one** identity field to be supplied
110
+ at runtime — a body carrying only `subject_id` returns a 422.
111
+
112
+ The runtime check is a "must have something to match against"
113
+ rule that the schema can't express in TypeScript / JSON Schema.
114
+
115
+ ### Verification is per-field, with field-specific match rules
116
+
117
+ Each supplied identity field is checked independently against
118
+ the subject record. The platform uses fuzzy matching for the
119
+ string fields and exact matching for the structured ones:
120
+
121
+ ```
122
+ family_name Jaro distance ≥ 0.85
123
+ given_name Jaro distance ≥ 0.80
124
+ birth_date component-wise fuzzy match ≥ 0.80
125
+ identifiers exact (system, value) match
126
+ ```
127
+
128
+ All supplied fields must pass for the overall result to be
129
+ `'verified'`. A single failing field flips the result to
130
+ `'not_verified'` and surfaces the field name in `errors`.
131
+
132
+ The exact thresholds and field set are **domain-scoped** —
133
+ healthcare-domain datalakes use the FHIR-shaped demographics
134
+ listed above; future domains may extend the field set with
135
+ additional verification predicates. The verify endpoint accepts
136
+ the union of fields the parent datalake's domain knows how to
137
+ match against; unknown fields are rejected as a 422.
138
+
139
+ ### `subject_id` must exist in the datalake's regulated schema
140
+
141
+ If the supplied `subject_id` doesn't resolve to a master record
142
+ in the datalake's regulated schema, the response is a 404, not
143
+ a `'not_verified'`. The distinction matters:
144
+
145
+ - `'not_verified'` → "subject exists, identity fields didn't match"
146
+ - 404 → "subject doesn't exist at all"
147
+
148
+ A consumer that conflates the two will mis-route an identity
149
+ challenge as a missing-record error.
150
+
151
+ ## 3. Field ownership
152
+
153
+ **Server-derived (Response-only).**
154
+
155
+ ```
156
+ status enum — 'verified' | 'not_verified'
157
+ verified_at string — ISO 8601 timestamp of the verification attempt
158
+ errors object — present only when status === 'not_verified';
159
+ maps field name to an array of failure reasons
160
+ ```
161
+
162
+ **Caller-supplied (round-trip on the verified branch).**
163
+
164
+ ```
165
+ subject_id required UUID — the master record to verify against
166
+ family_name optional string — fuzzy-matched (string distance)
167
+ given_name optional string — fuzzy-matched (string distance)
168
+ birth_date optional date — fuzzy-matched component-wise
169
+ identifiers optional array — [{ system, value }] exact-matched
170
+ ```
171
+
172
+ **Write-only (Request-only).** None.
173
+
174
+ ## 4. Error envelopes
175
+
176
+ Standard JSON:API envelopes per `errors.md`. Common rejections:
177
+
178
+ | `source.pointer` | Cause |
179
+ |-------------------------------|--------------------------------------------------------|
180
+ | `/subject_id` | missing, or the subject doesn't exist in the datalake |
181
+ | `errors.base` | no identity fields supplied (subject_id alone) — 422 response with `status: "not_verified"` in the body |
182
+ | `/family_name` etc. | field structurally invalid (wrong type, malformed) |
183
+ | `/identifiers/0/system` | missing system on an identifier entry |
184
+ | `/identifiers/0/value` | missing value on an identifier entry |
185
+
186
+ The `not_verified` outcome surfaces in two response shapes:
187
+
188
+ - **Identity mismatch (most common)** — 200 response with
189
+ `status: 'not_verified'` and a field-keyed `errors` map naming
190
+ the demographics that failed (e.g. `errors.family_name`). The
191
+ subject exists; the supplied identity didn't match.
192
+ - **No identity fields supplied** — 422 response with
193
+ `status: 'not_verified'` in the body and `errors.base` set to
194
+ `["at least one verification field is required"]`. Verification
195
+ was structurally impossible.
196
+
197
+ Pattern-match on `status` first, then on the HTTP status code to
198
+ distinguish the two not_verified shapes. The 404 case (subject
199
+ doesn't exist) is a separate envelope — see §6 gotcha 2.
200
+
201
+ ## 5. Lifecycle
202
+
203
+ ### `.verify` is synchronous
204
+
205
+ The verify call returns the resolution outcome in the response —
206
+ no async polling, no job id. The platform performs the fuzzy
207
+ match against the regulated master record inline.
208
+
209
+ ### Other MDM operations are platform-internal
210
+
211
+ Beyond `.verify`, MDM also runs at two points without a direct
212
+ SDK surface:
213
+
214
+ - **During data activation ingestion.** Each inbound row that
215
+ carries an `mdm_input_config` on its bound interoperability
216
+ contract gets routed through the platform's resolution
217
+ pipeline before the dataset upsert. The pipeline matches the
218
+ rendered MDM input against existing subjects (or creates one
219
+ if no match) and produces an `mdm_output` carried forward to
220
+ the regulated upsert. Consumers configure this implicitly via
221
+ the contract's `mdm_input_config` — see
222
+ `interoperability_contracts.md` §2 and `data_activation_clients.md`
223
+ §6.
224
+
225
+ - **Conflict reconciliation.** When two master records turn out
226
+ to represent the same subject (e.g. an MRN-only record and a
227
+ demographics-only record that operators later confirm are the
228
+ same person), the platform supports merge / unmerge operations.
229
+ These are administrative actions surfaced in the admin console,
230
+ not SDK-exposed verbs.
231
+
232
+ ### Read shapes
233
+
234
+ ```
235
+ .verify(tenantSlug, datalakeSlug, body) Single round-trip; see §1
236
+ ```
237
+
238
+ Today there is no `.list`, `.get`, or `.metadata` on the MDM
239
+ namespace — subjects themselves are queried through the dataset
240
+ search surface (see `data_activation_clients.md` §6.5), not
241
+ through `api.mdm`.
242
+
243
+ ## 6. Gotchas
244
+
245
+ 1. **`'not_verified'` is usually a successful 200 response, not
246
+ an error — but the "no fields supplied" case is a 422 with a
247
+ `not_verified` body.** Pattern-match on `result.status === 'verified'`
248
+ to gate the downstream "act on this person" path. Throwing on
249
+ `'not_verified'` collapses two distinct outcomes (subject
250
+ verified vs identity mismatch) into one branch and loses the
251
+ `errors` payload that explains which fields failed. The 422
252
+ sub-case (no identity fields, just `subject_id`) needs HTTP-status
253
+ handling on top of body-status handling — see §4 above.
254
+
255
+ 2. **`subject_id` missing → 404, identity mismatch → 200.** A
256
+ verify call against a deleted or never-existed subject id
257
+ returns a 404 envelope, NOT a `'not_verified'` response.
258
+ Consumers that handle only the polymorphic 200 response will
259
+ surface the 404 as an unexpected exception. Wrap the verify
260
+ call in standard 4xx handling per `errors.md`.
261
+
262
+ 3. **At least one identity field is required.** A body with
263
+ only `subject_id` and no identity fields returns a 422 with
264
+ `errors.base` set to `["at least one verification field is
265
+ required"]` and `status: "not_verified"` in the response
266
+ body. The platform cannot verify identity against zero
267
+ attributes; this is enforced at runtime rather than in the
268
+ request schema, so the TypeScript type permits the
269
+ no-identity-field body but the wire rejects it.
270
+
271
+ 4. **The verification field set is domain-scoped.** Today the
272
+ healthcare-domain verifier accepts FHIR-shaped demographics
273
+ (family_name, given_name, birth_date, identifiers). Other
274
+ domains will expose verifier-appropriate field sets as they
275
+ land. Querying `api.mdm.verify` against a datalake whose
276
+ domain doesn't support a supplied field returns a 422 on
277
+ that field's pointer — don't assume the full healthcare
278
+ field set works on every domain.
279
+
280
+ 5. **MDM also runs at ingestion — and you don't call it
281
+ directly.** The `mdm_input_config` on each interoperability
282
+ contract feeds the platform's resolution pipeline at
283
+ ingestion time, producing the `mdm_output` carried into the
284
+ dataset upsert. There is no `api.mdm.resolve` SDK verb; you
285
+ configure resolution by shaping the contract's
286
+ `mdm_input_config`. See `interoperability_contracts.md` §2.
287
+
288
+ 6. **`identifiers` matches are exact, not fuzzy.** Whitespace,
289
+ case, and trailing slashes in `system` URIs all matter.
290
+ Compare with the master record's identifier system strings
291
+ character-for-character; a `'http://hospital.org/mrn'` vs
292
+ `'http://hospital.org/mrn/'` mismatch will flip the verifier
293
+ to `'not_verified'` even when the value is correct.
@@ -0,0 +1,126 @@
1
+ # Mutations
2
+
3
+ Every resource exposes the same three mutation methods on the typed client:
4
+ `create(body)`, `update(id, body)`, and `delete(id)`. Two rules cover almost
5
+ everything:
6
+
7
+ 1. **`update()` replaces the whole resource.** There is no partial update —
8
+ resupply the full body with your change applied. A tiny, explicitly-listed
9
+ set of methods are the exception (below).
10
+ 2. **`create()` returns the full record**, including server-derived fields
11
+ (`id`, `slug`, `status`, timestamps). Use that returned record for
12
+ downstream references — never pre-compute a server-derived field yourself.
13
+
14
+ Non-CRUD methods are out of scope for this page — RESTful sub-actions
15
+ (`.syncRoutes`, `.resolvePage`, `.testInvocation`), artifact issuers
16
+ (`.createUploadLink`, `.createDownloadLink`), and async triggers (`.run`,
17
+ `.execute`, `.ingest`) each document their own semantics in their resource's MD.
18
+
19
+ ## `create()` — make a new record
20
+
21
+ `create(body)` returns the full `<Resource>Response`, including every
22
+ server-derived field (see `type_naming.md` "Server-derived fields"). Read the
23
+ ids and slugs you need off that response.
24
+
25
+ ## `update()` — replace the whole record
26
+
27
+ `update(id, body)` replaces the resource wholesale — it is **not** a partial
28
+ update. To change one field, read the current record, change the field in
29
+ memory, and send the entire body back:
30
+
31
+ ```typescript
32
+ // 1. read current
33
+ const { data: current } = await api.tools.get(
34
+ tenantSlug, datalakeSlug, toolId,
35
+ )
36
+
37
+ // 2. change in memory
38
+ const next = { ...current, status: 'inactive' }
39
+
40
+ // 3. send the whole body back
41
+ const { data: updated } = await api.tools.update(
42
+ tenantSlug, datalakeSlug, toolId, next,
43
+ )
44
+ ```
45
+
46
+ Omitting a required field on `update()` is rejected with a `422 AlveraApiError`
47
+ on that field — even when its value is unchanged from the stored row — because
48
+ the call replaces the whole resource (see `errors.md`).
49
+
50
+ ## Partial-update exceptions
51
+
52
+ A small set of methods accept a narrow partial body instead of replacing the
53
+ whole resource. Each is named here and documents its partial-body contract in
54
+ its TypeScript method's JSDoc and its per-resource MD §5 (Lifecycle):
55
+
56
+ | SDK method | Resource MD |
57
+ |---------------------------------------------|----------------------|
58
+ | `api.connectedApps.updateMessageTracking` | `connected_apps.md` |
59
+
60
+ For every other method, the default holds: `update()` replaces the whole
61
+ resource.
62
+
63
+ > This is the canonical index of partial-update methods. If a future method
64
+ > joins, it lands here. If you find a method whose JSDoc claims partial-body
65
+ > behavior but it isn't listed here, this index is stale and needs a refresh.
66
+
67
+ ## The discriminator can't change on update
68
+
69
+ For polymorphic resources (tools, a datalake's cloud storage, …), the body's
70
+ discriminator value must match the stored record's on `update()`. The platform
71
+ rejects a discriminator change with a `422` on the discriminator field. To
72
+ change body type, `delete()` and `create()` fresh — you cannot morph it in
73
+ place.
74
+
75
+ ## Polymorphic discriminator naming
76
+
77
+ Resources with polymorphic bodies carry an explicit discriminator field. Its
78
+ **wire name** is what the SDK type expects:
79
+
80
+ | Resource | Discriminator (wire) |
81
+ |--------------------------------|--------------------------|
82
+ | Tool body | `tool_body_type` |
83
+ | Datalake cloud-storage embed | `cloud_storage_type` |
84
+
85
+ The wire name is what appears in your request body's JSON and in the
86
+ `<Resource>RequestWritable` TypeScript types. Each resource's MD §1 (Wire
87
+ shape) names its discriminator and lists every branch's TypeScript type.
88
+
89
+ ## `delete()` — usually synchronous
90
+
91
+ `delete(id)` removes the record. A few resources have semantic guards (e.g. you
92
+ cannot delete a default-flagged data activation client, or a datalake that
93
+ still has dependents) that surface as `422`s with `source.pointer` naming the
94
+ field that's blocking the delete.
95
+
96
+ For asynchronous deletes (e.g. AWS Lambda tools' out-of-band cleanup), poll the
97
+ resource's status until it's gone — see `async.md`.
98
+
99
+ ## The parent scope comes from the method arguments, not the body
100
+
101
+ Every resource method takes its parent scope as leading arguments —
102
+ `tenantSlug` and `datalakeSlug` — which become the URL path:
103
+
104
+ ```
105
+ /api/v1/tenants/{tenant_slug}/datalakes/{datalake_slug}/<resource>[/{id}]
106
+ ```
107
+
108
+ A body often also carries a `datalake_id` (and sometimes `tenant_id`) naming
109
+ the same parent. **The method arguments win.** If the body names a different
110
+ parent than the arguments, the body field is silently ignored and the record
111
+ lands under the argument-named parent. The practical consequences:
112
+
113
+ - **You can't "redirect" a write with a body field.** To target a different
114
+ datalake, change the `datalakeSlug` argument.
115
+ - **Reusing a body across datalakes is safe.** A `datalake_id` you captured
116
+ from an earlier call can ride along on a write under any scope — the
117
+ arguments govern where it lands.
118
+ - **A `datalake_id` mismatch never 422s** — the platform just ignores the body
119
+ value.
120
+
121
+ ## No bulk mutations on standard CRUD
122
+
123
+ Each `create()` / `update()` / `delete()` touches exactly one resource — there
124
+ are no batch creates or updates on the standard methods. Some ingestion paths
125
+ (data-activation-client bulk runs and file uploads) ARE batch by design; those
126
+ are documented in `data_activation_clients.md`.
@@ -0,0 +1,98 @@
1
+ # Templates
2
+
3
+ Templates are an **INFRASTRUCTURE** building block: the platform
4
+ ships a library of Liquid templates that other infrastructure
5
+ resources consume — interoperability contracts, AI agent prompts,
6
+ workflow definitions, status poller bodies. Templates are
7
+ **read-only** from the SDK; the platform composes them
8
+ per-industry, and each datalake's `data_domain` selects which
9
+ surface in its catalog.
10
+
11
+ SDK namespace: `api.templates`.
12
+
13
+ For the safety contract that bounds every template body the
14
+ platform accepts — the consumer-author trust boundary, the 11
15
+ custom Liquid filters, the SQL-fragment boundary, and the
16
+ compliance gates that compose with them — see `ai_sandbox.md`.
17
+
18
+ ## 1. Wire shape
19
+
20
+ Three discovery methods, two complementary response shapes —
21
+ structured (for code) and markdown (for agents):
22
+
23
+ ```typescript
24
+ import type { SystemTemplate } from '@alvera-ai/platform-sdk'
25
+
26
+ // Structured catalog
27
+ const { data: catalog } = await api.templates.systemTemplates(
28
+ tenantSlug,
29
+ datalakeSlug,
30
+ )
31
+ // catalog.data: SystemTemplate[]
32
+ // { path, content, output_schema }
33
+ // path category/sub-category/name segment string
34
+ // content Liquid template body
35
+ // output_schema null | object — rendered output's expected shape
36
+
37
+ // Markdown catalog
38
+ const { data: catalogMd } = await api.templates.metadata(
39
+ tenantSlug,
40
+ datalakeSlug,
41
+ )
42
+ // catalogMd: string — agent-facing markdown listing in-scope templates
43
+
44
+ // Markdown body for one template
45
+ const { data: templateMd } = await api.templates.metadataDetails(
46
+ tenantSlug,
47
+ datalakeSlug,
48
+ basename, // e.g. 'delivery_status' or 'contact_message_categorizer'
49
+ intent, // e.g. 'status_poller' or 'ai_agent' — note: intent
50
+ // != path segment;
51
+ // see §4 Gotcha 1
52
+ )
53
+ // templateMd: string — agent-facing markdown describing the template
54
+ ```
55
+
56
+ ## 2. Path structure
57
+
58
+ Template paths follow `<category>/<sub-category>/<name>`.
59
+ Categories the SDK exposes include
60
+ `data_activation/interoperability/`, `ai_agents/`, `workflows/`,
61
+ `status_poller/`. Categories with an industry segment (e.g.
62
+ `ai_agents/<industry>/*`) filter to the datalake's `data_domain`;
63
+ categories without (e.g. `status_poller/*/*`) are globals
64
+ present in every catalog.
65
+
66
+ ## 3. Lifecycle
67
+
68
+ Templates are static — they ship with the platform, not created
69
+ via SDK. New templates arrive via platform releases. If you need
70
+ a custom template, supply it inline (e.g. an interop contract's
71
+ `template_config: { type: 'custom', body: '...' }`) rather than
72
+ trying to add to the catalog.
73
+
74
+ ## 4. Gotchas
75
+
76
+ 1. **`basename` + `intent` is the composite key.** The `intent`
77
+ value is a fixed set of category identifiers — it does NOT
78
+ map cleanly to path segments. Some intents match (e.g.
79
+ `status_poller/...` → `'status_poller'`); some are
80
+ singularizations (e.g. `ai_agents/<industry>/<name>` →
81
+ `'ai_agent'`); some collapse multiple path segments (e.g.
82
+ `data_activation/interoperability/<industry>/...` →
83
+ `'data_activation_interoperability'`). Check the typed
84
+ parameter for the valid set; multiple templates can share a
85
+ basename across intents.
86
+
87
+ 2. **`output_schema` may be `null`.** Some templates render plain
88
+ strings without structured output. Test for null before
89
+ treating it as an object.
90
+
91
+ 3. **Templates from other industries never appear.** The
92
+ platform filters per-datalake. Walking the catalog gives only
93
+ in-scope entries; no need to filter by industry in your code.
94
+
95
+ 4. **Read-only from SDK.** For custom template content, use
96
+ inline `template_config` on the consuming resource (interop
97
+ contracts, AI agents, etc.) rather than seeking a catalog
98
+ addition.
@@ -0,0 +1,90 @@
1
+ <!-- alvera:doc kind="tool-call-configs" generated-by="mix alvera.dump.static_metadata" -->
2
+
3
+ # Tool Call Configurations
4
+
5
+ Per-invocation invocation-side schemas for Alvera tools. Each section
6
+ documents one variant of `Platform.Tools.ToolCallConfig`, identified
7
+ by its atom and rendered by `ToolCallConfig.metadata_details/2`.
8
+
9
+ <!-- alvera:section kind="tool-call-config" atom="restapi_request" module="Platform.Tools.ToolCallConfig.RESTAPIRequest" -->
10
+
11
+ ## Tool Call Configuration (restapi_request)
12
+
13
+ Fetches data via REST API with pagination support.
14
+
15
+ - **method** (enum: head, get, put, post, delete, patch) — HTTP method
16
+ - **path** (TemplateConfig) — API endpoint path, rendered as Liquid template
17
+ - **body** (TemplateConfig, nullable) — Request body, rendered as Liquid template
18
+ - **params** (TemplateConfig, nullable) — Query parameters, rendered as Liquid template
19
+ - **pagination_context_template** (TemplateConfig) — Pagination control template, must render to JSON with `has_next` boolean field
20
+
21
+ <!-- alvera:section kind="tool-call-config" atom="sql_query" module="Platform.Tools.ToolCallConfig.SQLQuery" -->
22
+
23
+ ## Tool Call Configuration (sql_query)
24
+
25
+ Fetches data via SQL query with Liquid template variables for pagination.
26
+
27
+ - **query** (TemplateConfig) — SQL query template with pagination variables
28
+
29
+ <!-- alvera:section kind="tool-call-config" atom="sftp_request" module="Platform.Tools.ToolCallConfig.SFTPRequest" -->
30
+
31
+ ## Tool Call Configuration (sftp_request)
32
+
33
+ Fetches data from a remote SFTP server.
34
+
35
+ - **path** (string) — Remote file path on SFTP server
36
+ - **content_type** (string) — MIME type of the file
37
+
38
+ <!-- alvera:section kind="tool-call-config" atom="microsoft_share_point_excel_request" module="Platform.Tools.ToolCallConfig.MicrosoftSharePointExcelRequest" -->
39
+
40
+ ## Tool Call Configuration (microsoft_share_point_excel_request)
41
+
42
+ Fetches data from a Microsoft SharePoint drive (Excel files).
43
+
44
+ - **drive_url** (string) — SharePoint drive URL
45
+ - **azure_tenant_id** (string) — Microsoft Azure tenant identifier
46
+ - **sheet_number** (integer) — 0-indexed Excel sheet number
47
+ - **search_params** (string) — Search parameters for locating files
48
+
49
+ <!-- alvera:section kind="tool-call-config" atom="aws_lambda_request" module="Platform.Tools.ToolCallConfig.AWSLambdaRequest" -->
50
+
51
+ ## Tool Call Configuration (aws_lambda_request)
52
+
53
+ Invokes an AWS Lambda function to fetch data.
54
+
55
+ - **payload** (TemplateConfig) — Lambda JSON payload, rendered as Liquid template
56
+ - **timeout_ms** (integer, default: 600000, max: 900000) — Invocation timeout in milliseconds
57
+
58
+ <!-- alvera:section kind="tool-call-config" atom="s3_request" module="Platform.Tools.ToolCallConfig.S3Request" -->
59
+
60
+ ## Tool Call Configuration (s3_request)
61
+
62
+ Fetches data from an S3 bucket.
63
+
64
+ - **file_path** (string) — S3 object key (no `s3://` prefix)
65
+
66
+ <!-- alvera:section kind="tool-call-config" atom="manual_upload" module="Platform.Tools.ToolCallConfig.ManualUpload" -->
67
+
68
+ ## Tool Call Configuration (manual_upload)
69
+
70
+ Manual file upload — data is uploaded directly by the user. No additional configuration fields.
71
+
72
+ <!-- alvera:section kind="tool-call-config" atom="sms_request" module="Platform.Tools.ToolCallConfig.SMSRequest" -->
73
+
74
+ ## Tool Call Configuration (sms_request)
75
+
76
+ Sends an SMS message via the configured SMS provider.
77
+
78
+ - **to** (TemplateConfig) — Recipient phone number in E.164 format, rendered as Liquid template
79
+ - **body** (TemplateConfig) — Message body, rendered as Liquid template
80
+ - **sms_type** (enum: transactional, promotional) — Message classification; defaults to `transactional`
81
+
82
+ <!-- alvera:section kind="tool-call-config" atom="email_request" module="Platform.Tools.ToolCallConfig.EmailRequest" -->
83
+
84
+ ## Tool Call Configuration (email_request)
85
+
86
+ Sends an email message via the configured email provider.
87
+
88
+ - **to** (TemplateConfig) — Recipient email address (RFC 5322), rendered as Liquid template
89
+ - **subject** (TemplateConfig) — Email subject line, rendered as Liquid template
90
+ - **body** (TemplateConfig) — Email body, rendered as Liquid template