@alvera-ai/platform-sdk 0.17.0 → 0.18.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 +82 -144
- package/.agent/account_management.md +2 -2
- package/.agent/action_logs.md +4 -4
- package/.agent/ai_agents.md +28 -21
- package/.agent/ai_sandbox.md +49 -39
- package/.agent/connected_apps.md +3 -3
- package/.agent/cookbook/_fixtures/README.md +1 -1
- package/.agent/cookbook/_fixtures/{foundation → organic-marketing}/_lead_submissions_foundation_generic_table.liquid +1 -1
- package/.agent/cookbook/_fixtures/organic-marketing/_lead_submissions_foundation_legal_entity.liquid +80 -0
- package/.agent/cookbook/_fixtures/{foundation → organic-marketing}/_lead_submissions_foundation_mdm.liquid +2 -1
- package/.agent/cookbook/_fixtures/payments-compliance/_compliance_screenings_generic_table.liquid +57 -0
- package/.agent/cookbook/_fixtures/payments-compliance/_compliance_screenings_legal_entity.liquid +30 -0
- package/.agent/cookbook/_fixtures/payments-compliance/_compliance_screenings_mdm.liquid +44 -0
- package/.agent/cookbook/_fixtures/payments-compliance/_payment_accounts_generic_table.liquid +57 -0
- package/.agent/cookbook/_fixtures/payments-compliance/_payment_accounts_legal_entity.liquid +36 -0
- package/.agent/cookbook/_fixtures/payments-compliance/_payment_accounts_mdm.liquid +41 -0
- package/.agent/cookbook/_fixtures/primary-care-feedback/_cahps_appointments_generic_table.liquid +70 -0
- package/.agent/cookbook/_fixtures/primary-care-feedback/_cahps_appointments_legal_entity.liquid +52 -0
- package/.agent/cookbook/_fixtures/primary-care-feedback/_cahps_appointments_mdm.liquid +42 -0
- package/.agent/cookbook/_fixtures/subscription-saas/_customers_subscription_generic_table.liquid +38 -0
- package/.agent/cookbook/_fixtures/subscription-saas/_customers_subscription_legal_entity.liquid +48 -0
- package/.agent/cookbook/_fixtures/subscription-saas/_customers_subscription_mdm.liquid +49 -0
- package/.agent/cookbook/organic-marketing.md +2801 -0
- package/.agent/cookbook/payments-compliance.md +2180 -0
- package/.agent/cookbook/primary-care.md +2175 -0
- package/.agent/cookbook/subscription-saas.md +2403 -0
- package/.agent/data_activation_clients.md +65 -52
- package/.agent/datalakes.md +338 -171
- package/.agent/errors.md +3 -3
- package/.agent/generic_tables.md +151 -62
- package/.agent/interoperability_contracts.md +57 -22
- package/.agent/mdm.md +136 -153
- package/.agent/messages.md +36 -34
- package/.agent/mock-services.md +1 -1
- package/.agent/mutations.md +2 -2
- package/.agent/templates.md +14 -13
- package/.agent/tools.md +63 -21
- package/.agent/type_naming.md +13 -13
- package/.agent/workflows.md +99 -53
- package/README.md +2 -2
- package/dist/bin/platform-sdk.mjs +33 -47
- package/dist/bin/platform-sdk.mjs.map +1 -1
- package/dist/index.d.mts +565 -379
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +494 -59
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
- package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_legal_entity.liquid +0 -88
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_appointment.liquid +0 -47
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_mdm.liquid +0 -24
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_patient.liquid +0 -38
- package/.agent/cookbook/_fixtures/payments/_compliance_screenings_payments_compliance_screening.liquid +0 -59
- package/.agent/cookbook/_fixtures/payments/_compliance_screenings_payments_mdm.liquid +0 -36
- package/.agent/cookbook/_fixtures/payments/_payment_accounts_payments_mdm.liquid +0 -30
- package/.agent/cookbook/_fixtures/payments/_payment_accounts_payments_payment_account.liquid +0 -55
- package/.agent/cookbook/_fixtures/subscription/_customers_subscription_mdm.liquid +0 -20
- package/.agent/cookbook/_setup/foundation.md +0 -359
- package/.agent/cookbook/_setup/healthcare.md +0 -361
- package/.agent/cookbook/_setup/payments.md +0 -365
- package/.agent/cookbook/_setup/subscription.md +0 -364
- package/.agent/cookbook/action-status-updaters.md +0 -278
- package/.agent/cookbook/ai-agent-invoke.md +0 -279
- package/.agent/cookbook/appointment-review-sms-workflow.md +0 -801
- package/.agent/cookbook/birthday-greeting-sms-trigger.md +0 -696
- package/.agent/cookbook/bulk-ingest.md +0 -302
- package/.agent/cookbook/contact-us-triage-with-llm.md +0 -663
- package/.agent/cookbook/dunning-sms-for-delinquent.md +0 -659
- package/.agent/cookbook/generic-tables.md +0 -244
- package/.agent/cookbook/invite-team.md +0 -200
- package/.agent/cookbook/kyc-notification-on-account-activation.md +0 -661
- package/.agent/cookbook/marketing-campaign-send.md +0 -1044
- package/.agent/cookbook/paginated-restapi-poller.md +0 -383
- package/.agent/cookbook/rest-fetch.md +0 -273
- package/.agent/cookbook/sanctions-screening-with-agent-review.md +0 -773
- package/.agent/cookbook/score-leads-with-llm-categorization.md +0 -665
- package/.agent/cookbook/system-templates.md +0 -165
- package/.agent/cookbook/talk-to-data.md +0 -178
- package/.agent/cookbook/triage-prospects-by-priority.md +0 -571
- package/.agent/cookbook/welcome-sms-for-customers.md +0 -647
- /package/.agent/cookbook/_fixtures/{healthcare → primary-care-feedback}/memorandum-of-association-01.png +0 -0
- /package/.agent/cookbook/_fixtures/{healthcare → primary-care-feedback}/sample_two_page.pdf +0 -0
- /package/.agent/cookbook/_fixtures/{subscription → subscription-saas}/_customers_subscription_customer.liquid +0 -0
- /package/.agent/cookbook/_fixtures/{subscription → subscription-saas}/stripe_customers_batch1.csv +0 -0
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Capability: read an uploaded document and pull structured fields out of it"
|
|
3
|
-
summary: A capability walk for direct AI-agent invocation with file vision. Upload a PDF + image, register an LLM-enrichment tool (the provider adapter) and an AI agent constrained to an output schema, then invoke the agent with the files (`api.aiAgents.invoke`) to get structured JSON back. This is the correct path for reading an uploaded file — the file is uploaded to storage and the agent reads it; the agent does NOT ingest the file as a dataset row.
|
|
4
|
-
industry: healthcare
|
|
5
|
-
slug: ai-agent-invoke
|
|
6
|
-
vitest_source:
|
|
7
|
-
- integration-tests/tests/healthcare/ai-agent-invoke.test.ts
|
|
8
|
-
- integration-tests/tests/healthcare/bootstrap.test.ts
|
|
9
|
-
status: green
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
# Capability
|
|
13
|
-
|
|
14
|
-
**What you get:** structured JSON pulled out of an uploaded document or image —
|
|
15
|
-
a scanned form, a PDF, an ID — by an AI agent, in one call.
|
|
16
|
-
|
|
17
|
-
The shape:
|
|
18
|
-
|
|
19
|
-
1. **Upload** the file(s) to storage (`datalakes.createUploadLink` + a raw PUT)
|
|
20
|
-
and keep the returned `key`s.
|
|
21
|
-
2. Register an **LLM-enrichment tool** — the provider adapter. Its `base_body`
|
|
22
|
-
authors the provider's multimodal request and its `response_extractor` maps
|
|
23
|
-
the provider's envelope back to a canonical `{ output_json, … }`.
|
|
24
|
-
3. Register an **AI agent** that points at the tool, constrained by an
|
|
25
|
-
`llm_response_schema` (the JSON shape you want back) and an `input_schema`.
|
|
26
|
-
4. `aiAgents.invoke(..., { input, files: [{ key, content_type }] })` → the
|
|
27
|
-
parsed JSON, an explanation, and token usage.
|
|
28
|
-
|
|
29
|
-
> **File-ingestion note (read this).** This is how you make an agent *read* a
|
|
30
|
-
> file. It is **not** how you turn a file into dataset rows — that is bulk
|
|
31
|
-
> ingestion (`dataActivationClients.ingestFile`; see `bulk-ingest.md`). An AI
|
|
32
|
-
> agent does **enrichment / extraction** on content handed to it; it does not
|
|
33
|
-
> ingest files. When a contract needs per-row vision enrichment during
|
|
34
|
-
> ingestion, nest the agent on the contract (`interoperability_contracts.md`
|
|
35
|
-
> §6) — the row references the uploaded file's key and the agent reads it as
|
|
36
|
-
> enrichment. The file→row step is always the DAC, never the agent.
|
|
37
|
-
|
|
38
|
-
This is **global** to every datalake. See `ai_agents.md` for the agent
|
|
39
|
-
reference. The walk uses a WireMock-stubbed provider so it runs deterministically
|
|
40
|
-
on the mock stack; swap the tool's `base_url` + adapter for a real provider
|
|
41
|
-
unchanged.
|
|
42
|
-
|
|
43
|
-
# Walkthrough
|
|
44
|
-
|
|
45
|
-
The `_setup/healthcare.md` bootstrap left `api`, `tenantSlug`, `datalakeSlug`,
|
|
46
|
-
and `ctx.datalakeId` populated.
|
|
47
|
-
|
|
48
|
-
## 001 — upload the document and image
|
|
49
|
-
|
|
50
|
-
Mint a presigned URL per file and PUT the bytes with a **raw `fetch`** (the
|
|
51
|
-
upload goes to object storage, not through the SDK). Keep each returned `key` —
|
|
52
|
-
that is how you hand the file to the agent. The fixtures are a 2-page PDF and a
|
|
53
|
-
document image.
|
|
54
|
-
|
|
55
|
-
```typescript
|
|
56
|
-
const { readFileSync } = await import('node:fs')
|
|
57
|
-
const { join } = await import('node:path')
|
|
58
|
-
|
|
59
|
-
async function uploadFixture(filename: string, contentType: string): Promise<string> {
|
|
60
|
-
const bytes = readFileSync(join(process.env.COOKBOOK_FIXTURES_DIR!, 'healthcare', filename))
|
|
61
|
-
const { data: link } = await api.datalakes.createUploadLink(tenantSlug, datalakeSlug, {
|
|
62
|
-
filename,
|
|
63
|
-
content_type: contentType,
|
|
64
|
-
})
|
|
65
|
-
const put = await fetch(link.url!, { method: 'PUT', headers: { 'Content-Type': contentType }, body: bytes })
|
|
66
|
-
if (put.status !== 200) throw new Error(`upload of ${filename} failed: ${put.status}`)
|
|
67
|
-
return link.key!
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
ctx.pdfKey = await uploadFixture('sample_two_page.pdf', 'application/pdf')
|
|
71
|
-
ctx.imageKey = await uploadFixture('memorandum-of-association-01.png', 'image/png')
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## 002 — register the LLM-enrichment tool (the provider adapter)
|
|
75
|
-
|
|
76
|
-
The tool is the complete provider adapter. `base_body` authors the provider's
|
|
77
|
-
multimodal request (here the OpenAI chat-completions shape, with the agent's
|
|
78
|
-
`llm_response_schema` injected as `{{ schema }}` and uploaded images appended as
|
|
79
|
-
`image_url` parts). `response_extractor` reads the provider's envelope back into
|
|
80
|
-
the canonical `{ output_json, explanation, …_tokens }`; its `output_schema` is
|
|
81
|
-
required for an `llm_enrichment` tool.
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
const ENRICHMENT_OUTPUT_SCHEMA = {
|
|
85
|
-
type: 'object',
|
|
86
|
-
properties: {
|
|
87
|
-
output_json: {},
|
|
88
|
-
input_tokens: { type: ['integer', 'null'] },
|
|
89
|
-
output_tokens: { type: ['integer', 'null'] },
|
|
90
|
-
total_tokens: { type: ['integer', 'null'] },
|
|
91
|
-
explanation: { type: ['string', 'null'] },
|
|
92
|
-
},
|
|
93
|
-
required: ['output_json'],
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const OPENAI_BASE_BODY =
|
|
97
|
-
'{"model": "{{ model }}", "messages": [{"role": "user", "content": [{"type": "text", "text": "{{ rendered_prompt | json_escape }}"}{% for img in images %}, {"type": "image_url", "image_url": {"url": "data:{{ img.content_type }};base64,{{ img.data }}"}}{% endfor %}]}], "response_format": {"type": "json_schema", "json_schema": {"name": "output", "strict": true, "schema": {{ schema | to_json }}}}}'
|
|
98
|
-
|
|
99
|
-
const OPENAI_EXTRACTOR =
|
|
100
|
-
'{"output_json": "{{ msg.choices[0].message.content | json_escape }}", "explanation": "{{ msg.choices[0].message.reasoning_content | json_escape }}", "input_tokens": {{ msg.usage.prompt_tokens | default: 0 }}, "output_tokens": {{ msg.usage.completion_tokens | default: 0 }}, "total_tokens": {{ msg.usage.total_tokens | default: 0 }}}'
|
|
101
|
-
|
|
102
|
-
const { data: tool } = await api.tools.create(tenantSlug, datalakeSlug, {
|
|
103
|
-
name: `Legal-Entity Extraction Tool ${runSuffix}`,
|
|
104
|
-
description: 'Multimodal LLM-enrichment adapter for legal_entity extraction.',
|
|
105
|
-
intent: 'llm_enrichment',
|
|
106
|
-
status: 'active',
|
|
107
|
-
datalake_id: ctx.datalakeId,
|
|
108
|
-
response_extractor: { type: 'custom', body: OPENAI_EXTRACTOR, output_schema: ENRICHMENT_OUTPUT_SCHEMA },
|
|
109
|
-
body: {
|
|
110
|
-
tool_body_type: 'rest_api',
|
|
111
|
-
base_url: 'http://localhost:8080/openai',
|
|
112
|
-
base_path: { type: 'custom', body: '/v1/chat/completions' },
|
|
113
|
-
auth_method: 'api_key',
|
|
114
|
-
api_key: 'stub-key',
|
|
115
|
-
api_key_name: 'Authorization',
|
|
116
|
-
api_key_location: 'header',
|
|
117
|
-
request_type: 'json',
|
|
118
|
-
response_type: 'json',
|
|
119
|
-
timeout_ms: 300_000,
|
|
120
|
-
base_body: { type: 'custom', body: OPENAI_BASE_BODY },
|
|
121
|
-
},
|
|
122
|
-
})
|
|
123
|
-
toolId = tool.id!
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## 003 — register the extraction agent
|
|
127
|
-
|
|
128
|
-
The agent points at the tool and is constrained by two schemas: `input_schema`
|
|
129
|
-
(what `invoke` must pass — here `instructions`) and `llm_response_schema` (the
|
|
130
|
-
shape the model must return — load-bearing, the platform constrains the model to
|
|
131
|
-
it). `data_access: 'unregulated'` is the compliance gate for what the agent may
|
|
132
|
-
read.
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
const LEGAL_ENTITY_RESPONSE_SCHEMA = {
|
|
136
|
-
type: 'object',
|
|
137
|
-
properties: {
|
|
138
|
-
company_name: { type: 'string', nullable: true, maxLength: 200 },
|
|
139
|
-
registered_address: { type: 'string', nullable: true, maxLength: 300 },
|
|
140
|
-
date_of_formation: { type: 'string', nullable: true, maxLength: 40 },
|
|
141
|
-
capital_amount: { type: 'number', nullable: true },
|
|
142
|
-
capital_currency: { type: 'string', nullable: true, maxLength: 20 },
|
|
143
|
-
},
|
|
144
|
-
required: ['company_name'],
|
|
145
|
-
additionalProperties: false,
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const { data: agent } = await api.aiAgents.create(tenantSlug, datalakeSlug, {
|
|
149
|
-
name: `Legal Entity Extraction Agent ${runSuffix}`,
|
|
150
|
-
description: 'Extracts legal_entity-shaped fields from corporate documents.',
|
|
151
|
-
tool_id: toolId,
|
|
152
|
-
model: 'gpt-4o',
|
|
153
|
-
data_access: 'unregulated',
|
|
154
|
-
temperature: 0.0,
|
|
155
|
-
max_tokens: 8_192,
|
|
156
|
-
enabled: true,
|
|
157
|
-
input_schema: { type: 'object', properties: { instructions: { type: 'string' } }, required: ['instructions'] },
|
|
158
|
-
llm_response_schema: LEGAL_ENTITY_RESPONSE_SCHEMA,
|
|
159
|
-
prompt_config: {
|
|
160
|
-
type: 'custom',
|
|
161
|
-
body: 'You are a legal-entity data extraction specialist.\nExtract structured corporate information from the provided content and return a JSON object aligned to the legal_entity schema.\n\n{{ instructions }}',
|
|
162
|
-
},
|
|
163
|
-
})
|
|
164
|
-
aiAgentId = agent.id!
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
## 004 — invoke the agent with the files
|
|
168
|
-
|
|
169
|
-
`invoke` runs the agent against the uploaded files: `input` satisfies the
|
|
170
|
-
`input_schema`, and `files` lists the storage keys + content types to attach. The
|
|
171
|
-
result is the parsed JSON (`output`, matching `llm_response_schema`), an
|
|
172
|
-
`explanation`, and token `usage`.
|
|
173
|
-
|
|
174
|
-
```typescript
|
|
175
|
-
const { data: result } = await api.aiAgents.invoke(tenantSlug, datalakeSlug, aiAgentId, {
|
|
176
|
-
input: { instructions: 'Extract the company name and any visible registration details from the attached documents.' },
|
|
177
|
-
files: [
|
|
178
|
-
{ key: ctx.pdfKey, content_type: 'application/pdf' },
|
|
179
|
-
{ key: ctx.imageKey, content_type: 'image/png' },
|
|
180
|
-
],
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
if (!result.output || typeof result.output !== 'object') {
|
|
184
|
-
throw new Error('invoke did not return a structured output object')
|
|
185
|
-
}
|
|
186
|
-
if (!(result.output as Record<string, unknown>).company_name) {
|
|
187
|
-
throw new Error('expected a company_name in the extracted output')
|
|
188
|
-
}
|
|
189
|
-
if (!result.usage || (result.usage as { input_tokens?: number }).input_tokens === undefined) {
|
|
190
|
-
throw new Error('expected token usage on the invoke result')
|
|
191
|
-
}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## 005 — a malformed input is rejected
|
|
195
|
-
|
|
196
|
-
`invoke` validates `input` against the agent's `input_schema` before calling the
|
|
197
|
-
model. Omitting the required `instructions` returns a 422 — caught here so the
|
|
198
|
-
walk proves the gate without aborting.
|
|
199
|
-
|
|
200
|
-
```typescript
|
|
201
|
-
let rejected = false
|
|
202
|
-
try {
|
|
203
|
-
await api.aiAgents.invoke(tenantSlug, datalakeSlug, aiAgentId, {
|
|
204
|
-
input: { wrong_field: 'no instructions here' },
|
|
205
|
-
files: [],
|
|
206
|
-
})
|
|
207
|
-
} catch (err) {
|
|
208
|
-
const status = (err as { _httpStatus?: number })._httpStatus
|
|
209
|
-
if (status !== 422) throw err
|
|
210
|
-
rejected = true
|
|
211
|
-
}
|
|
212
|
-
if (!rejected) {
|
|
213
|
-
throw new Error('expected a 422 for input that violates the agent input_schema')
|
|
214
|
-
}
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
## 006 — write the integration test
|
|
218
|
-
|
|
219
|
-
End the build with a test you keep: re-read the agent and probe the one
|
|
220
|
-
behaviour that is provable deterministically — the input gate. A real
|
|
221
|
-
extraction (§004) needs a live provider behind the tool; the schema gate
|
|
222
|
-
does not, which is exactly what makes it the durable test. This block
|
|
223
|
-
runs live under `make validate-cookbook`.
|
|
224
|
-
|
|
225
|
-
```typescript
|
|
226
|
-
// Re-GET — the agent must be enabled, or every invoke will refuse.
|
|
227
|
-
const { data: agentRow } = await api.aiAgents.get(tenantSlug, datalakeSlug, aiAgentId)
|
|
228
|
-
if (agentRow.enabled !== true) {
|
|
229
|
-
throw new Error('expected enabled=true on agent read-back')
|
|
230
|
-
}
|
|
231
|
-
// Behavioural probe — the input_schema gate fires BEFORE the model:
|
|
232
|
-
// a malformed input must 422 even with no working provider.
|
|
233
|
-
let gateFired = false
|
|
234
|
-
try {
|
|
235
|
-
await api.aiAgents.invoke(tenantSlug, datalakeSlug, aiAgentId, {
|
|
236
|
-
input: { wrong_field: 'test — no instructions here' },
|
|
237
|
-
files: [],
|
|
238
|
-
})
|
|
239
|
-
} catch (err) {
|
|
240
|
-
const status = (err as { _httpStatus?: number })._httpStatus
|
|
241
|
-
if (status !== 422) throw err
|
|
242
|
-
gateFired = true
|
|
243
|
-
}
|
|
244
|
-
if (!gateFired) {
|
|
245
|
-
throw new Error('agent accepted input that violates its input_schema (expected 422)')
|
|
246
|
-
}
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
If the gate stops firing in production, escalate with the
|
|
250
|
-
accepted-payload evidence — don't loosen the `input_schema` to make the
|
|
251
|
-
error go away.
|
|
252
|
-
|
|
253
|
-
# Gotchas
|
|
254
|
-
|
|
255
|
-
- **Uploading a file is not ingesting it.** The upload + `invoke` here makes the
|
|
256
|
-
agent *read* the file. To turn a file into dataset rows, use
|
|
257
|
-
`dataActivationClients.ingestFile` (`bulk-ingest.md`). Don't reach for an agent
|
|
258
|
-
to "ingest" a document — agents enrich, the DAC ingests.
|
|
259
|
-
- **`llm_response_schema` is load-bearing.** It is what constrains the model's
|
|
260
|
-
output; the tool's `response_extractor.output_schema` is required too (a
|
|
261
|
-
missing one is a 422 at `/response_extractor/output_schema`).
|
|
262
|
-
- **The model lives on the agent, not the tool.** The tool is the provider
|
|
263
|
-
adapter (URL + request/response shape); the agent sets the `model`. Swapping
|
|
264
|
-
providers means a new tool adapter + the agent's `model`.
|
|
265
|
-
- **The file PUT is raw HTTP.** `createUploadLink` is an SDK call; the upload is a
|
|
266
|
-
plain `fetch` PUT to the presigned URL, exactly like bulk ingest.
|
|
267
|
-
- **`data_access` gates what the agent may read.** `unregulated` here; a stricter
|
|
268
|
-
setting changes what content the agent is allowed to see.
|
|
269
|
-
|
|
270
|
-
# See also
|
|
271
|
-
|
|
272
|
-
- `ai_agents.md` — agent wire shape, `input_schema` / `llm_response_schema`, invoke
|
|
273
|
-
- `interoperability_contracts.md` §6 — nesting an agent on a contract for per-row
|
|
274
|
-
enrichment during ingestion (the file→row path stays the DAC's)
|
|
275
|
-
- `bulk-ingest.md` — the correct path for turning a file into dataset rows
|
|
276
|
-
- `_setup/healthcare.md` — the bootstrap this walk starts from
|
|
277
|
-
- `_fixtures/healthcare/` — the vendored PDF + image
|
|
278
|
-
- `integration-tests/tests/healthcare/ai-agent-invoke.test.ts` — the green test
|
|
279
|
-
these calls are lifted from
|