agent

package
v1.17.1 Latest Latest
Warning

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

Go to latest
Published: Dec 31, 2025 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package agent defines the core agent interfaces and types for Hector v2.

Agent Interface

The Agent interface is the fundamental abstraction for all agents:

type Agent interface {
    Name() string
    Description() string
    Run(InvocationContext) iter.Seq2[*Event, error]
    SubAgents() []Agent
}

Context Hierarchy

The package provides a three-tier context hierarchy:

  • InvocationContext: Full access during agent execution
  • ReadonlyContext: Read-only access for tools and callbacks
  • CallbackContext: State modification for callbacks

Creating Agents

Use the provided constructors to create agents:

agent, err := agent.New(agent.Config{
    Name:        "my-agent",
    Description: "A helpful assistant",
    Run:         myRunFunc,
})

For LLM-based agents, use the llmagent subpackage:

agent, err := llmagent.New(llmagent.Config{
    Name:        "llm-agent",
    Model:       myModel,
    Instruction: "You are a helpful assistant.",
})

Index

Constants

View Source
const (
	// AuthorUser represents events authored by the user (human input).
	// Used when tool results or other events come from user interactions.
	AuthorUser = "user"

	// AuthorSystem represents events authored by the system.
	// Used for system-generated events like errors or notifications.
	AuthorSystem = "system"
)

Event author constants

Variables

This section is empty.

Functions

func FindAgentPath

func FindAgentPath(root Agent, name string) []string

FindAgentPath returns the path to an agent in the tree. The path is a slice of agent names from root to the target (exclusive of root). Returns nil if the agent is not found.

Example:

// For a tree: coordinator -> team_a -> specialist
path := agent.FindAgentPath(coordinator, "specialist")
// path = ["team_a", "specialist"]

func WalkAgents

func WalkAgents(root Agent, visitor func(Agent, int) bool)

WalkAgents visits all agents in the tree depth-first. The visitor function is called for each agent with its depth level. If the visitor returns false, the walk stops.

Example:

agent.WalkAgents(root, func(ag Agent, depth int) bool {
    fmt.Printf("%s%s\n", strings.Repeat("  ", depth), ag.Name())
    return true // continue walking
})

Types

type AfterAgentCallback

type AfterAgentCallback func(CallbackContext) (*a2a.Message, error)

AfterAgentCallback is called after the agent completes. If it returns non-nil content or error, a new event is created.

type Agent

type Agent interface {
	// Name returns the unique identifier for this agent within the agent tree.
	// Agent name cannot be "user" as it's reserved for end-user input.
	Name() string

	// DisplayName returns the human-readable name of the agent.
	// Used for UI attribution.
	DisplayName() string

	// Description returns a human-readable description of the agent's capability.
	// Used by LLMs to determine whether to delegate control to this agent.
	Description() string

	// Run executes the agent and yields events.
	// The iterator pattern allows clean streaming of results.
	Run(InvocationContext) iter.Seq2[*Event, error]

	// SubAgents returns child agents that this agent can delegate to.
	SubAgents() []Agent

	// Type returns the agent type for introspection.
	// Used by the runner to determine workflow vs delegation semantics.
	Type() AgentType
}

Agent is the base interface which all agents must implement.

Agents are created with constructors to ensure correct initialization:

  • agent.New for custom agents
  • llmagent.New for LLM-based agents
  • remoteagent.NewA2A for remote A2A agents
  • workflowagents for sequential/parallel/loop patterns

func FindAgent

func FindAgent(root Agent, name string) Agent

FindAgent searches for an agent by name in the agent tree. It performs a depth-first search starting from the root agent.

This provides the same functionality as ADK-Go's find_agent() method.

Example:

root, _ := llmagent.New(llmagent.Config{
    Name: "coordinator",
    SubAgents: []agent.Agent{researcher, writer},
})

// Find a descendant by name
found := agent.FindAgent(root, "researcher")
if found != nil {
    // Use the found agent
}

func ListAgents

func ListAgents(root Agent) []Agent

ListAgents returns a flat list of all agents in the tree. The root agent is included first, followed by descendants depth-first.

func New

func New(cfg Config) (Agent, error)

