core

package
v1.12.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2026 License: Apache-2.0 Imports: 15 Imported by: 14

Documentation

Overview

Package core implements Genkit actions and other essential machinery. This package is primarily intended for Genkit internals and for plugins. Genkit applications should use the genkit package.

Package core implements Genkit's foundational action system and runtime machinery.

This package is primarily intended for plugin developers and Genkit internals. Application developers should use the genkit package instead, which provides a higher-level, more convenient API.

Actions

Actions are the fundamental building blocks of Genkit. Every operation - flows, model calls, tool invocations, retrieval - is implemented as an action. Actions provide:

  • Type-safe input/output with JSON schema validation
  • Automatic tracing and observability
  • Consistent error handling
  • Registration in the action registry

Define a non-streaming action:

action := core.NewActionOf(api.ActionTypeCustom, "myAction", nil,
	func(ctx context.Context, input string) (string, error) {
		return "processed: " + input, nil
	},
)
action.Register(registry)

result, err := action.Run(context.Background(), "hello")

Define a streaming action that sends chunks during execution:

streamingAction := core.NewStreamingActionOf(api.ActionTypeCustom, "countdown", nil,
	func(ctx context.Context, start int, cb core.StreamCallback[string]) (string, error) {
		for i := start; i > 0; i-- {
			if cb != nil {
				if err := cb(ctx, fmt.Sprintf("T-%d", i)); err != nil {
					return "", err
				}
			}
			time.Sleep(time.Second)
		}
		return "Liftoff!", nil
	},
)
streamingAction.Register(registry)

Flows

Flows are user-defined actions that orchestrate AI operations. They are the primary way application developers define business logic in Genkit:

flow := core.NewFlow("myFlow",
	func(ctx context.Context, input string) (string, error) {
		// Use Run to create traced sub-steps
		result, err := core.Run(ctx, "step1", func() (string, error) {
			return process(input), nil
		})
		if err != nil {
			return "", err
		}
		return result, nil
	},
)
flow.Register(registry)

Streaming flows can send intermediate results to callers:

streamingFlow := core.NewStreamingFlow("generateReport",
	func(ctx context.Context, input Input, cb core.StreamCallback[Progress]) (Report, error) {
		for i := 0; i < 100; i += 10 {
			if cb != nil {
				cb(ctx, Progress{Percent: i})
			}
			// ... work ...
		}
		return Report{...}, nil
	},
)
streamingFlow.Register(registry)

Traced Steps with Run

Use Run within flows to create traced sub-operations. Each Run call creates a span in the trace that's visible in the Genkit Developer UI:

result, err := core.Run(ctx, "fetchData", func() (Data, error) {
	return fetchFromAPI()
})

processed, err := core.Run(ctx, "processData", func() (Result, error) {
	return process(result)
})

Middleware

Actions support middleware for cross-cutting concerns like logging, metrics, or authentication:

loggingMiddleware := func(next core.StreamingFunc[string, string, struct{}]) core.StreamingFunc[string, string, struct{}] {
	return func(ctx context.Context, input string, cb core.StreamCallback[struct{}]) (string, error) {
		log.Printf("Input: %s", input)
		output, err := next(ctx, input, cb)
		log.Printf("Output: %s, Error: %v", output, err)
		return output, err
	}
}

Chain multiple middleware together:

combined := core.ChainMiddleware(loggingMiddleware, metricsMiddleware)
wrappedFn := combined(originalFunc)

Schema Management

Register JSON schemas for use in prompts and validation:

// Register a schema from a map
registry.RegisterSchema("Person", map[string]any{
	"type": "object",
	"properties": map[string]any{
		"name": map[string]any{"type": "string"},
		"age":  map[string]any{"type": "integer"},
	},
	"required": []any{"name"},
})

// Register a schema inferred from a Go type (recommended)
registry.RegisterSchema("Person", core.InferSchemaMap(Person{}))

Schemas can be referenced in .prompt files by name.

Plugin Development

Plugins extend Genkit's functionality by providing models, tools, retrievers, and other capabilities. Implement the api.Plugin interface:

type MyPlugin struct {
	APIKey string
}

func (p *MyPlugin) Name() string {
	return "myplugin"
}

func (p *MyPlugin) Init(ctx context.Context) []api.Action {
	// Initialize the plugin and return actions to register
	model := ai.NewModelAction(...)
	tool := ai.NewTool(...)
	return []api.Action{model, tool}
}

For plugins that resolve actions dynamically (e.g., listing available models from an API), implement api.DynamicPlugin:

type DynamicModelPlugin struct{}

func (p *DynamicModelPlugin) ListActions(ctx context.Context) []api.ActionDesc {
	// Return descriptors of available actions
	return []api.ActionDesc{
		{Key: "/model/myplugin/model-a", Name: "model-a"},
		{Key: "/model/myplugin/model-b", Name: "model-b"},
	}
}

func (p *DynamicModelPlugin) ResolveAction(atype api.ActionType, id string) api.Action {
	// Create and return the action on demand
	return createModel(id)
}

Background Actions

For long-running operations, use background actions that return immediately with an operation ID that can be polled for completion:

bgAction := core.NewBackgroundActionOf(api.ActionTypeCustom, "longTask",
	&core.BackgroundActionOptions[Input, Output]{
		// Check polls operation status; omitting Cancel means the
		// action does not support cancellation.
		Check: func(ctx context.Context, op *core.Operation[Output]) (*core.Operation[Output], error) {
			return checkOperationStatus(op)
		},
	},
	func(ctx context.Context, input Input) (*core.Operation[Output], error) {
		// Start the operation
		return startLongOperation(input)
	},
)
bgAction.Register(registry)

Error Handling

Errors live in github.com/firebase/genkit/go/core/status. Classify a failure with a sentinel so callers can branch on it with errors.Is rather than by matching message text, and mark a message public only when it is safe to return to a client:

import "github.com/firebase/genkit/go/core/status"

Return user-facing errors with appropriate status codes:

if err := validate(input); err != nil {
	return nil, status.PublicErrorf(status.ErrInvalidArgument, "Invalid input").WithDetails(map[string]any{
		"field": "email",
		"error": err.Error(),
	})
}

