Define agents
In Genkit, agents are actions with conversation state. A standard agent renders a prompt on each turn, appends conversation history, calls the model, streams chunks, updates state, and optionally persists a snapshot. A custom agent keeps that runtime shell, but replaces the prompt-backed loop with your own code.
This page covers defining the agent itself. For when to choose an agent over a plain flow, see Full-stack agents.
Constructor choices
Section titled “Constructor choices”genkitx.DefineAgentkeeps inline prompt configuration beside the agent wiring. Use it for most prompt-backed agents.genkitx.DefinePromptAgentwraps a prompt that is already registered, including prompts loaded from Dotprompt files.genkitx.DefineCustomAgentreplaces the prompt loop with your own code, for a custom per-turn loop, direct session control, or multiple model calls.
All agents implement api.BidiAction, so transports and route helpers can serve them directly. Server-managed agents also expose typed snapshot helpers and companion actions.
Define a prompt-backed agent
Section titled “Define a prompt-backed agent”DefineAgent registers a prompt-backed agent from an aix.InlinePrompt. The inline prompt is a list of prompt options.
import ( aix "github.com/firebase/genkit/go/ai/exp" "github.com/firebase/genkit/go/ai/exp/localstore" genkitx "github.com/firebase/genkit/go/genkit/exp")store, err := localstore.NewFileSessionStore[TaskState]("./.genkit/snapshots/tasks")if err != nil { // Fails if the snapshot directory cannot be created or is not writable. log.Fatalf("open task store: %v", err)}
taskAgent := genkitx.DefineAgent(g, "taskAgent", aix.InlinePrompt{ ai.WithModelName("googleai/gemini-flash-latest"), ai.WithSystem("Manage a task list. Use tools when changing tasks."), ai.WithTools(addTaskTool, toggleTaskTool), }, aix.WithSessionStore(store), aix.WithDescription[TaskState]("Task management assistant"),)The agent’s custom state type is inferred from typed options such as WithSessionStore[TaskState], WithStateTransform[TaskState], or the explicit type argument on DefineAgent[TaskState].
Agent options
Section titled “Agent options”aix.WithSessionStore(store)persists snapshots and switches the agent to server-managed state.aix.WithStateTransform(fn)redacts or reshapes session state returned to clients and snapshot readers.aix.WithStreamTransform[State](fn)redacts or reshapes each streamed chunk before it is sent to clients.aix.WithDescription[State](text)adds a human-readable description to action metadata and developer tooling.aix.WithNamedPrompt[State](name, input)pointsDefinePromptAgentat a specific registered prompt and renders input.
Typed options are deliberately strict. Passing a state option with the wrong State type fails at compile time.
Wrap an existing prompt
Section titled “Wrap an existing prompt”DefinePromptAgent wraps a prompt already registered in the prompt registry. With no prompt-source option, it uses a prompt with the same name as the agent.
chef := genkitx.DefinePromptAgent[ChefState](g, "chef", aix.WithSessionStore(store), aix.WithDescription[ChefState]("Chef assistant loaded from ./prompts/chef.prompt"),)Use WithNamedPrompt when several agents share one prompt or when the prompt name differs from the agent name.
friendlyChef := genkitx.DefinePromptAgent[ChefState](g, "friendlyChef", aix.WithNamedPrompt[ChefState]("chef", map[string]any{ "personality": "friendly", }), aix.WithSessionStore(store),)The prompt input is rendered at definition time as a smoke test. If it does not satisfy the prompt schema, the constructor panics during setup rather than during the first request.
Define a custom agent implementation
Section titled “Define a custom agent implementation”DefineCustomAgent gives you the agent runtime without the built-in prompt loop. Use it for a custom per-turn loop, multiple model calls in one turn, or direct session control. The function receives a Responder for streaming and a SessionRunner for turn processing, messages, custom state, artifacts, and snapshots.
coder := genkitx.DefineCustomAgent(g, "coder", func(ctx context.Context, resp aix.Responder, sess *aix.SessionRunner[CoderState]) (*aix.AgentResult, error) { // Your own per-turn loop. See Custom orchestration for the full pattern. }, aix.WithSessionStore(store), aix.WithDescription[CoderState]("Concise code helper"),)See Custom orchestration for the runtime contract, a complete example, turn context, responder behavior, and failure handling.