New creates an Agent with custom logic defined by the Run function.

type AgentType

type AgentType string

AgentType identifies the kind of agent for introspection.

const (
	TypeCustomAgent     AgentType = "custom"
	TypeLLMAgent        AgentType = "llm"
	TypeSequentialAgent AgentType = "sequential"
	TypeParallelAgent   AgentType = "parallel"
	TypeLoopAgent       AgentType = "loop"
	TypeRemoteAgent     AgentType = "remote"
	TypeRunnerAgent     AgentType = "runner"
)

type ArtifactInfo

type ArtifactInfo struct {
	Name    string
	Version int64
}

ArtifactInfo describes a stored artifact.

type ArtifactListResponse

type ArtifactListResponse struct {
	Artifacts []ArtifactInfo
}

ArtifactListResponse is returned when listing artifacts.

type ArtifactLoadResponse

type ArtifactLoadResponse struct {
	Name    string
	Version int64
	Part    a2a.Part
}

ArtifactLoadResponse is returned when loading an artifact.

type ArtifactSaveResponse

type ArtifactSaveResponse struct {
	Name    string
	Version int64
}

ArtifactSaveResponse is returned when saving an artifact.

type Artifacts

type Artifacts interface {
	Save(ctx context.Context, name string, part a2a.Part) (*ArtifactSaveResponse, error)
	List(ctx context.Context) (*ArtifactListResponse, error)
	Load(ctx context.Context, name string) (*ArtifactLoadResponse, error)
	LoadVersion(ctx context.Context, name string, version int) (*ArtifactLoadResponse, error)
}

Artifacts provides artifact storage operations.

type BeforeAgentCallback

type BeforeAgentCallback func(CallbackContext) (*a2a.Message, error)

BeforeAgentCallback is called before the agent starts. If it returns non-nil content or error, agent run is skipped.

type CallbackContext

type CallbackContext interface {
	ReadonlyContext

	// Artifacts returns the artifact service.
	Artifacts() Artifacts

	// State returns mutable session state.
	State() State
}

CallbackContext provides state modification for callbacks.

type CancellableTask

type CancellableTask interface {
	// RegisterExecution registers a child execution for cascade cancellation.
	RegisterExecution(exec *ChildExecution)

	// UnregisterExecution removes a child execution from tracking.
	UnregisterExecution(callID string)

	// CancelExecution cancels a specific child execution.
	CancelExecution(callID string) bool

	// GetID returns the task ID.
	GetID() string
}

CancellableTask provides task-level cancellation support. Defined in agent package to avoid circular imports with pkg/task. The task.Task type implements this interface.

type Checkpointable

type Checkpointable interface {
	Agent

	// CaptureCheckpointState returns the agent's current execution state.
	// Called by the checkpoint manager at strategic points (pre-LLM, post-tool, etc.)
	CaptureCheckpointState() (map[string]any, error)

	// RestoreCheckpointState restores the agent's execution state from a checkpoint.
	// Called by the recovery manager when resuming from a checkpoint.
	RestoreCheckpointState(state map[string]any) error
}

Checkpointable is an optional interface for agents that support state checkpointing.

Agents implementing this interface can have their execution state captured for fault tolerance and HITL workflow recovery.

Implementation Note (ported from legacy Hector):

Checkpoints capture the state of the CURRENTLY EXECUTING agent only.
The full multi-agent history is preserved in session events (the source
of truth). On recovery:
  1. Checkpoint identifies which agent was active
  2. Session events provide full conversation history
  3. Runner.findAgentToRun() routes to the correct agent

Not all agents need to implement this - only agents with internal state that cannot be reconstructed from session events alone.

type ChildExecution

type ChildExecution struct {
	// CallID is the unique identifier for this execution.
	CallID string

	// Name is the tool or agent name.
	Name string

	// Type is either "tool" or "agent".
	Type string

	// Cancel is called to cancel this execution.
	Cancel func() bool
}

ChildExecution represents an active tool or sub-agent execution. Used for cascade cancellation when a task is cancelled.

type Config