For internal errors that should be logged but not exposed to users:

return nil, status.Errorf(status.ErrInternal, "database connection failed: %w", err)

Context

Access action context for metadata and configuration:

ctx := core.FromContext(ctx)
if ctx != nil {
	// Access action-specific context values
}

Set action context for nested operations:

ctx = core.WithActionContext(ctx, core.ActionContext{
	"requestId": requestID,
})

For more information, see https://genkit.dev/docs/plugins

Package core provides base error types and utilities for Genkit.

The error surface in this file is deprecated in favour of github.com/firebase/genkit/go/core/status, which unifies the two error types below into one and adds sentinel classification so callers can branch with errors.Is instead of matching on message text. Everything here is an alias or a thin wrapper over that package: GenkitError and status.Error are the same type, so an errors.As for either finds errors raised by any part of Genkit, old or new.

Example (RegisterSchema)

This example demonstrates registering a schema from a map.

package main

import (
	"fmt"

	"github.com/firebase/genkit/go/internal/registry"
)

func main() {
	r := registry.New()

	// Register a JSON schema defined as a map
	r.RegisterSchema("Address", map[string]any{
		"type": "object",
		"properties": map[string]any{
			"street": map[string]any{"type": "string"},
			"city":   map[string]any{"type": "string"},
			"zip":    map[string]any{"type": "string"},
		},
		"required": []any{"street", "city"},
	})

	fmt.Println("Schema registered: Address")
}
Output:
Schema registered: Address

Index

Examples

Constants

View Source
const (
	OK                  = status.OK
	CANCELLED           = status.Cancelled
	UNKNOWN             = status.Unknown
	INVALID_ARGUMENT    = status.InvalidArgument
	DEADLINE_EXCEEDED   = status.DeadlineExceeded
	NOT_FOUND           = status.NotFound
	ALREADY_EXISTS      = status.AlreadyExists
	PERMISSION_DENIED   = status.PermissionDenied
	UNAUTHENTICATED     = status.Unauthenticated
	RESOURCE_EXHAUSTED  = status.ResourceExhausted
	FAILED_PRECONDITION = status.FailedPrecondition
	ABORTED             = status.Aborted
	OUT_OF_RANGE        = status.OutOfRange
	UNIMPLEMENTED       = status.Unimplemented
	INTERNAL            = status.Internal
	UNAVAILABLE         = status.Unavailable
	DATA_LOSS           = status.DataLoss
)

Constants for canonical status names.

Deprecated: use the Go-cased constants in github.com/firebase/genkit/go/core/status (status.InvalidArgument, status.NotFound, ...). These alias them, so the values are identical and the wire format is unchanged.

View Source
const (
	// CodeOK means not an error; returned on success.
	CodeOK = 0
	// CodeCancelled means the operation was cancelled, typically by the caller.
	CodeCancelled = 1
	// CodeUnknown means an unknown error occurred.
	CodeUnknown = 2
	// CodeInvalidArgument means the client specified an invalid argument.
	CodeInvalidArgument = 3
	// CodeDeadlineExceeded means the deadline expired before the operation could complete.
	CodeDeadlineExceeded = 4
	// CodeNotFound means some requested entity (e.g., file or directory) was not found.
	CodeNotFound = 5
	// CodeAlreadyExists means the entity that a client attempted to create already exists.
	CodeAlreadyExists = 6
	// CodePermissionDenied means the caller does not have permission to execute the operation.
	CodePermissionDenied = 7
	// CodeUnauthenticated means the request does not have valid authentication credentials.
	CodeUnauthenticated = 16
	// CodeResourceExhausted means some resource has been exhausted.
	CodeResourceExhausted = 8
	// CodeFailedPrecondition means the operation was rejected because the system is not in a state required.
	CodeFailedPrecondition = 9
	// CodeAborted means the operation was aborted, typically due to some issue.
	CodeAborted = 10
	// CodeOutOfRange means the operation was attempted past the valid range.
	CodeOutOfRange = 11
	// CodeUnimplemented means the operation is not implemented or not supported/enabled.
	CodeUnimplemented = 12
	// CodeInternal means internal errors. Some invariants expected by the underlying system were broken.
	CodeInternal = 13
	// CodeUnavailable means the service is currently unavailable.
	CodeUnavailable = 14
	// CodeDataLoss means unrecoverable data loss or corruption.
	CodeDataLoss = 15
)

Constants for canonical status codes (integer values).

Deprecated: use status.Name.Code.

Variables

View Source
var ErrActionCompleted = status.ErrFailedPrecondition.Subtype("action has completed")

ErrActionCompleted indicates a Send on a connection whose action has already returned. Test with errors.Is; the action's result is available via BidiConnection.Output.

View Source
var ErrConnectionClosed = status.ErrFailedPrecondition.Subtype("connection is closed")

ErrConnectionClosed indicates a Send on a connection whose input side was closed with BidiConnection.Close. Test with errors.Is.

StatusNameToCode maps status names to their integer code values.

Deprecated: use status.Name.Code, which is correct for every name rather than only the ones present in this map.

Functions

func FlowNameFromContext added in v1.0.0

func FlowNameFromContext(ctx context.Context) string

FlowNameFromContext returns the flow name from context if we're in a flow, empty string otherwise.

func HTTPStatusCode deprecated added in v0.5.3

func HTTPStatusCode(name StatusName) int

HTTPStatusCode gets the corresponding HTTP status code for a given Genkit status name.

Deprecated: use status.Name.HTTPCode.

func InferSchemaMap added in v0.7.0

func InferSchemaMap(value any) map[string]any

InferSchemaMap infers a JSON schema from a Go value and converts it to a map.

Example

This example demonstrates registering a schema inferred from a Go type.

package main

import (
	"fmt"

	"github.com/firebase/genkit/go/core"
	"github.com/firebase/genkit/go/internal/registry"
)

