Appearance
Tutorial: Integrate One Agent End-to-End
Ship a first production-ready Aionis integration with replay-ready provenance.
Before you start
- You have a running Aionis endpoint (
BASE_URL). - You have API key or bearer-token auth configured.
- You have a test
tenant_idandscope.
What you will finish with
A working flow that does write -> recall -> policy -> decision and preserves the IDs needed for replay and debugging.
Tip - Copy and run Use the copy button at the top-right of each code block. If you have not prepared variables yet, run One-click Environment Template first.
Input
Environment contract
Use these values across all requests:
tenant_id = defaultscope = supportrun_id = run_<timestamp>
Input fields
| Field | Required | Used in steps | Example |
|---|---|---|---|
BASE_URL | Yes | All | http://localhost:3001 |
AIONIS_API_KEY | Yes | All | aionis_live_xxx |
tenant_id | Yes | 1, 2, 3, 4 | default |
scope | Yes | 1, 2, 3, 4 | support |
query_text | Yes | 2 | invoice request |
run_id | Yes | 3 | run_1741311000 |
candidates[] | Yes | 3 | ["ticket_router","email_sender"] |
uri | Yes | 4 | aionis://default/support/decision/<decision_id> |
Output fields to persist
| Field | Source step | Why keep it |
|---|---|---|
request_id | 1, 2, 3, 4 | Request-level trace and incident correlation |
data.commit_id | 1 | Commit lineage and audit |
data.commit_uri | 1 | Resolve/replay path reconstruction |
run_id | 3 | End-to-end workflow correlation |
decision.decision_id | 3 | Policy/action decision provenance |
decision.decision_uri | 3 | Deterministic object lookup |
selection.selected | 3 | Action outcome validation |
Steps
Step 1: Write one memory event
TypeScript
ts
const baseUrl = process.env.BASE_URL!
const apiKey = process.env.AIONIS_API_KEY!
const writeRes = await fetch(`${baseUrl}/v1/memory/write`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-api-key': apiKey
},
body: JSON.stringify({
tenant_id: 'default',
scope: 'support',
input_text: 'Customer requested invoice PDF',
nodes: [
{
type: 'event',
memory_lane: 'shared',
text_summary: 'Customer requested invoice PDF'
}
]
})
})
const writeData = await writeRes.json()
console.log(writeData)Python
python
import os
import requests
base_url = os.environ["BASE_URL"]
api_key = os.environ["AIONIS_API_KEY"]
resp = requests.post(
f"{base_url}/v1/memory/write",
headers={"content-type": "application/json", "X-Api-Key": api_key},
json={
"tenant_id": "default",
"scope": "support",
"input_text": "Customer requested invoice PDF",
"nodes": [
{
"type": "event",
"memory_lane": "shared",
"text_summary": "Customer requested invoice PDF",
}
],
},
timeout=20,
)
print(resp.json())cURL
bash
curl -sS "$BASE_URL/v1/memory/write" \
-H "X-Api-Key: $AIONIS_API_KEY" \
-H 'content-type: application/json' \
-d '{
"tenant_id":"default",
"scope":"support",
"input_text":"Customer requested invoice PDF",
"nodes":[
{
"type":"event",
"memory_lane":"shared",
"text_summary":"Customer requested invoice PDF"
}
]
}' | jqPersist:
request_iddata.commit_iddata.commit_uri
Step 2: Recall context by text
TypeScript
ts
const recallRes = await fetch(`${baseUrl}/v1/memory/recall_text`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-api-key': apiKey
},
body: JSON.stringify({
tenant_id: 'default',
scope: 'support',
query_text: 'invoice request',
limit: 5
})
})
const recallData = await recallRes.json()
console.log(recallData)Python
python
recall = requests.post(
f"{base_url}/v1/memory/recall_text",
headers={"content-type": "application/json", "X-Api-Key": api_key},
json={
"tenant_id": "default",
"scope": "support",
"query_text": "invoice request",
"limit": 5,
},
timeout=20,
)
print(recall.json())cURL
bash
curl -sS "$BASE_URL/v1/memory/recall_text" \
-H "X-Api-Key: $AIONIS_API_KEY" \
-H 'content-type: application/json' \
-d '{
"tenant_id":"default",
"scope":"support",
"query_text":"invoice request",
"limit":5
}' | jqPersist:
request_idtenant_idscope
Step 3: Evaluate rules and select tool
TypeScript
ts
const runId = `run_${Date.now()}`
await fetch(`${baseUrl}/v1/memory/rules/evaluate`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-api-key': apiKey
},
body: JSON.stringify({
tenant_id: 'default',
scope: 'support',
context: { intent: 'billing_support' }
})
})
const selectRes = await fetch(`${baseUrl}/v1/memory/tools/select`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-api-key': apiKey
},
body: JSON.stringify({
tenant_id: 'default',
scope: 'support',
run_id: runId,
context: { intent: 'billing_support' },
candidates: ['ticket_router', 'email_sender']
})
})
const selectData = await selectRes.json()
console.log(selectData)Python
python
import time
run_id = f"run_{int(time.time())}"
requests.post(
f"{base_url}/v1/memory/rules/evaluate",
headers={"content-type": "application/json", "X-Api-Key": api_key},
json={"tenant_id": "default", "scope": "support", "context": {"intent": "billing_support"}},
timeout=20,
)
selection = requests.post(
f"{base_url}/v1/memory/tools/select",
headers={"content-type": "application/json", "X-Api-Key": api_key},
json={
"tenant_id": "default",
"scope": "support",
"run_id": run_id,
"context": {"intent": "billing_support"},
"candidates": ["ticket_router", "email_sender"],
},
timeout=20,
)
print(selection.json())cURL
bash
RUN_ID="run_$(date +%s)"
curl -sS "$BASE_URL/v1/memory/rules/evaluate" \
-H "X-Api-Key: $AIONIS_API_KEY" \
-H 'content-type: application/json' \
-d '{"tenant_id":"default","scope":"support","context":{"intent":"billing_support"}}' | jq
curl -sS "$BASE_URL/v1/memory/tools/select" \
-H "X-Api-Key: $AIONIS_API_KEY" \
-H 'content-type: application/json' \
-d "{\"tenant_id\":\"default\",\"scope\":\"support\",\"run_id\":\"$RUN_ID\",\"context\":{\"intent\":\"billing_support\"},\"candidates\":[\"ticket_router\",\"email_sender\"]}" | jqPersist:
run_iddecision.decision_iddecision.decision_uriselection.selected
Step 4: Validate provenance chain
Use resolve on decision_uri:
bash
curl -sS "$BASE_URL/v1/memory/resolve" \
-H "X-Api-Key: $AIONIS_API_KEY" \
-H 'content-type: application/json' \
-d '{
"tenant_id":"default",
"scope":"support",
"uri":"aionis://default/support/decision/<decision_id>",
"include_meta":true
}' | jqExpected response sample
json
{
"status": "ok",
"request_id": "req_123",
"tenant_id": "default",
"scope": "support",
"data": {
"commit_id": "commit_123",
"commit_uri": "memory://commit/commit_123"
},
"decision": {
"decision_id": "8fe92f61-9466-4f9e-96ef-04bc56b96b19",
"decision_uri": "aionis://default/support/decision/8fe92f61-9466-4f9e-96ef-04bc56b96b19"
}
}Common failure and fix
Failure:
json
{"error":"write_nodes_required","message":"write request must include at least one node"}Fix:
- Add at least one recallable node in
nodes[]. - Keep
tenant_id+scopeexplicit. - Retry once with corrected payload.
Success criteria
writesucceeds and returnscommit_id+commit_uri.recall_textreturns context/candidates without auth or scope errors.tools/selectreturns oneselection.selectedand adecision_id.resolveon decision URI returns a concrete decision object.
Production checklist
- Always send both
tenant_idandscope. - Log
request_id,run_id,decision_id,commit_urifor each user-visible action. - Reject actions when policy response is missing or invalid.