Tools are functions the Ekanos assistant (and, where the host allows it, the workflow engine) can call. Each tool declares a name, a description the model reads, an optional parameter schema, and an async run.
Handler behavior
Success
Return a plain JSON-serializable value:
Expected failure (user-facing)
Return { error: '…' }. The model reads this and explains it to the user:
Genuine fault (throw)
Throw for a genuine fault rather than returning { error }:
PublicActionError from @ekanos/sdk/integration belongs to actions
(widget-invoked handlers called through useIntegrationAction()), not tools.
An action handler’s throw is, by default, collapsed to a generic "Action failed." response under the handler_error code; throwing
PublicActionError surfaces its message to the user verbatim instead.
Parameters
Parameters are a narrow slice of JSON Schema — only the wrapper is restricted, not the contents:
Valid at root: type (must be 'object'), properties, required, additionalProperties
Invalid at root: title, description, $schema, oneOf, anything other than the four above
Inside properties, you are unconstrained — nested objects, arrays, enums, descriptions all pass.
Tool names are ^[a-z][a-z0-9_]*$ — lowercase snake_case:
- ✅ Valid:
list_payments, get_customer, refund_payment
- ❌ Invalid:
ListPayments, list-payments, list payments
The effective name the assistant sees is namespaced by your slug. acme-payments + list_payments becomes acme_payments_list_payments (hyphens → underscores).
If you declare acme_payments_list_payments as the raw name, the effective name stays the same (no double prefix). Collisions across two integrations in the same platform are detected and rejected.
Output example
Small, honest examples of what the tool returns. Used by the model as a shape hint:
Keep it short. The model uses it to understand the shape, not to hallucinate realistic data.
Common patterns
Read data
Testing
Use createMockContext() to test tools:
Troubleshooting
Check:
- Tool name matches
^[a-z][a-z0-9_]*$
- No duplicate names in your
tools array
proposes.credentialModel is declared if the tool is for a workflow
- The integration is activated on the account
defineIntegration() rejects your parameters
Your parameters object has a key other than type, properties, required, or additionalProperties at the root (title, description, $schema, …), or a root type other than 'object'. The root is .strict(), so the error points at tools.<index>.parameters. Remove the key, or move a description into the relevant property schema.
Next steps