func main() {
	r := registry.New()

	// Define a struct type
	type Person struct {
		Name string `json:"name"`
		Age  int    `json:"age"`
	}

	// Register the inferred schema; it can then be referenced in .prompt files
	r.RegisterSchema("Person", core.InferSchemaMap(Person{}))

	fmt.Println("Schema registered")
}
Output:
Schema registered

func ResolveSchema added in v1.3.0

func ResolveSchema(r api.Registry, schema map[string]any) (map[string]any, error)

ResolveSchema resolves a schema that may contain a $ref to a registered schema. If the schema contains a $ref with the "genkit:" prefix, it looks up the schema by name. Returns the original schema if no $ref is present, or the resolved schema if found. Returns an error if the schema reference cannot be resolved.

func Run added in v0.3.0

func Run[Out any](ctx context.Context, name string, fn func() (Out, error)) (Out, error)

Run runs the function f in the context of the current flow and returns what f returns. It returns an error if no flow is active.

Each call to Run results in a new step in the flow. A step has its own span in the trace, and its result is cached so that if the flow is restarted, f will not be called a second time.

The step's context is not available to fn, so anything inside it that takes a context and traces its own work, such as an HTTP client or a database call, reports against the enclosing flow rather than against this step. Use RunWithContext for those; keep Run for pure work that traces nothing.

Example

This example demonstrates using Run to create traced sub-steps.

package main

import (
	"context"
	"fmt"
	"strings"

	"github.com/firebase/genkit/go/core"
	"github.com/firebase/genkit/go/internal/registry"
)

func main() {
	r := registry.New()

	// Create a flow that uses Run for traced steps
	flow := core.NewFlow("pipeline",
		func(ctx context.Context, input string) (string, error) {
			// Each Run creates a traced step visible in the Dev UI
			upper, err := core.Run(ctx, "toUpper", func() (string, error) {
				return strings.ToUpper(input), nil
			})
			if err != nil {
				return "", err
			}

			result, err := core.Run(ctx, "addPrefix", func() (string, error) {
				return "RESULT: " + upper, nil
			})
			return result, err
		},
	)
	flow.Register(r)

	result, err := flow.Run(context.Background(), "hello")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println(result)
}
Output:
RESULT: HELLO

func RunWithContext added in v1.12.0

func RunWithContext[Out any](ctx context.Context, name string, fn func(context.Context) (Out, error)) (Out, error)

RunWithContext is Run with the step's own context passed to fn.

Work that fn starts with that context nests under the step in the trace instead of under the flow, which is what makes a step's span cover the calls it is timing:

file, err := core.RunWithContext(ctx, "upload-image", func(ctx context.Context) (*File, error) {
	return client.Files.Upload(ctx, path) // its spans nest under "upload-image"
})

Passing the enclosing context instead of the one supplied here is the whole difference, and it is silent: the step still records the right duration while the calls it made appear beside it rather than beneath it.

func SchemaRef added in v1.3.0

func SchemaRef(name string) map[string]any

SchemaRef returns a JSON schema reference map for the given name.

func WithActionContext added in v0.3.0

func WithActionContext(ctx context.Context, actionCtx ActionContext) context.Context

WithActionContext returns a new Context with Action runtime context (side channel data) value set.

func WithFlowContext added in v1.10.0

func WithFlowContext(ctx context.Context, flowName string) context.Context

WithFlowContext attaches flow-context metadata to ctx so that Run and FlowNameFromContext work from within. Use it when wiring a custom flow-like action (e.g. via NewBidiActionOf) that should behave like a flow from the user's perspective — letting them call Run for sub-step tracking and see the flow name in spans — without going through the flow constructors.

The flow constructors attach this context themselves; direct callers only need it when bypassing them, e.g. to set custom BidiActionOptions.

Types

type Action

type Action[In, Out, Stream any] struct {
	// contains filtered or unexported fields
}

An Action is a named, observable operation that underlies all Genkit primitives. It consists of a function that takes an input of type In and returns an output of type Out, optionally streaming values of type Stream incrementally by invoking a callback.

It optionally has other metadata, like a description and JSON Schemas for its input and output which it validates against.

Each time an Action is run, it results in a new trace span.

For internal use only.

func LookupActionFor deprecated

func LookupActionFor[In, Out, Stream any](r api.Registry, atype api.ActionType, name string) *Action[In, Out, Stream]

LookupActionFor returns the action for the given key in the global registry, or nil if there is none. It panics if the action is of the wrong api.

Deprecated: Use ResolveActionFor.

func NewAction deprecated added in v0.6.0

func NewAction[In, Out any](
	name string,
	atype api.ActionType,
	metadata map[string]any,
	inputSchema map[string]any,
	fn Func[In, Out],
) *Action[In, Out, struct{}]

NewAction creates a new non-streaming Action without registering it. If inputSchema is nil, it is inferred from the function's input type.

Deprecated: Use NewActionOf, which takes the action type first and an ActionOptions struct covering all schema slots.

func NewActionOf added in v1.12.0

func NewActionOf[In, Out any](
	atype api.ActionType,
	name string,
	opts *ActionOptions,
	fn Func[In, Out],
) *Action[In, Out, struct{}]

NewActionOf creates a new non-streaming Action without registering it.

func NewStreamingAction deprecated added in v0.7.0

func NewStreamingAction[In, Out, Stream any](
	name string,
	atype api.ActionType,
	metadata map[string]any,
	inputSchema map[string]any,
	fn StreamingFunc[In, Out, Stream],
) *Action[In, Out, Stream]

NewStreamingAction creates a new streaming Action without registering it. If inputSchema is nil, it is inferred from the function's input type.

Deprecated: Use NewStreamingActionOf, which takes the action type first and an ActionOptions struct covering all schema slots.

func NewStreamingActionOf added in v1.12.0

func NewStreamingActionOf[In, Out, Stream any](
	atype api.ActionType,
	name string,
	opts *ActionOptions,
	fn StreamingFunc[In, Out, Stream],
) *Action[In, Out, Stream]

NewStreamingActionOf creates a new streaming Action without registering it.

func ResolveActionFor added in v0.6.2

func ResolveActionFor[In, Out, Stream any](r api.Registry, atype api.ActionType, name string) *Action[In, Out, Stream]

