Chat & Session Management API¶
Endpoints for sending chat messages, retrieving conversation history, and managing chat sessions.
Base URL¶
All chat routes below are relative to this base URL. Full example: POST ${BASE_URL}/agents-service/api/v1/agentcore/chat/stream
Authentication¶
Tenant and user come from the JWT. Do not send tenant_id or user_id in the request body.
Chat flow¶
- Mint a session id (
fermi-{uuid}) or reuse one from the session list. - Optional: upload files with
POST /agents-service/api/v1/agentcore/chat/files. POST /agents-service/api/v1/agentcore/chat/streamwith{ "message", "session_id" }.- If the model pauses for human input,
POST /agents-service/api/v1/agentcore/chat/resumewithtool_call_idand the tool result. - List, reload, or delete sessions on
/agents-service/api/v1/agentcore/sessions.
Always use session_id from the JSON response (non-stream) or from the session list. The API may return a different id than the one you sent.
threadId is accepted as an alias of session_id on chat bodies.
Do not send Ask Fermi traffic to POST /public/v1/analytics/chat. That path is for onboarding and graph_modification only.
Stream a message¶
POST /agents-service/api/v1/agentcore/chat/stream
Response is assistant-ui / Vercel AI SDK data-stream v1 (text/plain), not JSON.
Headers:
Response headers include x-vercel-ai-data-stream: v1.
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes unless messages or attachments | User question |
messages | array | Alternative to message | assistant-ui turns; last role: "user" text is used |
session_id | string | No | Session to continue; also accepted as threadId |
attachments | array | No | { "s3_key": "...", "name"?, "content_type"?, "size"? } from the files upload |
cURL:
curl --request POST \
--url "${BASE_URL}/agents-service/api/v1/agentcore/chat/stream" \
--header "Authorization: Bearer <token>" \
--header "Content-Type: application/json" \
--data '{
"message": "What were last month sales by region?",
"session_id": "my-chat-session-123"
}'
Stream body: one chunk per line, {type}:{json}\n. Text deltas are type 0. The stream ends with a type d finish payload (finishReason is stop, tool-calls, or error). Tool calls use types b / c / a.
Errors: 400 invalid JSON or missing user text (unless attachments are present), 422 body validation, 503 chat runtime not configured or invoke failed.
Non-streaming chat¶
POST /agents-service/api/v1/agentcore/chat
Same request body as stream. Waits for the full run. The response includes session_id — store that value for messages, cancel, and delete.
Async chat (no long HTTP hold)¶
POST /agents-service/api/v1/agentcore/chat/async
callback_url is required (HTTPS). Omitting it returns 422. Request body:
{
"session_id": "my-chat-session-123",
"callback_url": "https://example.com/hooks/fermi-chat",
"message": "What were last month sales by region?"
}
Returns 202:
When the run finishes, Fermi POSTs JSON to callback_url:
On failure: { "session_id", "status": "failed", "error" }.
Resume after human input¶
POST /agents-service/api/v1/agentcore/chat/resume
When the stream finishes with finishReason: "tool-calls" (typically request_human_input), POST the human result. tool_call_id is required (422 without it). Response is the same data-stream as /chat/stream.
{
"session_id": "my-chat-session-123",
"tool_call_id": "tooluse-abc",
"tool_name": "request_human_input",
"tool_input": {},
"result": { "answers": ["Yes"] }
}
| Field | Type | Required |
|---|---|---|
tool_call_id | string | Yes |
tool_input | object | Yes |
result | any | Yes |
tool_name | string | No (default request_human_input) |
session_id / threadId | string | No |
Cancel a run¶
POST /agents-service/api/v1/agentcore/chat/cancel
{
"session_id": "my-chat-session-123",
"cancelled": true,
"had_live_run": true,
"runtime_stopped": true
}
Reattach to an in-flight stream¶
POST /agents-service/api/v1/agentcore/chat/attach
Body: { "session_id" } (or threadId). Returns data-stream v1 by polling session memory. Use this after refresh while a turn is still running.
List sessions¶
GET /agents-service/api/v1/agentcore/sessions
curl --request GET \
--url "${BASE_URL}/agents-service/api/v1/agentcore/sessions?max_results=20" \
--header "Authorization: Bearer <token>"
| Query | Type | Default | Description |
|---|---|---|---|
max_results | integer | 20 | 1–100 |
next_token | string | none | Activity cursor from the previous page |
include_preview | boolean | true | Include sidebar preview text |
{
"sessions": [
{
"sessionId": "my-chat-session-123",
"actorId": "user-123",
"createdAt": "2026-08-26T10:00:00+00:00",
"lastMessageAt": "2026-08-26T10:02:10+00:00",
"preview": "What were last month sales by region?",
"running": false,
"requiresAction": false
}
],
"nextToken": null
}
Sessions are ranked by last activity. nextToken is an activity cursor.
Session messages¶
GET /agents-service/api/v1/agentcore/sessions/{session_id}/messages
curl --request GET \
--url "${BASE_URL}/agents-service/api/v1/agentcore/sessions/my-chat-session-123/messages?max_results=100" \
--header "Authorization: Bearer <token>"
| Query | Type | Default | Description |
|---|---|---|---|
max_results | integer | 100 | 1–100 |
include_partial | boolean | false | Keep an in-flight assistant turn (reconnect) |
Use max_results. Other page-size query names are ignored.
{
"sessionId": "my-chat-session-123",
"messages": [
{
"id": "evt-1",
"role": "user",
"content": [{ "type": "text", "text": "Hi, how are you?" }]
},
{
"id": "evt-2",
"role": "assistant",
"content": [{ "type": "text", "text": "Your email has been sent." }],
"status": "complete"
}
],
"preview": "Hi, how are you?",
"running": false,
"requiresAction": false
}
Assistant content may include { "type": "tool-call", "toolCallId", "toolName", "args", "result?" }.
Session run status¶
GET /agents-service/api/v1/agentcore/sessions/{session_id}/status
Delete a session¶
DELETE /agents-service/api/v1/agentcore/sessions/{session_id}
If the session has no events: { "sessionId", "deletedEvents": 0 }.
Chat files¶
GET /agents-service/api/v1/agentcore/chat/files/limits
Treat the live /limits response as source of truth.
POST /agents-service/api/v1/agentcore/chat/files — multipart/form-data
| Field | Type | Required |
|---|---|---|
session_id | string | Yes |
file | file | Yes |
{
"id": "example-org/example-user/my-chat-session-123/file.pdf",
"name": "file.pdf",
"s3_key": "example-org/example-user/my-chat-session-123/file.pdf",
"bucket": "example-bucket",
"content_type": "application/pdf",
"size": 12345,
"s3_uri": "s3://example-bucket/example-org/example-user/my-chat-session-123/file.pdf",
"session_id": "my-chat-session-123"
}
Pass s3_key (and optional name / content_type / size) in the next /chat/stream attachments array. Do not send file bytes on the chat POST.
GET /agents-service/api/v1/agentcore/chat/files?session_id= → { "session_id", "files" }
DELETE /agents-service/api/v1/agentcore/chat/files?s3_key=&session_id= → { "deleted": true, "s3_key" }
GET /agents-service/api/v1/agentcore/chat/files/url?s3_key=&session_id= → { "url", "s3_key" } (presigned GET)
Summary¶
| Method | Path | Notes |
|---|---|---|
| POST | /agents-service/api/v1/agentcore/chat/stream | Send; data-stream v1 |
| POST | /agents-service/api/v1/agentcore/chat | JSON { session_id, answer } |
| POST | /agents-service/api/v1/agentcore/chat/async | 202 + callback_url |
| POST | /agents-service/api/v1/agentcore/chat/resume | Continue after human input; data-stream |
| POST | /agents-service/api/v1/agentcore/chat/cancel | Stop in-flight run |
| POST | /agents-service/api/v1/agentcore/chat/attach | Reconnect in-flight; data-stream |
| GET | /agents-service/api/v1/agentcore/sessions | { sessions, nextToken } |
| GET | /agents-service/api/v1/agentcore/sessions/{id}/messages | History |
| GET | /agents-service/api/v1/agentcore/sessions/{id}/status | { running } |
| DELETE | /agents-service/api/v1/agentcore/sessions/{id} | { deletedEvents } |
| GET/POST/DELETE | /agents-service/api/v1/agentcore/chat/files | Attachments |
Next Steps¶
- Validation — review findings after connectors
- Brain API — knowledge graph visualization
- Data Connectors — connect sources before asking questions
- Examples