feat(go/core): add options-struct New*ActionOf constructors and delete registry-taking Define* helpers - #5862
Open
apascal07 wants to merge 10 commits into
Open
feat(go/core): add options-struct New*ActionOf constructors and delete registry-taking Define* helpers#5862apascal07 wants to merge 10 commits into
New*ActionOf constructors and delete registry-taking Define* helpers#5862apascal07 wants to merge 10 commits into
Conversation
Contributor
There was a problem hiding this comment.
Code Review
This pull request refactors the action definition and registration API in Genkit by deprecating flat-argument constructors (e.g., NewAction, NewBackgroundAction) in favor of options-based constructors (e.g., NewActionOf, NewBackgroundActionOf) that accept a new ActionOptions struct. It also removes global Define* helpers in favor of explicit creation and registration (e.g., calling .Register(r) or r.RegisterSchema). Feedback on the changes suggests simplifying the description assignment in go/ai/exp/agent.go by setting it directly on the BidiActionOptions struct instead of using a conditional block.
ConvertToExact converts a dynamically typed value to T without coercing between mismatched Go types: exactly T, *T, or map[string]any (JSON wire form) are accepted, anything else errors wrapping ErrTypeMismatch. SchemaMapFor infers a JSON schema from a type parameter, returning nil for interface types. Both back the upcoming typed-config constructors and are reusable by plugins.
…tructors Adds core.ActionOptions covering description, metadata, and all three schema slots (output and stream previously had no override at all), and New[Streaming]ActionWithOptions, NewBackgroundActionWithOptions, and NewBidiActionWithOptions constructors that lead with the action type, matching ResolveActionFor. Only New* constructors are added; registration composes via the existing Register methods. The flat-argument New*/Define* constructors are deprecated and delegate to the new ones, so descriptors are built on one code path (pinned by TestDeprecatedConstructorsDelegate). NewBackgroundActionWithOptions no longer leaks the start action's schema slots into the check/cancel sub-actions; they keep the shared description and metadata but infer their own Operation schemas. BidiActionOptions gains Description.
…ructors Moves flows, tools, prompts, resources, agent snapshot/abort actions, and the bidi tests off the deprecated flat-argument core constructors onto New*WithOptions + Register. No behavior change; plugins migrate in follow-up PRs.
NewActionOf, NewStreamingActionOf, NewBackgroundActionOf, and NewBidiActionOf read as "new action of <type>" with the leading action type argument, and drop the WithOptions mouthful. These names shipped earlier on this branch and were never released, so this is a rename, not a break.
…dActionOptions The cancel function is optional, so it belongs in the options struct rather than as a trailing nil-able positional argument, mirroring how BidiActionOptions carries the bidi-specific InitSchema slot. It is generic in the operation's output type, so it gets its own BackgroundActionOptions[Out] instead of a slot on the shared ActionOptions; a nil options value still infers cleanly from the start/check functions.
…ActionOptions data-only Options structs in this package hold descriptor data only; an action's implementation functions are positional constructor arguments, with optional ones accepting nil. Cancel is a third of the background action's implementation and its presence changes the registered surface (whether a cancel.operation action exists), so it moves back to a positional nil-able argument. BackgroundActionOptions stays, but as the data-only per-shape options struct (ActionOptions minus the stream slot), which also makes it non-generic again. The invariant is documented on ActionOptions.
Matches background_action.go and the file's contents (BidiAction and its constructors). Test file follows.
The "dynamic" metadata marker means created at runtime outside any registry (ai.NewTool, ai.NewMultipartTool, and ai.NewResource stamp it). Registering such an action makes the marker false by definition, so Action.Register and BidiAction.Register now remove it instead of leaving stale construction-time state. This also makes New* + Register produce the same descriptor as the registry-taking Define helpers, unblocking their removal.
A registry is unobtainable outside the framework: plugins return actions from Init for the framework to register and applications go through the genkit package, so the registry-taking Define helpers had no reachable external callers. Instead of carrying them through a deprecation cycle, delete them; the genkit wrappers remain the user touchpoints and now compose New* + Register directly. Deleted: core.Define[Streaming]Action, core.DefineBackgroundAction, core.DefineBidiAction, core.Define[Streaming]Flow, core.DefineSchema, and core.DefineSchemaFor. Tests use package-local define helpers that compose New* + Register, which also exercises the composition path users are pointed at.
Makes the concrete action type names consistent: Action, BackgroundAction, BidiAction, Flow. The Def suffix carried no distinction since the action interface already lives at api.Action. The old name remains as a deprecated alias.
apascal07
force-pushed
the
ap/go-action-constructors
branch
from
July 31, 2026 22:28
6b639ec to
a0c6bfd
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reworks the
coreaction constructor surface as a non-breaking addition for the next minor release: options-struct constructors under new names (New*ActionOf), deprecated old constructors delegating to them, and outright deletion of the registry-takingDefine*helpers, which have no reachable external callers. This is the base PR of a train: the typed-config primitive constructors (ai.NewTyped*) build on it next, followed by plugin migrations.Options-struct action constructors
The
coreconstructors gain variants that lead with the action type (matchingResolveActionFor, which already leads with it) and take one options struct covering all schema slots. The names read as "new action of <type>".Before: metadata and the input schema are positional, and output and stream schemas have no override at all.
After: all schema slots share one inference and override path.
core.BackgroundActionDefis renamed toBackgroundActionso the concrete action type names are consistent (Action,BackgroundAction,BidiAction,Flow); theDefsuffix carried no distinction since the action interface already lives atapi.Action. The old name remains as a deprecated alias, mirroring the existingActionDefalias.Options structs hold descriptor data only (documented on
ActionOptions); implementation functions are positional, with optional ones nil-able, so the background cancel function stays a trailing argument.NewBackgroundActionOftakes its own data-onlyBackgroundActionOptions(ActionOptionsminus the stream slot, since the component actions are non-streaming) and no longer leaks the start action's schema slots into the check/cancel sub-actions; they keep the shared description and metadata but infer their ownOperationschemas. The bidi constructors already took an options struct, so theirOfvariant only changes the argument order;BidiActionOptionsgainsDescriptionto matchActionOptions.All framework-internal call sites (flows, tools, prompts, resources, generate, agent snapshot/abort actions) now use the new constructors.
New shared helpers back this and the follow-up typed-config work, reusable by in-repo plugins:
base.ConvertToExact(exact-type conversion withbase.ErrTypeMismatch) andbase.SchemaMapFor[T](schema inference that returns nil for interface types).core.InferSchemaMapremains the exported value-based helper.Registry-taking Define helpers deleted
A registry is unobtainable outside the framework: plugins return actions from
Initfor the framework to register, and applications go through the genkit package. So the registry-takingDefine*helpers incorehad no reachable external callers and are deleted outright rather than deprecated; the genkit wrappers remain the user touchpoints and now composeNew* + Registerdirectly.Deleted:
DefineAction,DefineStreamingAction,DefineBackgroundAction,DefineBidiAction,DefineFlow,DefineStreamingFlow,DefineSchema,DefineSchemaFor.To make
New* + Registerfully equivalent to the oldDefine*, the"dynamic"metadata marker ("created at runtime, outside any registry") is now registration-derived:Registerremoves it instead of leaving stale construction-time state (pinned by test; nothing in the Go codebase reads the flag).Deprecations
Deprecated, delegating to the new functions with identical behavior:
core.NewAction,core.NewStreamingAction,core.NewBackgroundAction,core.NewBidiAction(each pointing at itsNew*ActionOfcounterpart).When the deprecated functions are removed in the next major, the new ones can collapse back to the plain names with the same signatures, so migrating now is the last rename.
Scope
Define*Ofsurface. Registration composes through the existingRegistermethods, so a parallelDefine*family would only beNew* + Registerunder a second name. The genkit wrappers stay the registering touchpoint.BackgroundActionOptions. Holding aCancelOpFunc[Out]would force the options struct to become generic overOutfor one optional field, so it stays a nil-able trailing argument and the struct stays data-only.aiandgenkitlayers are untouched here. Their constructors move in feat(go/ai): add typed-configNewTyped*constructors #5849, which builds on this; plugin migrations follow that.Verification
Go 1.26.3, full
go build ./...andgo test ./...ingo/: 40 packages with tests pass, no failures.New coverage in
core/action_options_test.go: each schema slot is inferred when the option is nil and honored when set,Descriptionwins overMetadata["description"]and falls back to it, a streaming action infers its stream schema, the deprecated constructors delegate to theirOfcounterparts, andRegisterclears the"dynamic"marker.core/define_test.goholds test-localNew* + Registerhelpers standing in for the deleted registry-takingDefine*, so the existing suites keep exercising the same construction paths under the new constructors.