ResolveActionFor returns the action for the given key in the global registry, or nil if there is none. It panics if the action is of the wrong type. That includes bidi actions, which are a distinct type; resolve those via ResolveBidiActionFor.

func (*Action[In, Out, Stream]) Desc added in v0.0.2

func (a *Action[In, Out, Stream]) Desc() api.ActionDesc

Desc returns a descriptor of the action with resolved schema references. Schema references that cannot be resolved (e.g., the action is not yet registered, or the referenced schema has not been defined) are returned as-is.

func (*Action[In, Out, Stream]) Name

func (a *Action[In, Out, Stream]) Name() string

Name returns the Action's Name.

func (*Action[In, Out, Stream]) Register added in v0.7.0

func (a *Action[In, Out, Stream]) Register(r api.Registry)

Register registers the action with the given registry.

Register writes the action's registry reference (and, on definition-time registration, its metadata) without synchronization, like the constructors it composes with. Register an action before sharing it across goroutines; registering one that is concurrently in use is a data race.

func (*Action[In, Out, Stream]) Run

func (a *Action[In, Out, Stream]) Run(ctx context.Context, input In, cb StreamCallback[Stream]) (output Out, err error)

Run executes the Action's function in a new trace span.

func (*Action[In, Out, Stream]) RunJSON added in v0.0.2

func (a *Action[In, Out, Stream]) RunJSON(ctx context.Context, input json.RawMessage, cb StreamCallback[json.RawMessage]) (json.RawMessage, error)

RunJSON runs the action with a JSON input, and returns a JSON result.

func (*Action[In, Out, Stream]) RunJSONWithTelemetry added in v1.10.0

func (a *Action[In, Out, Stream]) RunJSONWithTelemetry(ctx context.Context, input json.RawMessage, cb StreamCallback[json.RawMessage]) (*api.ActionRunResult[json.RawMessage], error)

RunJSONWithTelemetry runs the action with a JSON input, and returns a JSON result along with telemetry info.

type ActionContext added in v0.3.0

type ActionContext = map[string]any

ActionContext is the runtime context for an Action.

func FromContext added in v0.3.0

func FromContext(ctx context.Context) ActionContext

FromContext returns the Action runtime context (side channel data) from context.

type ActionDef deprecated added in v0.3.0

type ActionDef[In, Out, Stream any] = Action[In, Out, Stream]

ActionDef is the previous name for Action.

Deprecated: use Action.

type ActionOptions added in v1.12.0

type ActionOptions struct {
	// Description is the action's human-readable description and is the field
	// tooling reads. When empty, Metadata["description"] is used if present,
	// which is how the deprecated flat constructors supply one. The fallback
	// is one-way: Metadata reaches the descriptor exactly as given, so a
	// caller setting both to different strings gets Description on the
	// descriptor and its own value left in the metadata map.
	Description string
	// Metadata is arbitrary key-value data attached to the action descriptor.
	Metadata map[string]any
	// InputSchema is the JSON schema for the action's input. Inferred from In if nil.
	InputSchema map[string]any
	// OutputSchema is the JSON schema for the action's output. Inferred from Out if nil.
	OutputSchema map[string]any
	// StreamSchema is the JSON schema for outgoing stream chunks. Inferred
	// from Stream if nil; when nil, non-streaming actions advertise none. An
	// explicit schema is always advertised as given.
	StreamSchema map[string]any
}

ActionOptions configures the optional attributes of an Action. A nil options value is valid: schemas are inferred from the action's type parameters and the descriptor carries no metadata.

Options structs in this package hold descriptor data (schemas, metadata), so a constructor reads as: identity, descriptor, implementation. An action's primary function is always a positional constructor argument, and typed customization of a single-function action composes by wrapping that function, which is why this struct stays non-generic. A bundle with separately-invoked lifecycle functions (a background action's check and cancel) carries them as typed options fields instead; holding those is what makes such an options struct generic. See BackgroundActionOptions.

type BackgroundAction added in v1.12.0

type BackgroundAction[In, Out any] struct {
	// contains filtered or unexported fields
}

BackgroundAction is a background action that can be used to start, check, and cancel background operations. It promotes the start action's methods (Name, Desc, Run, RunJSON), so it can be used anywhere an api.Action is accepted.

func LookupBackgroundAction added in v1.3.0

func LookupBackgroundAction[In, Out any](r api.Registry, key string) *BackgroundAction[In, Out]

LookupBackgroundAction looks up a background action by key (which includes the action type, provider, and name).

func NewBackgroundAction deprecated added in v1.3.0

func NewBackgroundAction[In, Out any](
	name string,
	atype api.ActionType,
	metadata map[string]any,
	startFn StartOpFunc[In, Out],
	checkFn CheckOpFunc[Out],
	cancelFn CancelOpFunc[Out],
) *BackgroundAction[In, Out]

NewBackgroundAction creates a new background action without registering it.

Deprecated: Use NewBackgroundActionOf, which takes the action type first and a BackgroundActionOptions struct covering the schema slots and the check and cancel functions.

func NewBackgroundActionOf added in v1.12.0

func NewBackgroundActionOf[In, Out any](
	atype api.ActionType,
	name string,
	opts *BackgroundActionOptions[In, Out],
	startFn StartOpFunc[In, Out],
) *BackgroundAction[In, Out]

NewBackgroundActionOf creates a new background action without registering it. Register it with BackgroundAction.Register.

startFn starts an operation; the rest of the operation lifecycle rides in opts: BackgroundActionOptions.Check is required and BackgroundActionOptions.Cancel is optional.

func (*BackgroundAction[In, Out]) Cancel added in v1.12.0

func (b *BackgroundAction[In, Out]) Cancel(ctx context.Context, op *Operation[Out]) (*Operation[Out], error)

Cancel attempts to cancel a background operation. It returns an error if the background action does not support cancellation.

func (*BackgroundAction[In, Out]) Check added in v1.12.0

func (b *BackgroundAction[In, Out]) Check(ctx context.Context, op *Operation[Out]) (*Operation[Out], error)

Check checks the status of a background operation.

