BackendHTTP API
Agent HTTP endpoints
Agent HTTP endpoints
Unless noted, success body is { "data": … } and the tables describe the payload inside data.
Shared session model, tools, and intervention policy: agent.md.
GET /api/trips/:tripId/agent/messages
- Auth: session + member; agent enabled
- Response:
AgentHistoryDto— up to ~200 messages plus active suggestions (dismissed-for-this-user hidden).
POST /api/trips/:tripId/agent/messages
- Auth: session + member; agent enabled
- Body:
{
text?: string; // trim, max 4000; optional when files are present
files?: Array<{
type: "file";
mediaType: string;
url: string; // trip-owned /api/uploads/trips/… URL (not data:)
filename?: string;
}>; // max 8
}At least one of text (non-empty) or files is required. File URLs must belong
to this trip’s managed upload namespace; unsupported MIME types are dropped.
- Response:
{ addressed: boolean; message: AgentMessageDto }message— the inserted row (echo the write so clients cansetQueryDatawithout an immediate list GET that may hit a stale Hyperdrive cache).addressed— immediate flag only:truewhen the text contains an explicit@agentmention (ambient reply is deferred and will arrive via polling).falsefor every non-mention message, even when the server still schedulesmaybeReplyIfAddressedin the background. A later model judgment may still produce an ambient reply; that outcome is not reflected in this response. Clients should pollGET …/agent/eventsfor any reply rather than treatingaddressed: falseas “no reply will ever come.”
POST /api/trips/:tripId/agent/chat
- Auth: session + member; agent enabled
- Response: streaming AI SDK UI message stream — not the
{ data }envelope. Clients (e.g. Vercel AI SDKuseChat/DefaultChatTransport) should consume the stream protocol, notapiFetchJSON helpers. - Body:
{
messages?: Array<{
id?: string;
role: string;
parts: Array<
| { type: "text"; text: string }
| { type: "file"; mediaType: string; url: string; filename?: string }
| { type: string; /* AI SDK tool/reasoning passthrough */ }
>;
}>;
message?: { id?: string; role: string; parts: … } | null; // legacy single turn
}Server persists new user text and file parts (and finished assistant
messages) using client UIMessage ids for live/history dedupe. Attachment-only
turns are allowed. Tool-approval continuation uses the full messages list
with approval parts.
GET /api/trips/:tripId/agent/events
- Auth: session + member; agent enabled
- Query:
after— integer ≥ 0 (default0); return messages withseq > after - Response:
AgentEventsDto
POST …/suggestions/:suggestionId/approve
- Auth: session + member; apply requires edit permission
- Body (AI SDK approval shape):
{ id?: string; approved: boolean; reason?: string } // reason max 500id defaults to path suggestionId.
- Response when
approved: true: fullTripDtoafter patch apply - Response when
approved: false:{ dismissed: true }(toast hidden for this user only) - Errors:
409when suggestion not pending / stale / expired;403if viewer tries to apply
POST …/suggestions/:suggestionId/apply
- Alias:
approveddefaults totrueif omitted. - Response: same as approve with
approved: true.
POST …/suggestions/:suggestionId/dismiss
- Forces
approved: false. - Response:
{ dismissed: true }.
Behavior, tools, intervention: agent.md.