Agent API
Use the Agent API for interactive conversational agents and structured task agents. All requests require access to the target agent and are scoped to the authenticated user and Space.
Choose the correct endpoint
| Need | Endpoint | Client method |
|---|---|---|
| Interactive, multimodal, streaming conversation | POST /api/agents/{agentId}/chat | client.agents.chatStream() |
| Non-streaming conversational response | POST /api/agents/{agentId}/chat with stream: false | client.agents.chat() |
| Structured task-agent execution | POST /api/agents/{agentId}/execute | client.agents.execute() |
| Long-running task-agent execution | POST /api/agent-jobs | client.agents.invokeAsync() |
| Resume a user-choice interaction | POST /api/agents/{agentId}/turns/{turnId}/resume | HTTP V3 stream request |
| Read or compact chat context | session context endpoints | HTTP request |
Do not send OpenAI messages[] to the Agent chat endpoint. It uses GeniSpace contents[]. The Models relay is a separate OpenAI-compatible API.
Interactive chat
Request
POST /api/agents/{agentId}/chat
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Accept: text/event-stream
X-GeniSpace-Stream-Protocol: langgraph-v3
{
"contents": [
{ "type": "text", "text": "Compare the attached chart with our policy" },
{ "type": "image_url", "image_url": { "url": "https://example.com/chart.png" } }
],
"session_id": "session-123",
"turnId": "1a11bb22-333c-444d-855e-666666666666",
"stream": true,
"settings": {
"temperature": 0.3,
"max_tokens": 2000,
"chat_mode": "agent",
"disable_web_search": false
}
}
contents must be non-empty. API content types are text, image_url, audio, and file. Use session_id to continue a conversation. Generate one stable UUID turnId for each user turn so retries can be identified safely.
settings.chat_mode accepts ask or agent. Ask mode does not execute action tools. Only send settings supported by the endpoint; unknown fields are rejected.
LangGraph V3 stream contract
Streaming requests must send X-GeniSpace-Stream-Protocol: langgraph-v3. The response must acknowledge the same value. Missing or different values return HTTP 426 Upgrade Required.
Each SSE data: frame is a JSON envelope with a contiguous sequence number:
{
"type": "event",
"method": "custom:genispace",
"params": { "data": { "event": "content-delta", "delta": "Hello" } },
"seq": 7
}
The wire methods are updates-derived product events represented as custom:genispace, plus messages, tools, lifecycle, and input. Consumers must preserve order and reject non-contiguous or unsupported frames. Use the JavaScript SDK rather than maintaining a second parser.
The SDK projects the wire stream into product events such as:
session.started;content.delta;tool.executionwith structured arguments and result metadata;knowledge.evidence;agent.input.required;local.tool.call;context.usage;response.completed;turn.persist_pending,error.occurred, andstream.ended.
Do not render only the event description: tool arguments, results, errors, plugin metadata, and evidence are part of the user-visible execution process.
JavaScript SDK example
import { GeniSpace } from 'genispace';
const client = new GeniSpace({
apiKey: process.env.GENISPACE_API_KEY!,
baseURL: 'https://api.genispace.ai/api',
});
const controller = new AbortController();
const stream = client.agents.chatStream(
'AGENT_ID',
{
contents: [{ type: 'text', text: 'Find the relevant policy evidence.' }],
session_id: 'session-123',
turnId: crypto.randomUUID(),
settings: { temperature: 0.2, max_tokens: 1200 },
},
{ signal: controller.signal, language: 'en' },
);
for await (const event of stream) {
if (event.type === 'content.delta') process.stdout.write(event.content ?? '');
if (event.type === 'tool.execution') renderToolResult(event.metadata);
if (event.type === 'agent.input.required') renderUserChoice(event.metadata);
if (event.type === 'error.occurred') throw new Error(event.error);
}
AgentStreamClient and AgentStreamDecoder are also exported for built-in-agent streams and byte-forwarding desktop proxies.
Resume a user-choice interaction
When the stream emits agent.input.required, persist the interaction metadata and render the supplied single-choice or multiple-choice form. Submit option IDs, not labels:
POST /api/agents/{agentId}/turns/{turnId}/resume
X-GeniSpace-Stream-Protocol: langgraph-v3
{
"sessionId": "session-123",
"interactionId": "interaction-456",
"selectedOptionIds": ["candidate-42"],
"otherText": null
}
The resume response is another V3 stream. A duplicate submission returns an idempotent success response rather than executing the choice twice. Pending interactions can be listed with:
GET /api/agents/{agentId}/sessions/{sessionId}/interactions/pending
Use otherText only for the form's custom-answer input. Do not add a second “Other” option yourself.
Context status and compaction
POST /api/agents/{agentId}/sessions/{sessionId}/context/status
POST /api/agents/{agentId}/sessions/{sessionId}/context/compact
Both accept an empty JSON body at the public API. Status reports used, remaining, and maximum tokens, whether values are estimated, compaction count, summary state, and message count. Manual compaction returns 409 while a user interaction is pending and 404 if no checkpoint exists.
Compaction summarizes model context; it does not delete the stored transcript. See Context management.
Structured task execution
Use /execute for a task agent with defined input/output rather than an interactive UI:
const result = await client.agents.execute('TASK_AGENT_ID', {
inputs: {
query: 'Extract the invoice fields',
documentUrl: 'https://example.com/invoice.pdf',
},
settings: { temperature: 0.1, maxTokens: 1200 },
});
For an operation that may run for minutes, use invokeAsync(). It creates an AGENT_INVOKE job and polls its status without holding one HTTP request open:
const result = await client.agents.invokeAsync(
'invoice-extractor',
{ query: 'Extract and validate the fields' },
{
timeoutMs: 600_000,
idempotencyKey: 'invoice-2026-00042',
onProgress: (job) => updateProgress(job.phase, job.progress),
},
);
Stopping local polling does not cancel the server job. Use the job cancellation API for cooperative cancellation.
Cancellation
Cancel an active conversational turn with:
POST /api/agents/{agentId}/turns/{turnId}/cancel
{ "sessionId": "session-123" }
Also abort the browser stream so the interface stops reading. A distributed cancellation may take a short time to reach the active runtime.
Errors
| Status | Typical cause |
|---|---|
| 400 | Invalid content, setting, session, or interaction payload |
| 401 | Missing or invalid credential |
| 402 | Insufficient user or Space quota |
| 403 | No access to the agent, tool, or Space resource |
| 404 | Agent, session checkpoint, turn, or interaction not found |
| 409 | Turn already active or compaction blocked by pending input |
| 426 | Missing or incorrect langgraph-v3 stream header |
| 503 | Runtime or context compaction unavailable |
Treat error.occurred as a failed stream even when the HTTP connection was initially successful. Preserve the turn ID, request ID, and last valid sequence number in diagnostics.
Security and reliability
- Keep API keys on a trusted server; browser applications should use authenticated access tokens.
- Generate a unique
turnIdper user turn and reuse it only when retrying that same turn. - Do not execute a local tool unless it is registered and authorized by the host application.
- Render tool evidence as untrusted data; never interpret it as executable HTML.
- Respect Space access and avoid requesting output fields the user should not see.
- Use an idempotency key for consequential background work.