Corteksa

Frontend Integration

AI — Frontend Integration

For web (React/Next.js) and mobile developers building the chat UI on the v2 multi-agent assistant (LangGraph). The live surface is the WebSocket namespace /ai-v2/chat; REST (/ai-v2/...) is the blocking fallback.

Auth

Both surfaces use the admin login JWT — the same token as the rest of the API. There's no separate AI permission; routes run AiV2EnabledGuard + AdminAuthGuard, so any authenticated admin can chat when AI_V2_ENABLED is on (else 404).

Authorization: Bearer <jwt>

Base URL https://<workspace>.corteksa.com/api/v1. On the WebSocket, pass the JWT in the handshake (auth.token, query.token, or the Authorization header). The tenant is derived from the request host.

The flow

1. Create conversation  POST /ai-v2/conversations          → { slug }
2. Connect WS           WS   /ai-v2/chat                    → auth in handshake → assistant:ready
3. Send a message       emit assistant:send { conversationId, message }
4. Render the stream    on   assistant:agent / :token / :tool_start / :tool_result
5. Handle a write       on   assistant:confirmation_required → emit assistant:confirm / :reject
6. Turn done            on   assistant:complete   (or assistant:handoff)

Prefer the WebSocket for anything interactive. Use REST (POST /ai-v2/conversations/{slug}/messages) only when you want the full answer in one blocking call — see REST API.

Streaming events (WebSocket /ai-v2/chat)

On connect the server emits assistant:ready { agent: "supervisor" }. Then, per turn:

Server → client

EventFires whenKey fields
assistant:thinkingTurn acceptedconversationId
assistant:agentThe supervisor routed the turn to a specialist (v2-only)which agent — switch UI mode
assistant:tokenA token of the answer streamedconversationId, delta
assistant:tool_startA tool call begantool name + args
assistant:tool_resultA tool call returnedtool name, success, summary
assistant:confirmation_requiredA write batch needs approval (the gate)the pending calls + their ids
assistant:completeTurn finishedthe final message + usage
assistant:handoffThe supervisor handed off (e.g. open the workspace builder) — terminal (v2-only)the target
assistant:errorSomething failedcode, message, conversationId?, retryAfter?

Client → server

EventPayloadMeaning
assistant:send{ conversationId?, message, agent?, object_slug? }Start / continue a turn. Omit conversationId to start fresh; agent pins a specialist; object_slug is focus context.
assistant:confirm{ conversationId?, approvedCallIds? }Approve pending writes — the server runs only the echoed call ids
assistant:reject{ conversationId? }Decline the pending writes
assistant:cancel_generationStop the in-flight turn

Send a message

socket.emit('assistant:send', { conversationId, message: 'how many open deals?' });
socket.on('assistant:agent', (e) => setActiveAgent(e));          // route → UI mode
socket.on('assistant:token', (e) => appendDelta(e.delta));       // stream the answer
socket.on('assistant:tool_start', (e) => showToolChip(e));
socket.on('assistant:complete', (e) => finalize(e));

The write-confirmation gate

When a turn wants to create, update, or delete, it does not act — it emits assistant:confirmation_required with the pending calls and pauses. Render a card, then echo back the exact call ids to approve:

socket.on('assistant:confirmation_required', (c) => {
  showCard(c);                                  // list the pending writes
  // On Approve — run only what the card showed:
  socket.emit('assistant:confirm', { conversationId: c.conversationId, approvedCallIds: c.callIds });
  // On Decline:
  // socket.emit('assistant:reject', { conversationId: c.conversationId });
});

The gate is backend-enforced: the server re-checks each approved call and runs only those still pending — a missing card can never cause an unconfirmed write. This is a hard law: see Write-confirmation law.

UI concerns

  • Stream, don't block — render assistant:token into the bubble; spinner on assistant:thinking, tool chips on assistant:tool_start, agent badge on assistant:agent.
  • Never auto-run writes — always surface assistant:confirmation_required as an explicit Approve/Decline card, and only send approvedCallIds the user OK'd.
  • Handle hand-offs — on assistant:handoff, transition the UI (e.g. open the workspace builder) rather than treating it as a normal completion.
  • Errors — map assistant:error.code (AUTH_INVALID, RATE_LIMIT, TOKEN_BUDGET_EXCEEDED, …); see Troubleshooting.

Next

On this page