func (*BackgroundAction[In, Out]) Register added in v1.12.0

func (b *BackgroundAction[In, Out]) Register(r api.Registry)

Register registers the model with the given registry.

func (*BackgroundAction[In, Out]) Start added in v1.12.0

func (b *BackgroundAction[In, Out]) Start(ctx context.Context, input In) (*Operation[Out], error)

Start starts a background operation.

func (*BackgroundAction[In, Out]) SupportsCancel added in v1.12.0

func (b *BackgroundAction[In, Out]) SupportsCancel() bool

SupportsCancel returns whether the background action supports cancellation.

type BackgroundActionDef deprecated added in v1.3.0

type BackgroundActionDef[In, Out any] = BackgroundAction[In, Out]

BackgroundActionDef is the previous name for BackgroundAction.

Deprecated: use BackgroundAction.

type BackgroundActionOptions added in v1.12.0

type BackgroundActionOptions[In, Out any] struct {
	Description  string         // Human-readable description of the action. Metadata["description"] is used if empty; see [ActionOptions].
	Metadata     map[string]any // Arbitrary key-value data attached to the action descriptor.
	InputSchema  map[string]any // JSON schema for the start action's input. Inferred from In if nil.
	OutputSchema map[string]any // JSON schema for the start action's output. Inferred if nil.

	// Check checks the status of a background operation. It is required:
	// polling is currently the only way callers resolve a pending operation.
	Check CheckOpFunc[Out]
	// Cancel cancels a background operation. Optional: nil means the action
	// does not support cancellation and no cancel action is registered.
	Cancel CancelOpFunc[Out]
}

BackgroundActionOptions configures a background action created with NewBackgroundActionOf. The descriptor slots are ActionOptions minus the stream slot: the component actions are non-streaming, so a background action never advertises a stream schema. When ActionOptions gains a field, mirror it here (and copy it through in NewBackgroundActionOf) unless it is stream-specific.

The operation lifecycle functions beyond start also live here. They are fields rather than constructor arguments so that adding one, or relaxing which ones are required, is never a signature change; In is reserved for future lifecycle functions typed on the action's input.

type BidiAction added in v1.10.0

type BidiAction[In, Out, Stream, Init any] struct {
	*Action[In, Out, Stream]
	// contains filtered or unexported fields
}

A BidiAction is a named, observable bidirectional streaming operation. It receives an initial configuration of type Init when a session starts, then consumes a stream of In messages while producing a stream of Stream chunks, and finishes with a final output of type Out.

BidiAction embeds Action, so it can also be invoked through the regular unary surface (Run, RunJSON): the input is delivered as a single chunk on the input stream with the zero Init value. Use BidiAction.RunBidi or BidiAction.RunBidiJSON for one-shot calls that supply init.

For internal use only.

Experimental: bidirectional streaming is experimental and subject to change.

func NewBidiAction deprecated added in v1.10.0

func NewBidiAction[In, Out, Stream, Init any](
	name string,
	atype api.ActionType,
	opts *BidiActionOptions,
	fn BidiFunc[In, Out, Stream, Init],
) *BidiAction[In, Out, Stream, Init]

NewBidiAction creates a new bidirectional streaming BidiAction without registering it.

Deprecated: Use NewBidiActionOf, which takes the action type first like the other action constructors.

func NewBidiActionOf added in v1.12.0

func NewBidiActionOf[In, Out, Stream, Init any](
	atype api.ActionType,
	name string,
	opts *BidiActionOptions,
	fn BidiFunc[In, Out, Stream, Init],
) *BidiAction[In, Out, Stream, Init]

NewBidiActionOf creates a new bidirectional streaming BidiAction without registering it.

Experimental: bidirectional streaming is experimental and subject to change.

func ResolveBidiActionFor added in v1.10.0

func ResolveBidiActionFor[In, Out, Stream, Init any](r api.Registry, atype api.ActionType, name string) *BidiAction[In, Out, Stream, Init]

ResolveBidiActionFor returns the bidi action for the given name in the registry, or nil if there is none. It panics if the action is of the wrong type; plain actions resolve via ResolveActionFor.

Experimental: bidirectional streaming is experimental and subject to change.

func (*BidiAction[In, Out, Stream, Init]) Connect added in v1.10.0

func (b *BidiAction[In, Out, Stream, Init]) Connect(ctx context.Context, init Init) (*BidiConnection[In, Out, Stream], error)

Connect starts a bidirectional streaming connection with the given initial configuration. For actions whose Init type is struct{} (no init), pass struct{}{}. Returns an error if init fails validation against the action's InitSchema. A trace span is created that remains open for the lifetime of the connection.

Experimental: bidirectional streaming is experimental and subject to change.

func (*BidiAction[In, Out, Stream, Init]) ConnectJSON added in v1.10.0

func (b *BidiAction[In, Out, Stream, Init]) ConnectJSON(ctx context.Context, opts *api.BidiJSONOptions) (api.BidiJSONConnection, error)

ConnectJSON starts a bidirectional streaming session using JSON-encoded messages. Returns an error if the init carried by opts fails to decode or validate.

Experimental: bidirectional streaming is experimental and subject to change.

func (*BidiAction[In, Out, Stream, Init]) Register added in v1.10.0

func (b *BidiAction[In, Out, Stream, Init]) Register(r api.Registry)

Register registers the bidi action with the given registry. It overrides the embedded Action's Register so that the registry holds the BidiAction itself; registry lookups must satisfy api.BidiAction.

func (*BidiAction[In, Out, Stream, Init]) RunBidi added in v1.10.0

func (b *BidiAction[In, Out, Stream, Init]) RunBidi(ctx context.Context, init Init, input In, cb StreamCallback[Stream]) (Out, error)

RunBidi executes the bidi action as a single one-shot call with the given initial configuration: input is delivered as the only chunk on the input stream and outgoing chunks are forwarded to cb. Returns an error if init fails validation against the action's InitSchema.

Experimental: bidirectional streaming is experimental and subject to change.

func (*BidiAction[In, Out, Stream, Init]) RunBidiJSON added in v1.10.0

