@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
|
@@ -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).
|