type Config struct {
	// Name must be a non-empty string, unique within the agent tree.
	Name string

	// DisplayName is the human-readable name (optional).
	DisplayName string

	// Description of the agent's capability (used for delegation decisions).
	Description string

	// SubAgents are child agents this agent can delegate tasks to.
	SubAgents []Agent

	// BeforeAgentCallbacks are called before the agent starts its run.
	// If any returns non-nil content or error, agent run is skipped.
	BeforeAgentCallbacks []BeforeAgentCallback

	// Run defines the agent's execution logic.
	Run func(InvocationContext) iter.Seq2[*Event, error]

	// AgentType allows specifying the agent type (optional).
	// If empty, defaults to TypeCustomAgent.
	AgentType AgentType

	// AfterAgentCallbacks are called after the agent completes its run.
	AfterAgentCallbacks []AfterAgentCallback
}

Config is the configuration for creating a new custom Agent.

type Content

type Content struct {
	Parts []a2a.Part
	Role  a2a.MessageRole
}

Content is a convenience type for building message content.

func NewTextContent

func NewTextContent(text string, role a2a.MessageRole) *Content

NewTextContent creates content with a text part.

func (*Content) AddPart

func (c *Content) AddPart(part a2a.Part)

AddPart appends a part to the content.

func (*Content) AddText

func (c *Content) AddText(text string)

AddText appends a text part to the content.

func (*Content) ToMessage

func (c *Content) ToMessage() *a2a.Message

ToMessage converts Content to an a2a.Message.

type Event

type Event struct {
	// ID is the unique identifier for this event.
	ID string

	// Timestamp when the event was created.
	Timestamp time.Time

	// InvocationID links this event to its invocation.
	InvocationID string

	// Branch isolates conversation history for parallel agents.
	// Format: "agent_1.agent_2.agent_3" (parent chain).
	Branch string

	// Author is the display name of the agent (or "user"/"system").
	// This is used for UI rendering and attribution.
	Author string

	// AgentID is the unique identifier of the agent that produced this event.
	// Used for internal routing, logic, and state tracking.
	AgentID string

	// Message contains the A2A message content (text, files, data).
	// This maps directly to a2a.Message for seamless translation.
	Message *a2a.Message

	// Actions captures side effects (state changes, transfers, etc).
	Actions EventActions

	// LongRunningToolIDs identifies tools awaiting external completion.
	LongRunningToolIDs []string

	// Partial indicates this is a streaming chunk, not a complete event.
	Partial bool

	// TurnComplete indicates this is the final event of a turn.
	TurnComplete bool

	// Interrupted indicates this event was cut off due to cancellation or timeout.
	// When true, the response may be incomplete. This helps distinguish between:
	// - A complete response that ended naturally (Interrupted=false)
	// - A partial response that was forcibly stopped (Interrupted=true)
	Interrupted bool

	// ErrorCode is a machine-readable error identifier (e.g., "rate_limit", "timeout").
	ErrorCode string

	// ErrorMessage is a human-readable error description.
	ErrorMessage string

	// Thinking captures the model's reasoning process (for thinking-enabled models).
	// This is rendered as a collapsible ThinkingWidget in the UI.
	Thinking *ThinkingState

	// ToolCalls captures tool invocations in this event.
	// Each tool call is rendered as a ToolWidget in the UI.
	ToolCalls []ToolCallState

	// ToolResults captures tool execution results in this event.
	// These update the corresponding ToolWidget status.
	ToolResults []ToolResultState

	// CustomMetadata for application-specific data.
	CustomMetadata map[string]any

	// OnPersisted is a callback invoked after the event is persisted to the session.
	// Used by async agents (like ParallelAgent) to synchronize with the persistence layer.
	// This field is not serialized.
	OnPersisted func() `json:"-"`
}

Event represents an interaction in an agent conversation. Events are yielded by Agent.Run() and translated to A2A events by the server.

func NewEvent

func NewEvent(invocationID string) *Event

NewEvent creates a new event with generated ID and current timestamp.

func (*Event) HasToolCalls

func (e *Event) HasToolCalls() bool

HasToolCalls returns true if this event contains tool call requests. Tool calls indicate the LLM wants to execute tools before providing a final response.

func (*Event) HasToolResults

func (e *Event) HasToolResults() bool