func (b *BidiAction[In, Out, Stream, Init]) RunBidiJSON(ctx context.Context, input json.RawMessage, cb StreamCallback[json.RawMessage], opts *api.BidiJSONOptions) (*api.ActionRunResult[json.RawMessage], error)

RunBidiJSON runs the bidi action as a single one-shot call: input is delivered as the only chunk on the input stream, outgoing chunks are forwarded to cb, and opts carries the session init. Returns an error if input is absent or init fails to decode or validate.

Experimental: bidirectional streaming is experimental and subject to change.

type BidiActionOptions added in v1.10.0

type BidiActionOptions struct {
	Description  string         // Human-readable description of the action. Metadata["description"] is used if empty; see [ActionOptions].
	Metadata     map[string]any // Arbitrary key-value data attached to the action descriptor.
	InputSchema  map[string]any // JSON schema for messages streamed into the action. Inferred from In if nil.
	OutputSchema map[string]any // JSON schema for the action's final output. Inferred from Out if nil.
	StreamSchema map[string]any // JSON schema for outgoing streamed chunks. Inferred from Stream if nil.
	InitSchema   map[string]any // JSON schema for the session's initial configuration. Inferred from Init if nil.
}

BidiActionOptions configures the optional attributes of a BidiAction. It is ActionOptions plus the init schema slot. A nil options value is valid: schemas are inferred from the action's type parameters and the descriptor carries no metadata.

Experimental: bidirectional streaming is experimental and subject to change.

type BidiConnection added in v1.10.0

type BidiConnection[In, Out, Stream any] struct {
	// contains filtered or unexported fields
}

BidiConnection represents an active bidirectional streaming session.

The connection applies backpressure: the action blocks writing a chunk until the consumer reads earlier ones, so a session that streams more than one chunk requires the caller to drain BidiConnection.Receive before (or concurrently with) waiting on BidiConnection.Output.

Experimental: bidirectional streaming is experimental and subject to change.

func (*BidiConnection[In, Out, Stream]) Cancel added in v1.10.0

func (c *BidiConnection[In, Out, Stream]) Cancel()

Cancel aborts the session by cancelling the connection's context: the action's context is cancelled, blocked Sends unblock, and Output reports the cancellation error unless the action already completed. Safe to call multiple times and after completion.

func (*BidiConnection[In, Out, Stream]) Close added in v1.10.0

func (c *BidiConnection[In, Out, Stream]) Close() error

Close signals that no more inputs will be sent. It does not terminate the session: the action keeps running until it returns on its own, typically after observing the closed input stream. To abort the session and the work behind it, use BidiConnection.Cancel.

func (*BidiConnection[In, Out, Stream]) Done added in v1.10.0

func (c *BidiConnection[In, Out, Stream]) Done() <-chan struct{}

Done returns a channel that is closed when the connection completes.

func (*BidiConnection[In, Out, Stream]) Output added in v1.10.0

func (c *BidiConnection[In, Out, Stream]) Output() (Out, error)

Output returns the final output after the action completes. Blocks until done or context cancelled. If the action streams more than one chunk, BidiConnection.Receive must be drained for the action to finish; see the BidiConnection doc.

func (*BidiConnection[In, Out, Stream]) Receive added in v1.10.0

func (c *BidiConnection[In, Out, Stream]) Receive() iter.Seq2[Stream, error]

Receive returns an iterator for receiving streamed response chunks. The iterator completes when the action finishes.

Breaking out of the loop stops consumption but does not abort the session: the action keeps running and later chunks remain subject to backpressure until Receive is iterated again or the session ends. Use BidiConnection.Cancel to abort the session. Chunks are delivered to a single consumer; concurrent Receive iterations split the stream between them.

func (*BidiConnection[In, Out, Stream]) Send added in v1.10.0

func (c *BidiConnection[In, Out, Stream]) Send(input In) (err error)

Send sends an input message to the bidi action. It blocks until the action reads the message (backpressure), the connection is cancelled, or the action completes. It fails with an error matching ErrConnectionClosed after BidiConnection.Close, with one matching ErrActionCompleted once the action has returned, or with the context's error if the connection's context is cancelled. Typed inputs are not re-validated against the action's InputSchema; the JSON transport path is.

type BidiFunc added in v1.10.0

type BidiFunc[In, Out, Stream, Init any] = func(ctx context.Context, init Init, inCh <-chan In, outCh chan<- Stream) (Out, error)

BidiFunc is the function signature for bidirectional streaming actions. It receives an initial configuration of type Init, reads incoming stream messages of type In from inCh, and writes outgoing stream messages of type Stream to outCh. It returns a final output of type Out when complete.

The function must honor ctx cancellation: the framework signals shutdown (consumer error, invalid inbound chunk on the JSON transport, session cancellation) by cancelling ctx, and a function that ignores it blocks its session indefinitely. The framework owns closing outCh; the function must never close it. Writes to outCh apply backpressure: they block until the consumer reads earlier chunks. A panic in the function is recovered and reported as an INTERNAL error rather than crashing the process, since the function runs in a framework-owned goroutine.

Experimental: bidirectional streaming is experimental and subject to change.

type CancelOpFunc added in v1.3.0

type CancelOpFunc[Out any] = func(ctx context.Context, op *Operation[Out]) (*Operation[Out], error)

CancelOpFunc cancels a background operation.

type CheckOpFunc added in v1.3.0

type CheckOpFunc[Out any] = func(ctx context.Context, op *Operation[Out]) (*Operation[Out], error)

CheckOpFunc checks the status of a background operation.

type ContextProvider added in v0.3.0

type ContextProvider = func(ctx context.Context, req RequestData) (ActionContext, error)

ContextProvider is a function that returns an ActionContext for a given request. It is used to provide additional context to the Action.

type Flow

type Flow[In, Out, Stream any] struct {
	*Action[In, Out, Stream]
}

A Flow is a user-defined Action. A Flow[In, Out, Stream] represents a function from In to Out. The Stream parameter is for flows that support streaming: providing their results incrementally.

func NewFlow added in v1.5.0

