Documentation
¶
Overview ¶
Package agui provides utilities for integrating gains with the AG-UI protocol.
AG-UI (Agent-User Interface) is an open, lightweight, event-based protocol that standardizes how AI agents connect to user-facing applications. This package provides mapping utilities to convert gains events to AG-UI events, enabling easy integration with AG-UI-compatible frontends.
Overview ¶
This package provides:
- Mapper: Stateful event converter that handles AG-UI's Start-Content-End pattern
- Message conversion utilities: ToGainsMessages, FromGainsMessages
- State management: DecodeState, MustDecodeState for typed frontend state access
The package does NOT provide HTTP handlers or transport implementations. Users are responsible for implementing their own server using the AG-UI SDK's SSE writer or their preferred transport mechanism.
Usage ¶
Create a Mapper for each run and use it to convert gains events:
// Create mapper for this run
mapper := agui.NewMapper(threadID, runID)
// Emit run started
writeEvent(mapper.RunStarted())
// Run agent and map events
for event := range myAgent.RunStream(ctx, messages) {
aguiEvent := mapper.MapEvent(event)
if aguiEvent != nil {
writeEvent(aguiEvent)
}
}
// Emit run finished
writeEvent(mapper.RunFinished())
Event Mapping ¶
The Mapper tracks state to properly emit AG-UI's Start-Content-End sequences:
- event.MessageDelta → TEXT_MESSAGE_START (on first delta), TEXT_MESSAGE_CONTENT
- event.StepEnd → TEXT_MESSAGE_END (if message active), STEP_FINISHED
- event.ToolCallStart → TOOL_CALL_START, TOOL_CALL_ARGS
- event.ToolCallResult → TOOL_CALL_END, TOOL_CALL_RESULT
Message Conversion ¶
Use ToGainsMessages to convert AG-UI messages to gains messages for input:
messages := agui.ToGainsMessages(aguiMessages) result := agent.Run(ctx, messages)
Use FromGainsMessages to convert gains messages to AG-UI format for snapshots:
snapshot := events.NewMessagesSnapshotEvent(agui.FromGainsMessages(history))
Shared State ¶
AG-UI supports bidirectional state synchronization between agents and frontends. The frontend can send state with each run via RunAgentInput.State, and agents can emit state updates via STATE_SNAPSHOT and STATE_DELTA events.
Reading frontend state:
type MyState struct {
Progress int `json:"progress"`
Items []string `json:"items"`
}
prepared, _ := input.Prepare()
state, err := agui.DecodeState[MyState](prepared)
// or: state := agui.MustDecodeState[MyState](prepared)
Emitting state to frontend:
// Full state snapshot
writeEvent(mapper.StateSnapshot(map[string]any{
"progress": 50,
"items": []string{"a", "b"},
}))
// Incremental delta (JSON Patch RFC 6902)
writeEvent(mapper.StateDelta(
event.Replace("/progress", 75),
event.Add("/items/-", "c"),
))
Or via gains events for integration with RunStream:
events <- event.NewStateSnapshot(state)
events <- event.NewStateDelta(
event.Replace("/progress", 100),
)
Thread Safety ¶
The Mapper is NOT safe for concurrent use. Each goroutine should have its own Mapper instance. Message conversion functions are stateless and safe for concurrent use.
Index ¶
- Constants
- Variables
- func DecodeState[T any](input *PreparedInput) (T, error)
- func FromGainsMessage(msg ai.Message, index int) events.Message
- func FromGainsMessages(msgs []ai.Message) []events.Message
- func MustDecodeState[T any](input *PreparedInput) T
- func ToGainsMessage(msg events.Message) ai.Message
- func ToGainsMessages(msgs []events.Message) []ai.Message
- func ToGainsTools(tools []Tool) []ai.Tool
- func ToolNames(tools []Tool) []string
- type Mapper
- func (m *Mapper) MapEvent(e event.Event) events.Event
- func (m *Mapper) MapStream(input <-chan event.Event) <-chan events.Event
- func (m *Mapper) RunError(err error) events.Event
- func (m *Mapper) RunFinished() events.Event
- func (m *Mapper) RunID() string
- func (m *Mapper) RunStarted() events.Event
- func (m *Mapper) StateDelta(patches ...event.JSONPatch) events.Event
- func (m *Mapper) StateSnapshot(state any) events.Event
- func (m *Mapper) ThreadID() string
- type PreparedInput
- type RunAgentInput
- type Tool
Constants ¶
const ( RoleUser = "user" RoleAssistant = "assistant" RoleSystem = "system" RoleTool = "tool" )
Role constants matching AG-UI protocol.
Variables ¶
var ErrNoMessages = errors.New("no messages provided")
ErrNoMessages is returned when the input contains no messages.
Functions ¶
func DecodeState ¶
func DecodeState[T any](input *PreparedInput) (T, error)
DecodeState decodes the raw state into a typed struct. Returns the zero value of T if State is nil.
func FromGainsMessage ¶
FromGainsMessage converts a single gains message to an AG-UI message. The index is used to generate a message ID if needed.
func FromGainsMessages ¶
FromGainsMessages converts gains messages to AG-UI messages.
func MustDecodeState ¶
func MustDecodeState[T any](input *PreparedInput) T
MustDecodeState is like DecodeState but panics on error.
func ToGainsMessage ¶
ToGainsMessage converts a single AG-UI message to a gains message.
func ToGainsMessages ¶
ToGainsMessages converts AG-UI messages to gains messages.
func ToGainsTools ¶
ToGainsTools converts a slice of AG-UI tools to gains tools.
Types ¶
type Mapper ¶
type Mapper struct {
// contains filtered or unexported fields
}
Mapper converts gains events to AG-UI events. With the unified event system, this is now a true 1:1 mapping - each gains event maps to exactly one AG-UI event.
Create a new Mapper for each run using NewMapper. The Mapper is not safe for concurrent use - each goroutine should have its own Mapper.
func NewMapper ¶
NewMapper creates a new Mapper for a single run. The threadID and runID are used in lifecycle events (RUN_STARTED, RUN_FINISHED).
func (*Mapper) MapEvent ¶
MapEvent converts a unified gains event to an AG-UI event. This is a true 1:1 mapping - each gains event maps to exactly one AG-UI event. Returns nil for events that have no AG-UI equivalent.
func (*Mapper) MapStream ¶
MapStream wraps a gains event channel and yields AG-UI events. Events that have no AG-UI equivalent (returning nil from MapEvent) are filtered out. The returned channel closes when the input channel closes.
func (*Mapper) RunFinished ¶
RunFinished returns a RUN_FINISHED event.
func (*Mapper) RunStarted ¶
RunStarted returns a RUN_STARTED event.
func (*Mapper) StateDelta ¶
StateDelta returns a STATE_DELTA event with the given JSON Patch operations.
func (*Mapper) StateSnapshot ¶
StateSnapshot returns a STATE_SNAPSHOT event with the given state.
type PreparedInput ¶
type PreparedInput struct {
ThreadID string
RunID string
Messages []ai.Message
Tools []Tool // Parsed frontend tools
ToolNames []string // Tool names for cleanup tracking
State any // Raw state from frontend
}
PreparedInput contains validated and converted input ready for agent execution.
func (*PreparedInput) GainsTools ¶
func (p *PreparedInput) GainsTools() []ai.Tool
GainsTools converts the parsed frontend tools to gains tools. Returns nil if no tools were parsed.
type RunAgentInput ¶
type RunAgentInput struct {
ThreadID string `json:"thread_id"`
RunID string `json:"run_id"`
Messages []events.Message `json:"messages"`
Tools []any `json:"tools,omitempty"` // Frontend-provided tools
Context []any `json:"context,omitempty"` // Context items
State any `json:"state,omitempty"` // State
ForwardedProps any `json:"forwarded_props,omitempty"` // Forwarded props
}
RunAgentInput represents the AG-UI protocol request for running an agent. This mirrors the AG-UI protocol specification and is transport-agnostic.
func (*RunAgentInput) Prepare ¶
func (r *RunAgentInput) Prepare() (*PreparedInput, error)
Prepare validates the input and converts it to gains types. Returns ErrNoMessages if Messages is empty. Returns an error if tool parsing fails.
type Tool ¶
type Tool struct {
Name string `json:"name"`
Description string `json:"description"`
Parameters json.RawMessage `json:"parameters,omitempty"`
}
Tool represents a tool definition from the AG-UI protocol. Frontend applications send these to define capabilities available to agents.
func ParseTools ¶
ParseTools parses a slice of any (from JSON unmarshaling) into Tool structs. This handles the Tools field from RunAgentInput which is []any.
func (Tool) ToGainsTool ¶
ToGainsTool converts an AG-UI tool to a gains Tool.