@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.
- package/.agent/AGENTS.md +499 -0
- package/.agent/account_management.md +456 -0
- package/.agent/action_status_updaters.md +264 -0
- package/.agent/ai_agents.md +462 -0
- package/.agent/ai_sandbox.md +265 -0
- package/.agent/async.md +112 -0
- package/.agent/connected_apps.md +408 -0
- package/.agent/cookbook/_fixtures/README.md +106 -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/accounts_receivable/stripe_customers_batch1.csv +5 -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/healthcare/memorandum-of-association-01.png +0 -0
- package/.agent/cookbook/_fixtures/healthcare/sample_two_page.pdf +43 -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/action-status-updaters.md +212 -0
- package/.agent/cookbook/ai-agent-invoke.md +243 -0
- package/.agent/cookbook/appointment-review-sms-workflow.md +761 -0
- package/.agent/cookbook/birthday-greeting-sms-trigger.md +656 -0
- package/.agent/cookbook/bulk-ingest.md +254 -0
- package/.agent/cookbook/contact-us-triage-with-llm.md +622 -0
- package/.agent/cookbook/custom-tables.md +201 -0
- package/.agent/cookbook/dunning-sms-for-delinquent.md +619 -0
- package/.agent/cookbook/invite-team.md +194 -0
- package/.agent/cookbook/kyc-notification-on-account-activation.md +619 -0
- package/.agent/cookbook/rest-fetch.md +246 -0
- package/.agent/cookbook/sanctions-screening-with-agent-review.md +733 -0
- package/.agent/cookbook/score-leads-with-llm-categorization.md +624 -0
- package/.agent/cookbook/system-templates.md +129 -0
- package/.agent/cookbook/triage-prospects-by-priority.md +533 -0
- package/.agent/cookbook/welcome-sms-for-customers.md +607 -0
- package/.agent/data_activation_clients.md +559 -0
- package/.agent/data_sources.md +235 -0
- package/.agent/datalakes.md +714 -0
- package/.agent/debugging.md +137 -0
- package/.agent/errors.md +190 -0
- package/.agent/generic_tables.md +351 -0
- package/.agent/interoperability_contracts.md +417 -0
- package/.agent/mdm.md +293 -0
- package/.agent/mutations.md +126 -0
- package/.agent/templates.md +98 -0
- package/.agent/tool-call-configs.md +90 -0
- package/.agent/tools.md +547 -0
- package/.agent/type_naming.md +129 -0
- package/.agent/workflows.md +617 -0
- package/README.md +178 -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 +1310 -44116
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1194 -7344
- package/dist/index.mjs.map +1 -1
- 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
|