func NewFlow[In, Out any](name string, fn Func[In, Out]) *Flow[In, Out, struct{}]

NewFlow creates a Flow that runs fn without registering it. fn takes an input of type In and returns an output of type Out.

Example

This example demonstrates defining a simple flow.

package main

import (
	"context"
	"fmt"
	"strings"

	"github.com/firebase/genkit/go/core"
	"github.com/firebase/genkit/go/internal/registry"
)

func main() {
	r := registry.New()

	// Create a flow that processes input and register it
	flow := core.NewFlow("uppercase",
		func(ctx context.Context, input string) (string, error) {
			return strings.ToUpper(input), nil
		},
	)
	flow.Register(r)

	// Run the flow
	result, err := flow.Run(context.Background(), "hello")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println(result)
}
Output:
HELLO

func NewStreamingFlow added in v1.5.0

func NewStreamingFlow[In, Out, Stream any](name string, fn StreamingFunc[In, Out, Stream]) *Flow[In, Out, Stream]

NewStreamingFlow creates a streaming Flow that runs fn without registering it.

Example

This example demonstrates defining a streaming flow.

package main

import (
	"context"
	"fmt"

	"github.com/firebase/genkit/go/core"
	"github.com/firebase/genkit/go/internal/registry"
)

func main() {
	r := registry.New()

	// Create a streaming flow that counts down and register it
	flow := core.NewStreamingFlow("countdown",
		func(ctx context.Context, start int, cb core.StreamCallback[int]) (string, error) {
			for i := start; i > 0; i-- {
				if cb != nil {
					if err := cb(ctx, i); err != nil {
						return "", err
					}
				}
			}
			return "Done!", nil
		},
	)
	flow.Register(r)

	// Use Stream() iterator to receive chunks
	iter := flow.Stream(context.Background(), 3)
	iter(func(val *core.StreamingFlowValue[string, int], err error) bool {
		if err != nil {
			fmt.Println("Error:", err)
			return false
		}
		if val.Done {
			fmt.Println("Result:", val.Output)
		} else {
			fmt.Println("Count:", val.Stream)
		}
		return true
	})
}
Output:
Count: 3
Count: 2
Count: 1
Result: Done!

func (*Flow[In, Out, Stream]) Run

func (f *Flow[In, Out, Stream]) Run(ctx context.Context, input In) (Out, error)

Run runs the flow in the context of another flow.

func (*Flow[In, Out, Stream]) Stream

func (f *Flow[In, Out, Stream]) Stream(ctx context.Context, input In) func(func(*StreamingFlowValue[Out, Stream], error) bool)

Stream runs the flow in the context of another flow and streams the output. It returns a function whose argument function (the "yield function") will be repeatedly called with the results.

If the yield function is passed a non-nil error, the flow has failed with that error; the yield function will not be called again.

If the yield function's StreamingFlowValue argument has Done == true, the value's Output field contains the final output; the yield function will not be called again.

Otherwise the Stream field of the passed StreamingFlowValue holds a streamed result.

type Func

type Func[In, Out any] = func(context.Context, In) (Out, error)

Func is an alias for non-streaming functions with input of type In and output of type Out.

type GenkitError deprecated added in v0.5.3

type GenkitError = status.Error

GenkitError is the base error type for Genkit errors.

Deprecated: use status.Error. This is an alias for it, so the two are the same type: an errors.As for a *GenkitError still matches every error Genkit raises, and a *status.Error can be used anywhere a *GenkitError is expected. Note that status.Error classifies failures with a sentinel, so prefer errors.Is against the sentinels in core/status (and the domain sentinels in ai, exp, and friends) over comparing the Status field.

func AsGenkitError deprecated added in v1.10.0

func AsGenkitError(err error) *GenkitError

AsGenkitError returns err as a *GenkitError, wrapping it in a fresh one with status INTERNAL if it isn't one already. Returns nil for a nil input.

Deprecated: use status.Convert, or status.Of when you only need the status. Note that Convert derives the status from the error (mapping a cancelled context to CANCELLED, for instance) rather than always using INTERNAL.

func NewError deprecated added in v0.5.3

func NewError(name StatusName, message string, args ...any) *GenkitError

NewError creates a new GenkitError with a stack trace.

Deprecated: use status.Errorf with a sentinel, which classifies the failure so callers can match it with errors.Is:

status.Errorf(status.ErrNotFound, "model %q not found", name)

Record a cause with %w rather than relying on the implicit wrapping of the last error argument that this function performs.

type Middleware added in v0.3.0

type Middleware[In, Out, Stream any] = func(StreamingFunc[In, Out, Stream]) StreamingFunc[In, Out, Stream]

Middleware is a function that wraps an action execution, similar to HTTP middleware. It can modify the input, output, and context, or perform side effects.

func ChainMiddleware added in v0.3.0

func ChainMiddleware[In, Out, Stream any](middlewares ...Middleware[In, Out, Stream]) Middleware[In, Out, Stream]

ChainMiddleware creates a new Middleware that applies a sequence of Middlewares, so that they execute in the given order when handling action request. In other words, ChainMiddleware(m1, m2)(handler) = m1(m2(handler))

Example

This example demonstrates using ChainMiddleware to combine middleware.

package main

import (
	"context"
	"fmt"
	"strings"

	"github.com/firebase/genkit/go/core"
)

func main() {
	// Define a middleware that wraps function calls
	logMiddleware := func(next core.StreamingFunc[string, string, struct{}]) core.StreamingFunc[string, string, struct{}] {
		return func(ctx context.Context, input string, cb core.StreamCallback[struct{}]) (string, error) {
			fmt.Println("Before:", input)
			result, err := next(ctx, input, cb)
			fmt.Println("After:", result)
			return result, err
		}
	}

	// The original function
	originalFn := func(ctx context.Context, input string, cb core.StreamCallback[struct{}]) (string, error) {
		return strings.ToUpper(input), nil
	}

	// Chain and apply middleware
	wrapped := core.ChainMiddleware(logMiddleware)(originalFn)

	result, _ := wrapped(context.Background(), "hello", nil)
	fmt.Println("Final:", result)
}
Output:
Before: hello
After: HELLO
Final: HELLO

