Documentation
¶
Overview ¶
Package agui serves PromptKit conversations over the AG-UI protocol (1.0), using the AG-UI community Go SDK's types. It provides bidirectional converters between PromptKit and AG-UI messages and tools, and an EventAdapter that turns one conversation turn into one AG-UI run.
Not produced: token-by-token text streaming (each message's text arrives in one TEXT_MESSAGE_CONTENT), reasoning events, STATE_DELTA, MESSAGES_SNAPSHOT, and the pendingToolCallIds of a run that leaves frontend tool calls unanswered. Message ids are minted per conversion, so converting the same message twice gives two ids.
Index ¶
- Variables
- func MessageFromAGUI(msg *aguitypes.Message) types.Message
- func MessageToAGUI(msg *types.Message) aguitypes.Message
- func MessagesFromAGUI(msgs []aguitypes.Message) []types.Message
- func MessagesToAGUI(msgs []types.Message) []aguitypes.Message
- func ToolsFromAGUI(aguiTools []aguitypes.Tool) []*tools.ToolDescriptor
- func ToolsToAGUI(descs []tools.ToolDescriptor) []aguitypes.Tool
- type AdapterOption
- type EventAdapter
- func (a *EventAdapter) Events() <-chan aguievents.Event
- func (a *EventAdapter) RunContinue(ctx context.Context) error
- func (a *EventAdapter) RunID() string
- func (a *EventAdapter) RunResume(ctx context.Context, results []ToolResult) error
- func (a *EventAdapter) RunSend(ctx context.Context, msg *types.Message) error
- func (a *EventAdapter) ThreadID() string
- type EventBusProvider
- type Sender
- type StateProvider
- type ToolResult
- type ToolResultProvider
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrContinueUnsupported = errors.New("agui: conversation does not support Continue")
ErrContinueUnsupported is returned by EventAdapter.RunContinue when the conversation cannot continue after an approval hold.
Functions ¶
func MessageFromAGUI ¶
MessageFromAGUI converts an AG-UI Message to a PromptKit Message. It maps roles, content (text or multimodal), tool calls, and tool call IDs.
A reasoning message becomes an assistant message whose Reasoning holds the text, never user input. MessagesFromAGUI folds it into the assistant message that follows it instead.
Example ¶
ExampleMessageFromAGUI converts an AG-UI Message back to a PromptKit Message, the inverse of agui.MessageToAGUI.
package main
import (
"fmt"
aguitypes "github.com/ag-ui-protocol/ag-ui/sdks/community/go/pkg/core/types"
"github.com/AltairaLabs/PromptKit/sdk/v2/agui"
)
func main() {
aguiMsg := &aguitypes.Message{
Role: aguitypes.RoleAssistant,
Content: "Hi there!",
}
msg := agui.MessageFromAGUI(aguiMsg)
fmt.Println(msg.Role, "->", msg.GetContent())
}
Output: assistant -> Hi there!
func MessageToAGUI ¶
MessageToAGUI converts a PromptKit Message to an AG-UI Message. It maps roles, content, tool calls, and tool results.
User and tool messages carry content parts (text, image, audio, video, document) when they hold media; assistant and system content is text, as AG-UI 1.0 defines it. A media part whose bytes are neither inline nor at a URL (a local file path or a storage reference) has no AG-UI form and is dropped with a warning.
Example ¶
ExampleMessageToAGUI converts a PromptKit Message to the AG-UI wire format used by AG-UI-compatible frontends.
package main
import (
"fmt"
"github.com/AltairaLabs/PromptKit/runtime/v2/types"
"github.com/AltairaLabs/PromptKit/sdk/v2/agui"
)
func main() {
msg := types.NewTextMessage("user", "Hello!")
aguiMsg := agui.MessageToAGUI(&msg)
fmt.Println(aguiMsg.Role, "->", aguiMsg.Content)
}
Output: user -> Hello!
func MessagesFromAGUI ¶
MessagesFromAGUI converts a slice of AG-UI Messages to PromptKit Messages.
A reasoning message is attached to the assistant message that follows it, as that message's Reasoning; with no assistant message after it, it is dropped. Activity messages are UI material that AG-UI says never travels back to the agent, and are dropped too.
func MessagesToAGUI ¶
MessagesToAGUI converts a slice of PromptKit Messages to AG-UI Messages.
func ToolsFromAGUI ¶
func ToolsFromAGUI(aguiTools []aguitypes.Tool) []*tools.ToolDescriptor
ToolsFromAGUI converts a slice of AG-UI Tool definitions to PromptKit ToolDescriptors. Each tool's Parameters (JSON Schema as any) is marshaled to json.RawMessage for InputSchema.
The tools in RunAgentInput.tools are the application's own, executed by the application, so each descriptor has Mode "client": a call to one suspends the turn until the application answers it.
func ToolsToAGUI ¶
func ToolsToAGUI(descs []tools.ToolDescriptor) []aguitypes.Tool
ToolsToAGUI converts a slice of PromptKit ToolDescriptors to AG-UI Tool definitions.
Types ¶
type AdapterOption ¶
type AdapterOption func(*adapterConfig)
AdapterOption configures an EventAdapter.
func WithRunID ¶
func WithRunID(id string) AdapterOption
WithRunID sets the AG-UI run ID for emitted events.
func WithStateProvider ¶
func WithStateProvider(sp StateProvider) AdapterOption
WithStateProvider sets a provider that produces state snapshots.
func WithThreadID ¶
func WithThreadID(id string) AdapterOption
WithThreadID sets the AG-UI thread ID for emitted events.
func WithToolResultProvider ¶
func WithToolResultProvider(provider ToolResultProvider) AdapterOption
WithToolResultProvider sets a callback that answers pending client tools on the server, inside the run. When the callback answers every pending call, the adapter resolves them, emits a TOOL_CALL_RESULT for each, and resumes the turn. Calls it leaves unanswered stay pending: the run finishes with them unanswered, as AG-UI requires for a frontend tool, and the application answers them in the next run (see EventAdapter.RunResume).
Use it only for tools the server itself can answer. A frontend tool, one the application advertised in RunAgentInput.tools, must not be answered by the producer.
func WithWorkflowSteps ¶
func WithWorkflowSteps(enabled bool) AdapterOption
WithWorkflowSteps enables STEP_STARTED / STEP_FINISHED events naming the workflow state a run executes in. It has an effect only when the conversation runs a workflow, as one passed to NewWorkflowEventAdapter does; NewWorkflowEventAdapter enables it by default.
type EventAdapter ¶
type EventAdapter struct {
// contains filtered or unexported fields
}
EventAdapter bridges a PromptKit conversation to an AG-UI event channel. It runs one conversation turn and translates the turn's messages into AG-UI protocol events. An adapter carries one run: its channel closes when the run ends.
func NewEventAdapter ¶
func NewEventAdapter(conv interface {
Sender
EventBusProvider
}, opts ...AdapterOption,
) *EventAdapter
NewEventAdapter creates a new EventAdapter for the given conversation. The conversation must implement both Sender and EventBusProvider. In practice, *sdk.Conversation satisfies both interfaces.
func NewWorkflowEventAdapter ¶ added in v2.11.0
func NewWorkflowEventAdapter(wc *sdk.WorkflowConversation, opts ...AdapterOption) *EventAdapter
NewWorkflowEventAdapter creates an EventAdapter for a workflow conversation. Each run opens a step named after the workflow state it executes in, and a transition the turn commits finishes that step and starts the next. Pass WithWorkflowSteps(false) to leave the steps out.
Client-tool results and approval resolutions go to the workflow's active conversation, the one serving the current state.
func (*EventAdapter) Events ¶
func (a *EventAdapter) Events() <-chan aguievents.Event
Events returns the read-only channel of AG-UI events. The channel is closed when the run ends, successfully or with an error.
Drain it concurrently with RunSend, RunResume or RunContinue, for example from another goroutine. The adapter never drops an event. When the channel's buffer is full it waits for the reader, so a reader that stops reading holds the run until the run's context is canceled; cancel it (an HTTP handler's request context is canceled when the client disconnects) to release the run.
func (*EventAdapter) RunContinue ¶ added in v2.11.0
func (a *EventAdapter) RunContinue(ctx context.Context) error
RunContinue continues a turn whose approval-held tool calls were resolved (sdk.Conversation.ResolveTool / RejectTool) and emits it as a new run.
Read Events() concurrently with the run, or cancel ctx: the run waits for the reader once the channel's buffer of 64 events is full. A caller that lets the run finish before reading blocks there; adapters before this version dropped the events that did not fit instead.
The held calls' results are emitted as TOOL_CALL_RESULT events, since only the agent knows them.
It returns ErrContinueUnsupported (after a RUN_ERROR) when the conversation has no Continue method.
func (*EventAdapter) RunID ¶
func (a *EventAdapter) RunID() string
RunID returns the run ID used by this adapter.
func (*EventAdapter) RunResume ¶ added in v2.11.0
func (a *EventAdapter) RunResume(ctx context.Context, results []ToolResult) error
RunResume answers the client tool calls a previous run left pending and emits the continued turn as a new run.
Read Events() concurrently with the run, or cancel ctx: the run waits for the reader once the channel's buffer of 64 events is full. A caller that lets the run finish before reading blocks there; adapters before this version dropped the events that did not fit instead.
In AG-UI the application answers a frontend tool call in the next run's input, as a tool message per call; ToolResultsFromAGUI extracts them. The answers are the application's own, so the run does not echo them back as TOOL_CALL_RESULT events. Nor does it repeat answers a ToolResultProvider gave in the earlier run, which reported them then: the resumed turn feeds every answer to the model, but none of them is new to the client.
func (*EventAdapter) RunSend ¶
RunSend sends a message through the conversation and emits the run's AG-UI events.
Event sequence on success:
- RUN_STARTED
- STATE_SNAPSHOT (if a StateProvider is configured)
- STEP_STARTED for the current workflow state (workflow conversations)
- For each assistant message the turn produced, in order: TEXT_MESSAGE_START / TEXT_MESSAGE_CONTENT / TEXT_MESSAGE_END, then TOOL_CALL_START / TOOL_CALL_ARGS / TOOL_CALL_END for each call it made; each tool result the turn fed back to the model is a TOOL_CALL_RESULT
- STEP_FINISHED / STEP_STARTED when the turn moved the workflow on
- If a ToolResultProvider answers the pending client tools: a TOOL_CALL_RESULT for each, then the resumed turn from step 4
- STEP_FINISHED for the open step
- RUN_FINISHED
A client tool call left pending ends the run with the call unanswered; the application answers it in the next run with EventAdapter.RunResume. An approval-held call (sdk.Conversation.OnToolAsync) ends the run with RUN_FINISHED carrying an interrupt outcome that names the held calls; the next run continues with EventAdapter.RunContinue.
Text arrives as one TEXT_MESSAGE_CONTENT per message once the turn has run; it is not streamed token by token.
On error, a RUN_ERROR ends the run. The events channel is always closed when RunSend returns.
Read Events() concurrently with the run, or cancel ctx: the run waits for the reader once the channel's buffer of 64 events is full. A caller that lets the run finish before reading blocks there; adapters before this version dropped the events that did not fit instead.
func (*EventAdapter) ThreadID ¶
func (a *EventAdapter) ThreadID() string
ThreadID returns the thread ID used by this adapter.
type EventBusProvider ¶
EventBusProvider abstracts access to the conversation's event bus.
type Sender ¶
type Sender interface {
Send(ctx context.Context, message any, opts ...sdk.SendOption) (*sdk.Response, error)
SendToolResult(ctx context.Context, callID string, result any) error
RejectClientTool(ctx context.Context, callID, reason string)
Resume(ctx context.Context) (*sdk.Response, error)
}
Sender abstracts the conversation methods needed by the adapter. In production code, *sdk.Conversation satisfies this interface.
type StateProvider ¶
StateProvider produces a state snapshot for the AG-UI StateSnapshotEvent.
type ToolResult ¶
type ToolResult struct {
CallID string // must match PendingClientTool.CallID
Result any // JSON-serializable, or []types.ContentPart; ignored when Rejected is true
Rejected bool
Reason string // rejection reason (used when Rejected is true)
// Error reports that the tool failed. Result, when also set, is the
// partial output it produced before failing.
Error string
}
ToolResult carries the caller-provided outcome for a single client tool call.
func ToolResultsFromAGUI ¶ added in v2.11.0
func ToolResultsFromAGUI(msgs []aguitypes.Message) []ToolResult
ToolResultsFromAGUI returns the answers a RunAgentInput carries for the client tool calls a previous run left pending: the tool messages at the end of msgs, after the last message of any other role. Pass them to EventAdapter.RunResume. It returns nil when msgs does not end with a tool message.
The trailing tool messages can include results the agent itself produced in that round (a server tool's TOOL_CALL_RESULT the application kept in its history). An sdk.Conversation resumes with an answer only for a call it has no result for yet, so passing them along is harmless.
A tool message's content becomes the Result: text that is a JSON document is passed through as JSON, other text as a string, and content parts as []types.ContentPart. Its error becomes Error.
type ToolResultProvider ¶
type ToolResultProvider func(ctx context.Context, tools []sdk.PendingClientTool) ([]ToolResult, error)
ToolResultProvider is a callback the caller implements to supply results for pending client tools. The adapter calls it when the LLM response contains deferred client tools that need fulfillment before the pipeline can continue.