mirror of
https://github.com/go-micro/go-micro.git
synced 2026-06-15 19:35:13 +02:00
* docs: map go-micro onto Anthropic's workflows-vs-agents taxonomy - new guide 'Agents and Workflows': adopts Anthropic's Building Effective Agents vocabulary — workflow (predefined path) = flow, agent (dynamic self-direction) = agent — maps the augmented-LLM building block and the five workflow patterns onto go-micro, and shows routing (chat router) and orchestrator-workers (conductor + plan/delegate) are already native. - flow package doc reframed as a workflow (predefined path) per the same taxonomy, with guidance on flow vs agent. - nav + README link the new guide. * feat: agent guardrails — step limit and tool approval hook Anthropic's Building Effective Agents stresses stopping conditions and human-in-the-loop checkpoints for autonomous agents. Add both as plain options enforced at the tool-handler choke point — no provider changes, no new abstraction: - MaxSteps(n): bound tool executions per Ask; beyond the limit, actions are refused and the model is told to stop and summarize. - ApproveTool(fn): gate each action before it runs; returning false blocks it and surfaces the reason to the model. The internal plan tool is never gated. Exposed at the micro package (AgentMaxSteps, AgentApproveTool, ApproveFunc). Tests cover the limit, blocking, and that plan is not gated. Guardrails section of the agents-and-workflows guide updated from 'active work' to documented options. * feat: flow can dispatch to an agent (flow triggers, agent reasons) Unify the engine without collapsing the workflow/agent distinction. A Flow with Agent set hands each event's rendered prompt to a named registered agent over RPC (Agent.Chat) instead of running its own LLM step — so the workflow stays the deterministic trigger and the agent is the reasoning engine, with its plan, delegate, memory, and guardrails. A plain flow is unchanged (single augmented-LLM step). - flow.Agent(name) / micro.FlowAgent(name); flow stores the client and skips model setup when dispatching. - test: dispatch routes to comms.Agent.Chat with the rendered prompt and records the reply. - guide: 'Flow triggers, Agent reasons' section. --------- Co-authored-by: Claude <noreply@anthropic.com>
163 lines
5.2 KiB
Go
163 lines
5.2 KiB
Go
// Package micro is a pluggable framework for microservices
|
|
package micro
|
|
|
|
import (
|
|
"context"
|
|
|
|
"go-micro.dev/v5/agent"
|
|
"go-micro.dev/v5/client"
|
|
"go-micro.dev/v5/flow"
|
|
"go-micro.dev/v5/server"
|
|
"go-micro.dev/v5/service"
|
|
)
|
|
|
|
type serviceKey struct{}
|
|
|
|
// Service is the interface for a go-micro service.
|
|
type Service = service.Service
|
|
|
|
// Agent is the interface for an AI agent that manages services.
|
|
type Agent = agent.Agent
|
|
|
|
// AgentOption configures an Agent.
|
|
type AgentOption = agent.Option
|
|
|
|
// Flow is an event-driven LLM orchestration unit.
|
|
type Flow = flow.Flow
|
|
|
|
// FlowOption configures a Flow.
|
|
type FlowOption = flow.Option
|
|
|
|
// Group is a set of services that share lifecycle management.
|
|
type Group = service.Group
|
|
|
|
type Option = service.Option
|
|
|
|
type Options = service.Options
|
|
|
|
// Event is used to publish messages to a topic.
|
|
type Event interface {
|
|
// Publish publishes a message to the event topic
|
|
Publish(ctx context.Context, msg interface{}, opts ...client.PublishOption) error
|
|
}
|
|
|
|
// Type alias to satisfy the deprecation.
|
|
type Publisher = Event
|
|
|
|
// New creates a new service with the given name and options.
|
|
//
|
|
// service := micro.New("greeter")
|
|
// service := micro.New("greeter", micro.Address(":8080"))
|
|
func New(name string, opts ...Option) Service {
|
|
return service.New(append([]Option{service.Name(name)}, opts...)...)
|
|
}
|
|
|
|
// NewService creates and returns a new Service based on the packages within.
|
|
// Deprecated: Use New(name, opts...) instead.
|
|
func NewService(opts ...Option) Service {
|
|
return service.New(opts...)
|
|
}
|
|
|
|
// NewAgent creates a new AI agent that manages the given services.
|
|
//
|
|
// agent := micro.NewAgent("task-mgr",
|
|
// micro.AgentServices("task"),
|
|
// micro.AgentPrompt("You manage tasks."),
|
|
// micro.AgentProvider("anthropic"),
|
|
// )
|
|
// agent.Run()
|
|
func NewAgent(name string, opts ...AgentOption) Agent {
|
|
return agent.New(append([]AgentOption{agent.Name(name)}, opts...)...)
|
|
}
|
|
|
|
// AgentServices sets which services the agent manages.
|
|
func AgentServices(names ...string) AgentOption { return agent.Services(names...) }
|
|
|
|
// AgentPrompt sets the agent's system prompt.
|
|
func AgentPrompt(p string) AgentOption { return agent.Prompt(p) }
|
|
|
|
// AgentProvider sets the LLM provider.
|
|
func AgentProvider(p string) AgentOption { return agent.Provider(p) }
|
|
|
|
// AgentModel sets the LLM model.
|
|
func AgentModel(m string) AgentOption { return agent.Model(m) }
|
|
|
|
// AgentAPIKey sets the API key for the LLM provider.
|
|
func AgentAPIKey(k string) AgentOption { return agent.APIKey(k) }
|
|
|
|
// ApproveFunc gates an agent's tool calls before they run.
|
|
type ApproveFunc = agent.ApproveFunc
|
|
|
|
// AgentMaxSteps bounds tool executions per Ask (0 = unbounded) — a
|
|
// stopping condition for autonomous agents.
|
|
func AgentMaxSteps(n int) AgentOption { return agent.MaxSteps(n) }
|
|
|
|
// AgentApproveTool sets a human-in-the-loop / policy hook called before
|
|
// each action the agent takes.
|
|
func AgentApproveTool(fn ApproveFunc) AgentOption { return agent.ApproveTool(fn) }
|
|
|
|
// NewFlow creates an event-driven LLM orchestration unit.
|
|
//
|
|
// f := micro.NewFlow("onboard-user",
|
|
// micro.FlowTrigger("events.user.created"),
|
|
// micro.FlowPrompt("New user: {{.Data}}. Send welcome email."),
|
|
// micro.FlowProvider("anthropic"),
|
|
// )
|
|
// f.Register(service.Options().Registry, service.Options().Broker, service.Client())
|
|
func NewFlow(name string, opts ...FlowOption) *Flow {
|
|
return flow.New(name, opts...)
|
|
}
|
|
|
|
// FlowTrigger sets the broker topic that triggers the flow.
|
|
func FlowTrigger(topic string) FlowOption { return flow.Trigger(topic) }
|
|
|
|
// FlowPrompt sets the prompt template. Use {{.Data}} for the event payload.
|
|
func FlowPrompt(p string) FlowOption { return flow.Prompt(p) }
|
|
|
|
// FlowProvider sets the LLM provider.
|
|
func FlowProvider(p string) FlowOption { return flow.Provider(p) }
|
|
|
|
// FlowAPIKey sets the API key for the LLM provider.
|
|
func FlowAPIKey(k string) FlowOption { return flow.APIKey(k) }
|
|
|
|
// FlowAgent makes the flow hand each event to a named agent over RPC —
|
|
// the flow triggers, the agent reasons. Without it, the flow runs a
|
|
// single LLM step itself.
|
|
func FlowAgent(name string) FlowOption { return flow.Agent(name) }
|
|
|
|
// NewGroup creates a service group for running multiple services
|
|
// in a single binary with shared lifecycle management.
|
|
func NewGroup(svcs ...Service) *Group {
|
|
return service.NewGroup(svcs...)
|
|
}
|
|
|
|
// FromContext retrieves a Service from the Context.
|
|
func FromContext(ctx context.Context) (Service, bool) {
|
|
s, ok := ctx.Value(serviceKey{}).(Service)
|
|
return s, ok
|
|
}
|
|
|
|
// NewContext returns a new Context with the Service embedded within it.
|
|
func NewContext(ctx context.Context, s Service) context.Context {
|
|
return context.WithValue(ctx, serviceKey{}, s)
|
|
}
|
|
|
|
// NewEvent creates a new event publisher.
|
|
func NewEvent(topic string, c client.Client) Event {
|
|
if c == nil {
|
|
c = client.NewClient()
|
|
}
|
|
|
|
return &event{c, topic}
|
|
}
|
|
|
|
// RegisterHandler is syntactic sugar for registering a handler.
|
|
func RegisterHandler(s server.Server, h interface{}, opts ...server.HandlerOption) error {
|
|
return s.Handle(s.NewHandler(h, opts...))
|
|
}
|
|
|
|
// RegisterSubscriber is syntactic sugar for registering a subscriber.
|
|
func RegisterSubscriber(topic string, s server.Server, h interface{}, opts ...server.SubscriberOption) error {
|
|
return s.Subscribe(s.NewSubscriber(topic, h, opts...))
|
|
}
|