Documentation
¶
Overview ¶
This sample demonstrates serving Genkit agents as plain HTTP endpoints.
Agents are bidirectional streaming actions, but the standard action handler also runs them one turn per request: "data" carries the turn's input (the user message), and the optional "init" field carries the session source that lets a conversation span requests.
Two agents show the two session-state modes:
- "chat" configures a session store (server-managed state). Each turn persists a snapshot; the response carries sessionId and snapshotId, and a later request resumes the conversation by sending {"init": {"sessionId": ...}} (or {"snapshotId": ...} to resume from a specific point in history). The store also gives the agent snapshot companion actions, served here at /agents/chat/getSnapshot and /agents/chat/abort.
- "statelessChat" has no store (client-managed state). The response carries the full conversation state; the client sends it back verbatim as {"init": {"state": ...}} on the next turn. The server keeps nothing between requests.
To run:
go run .
Start a conversation (no init starts a fresh session):
curl -X POST http://localhost:8080/agents/chat \
-H "Content-Type: application/json" \
-d '{"data": {"message": {"role": "user", "content": [{"text": "My name is Alex and I am planning a trip to Japan."}]}}}'
Continue it, using the sessionId from the response:
curl -X POST http://localhost:8080/agents/chat \
-H "Content-Type: application/json" \
-d '{"data": {"message": {"role": "user", "content": [{"text": "What is my name?"}]}}, "init": {"sessionId": "SESSION_ID"}}'
Stream a turn's model chunks and lifecycle events as server-sent events:
curl -N -X POST 'http://localhost:8080/agents/chat?stream=true' \
-H "Content-Type: application/json" \
-d '{"data": {"message": {"role": "user", "content": [{"text": "Suggest three day trips from Tokyo."}]}}}'
For statelessChat, resume by round-tripping the returned state instead:
curl -X POST http://localhost:8080/agents/statelessChat \
-H "Content-Type: application/json" \
-d '{"data": {"message": {"role": "user", "content": [{"text": "What is my name?"}]}}, "init": {"state": STATE_FROM_PREVIOUS_RESPONSE}}'
Server-managed state also unlocks background continuation. Send a turn with "detach": true and the response comes back immediately with finishReason "detached" and a pending snapshotId, while the turn keeps running on the server:
curl -X POST http://localhost:8080/agents/chat \
-H "Content-Type: application/json" \
-d '{"data": {"message": {"role": "user", "content": [{"text": "Plan a two-week Japan itinerary."}]}, "detach": true}}'
The companion endpoints follow the conversation from there. Each is a POST that carries the snapshotId in the {"data": ...} body and returns the {"result": ...} envelope, the same convention as the turn route. Poll the pending snapshot until its status leaves "pending" (the final state carries the result), using the snapshotId from the detach response:
curl -X POST http://localhost:8080/agents/chat/getSnapshot \
-H "Content-Type: application/json" \
-d '{"data": {"snapshotId": "SNAPSHOT_ID"}}'
Or abort the background work instead; an aborted snapshot finalizes with status "aborted":
curl -X POST http://localhost:8080/agents/chat/abort \
-H "Content-Type: application/json" \
-d '{"data": {"snapshotId": "SNAPSHOT_ID"}}'
Failures come in two tiers. A failed turn (e.g. the model call errors) still returns HTTP 200: the result reports finishReason "failed", a structured error ({status, message, details}), and the last-good conversation state (or a recovery snapshot ID), so the client can retry the turn without losing the conversation. A rejected init (an unknown session or snapshot ID, state sent to a store-backed agent) fails the request itself with a 4xx error before any turn runs.