HasToolResults returns true if this event contains tool execution results. Tool results indicate tools have been executed and the LLM needs to process them.

func (*Event) IsFinalResponse

func (e *Event) IsFinalResponse() bool

IsFinalResponse returns whether this event is a final response. Multiple events can be final when multiple agents participate in one invocation.

An event is NOT final if it: - Contains function/tool calls (awaiting execution) - Contains function/tool responses (awaiting LLM summarization) - Is a partial/streaming event

func (*Event) TextContent

func (e *Event) TextContent() string

TextContent extracts text content from the event's message.

type EventActions

type EventActions struct {
	// StateDelta contains key-value changes to session state.
	StateDelta map[string]any

	// ArtifactDelta tracks artifact updates (filename -> version).
	ArtifactDelta map[string]int64

	// SkipSummarization prevents LLM summarization of tool responses.
	SkipSummarization bool

	// TransferToAgent requests control transfer to another agent.
	TransferToAgent string

	// Escalate requests escalation to a higher-level agent.
	Escalate bool

	// RequireInput signals that human input is required (HITL pattern).
	// When true, the task transitions to `input_required` state.
	// This is used by long-running tools that need approval or additional info.
	RequireInput bool

	// InputPrompt is the message shown to the human when RequireInput is true.
	// Should explain what input is needed and why.
	InputPrompt string
}

EventActions represents side effects attached to an event.

type Events

type Events interface {
	All() iter.Seq[*Event]
	Len() int
	At(i int) *Event
}

Events provides access to session event history.

type InvocationContext

type InvocationContext interface {
	// Embed CallbackContext which embeds ReadonlyContext
	// This allows InvocationContext to be used wherever ReadonlyContext
	// or CallbackContext is expected.
	CallbackContext

	// Agent returns the current agent being executed.
	Agent() Agent

	// Session returns the session for this invocation.
	Session() Session

	// Memory provides access to cross-session memory.
	Memory() Memory

	// RunConfig returns the runtime configuration for this invocation.
	RunConfig() *RunConfig

	// EndInvocation signals that the invocation should stop.
	EndInvocation()

	// Ended returns whether the invocation has been ended.
	Ended() bool
}

InvocationContext represents the context of an agent invocation.

An invocation:

  1. Starts with a user message and ends with a final response.
  2. Can contain one or multiple agent calls.
  3. Is handled by runner.Run().

An agent call:

  1. Is handled by agent.Run().
  2. Ends when agent.Run() completes.

An agent call can contain multiple steps (LLM calls + tool executions).

┌─────────────────────── invocation ──────────────────────────┐
┌──────────── llm_agent_call_1 ────────────┐ ┌─ agent_call_2 ─┐
┌──── step_1 ────────┐ ┌───── step_2 ──────┐
[call_llm] [call_tool] [call_llm] [transfer]

func NewInvocationContext

func NewInvocationContext(ctx context.Context, params InvocationContextParams) InvocationContext

NewInvocationContext creates a new InvocationContext.

type InvocationContextParams

type InvocationContextParams struct {
	Artifacts   Artifacts
	Memory      Memory
	Session     Session
	Agent       Agent
	Branch      string
	UserContent *Content
	RunConfig   *RunConfig
}

InvocationContextParams contains parameters for creating an InvocationContext.

type Memory

type Memory interface {
	AddSession(ctx context.Context, session Session) error
	Search(ctx context.Context, query string) (*MemorySearchResponse, error)
}

Memory provides cross-session memory operations.

type MemoryResult

type MemoryResult struct {
	Content  string
	Score    float64
	Metadata map[string]any
}

MemoryResult is a single memory search result.

type MemorySearchResponse

type MemorySearchResponse struct {
	Results []MemoryResult
}

MemorySearchResponse contains memory search results.

type ReadonlyContext

type ReadonlyContext interface {
	context.Context

	// InvocationID returns the unique ID for this invocation.
	InvocationID() string

	// AgentName returns the current agent's name.
	AgentName() string

	// UserContent returns the user message that started this invocation.
	UserContent() *Content

	// ReadonlyState returns read-only access to session state.
	ReadonlyState() ReadonlyState

	// UserID returns the user identifier.
	UserID() string

	// AppName returns the application name.
	AppName() string

	// SessionID returns the session identifier.
	SessionID() string

	// Branch returns the agent hierarchy path.
	Branch() string
}