func Middlewares added in v0.3.0

func Middlewares[In, Out, Stream any](ms ...Middleware[In, Out, Stream]) []Middleware[In, Out, Stream]

Middlewares returns an array of middlewares that are passes in as an argument. core.Middlewares(apple, banana) is identical to []core.Middleware[InputType, OutputType]{apple, banana}

type Operation added in v1.3.0

type Operation[Out any] struct {
	Action   string         `json:"action"`             // Key of the action that created this operation.
	ID       string         `json:"id"`                 // ID of the operation.
	Done     bool           `json:"done"`               // Whether the operation is complete.
	Output   Out            `json:"output,omitempty"`   // Result when done.
	Error    error          `json:"error,omitempty"`    // Error if the operation failed.
	Metadata map[string]any `json:"metadata,omitempty"` // Additional metadata.
}

Operation represents a long-running operation started by a background action.

func CheckOperation added in v1.3.0

func CheckOperation[In, Out any](ctx context.Context, r api.Registry, op *Operation[Out]) (*Operation[Out], error)

CheckOperation checks the status of a background operation by looking up the action and calling its Check method.

type RequestData added in v0.3.0

type RequestData struct {
	Method  string            // Method is the HTTP method of the request (e.g. "GET", "POST", etc.)
	Headers map[string]string // Headers is the headers of the request. The keys are the header names in lowercase.
	Input   json.RawMessage   // Input is the body of the request.
}

RequestData is the data associated with a request. It is used to provide additional context to the Action.

type StartOpFunc added in v1.3.0

type StartOpFunc[In, Out any] = func(ctx context.Context, input In) (*Operation[Out], error)

StartOpFunc starts a background operation.

type Status deprecated added in v0.5.3

type Status struct {
	Name    StatusName `json:"name"`
	Message string     `json:"message,omitempty"`
}

Status represents a status condition, typically used in responses or errors.

Deprecated: use status.Error, which carries a status alongside the message and participates in errors.Is and errors.As.

func NewStatus deprecated added in v0.5.3

func NewStatus(name StatusName, message string) *Status

NewStatus creates a new Status object.

Deprecated: use status.Errorf.

type StatusName deprecated added in v0.5.3

type StatusName = status.Name

StatusName defines the set of canonical status names.

Deprecated: use status.Name. This is an alias for it, so the two are the same type and values are interchangeable.

func StatusFromHTTPCode deprecated added in v1.7.0

func StatusFromHTTPCode(code int) StatusName

StatusFromHTTPCode returns the canonical StatusName for an HTTP status code, following the gRPC / Google API reverse mapping.

Deprecated: use status.FromHTTPCode.

type StreamCallback added in v0.3.0

type StreamCallback[Stream any] = func(context.Context, Stream) error

StreamCallback is a function that is called during streaming to return the next chunk of the outgoing stream.

type StreamingFlowValue added in v0.5.0

type StreamingFlowValue[Out, Stream any] struct {
	Done   bool
	Output Out    // valid if Done is true
	Stream Stream // valid if Done is false
}

StreamingFlowValue is either a streamed value or a final output of a flow.

type StreamingFunc added in v0.3.0

type StreamingFunc[In, Out, Stream any] = func(context.Context, In, StreamCallback[Stream]) (Out, error)

StreamingFunc is an alias for streaming functions with input of type In, output of type Out, and outgoing stream chunk of type Stream.

type UserFacingError deprecated added in v0.5.3

type UserFacingError struct {
	Message string         `json:"message"` // Exclude from default JSON if embedded elsewhere
	Status  StatusName     `json:"status"`
	Details map[string]any `json:"details"` // Use map for arbitrary details
}

UserFacingError is the base error type for user facing errors.

Deprecated: use status.PublicErrorf, which produces a status.Error with Public set. Unlike this type, the result carries a sentinel and its status reaches HTTP transports, so a public INVALID_ARGUMENT returns 400 rather than falling through to 500.

func NewPublicError deprecated added in v0.5.3

func NewPublicError(status StatusName, message string, details map[string]any) *UserFacingError

NewPublicError allows a web framework handler to know it is safe to return the message in a request. Other kinds of errors will result in a generic 500 message to avoid the possibility of internal exceptions being leaked to attackers.

Deprecated: use status.PublicErrorf.

Example

This example demonstrates creating user-facing errors.

package main

import (
	"fmt"

	"github.com/firebase/genkit/go/core"
)

func main() {
	// Create a user-facing error with details
	err := core.NewPublicError(core.INVALID_ARGUMENT, "Invalid email format", map[string]any{
		"field": "email",
		"value": "not-an-email",
	})

	fmt.Println("Status:", err.Status)
	fmt.Println("Message:", err.Message)
}
Output:
Status: INVALID_ARGUMENT
Message: Invalid email format

func (*UserFacingError) Error added in v0.5.3

func (e *UserFacingError) Error() string

Error implements the standard error interface for UserFacingError.

func (*UserFacingError) PublicMessage added in v1.12.0

func (e *UserFacingError) PublicMessage() (string, bool)

PublicMessage reports the error's message as safe to return to clients. Transports call this to decide what reaches a client; implementing it keeps a UserFacingError public now that publicness is a property of the error rather than of its type.

func (*UserFacingError) Unwrap added in v1.12.0

func (e *UserFacingError) Unwrap() error

Unwrap returns the base sentinel for the error's status, so a UserFacingError classifies the same way a status.Error does: status.Of reports its Status rather than defaulting to INTERNAL, and errors.Is matches the corresponding base sentinel.

Directories

Path Synopsis
Package logger provides context-scoped structured logging for Genkit.
Package logger provides context-scoped structured logging for Genkit.
Package status defines Genkit's canonical status codes and the error type that carries them.
Package status defines Genkit's canonical status codes and the error type that carries them.
Package tracing provides execution trace support for Genkit operations.
Package tracing provides execution trace support for Genkit operations.
x
streaming
Package streaming provides experimental durable streaming APIs for Genkit.
Package streaming provides experimental durable streaming APIs for Genkit.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL