golemcloud/golem/golem-agent-reflection-go

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Calling Golem agents from Go without sharing their Go definition — caller-defined method-only and full agent clients, discovered (reflected) clients with canonical JSON, and fully dynamic invocation with packed values. Use when agent types or methods are selected at runtime, many agent types share a method shape, schemas must be inspected or rendered as JSON Schema, or an agent id must be parsed, built or rebound in a Go Golem project.

Install

npx vskill@latest install golemcloud/golem/golem-agent-reflection-go

SKILL.md

Calling Agents with Runtime Reflection (Go)

Normal RPC through the callee's definition package or a generated guest client (see golem-call-another-agent-go) is the baseline. Reflection adds three more levels, which compose through agent ids:

LevelUse it whenGo
Caller-defined, method-onlyMany agent types share a method shape; you have an idgolem.DefineAgentClient[Shape]() + Method[In, Out], Bind(id)
Caller-defined, fullYou own Go types for one target type, without its definitiongolem.DefineFullAgentClient[Id](name, spec) + Method[In, Out]
DiscoveredThe type or method is chosen at runtime and should be validatedreflection.DiscoverAgentType → Get / Bind → Call
Fully dynamicValues are already packed; no schema authority keptreflection.BindAgentID(id) → Call

Every level uses the same verbs: Call waits for the result, Trigger does not, Schedule runs it later. Discovered and dynamic clients live in the reflection package (github.com/golemcloud/golem/sdks/go/golem/reflection).

Method-Only Clients

A method-only client declares methods and nothing else, so it calls any existing agent that has them, whatever its type:

go
type Pingable struct{} // the shape's identity type
var (
Pinger = golem.DefineAgentClient[Pingable]()
Ping = Pinger.Method[golem.Unit, string]("ping")
)
func pingAll(ids []string) {
for _, id := range ids {
c, err := Pinger.Bind(id)
if err != nil {
continue
}
reply, err := Ping.Call(c, golem.Unit{})
fmt.Println(id, reply, err)
}
}

Bind checks nothing about the target, which the client does not describe; a target that is not deployed is reported by Bind, and a mismatch by the host or when the result is decoded. Binding does not create the agent, but the first call to a durable id does.

Full Clients

A full client also declares the target type's name, constructor and lifecycle, so it creates and addresses instances like the agent's own definition:

go
type CounterID struct{ Name string }
type AddIn struct{ By int64 }
var (
Counter = golem.DefineFullAgentClient[CounterID]("CounterAgent", golem.AgentClientSpec{})
Add = Counter.Method[AddIn, int64]("add")
)
c, err := Counter.Get(CounterID{Name: "main"}) // an error when the target is not deployed
total, err := Add.Call(c, AddIn{By: 5})
c, err = Counter.Bind(agentID) // the id must name CounterAgent with a CounterID constructor
id, err := Counter.AgentID(CounterID{Name: "main"}, golem.None[golem.UUID]()) // without creating it
  • Get, NewPhantom, Bind and AgentID work the same on an agent's own definition (DefineAgent), except that there Get, NewPhantom and AgentID panic instead of returning an error: the target is in the same component, so a failure is a programming mistake.
  • golem.AgentClientSpec{Mode: golem.Ephemeral} declares an ephemeral target: it has no durable identity, so Get and Bind are refused and NewPhantom addresses it.
  • golem.DefineConfiguredFullAgentClient[Id, Cfg] declares the target's configuration type, so Get(id, client.WithConfig(cfg)) passes typed creation-time overrides, checked at compile time against Cfg.

Generated guest clients are built on full clients.

Discover and Inspect

go
for _, t := range reflection.DiscoverAgentTypes() {
fmt.Println(t.Name(), t.Mode(), t.SourceLanguage())
for _, m := range t.Methods() {
fmt.Println(" ", m.Name(), m.Description(), m.ReadOnly())
}
}
counter, found := reflection.DiscoverAgentType("CounterAgent")
if !found {
panic("CounterAgent is not deployed in this environment")
}
add, known := counter.Method("add")
if !known {
panic("CounterAgent has no method add")
}
input := add.Input() // a schema.Ref of the parameter record
fmt.Println(golem.Must(input.ToJSONSchema(true))) // e.g. for an LLM
if output, hasOutput := add.Output().Get(); hasOutput {
fmt.Println(golem.Must(output.ToJSONSchema(true)))
}

Input() returns a schema.Ref for the parameter record (without host-filled fields such as the principal). Output() returns a golem.Option[schema.Ref]: golem.None[schema.Ref]() when there is no result. Use Get() and check its boolean before accessing the result schema. A schema.Ref from github.com/golemcloud/golem/sdks/go/core/schema packs and unpacks canonical JSON and renders JSON Schema. Constructor().Input() describes the constructor the same way. A discovery miss (not deployed, not visible to the caller) reports false. A snapshot never refreshes itself; discover again when a newer deployment matters.

Call a Discovered Agent

go
client, err := counter.Get(map[string]any{"name": "main"})
if err != nil {
panic(err)
}
total, invocation, err := client.Call("add", map[string]any{"by": "5"}) // s64 is a string
if err != nil {
var rce *golem.RemoteCallError
if errors.As(err, &rce) {
fmt.Println(rce.Kind, rce.Message)
}
panic(err)
}
fmt.Println(client.AgentID(), total, invocation.IdempotencyKey)
  • Get takes the constructor arguments by name and creates the agent if it does not exist; reflection.WithPhantomID(uuid) addresses a phantom instance and NewPhantom allocates one. Bind(agentID) addresses an existing id of this type.
  • reflection.WithConfigJSON(path, value) overrides one declared configuration value at creation, as canonical JSON (reflection.WithConfigValue(path, schema.SchemaValue) takes a schema-model value); Get, NewPhantom and Bind accept it. Undeclared paths, secrets and invalid values are refused before anything is sent. An agent that already exists keeps the configuration it was created with.
  • Call, Trigger and Schedule return the invocation's golem.InvocationID (agent id and idempotency key) — for an ephemeral agent, the only record of which instance ran.
  • CallAsync returns a *reflection.PendingCall: its ID is known at once, Get() returns the result (MustGet() panics on an error, and a second Get returns the same result), and Cancel() stops waiting (the call may already have run; Get then reports golem.ErrCallCancelled). It behaves like the *golem.Future that a typed CallAsync returns. A scheduled call is cancelled through the *golem.ScheduledInvocation that Schedule returns.
  • Missing, unexpected or invalid arguments fail with *schema.ValidationError, listing every problem, before anything is sent.
  • Remote failures are *golem.RemoteCallError; for a remote agent error, its Cause is a *golem.AgentError.

Agent IDs

go
typed := golem.Must(golem.ParseAgentID[CounterID](agentID))
fmt.Println(typed.TypeName, typed.ID.Name, typed.PhantomID.IsSome())
raw := golem.Must(reflection.ParseRawAgentID(agentID)) // no Go type needed
fmt.Println(raw.TypeName, golem.Must(raw.ConstructorJSON()))
t, found := reflection.DiscoverAgentTypeByID(agentID) // the type behind an existing agent
id := golem.Must(t.AgentID(map[string]any{"name": "other"}, golem.None[golem.UUID]()))

Parsing is strict and reports malformed ids; lookup by id never creates the agent. Agent ids are scoped to the caller's environment.

Fully Dynamic

A dynamic client sends values the caller packed itself and validates nothing. Keep a discovered snapshot beside it for validation:

go
t, _ := reflection.DiscoverAgentType(agentType)
m, _ := t.Method(method)
input := golem.Must(m.Input().PackJSON(args))
client := golem.Must(reflection.BindAgentID(agentID))
out, _, err := client.Call(method, input)
if err != nil {
panic(err)
}
if v, has := out.Get(); has {
if result, declared := m.Output().Get(); declared {
fmt.Println(golem.Must(result.UnpackJSON(v)))
}
}

A dynamic client also has CallAsync, Trigger and Schedule. reflection.MakeAgentID(typeName, constructor, phantom) builds an id from a packed constructor, so a dynamic caller can address any instance; the first call to it creates a durable agent.

Canonical JSON

  • Integers up to 32 bits are JSON numbers; s64, u64, duration nanoseconds and quantity mantissas are base-10 strings ("5"). A duration is {"nanoseconds": "…"}.
  • An absent option is null; a result is {"ok": …} or {"err": …}; a variant case is its name, or {name: payload}; a map is [[k, v], …]; flags are an array of names; binary is unpadded base64url.
  • Streams, futures and other capabilities cannot be packed as JSON; call such methods through a typed client.
Related Skills
SkillWhen to Load
golem-agent-reflectionChoosing between client approaches, identity rules
golem-call-another-agent-goTyped RPC through definitions and guest clients
golem-call-tool-goCalling tools the same ways
golem-multi-instance-agent-goAgent identities and phantoms

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
1,514
Repository forks
210
7-day trend score
0

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/golemcloud/golem/golem-agent-reflection-go/badge)](https://verified-skill.com/skills/golemcloud/golem/golem-agent-reflection-go)

Something wrong with this skill or its page? Tell us.