---
title: "Chat Main Agent"
method: POST
path: "/api/v1/chat/stream"
tags: ["chat"]
---

# Chat Main Agent

`POST /api/v1/chat/stream`

Receives and processes a streaming chat request via the AgentService.

This endpoint streams the agent's response in real-time using Server-Sent Events.

Args:
    request: The chat request data containing message and project_id (pre-validated).
    agent_service: The AgentService instance (dependency).

Returns:
    StreamingResponse with Server-Sent Events containing streaming chat data.

Raises:
    HTTPException: 400 for validation errors.
    HTTPException: 404 if project not found or user doesn't own it.
    HTTPException: 500 for unexpected errors.

## Request body

- ChatRequest
  - `message` string, required
  - `project_id` string, uuid, required
  - `current_focused_layer_id` string, uuid, nullable
  - `action_type` 'new_enrichment' | 'new_layer' | 'analyze_row' | 'invoke_skill' — Enum for different action types in the system.
  - `action_subtype` string, nullable — Optional preset identifier that disambiguates actions sharing an action_type. For detail-panel presets, matches the client-side noteSource (e.g. 'environment', 'zoning', 'summary').
  - `hidden_context` object, nullable
  - `current_view_id` string, nullable
  - `iterate_over_rows` boolean
  - `selected_model` string, nullable — Model-picker selection for this chat (a curated picker key, see GET /chat/models). Persisted on the chat; honored only when the workspace's model-picker feature toggle is on.
  - `feature_context` FeatureContext — Reference to a specific feature the user is viewing. Sent when the detail view is open so the agent knows which feature the user is talking about. Reused by @ mentions. `feature_id` is a string because sandbox-backed layers (place-type) use UUID feature ids, while CloudSQL `features.id` is bigint serialized as a numeric string. Validation only enforces non-empty.
    - `feature_id` string, required
    - `layer_id` string, uuid, required
  - `mentioned_feature_contexts` FeatureContext[], nullable
    - `feature_id` string, required
    - `layer_id` string, uuid, required
  - `prior_answer` InteractiveQuestionAnswer
    - `optionId` string, required
    - `label` string, required
    - `questionId` string, required
  - `tool_approval` ToolApprovalAnswer — The user's approve/decline for a pending tool call. ``message`` is wire-forward-compat: no UI affordance sends it yet (the card is approve/decline only), but the denial seam already threads it into the synthesized ToolDenied as context for a future decline-reason input. Capped because it persists into chat history and rides every subsequent model call.
    - `toolCallId` string, required
    - `approved` boolean, required
    - `message` string, nullable
  - `continue_turn` boolean — Continue a terminally-failed turn from its persisted partial without a new prompt. The FE sends an empty `message` and the endpoint runs a promptless turn on the persisted history (the same no-user-bubble shape as a tool approval, minus the approval payload) so the agent resumes where it left off.

## Response `200`

Successful Response

- unknown

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.net/maia-analytics/apis/maia-api.md) · [All operations](https://skmtc.net/maia-analytics/apis/maia-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/maia-analytics/maia-api/revisions/964b64b122c8/schema)
