Uh oh!
There was an error while loading. Please reload this page.
feat(js): implemented defineAgent - #5251
Conversation
…ectly into `ActionParams` and removing the separate `BidiActionParams` interface.
…eamline run/stream types
… lifecycle management with proper cleanup
…alues and add supporting test case
Add support for an `init` parameter in the action run pipeline to establish long-running session states. This propagates the parameter through the reflection server (v1 and v2), API schemas, and includes tests for both streaming and non-streaming action invocations.
Add `init` parameter to `streamFlow` and `runFlow` client functions and propagate it through the Express handler to action execution. This allows passing initialization data (defined via `initSchema`) from clients to flows and actions. Includes tests and documentation.
Stamp the agent's root action span with the session ID under "genkit:metadata:agent:sessionId" so traces from the same conversation can be correlated. This mirrors the JS agent (PR #5251), which sets the attribute once on the action span via setCustomMetadataAttributes; Go has no such helper, so the genkit:metadata: prefix is inlined. Align the per-turn span shape with JS's run() too: name "runTurn-N" (1-indexed) with type flowStep and no subtype, replacing "agent/turn/N".
Implement file-system snapshot watching for FileSessionStore using fs.watch with a polling fallback to backstop missed events on filesystems like network mounts. Callbacks are de-duplicated by serialized content and transient read errors are swallowed. Add configurable snapshotWatchPollIntervalMs option (defaulting to 2000ms) to control the polling fallback interval.
Add two construction options to localstore.FileSessionStore, mirroring the JS FileSessionStore (PR #5251): - WithMaxPersistedChainLength(n): on each save, walk the new snapshot's parentId chain and unlink rows past the newest n, capping per-conversation disk use. n must be >= 1; 0 or negative is rejected. - WithSnapshotPathPrefix(fn): derive a per-call subdirectory from context for tenant isolation. The prefix may nest via "/" and is sanitized against directory escape. Snapshots remain flat by id within the prefix (<dir>/<prefix>/<snapshotId>.json), so resume-by-snapshot, heartbeat, finalize, abort, and status subscription stay O(1) direct opens, while GetLatestSnapshot scans the prefix directory. With no options configured the on-disk layout is unchanged. Options follow the ai/option.go interface pattern (in a new option.go) and error if set more than once.
Add a per-turn chunk buffer in SessionRunner that captures all stream chunks emitted during a turn and stamps them onto the turn's trace span as a serialized JSON array (agent:chunks). This ensures traces capture everything that was streamed during each turn. The recording is best-effort, absorbing serialization or span-context failures so trace bookkeeping never fails an otherwise-successful turn.
Add `promptInput` option to `definePromptAgent` and `defineAgent` so a single prompt definition can be reused and customized across multiple agents (e.g. supplying different `role` or `tone` values). The new `I` type parameter provides type-checking against the prompt's input schema.
Remove the per-turn chunk buffer and recordTurnChunks logic that serialized streamed chunks onto the turn span. Instead, tag turn spans with the persisted snapshotId and emit the resulting session state as the turn span output, simplifying trace bookkeeping for both client- and server-managed agents.
Add generic `Init` type parameter to fastify handlers, flow wrappers, and helper types to support passing initialization data alongside input. The init data is extracted from request body and forwarded to action runs, including durable streaming.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Security: - json-patch: reject __proto__/prototype/constructor pointer tokens to prevent prototype pollution from server-sent patches. - FileSessionStore: validate snapshotId is a plain basename and assert the resolved path stays under the prefix dir (path traversal); serialize saves with a per-file lock and write atomically (temp file + rename). Correctness: - agent: an aborted turn now reports finishReason 'aborted' and skips the failed snapshot write instead of being reported as 'failed'. - session: deep-clone initial state and return a copy from getMessages() so handlers cannot reach back into caller/chat state. - agent client: bail before pushing the message when the abort signal is already aborted, and roll back the eagerly-pushed user message on a failed/aborted turn so it isn't re-sent next turn. Robustness: - agent: guard the parentId walk against cyclic chains (FAILED_PRECONDITION). - getSnapshot action now uses SessionSnapshotSchema instead of z.any(). Design: - drop invocationEnd + the snapshot `event` field + SnapshotEventSchema to align with the Go implementation (turn is the unit of persistence). - rename the remote agent client path /state -> /getSnapshot (keep /abort). - document the single-flight turn assumption and the in-order/no-loss customPatch transport requirement.
…ort{Request,Response}SchemaThe override was identical to the base GenkitAI.currentSession except it threw SessionError instead of GenkitError(FAILED_PRECONDITION). Removing it lets GenkitBeta inherit the base, collapsing to a single error type for one method down the inheritance chain (per review feedback).
Add a stable sessionId identifier to correlate snapshots and turns of a conversation. The sessionId is tracked on AgentChatImpl and exposed on both AgentChat and AgentResponse interfaces, with a fallback getter so server-managed agents that omit sessionId on the wire still resolve it from the chat's tracked value.
Allow specifying a human-readable description when defining a prompt agent, which is surfaced on the agent action's metadata. The description is now propagated from the prompt config through definePromptAgent and defineAgent.
Introduces
defineAgentand friends: a first-class, multi-turn agent API for Genkit JS. An agent bundles a model/prompt, conversational state, tool loops, interrupts, persistence, streaming, and abort/resume into a single ergonomic, transport-agnostic surface that runs identically in-process on the server and over HTTP from a browser.Highlights
snapshotId/statefor you.stateSchema).SessionStore(in-memory + file stores included), with server-managed sessions resumable bysessionId.restart/respond) for human-in-the-loop tools.clientTransformto redact/reshape state and stream chunks before they leave the server.AgentAPIis returned byai.defineAgent(...)on the server andremoteAgent(...)on the client.1. Define an agent
The headline API — one call wires up a prompt and a multi-turn agent:
Prompt-driven (reuse a registered
.prompt), with typedpromptInput:Full control via a custom turn handler:
2. Chat: send & stream
chat()returns a stateful conversation that tracksstate,messages,snapshotId, andsessionIdso you don't thread them by hand:3. Typed custom state
4. Persistence & resuming sessions
Attach a
SessionStoreto make an agent server-managed: turns are persisted as snapshots and a chat can be resumed later bysessionId(no need to track snapshot IDs) or by an exactsnapshotId:Built-in stores:
InMemorySessionStoreandFileSessionStore(with filesystem snapshot watching + configurable poll fallback). TheSessionStoreinterface uses an atomic mutator-basedsaveSnapshotto make concurrent writes (e.g. an abort racing a completion) safe.5. Interrupts & resume (human-in-the-loop)
When a tool interrupts, the turn finishes with
finishReason: 'interrupted'. Resume by either re-running the tool (restart) or supplying the answer directly (respond):6. Abort, detach & graceful failure
Failures resolve gracefully (
finishReason: 'failed') and preserve the last-good snapshot/state instead of corrupting the session; genuine API misuse throwsAgentInitError.7. Redact / reshape state for clients
8. Same API, server or browser
The server returns an
AgentAPI; the client gets the exact same shape fromremoteAgent(...), so UI code is identical whether it runs in-process or over HTTP:What's inside
js/ai/src/agent.ts—defineAgent/definePromptAgent/defineCustomAgent, schemas, session runner, finish reasons, error handling.js/ai/src/agent-core.ts— transport-agnosticAgentAPI/AgentChat/AgentResponse, in-process transport, custom-state patching.js/ai/src/session.ts,js/ai/src/session-stores.ts—Session,SessionStore,InMemorySessionStore,FileSessionStore, snapshot model + heartbeats.js/ai/src/json-patch.ts— minimal, pollution-safe JSON Patch used for streaming custom-state updates.js/genkit/src/client/*—remoteAgentHTTP client.js/genkit/src/beta.ts/genkit-beta.ts—ai.defineAgentetc. +ai.currentSession()exposed on the beta surface.agent_test.ts,agent_client_test.ts,session-stores_test.ts,json-patch_test.ts.Finish reasons:
stop,interrupted,failed,aborted,blocked,detached,unknown.Snapshot statuses:
pending,completed,failed,aborted,expired.