🧩 gopact-ext
Chinese documentation: README_zh.md
Official extensions for the redesigned gopact core.
Go 1.27+ only. Until Go 1.27.0 is released, use the Go 1.27 RC 2 toolchain. gopact-ext now publishes stable versions only.
The committed go.work joins every module in this repository. Cross-repository CI also
tests the extension sources against the current gopact and example sources without
changing any published dependency contract.
Extensions are versioned by domain module, and one module may contain several packages.
Add only the modules that contain the packages you use:
go get github.com/gopact-ai/gopact-ext/agents/react@v0.4.0
go get github.com/gopact-ai/gopact-ext/models/agnes@v0.2.0
go get github.com/gopact-ai/gopact-ext/stores@v0.2.0
The root module is no longer an umbrella that installs every extension. The
release manifest lists every domain module and
its declared release version.
Release verification
The manifest defines the release order. Each row names a module, its exact stable
version, and a package to compile from a clean consumer. Every row must name a real
package. The verifier uses a controlled module path below the extension Agent namespace,
so it can compile the repository's internal release anchors without making them public.
PUBLISHED_PREFIX is the longest leading sequence of manifest rows whose exact versions
are already available through the configured module proxy. When changing an earlier row,
lower the prefix to the preceding row in the release-preparation commit. Advance it only
after the new exact version is available; omitting the prefix checks the full manifest:
./scripts/clean-consumer.sh --validate-only scripts/release-versions.txt
./scripts/clean-consumer.sh --prefix-count N scripts/release-versions.txt
./scripts/clean-consumer.sh scripts/release-versions.txt
The script starts from an empty consumer, checks exact selected versions, and rejects missing modules, duplicate modules, packages outside their module, consumer or tagged-module replace directives, pseudo-versions, and v0.0.0. --validate-only checks manifest structure without downloading tags. During staged publication, only a successful prefix is release evidence.
Extension catalog
Model adapters
| Package |
Use it for |
models/openai |
OpenAI chat, Responses, embeddings, moderation, media, files, and multipart uploads |
models/openai/codex |
ChatGPT-plan Codex calls, account model discovery, and subscription usage |
models/agnes |
Agnes chat, model discovery, image generation/editing, and asynchronous video |
models/glm |
GLM Coding Plan chat and usage plus general embeddings, media, tools, files, and agents |
models/fake |
Deterministic offline tests and examples |
Provider capabilities reflect public upstream contracts rather than a fabricated lowest common denominator:
| Provider |
Generation and runtime APIs |
Model discovery |
Usage and quota |
| OpenAI API key |
Chat/Completions/Responses, embeddings, moderation, images, audio, videos, files, and multipart uploads |
List and retrieve models |
Organization usage and costs through a separate AdminClient and Admin API key |
| ChatGPT Codex OAuth |
Responses SSE model calls |
Models enabled for the signed-in ChatGPT account |
ChatGPT plan windows, credits, spending control, and additional limits |
| GLM/Z.AI API key |
Coding Plan chat; async chat, embeddings, moderation, image/video, speech/transcription, tools, files/document parsing, OCR, and specialized agents |
List and retrieve general API models |
Coding Plan quota plus model and tool usage |
| Agnes API key |
Chat, image generation/editing, and asynchronous video |
API model list |
Not exposed: Agnes has no documented public API-key subscription-usage endpoint |
| Fake |
Deterministic chat and embeddings |
One deterministic model |
Not applicable |
OpenAI organization usage is API-platform metering and is not the same thing as ChatGPT/Codex subscription usage. Agnes does not implement gopact.Embedder because no public Agnes embedding contract is documented.
Authentication
Agent compositions
The former agents/deep and agents/deepresearch packages have been removed.
They were opinionated end-to-end compositions and have no drop-in replacement.
Applications that still import them can remain on the root module at v0.6.0
while migrating. Finish or drain persisted runs created by those packages before
upgrading; newer code cannot reconstruct or resume their checkpoints.
Stores
| Package |
Use it for |
stores/dbstore |
Shared GORM checkpoint, lease, fencing, RunLog, and retention logic |
stores/sqlite |
Pure-Go local persistence using SQLite rollback journal mode |
stores/mysql |
Multi-host persistence on MySQL |
stores/mariadb |
Multi-host persistence on MariaDB through the MySQL dialect |
stores/postgres |
Multi-host persistence on PostgreSQL |
Middleware
| Package |
Use it for |
middleware/byted/fornax |
ByteDance-specific middleware for reporting Agent, Workflow, and node traces to Fornax |
For complete runnable applications, see gopact-examples.
Every official Agent expresses its algorithmic state machine as one Workflow. Workflow exclusively owns checkpoint, interrupt/resume, child lineage, node facts, and control history; the Agent layer retains model, tool, planning, routing, and research behavior.
Durable Agent execution
Workflow-backed Agent constructors expose WithWorkflowOptions, so production persistence and lease policy can be configured without bypassing the official Agent:
if err := sqlite.Migrate("agent.db"); err != nil { // deployment migration stage
return err
}
store, err := sqlite.Open("agent.db")
if err != nil {
return err
}
defer store.Close()
target, err := react.New(identity, model, react.WithWorkflowOptions(
workflow.WithStore(store),
workflow.WithCheckpointLease(3*time.Minute, time.Minute),
))
if err != nil {
return err
}
response, err := target.Invoke(ctx, request, gopact.WithRunID("run-123"))
Durable resume requires reconstructing the same Agent topology with the same identity name and version, opening the same Store, and resuming the same RunID. Do not supply a conflicting SessionID. External side effects remain at-least-once and must use a key stable across recovery, such as RunInfo.RunID + "/" + RunInfo.ActivationID.
That key is reliable only when the external API natively deduplicates it, or when application code writes a uniquely constrained dedup/outbox record in the same database transaction as its business data. gopact cannot atomically combine a checkpoint transaction with an arbitrary remote API and does not provide a generic outbox. An explicit business retry intended to produce another side effect must use a new operation key.
Use workflow.MemoryStore only for tests and short-lived processes. The SQLite Store is for one machine or multiple processes that safely share the same local database file. File databases require journal_mode=DELETE; explicit non-DELETE DSNs are rejected, and the first conversion of a persistent WAL database needs a maintenance window with all other SQLite connections stopped. SQLite, MySQL, MariaDB, and PostgreSQL all use Migrate(dsn) in the deployment stage followed by Open(dsn) in application instances; a true in-memory SQLite database is initialized by Open. Multi-host deployments should use the MySQL, MariaDB, or PostgreSQL Store. These stores derive lease expiry from the database clock inside the ownership transaction. For an existing schema, stop and drain all old writers before migration. The database advisory lock serializes migrators but does not make mixed-version writers safe. Schedule terminal and standalone-journal purge; exceptionally long active Runs can compact only their confirmed contiguous prefix with explicit AllowHistoryLoss, because the removed Retry/Fork/audit history cannot be reconstructed.
Breaking migration
This rebuild ships all affected modules at their next pre-v1 minor rather than reusing an old patch line.
| Previous entry point |
Replacement |
Root github.com/gopact-ai/gopact-ext as an extension bundle |
Add the domain module that contains the Agent, model, Store, or middleware package you use |
react.New(ChatModel, *tools.Registry, ...) / NewModelAgent |
react.New(agent.Identity, gopact.Model, ...Option) with tools supplied by WithTools(...agent.Tool) |
agenttool.New(a2a.Agent, ...Option) |
agenttool.New(gopact.ToolSpec, agent.Agent, agenttool.Adapter); the child executes as a typed Workflow invokable |
graph/template-based planexec and supervisor |
immutable agent.Directory plus package Planner/Replanner/Decider contracts; Workflow stores state and execution facts |
planexec.Planner.Plan(context.Context, planexec.PlanInput) |
planexec.Planner.Plan(context.Context, agent.Request); Replanner receives the current plan and completed step results |