ReadonlyContext provides read-only access to invocation data. Safe to pass to tools and external code.

type ReadonlyState

type ReadonlyState interface {
	Get(key string) (any, error)
	All() iter.Seq2[string, any]
}

ReadonlyState provides read-only access to session state.

type RunConfig

type RunConfig struct {
	// StreamingMode controls event streaming behavior.
	StreamingMode StreamingMode

	// SaveInputBlobsAsArtifacts saves file inputs as artifacts.
	SaveInputBlobsAsArtifacts bool

	// Task provides access to the parent task for cascade cancellation.
	// This is set by the executor when a task is associated with the invocation.
	Task CancellableTask

	// SkipAppendUserMessage skips appending the user message to session.
	// Used for checkpoint recovery where the message already exists in history.
	SkipAppendUserMessage bool
}

RunConfig contains runtime configuration for an invocation.

type Session

type Session interface {
	ID() string
	AppName() string
	UserID() string
	State() State
	Events() Events
}

Session represents a conversation session. Defined here to avoid circular imports with session package.

type State

type State interface {
	Get(key string) (any, error)
	Set(key string, value any) error
	Delete(key string) error
	All() iter.Seq2[string, any]
}

State is a mutable key-value store for session state.

type StreamingMode

type StreamingMode string

StreamingMode controls how events are streamed.

const (
	StreamingModeNone StreamingMode = "none"
	StreamingModeSSE  StreamingMode = "sse"
	StreamingModeFull StreamingMode = "full"
)

type TempClearable

type TempClearable interface {
	// ClearTempKeys removes all keys with the "temp:" prefix.
	// Called automatically after each invocation completes.
	ClearTempKeys()
}

TempClearable is implemented by state stores that support clearing temp keys.

type ThinkingState

type ThinkingState struct {
	// ID uniquely identifies this thinking block within a conversation.
	ID string `json:"id"`

	// Status indicates the lifecycle state: "active" | "completed".
	Status string `json:"status"`

	// Content is the thinking text (may stream incrementally).
	Content string `json:"content"`

	// Signature is used for multi-turn verification (e.g., Anthropic).
	Signature string `json:"signature,omitempty"`

	// Type categorizes the thinking: "default" | "planning" | "reflection" | "goal".
	Type string `json:"type,omitempty"`
}

ThinkingState represents the model's reasoning process. Maps to ThinkingWidget in the UI with proper lifecycle animations.

type ToolCallState

type ToolCallState struct {
	// ID uniquely identifies this tool call (matches LLM's tool_use ID).
	ID string `json:"id"`

	// Name is the tool being called.
	Name string `json:"name"`

	// Args are the arguments passed to the tool.
	Args map[string]any `json:"args"`

	// Status indicates lifecycle: "pending" | "working".
	Status string `json:"status"`
}

ToolCallState represents a tool invocation. Maps to ToolWidget in the UI with "working" status.

type ToolResultState

type ToolResultState struct {
	// ToolCallID links this result to its ToolCallState.
	ToolCallID string `json:"tool_call_id"`

	// Content is the tool's output.
	Content string `json:"content"`

	// Status indicates outcome: "success" | "failed".
	Status string `json:"status"`

	// IsError indicates if Content represents an error message.
	IsError bool `json:"is_error,omitempty"`
}

ToolResultState represents a tool execution result. Updates the corresponding ToolWidget to "success" | "failed".

Directories

Path Synopsis
Package llmagent provides an LLM-based agent implementation for Hector v2.
Package llmagent provides an LLM-based agent implementation for Hector v2.
Package remoteagent provides remote A2A agent support.
Package remoteagent provides remote A2A agent support.
Package runneragent provides a deterministic tool execution agent.
Package runneragent provides a deterministic tool execution agent.
Package workflowagent provides workflow agents for orchestrating multi-agent flows.
Package workflowagent provides workflow agents for orchestrating multi-agent flows.

Jump to

Keyboard shortcuts

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