AI chat endpoint — proxies multi-turn conversations through
the configured AI provider (Anthropic / OpenAI / Google / Ollama).
Mounted at /api/v1 (INF-005).
The system prompt includes a live workspace snapshot (projects, tests, recent runs, failures) so the AI can answer questions about the user's actual data without extra API calls from the frontend.
Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/api/v1/chat |
Send a message and receive an AI reply (SSE) |
Request body: { messages: [{ role: "user"|"assistant", content: string }] }
Response: Server-Sent Events stream of token deltas, then a [DONE] event.
- Source:
Methods
(inner) buildEntityContext(ctx, userMessage, optsopt) → {string}
Scan the user's message for entity references (TC-, RUN-, PRJ-*) and fetch detailed context for each.
Parameters:
| Name | Type | Attributes | Description | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ctx |
Object | { projects, tests, runs, projectsById, testsById, runsById } |
|||||||||||
userMessage |
string | The latest user message text. |
|||||||||||
opts |
Object |
<optional> |
Properties
|
- Source:
Returns:
Detailed entity context block, or empty string.
- Type
- string
(inner) buildWorkspaceContext(ctx) → {string}
Build a compact workspace snapshot for the system prompt. Kept small to avoid wasting tokens — only includes actionable data.
Parameters:
| Name | Type | Description |
|---|---|---|
ctx |
Object | { projects, tests, runs, projectsById, testsById, runsById } |
- Source:
Returns:
Workspace context block, or empty string if no data.
- Type
- string
(inner) findLatestTestResult(ctx, testId) → {Object|null}
Find the most recent run result for a specific test ID.
Parameters:
| Name | Type | Description |
|---|---|---|
ctx |
Object | { runs } |
testId |
string | The test ID to search for. |
- Source:
Returns:
{ runId, status, error, duration } or null.
- Type
- Object | null
(inner) trimConversationHistory(messages) → {Array.<{role: string, content: string}>}
Trim a conversation to fit within MAX_CONVERSATION_TURNS.
Strategy: keep the first message (initial context) and the most recent turns. Walk forward from the cut point to find a safe boundary at an assistant message — never split a user message from its assistant reply.
This is pure truncation — no extra LLM calls. The same single streamText() call is made regardless of whether trimming occurred.
Parameters:
| Name | Type | Description |
|---|---|---|
messages |
Array.<{role: string, content: string}> |
- Source:
Returns:
Trimmed copy (or original if short enough).
- Type
- Array.<{role: string, content: string}>