Skip to Content
How-To GuidesGoAdding Typed Configuration to a Go Agent

Adding Typed Configuration to a Go Agent

Overview

A Go agent’s configuration is a single config struct attached to the agent’s type. Each exported field becomes a config key; the platform provisions the values (from golem.yaml, env, or the CLI) and the agent reads them back at runtime as a typed struct. Config is materialized once per worker and cached, so reads on a hot method are near-free.

Two things change versus a plain agent:

  • define with golem.DefineConfiguredAgent[ID, Cfg] instead of golem.DefineAgent[ID],
  • implement with Agent.ImplementConfigured (its constructor receives an *golem.InitContext[ID, state, Cfg]),

then read the config with ctx.Config(Agent) inside a method, or ctx.Config() inside the constructor.

Steps

  1. Declare the config struct — one exported field per config key.
  2. Attach it with golem.DefineConfiguredAgent[ID, Cfg] in the definition.
  3. Implement with Agent.ImplementConfigured; read config from the InitContext in the constructor.
  4. Read at method time with ctx.Config(Agent).
  5. Provide values under agents.<Name>.config in golem.yaml.

Definition (agents/shop/shop.go)

// Package shop is the DEFINITION of the shop agent. package shop import "github.com/golemcloud/golem/sdks/go/golem" type ID struct{ Name string } // Config is the agent's whole config surface. Each exported field is a config // key; a nested struct flattens into multi-segment paths; a pointer field is // optional; list/map fields decode as their WIT shapes. type Config struct { Greeting string Tax TaxConfig // nested → paths tax.ratePct Timezone *string // optional (read back as nil when unset) Features []string // list Limits map[string]int64 // map } type TaxConfig struct{ RatePct int64 } var Agent = golem.DefineConfiguredAgent[ID, Config](golem.Spec{ Name: "ShopAgent", Description: "A shop whose behaviour is driven by config", }) var ( Greet = Agent.Method[golem.Unit, string]("greet", golem.Description("Greeting, from config")) Settings = Agent.Method[golem.Unit, []string]("settings", golem.Description("Return the configured features")) )

Field-name conventions match plain agent types: use sized integers (int64, not bare int), a *T field is option<T>, and nested structs recurse. Field names are lowerCamelCase for the wire, with each initialism as one word (RatePct → ratePct, APIKey → apiKey, AccountID → accountId).

Implementation (agents/shop/impl/impl.go)

// Package impl is the IMPLEMENTATION of the shop agent. package impl import ( "myapp/agents/shop" "github.com/golemcloud/golem/sdks/go/golem" ) type state struct{ greeting string } // ImplementConfigured binds the constructor; its InitContext exposes Config(). var agent = shop.Agent.ImplementConfigured(func(ctx *golem.InitContext[shop.ID, state, shop.Config]) *state { // Constructor-time config read: seed state once from config. return &state{greeting: ctx.Config().Greeting} }) func init() { agent.Handle(shop.Greet, func(ctx *golem.Context[state], _ golem.Unit) string { return ctx.State.greeting }) agent.Handle(shop.Settings, func(ctx *golem.Context[state], _ golem.Unit) []string { cfg := ctx.Config(shop.Agent) // method-time config read return cfg.Features }) }

ctx.Config(shop.Agent) returns the whole shop.Config value; ctx is the running method’s *golem.Context[state] (requiring it means config is only readable from inside a running method). The constructor reads the same config via ctx.Config() on its InitContext.

A config field takes the same golem restriction tag as a method parameter (see golem-add-agent-go), which publishes it in the config’s declared type:

type Config struct { Retries uint32 `golem:"max=5"` }

Providing Values in golem.yaml

Set defaults under agents.<Name>.config. Keys are camelCase — they match the Go field names in lowerCamelCase, with each initialism as one word (AccountID → accountId); nested structs are nested maps, and a map[string]V is a list of [key, value] pairs:

agents: ShopAgent: config: greeting: "Welcome to ACME" tax: ratePct: 20 features: ["fast-checkout", "gift-wrap"] limits: [["maxItems", 100]] # timezone is omitted → the optional *string field reads back as nil

Overriding Config Over RPC

When one agent calls another, the caller can override the callee’s local (non-secret) config at client creation with the callee definition’s WithConfig, which checks the config type at compile time:

client := shop.Agent.Get( shop.ID{Name: "acme"}, shop.Agent.WithConfig(shop.Config{Greeting: "Hi from the caller"}), )

Only declared local keys can be overridden; secret fields are always platform-provisioned and are skipped. WithConfig replaces every local value: it sends every local field of the struct, zero values included. To set only some, or to call an agent in another component, use the generated guest client’s With<Agent>Config option (see golem-call-another-agent-go). It sends only the fields you set, through golem.WithConfigEntries(golem.ConfigEntryOf(path, value)…).

Key Constraints

  • Config is agent-attached and instance-bound — read only from within that agent’s own constructor or methods, never from free-floating code.
  • Reading an undeclared key, or an unset required key, traps. Declare a field as a pointer (*T) to read an absent value back as nil instead of trapping.
  • Config is materialized once per worker and cached; local fields are read on first access and reused for the worker’s life. (Secret fields stay live — see golem-add-secret-go.)
  • Use golem.DefineAgent[ID] (no config) for agents that need none; golem.NoConfig is the empty config type and never needs naming.
GuideDescription
golem-add-agent-goDefine the base agent this config attaches to
golem-add-secret-goAdd golem.Secret[T] fields for sensitive values
golem-call-another-agent-goOverride a callee’s config with the definition’s WithConfig over RPC