Skip to content

Chat & AI API

Endpoints for talking to the AI agent. Source: services/api/src/routes/chat/ and services/api/src/routes/plan.ts.

List a project's chats

GET /projects/:projectId/chats

Returns chat metadata (title, mode, created/updated). Each project has at least one default chat.

Create a chat

POST /projects/:projectId/chats
{ "mode": "build" | "plan" | "chat" | "<custom>", "title": "Optional" }

Send a message (streaming)

POST /chat/:projectId/messages
Content-Type: application/json
Accept: text/event-stream

{
  "chatId": "...",
  "text": "Add a contact form below the hero",
  "model": "claude-sonnet-4",   // optional override
  "attachments": [               // optional
    { "type": "image", "url": "data:image/png;base64,..." }
  ]
}

The response is a Server-Sent-Events stream. Each data: line is a JSON-encoded DoCoreEvent. Important kinds:

type Payload
assistant.message_delta { delta: "..." }: text chunk
assistant.reasoning_delta { delta: "..." }: model reasoning chunk (thinking models)
tool.call { id, tool, args }: agent invoking a tool
tool.result { id, result }: tool output
tool.error { id, error }: denied or failed tool
assistant.message { text }: final assistant message
session.usage_info { inputTokens, outputTokens, cost }
session.compaction_start / compaction_complete Context auto-summarization
session.task_complete Stream done

Closing the connection cancels the in-flight model call.

The full event union is in packages/docore/src/events.ts.

Stop generation

POST /chat/:projectId/stop
{ "chatId": "..." }

Retrieve history

GET /chat/:projectId/messages?chatId=...&before=<cursor>&limit=50

Returns the persisted message timeline (the same events that were streamed).

Plan mode

Plan mode is identical except it forces the read-only tool subset and parses the final message into a structured plan:

POST /plan/:projectId
{ "chatId": "...", "text": "Refactor the auth flow into a separate module" }

Once the stream ends, fetch the structured plan:

GET /plan/:projectId/:chatId

Returns:

{
  steps: Array<{
    title: string;
    description: string;
    files: string[];
    risk: 'low' | 'medium' | 'high';
  }>;
  rawText: string;
}

The user can hit "Run plan", and the API switches the chat to Build mode and feeds the plan back as the next message.

Direct save (visual edit)

The visual editor sends AST-based patches directly without spending AI tokens:

POST /direct-save/:projectId
{
  "filePath": "src/Hero.tsx",
  "patches": [{ "selector": "h1", "property": "text", "value": "New title" }]
}

See services/api/src/direct-save/ and services/api/src/visual-edit-bridge-inline.ts.

Errors

{ "error": "no_provider", "message": "No AI provider configured for this workspace" }
{ "error": "credit_exhausted", "message": "Workspace credit limit reached" }
{ "error": "model_unavailable", "message": "anthropic returned 429" }

For streaming endpoints these arrive as a final SSE event:

data: {"type":"error","error":"credit_exhausted","message":"..."}

See also