Documentation
¶
Overview ¶
Package aisdk implements the Vercel AI SDK 6 data stream protocol (the SSE-based UIMessage stream) for Go backends: a streaming writer emitting the events @ai-sdk/react's useChat hook expects, and conversion between UI messages and model messages.
Protocol reference: https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol
Index ¶
- type ChatRequest
- type ContentPart
- type Logger
- type LoggerAware
- type MessagePart
- type ModelMessage
- type NopLogger
- type Tool
- type ToolCall
- type ToolFunction
- type UIMessage
- type UIMessageStream
- func (s *UIMessageStream) Done()
- func (s *UIMessageStream) File(url, mediaType string) error
- func (s *UIMessageStream) Finish() error
- func (s *UIMessageStream) FinishStep() error
- func (s *UIMessageStream) MessageMetadata(metadata any) error
- func (s *UIMessageStream) MessageStart(messageID string) error
- func (s *UIMessageStream) ReasoningDelta(id, delta string) error
- func (s *UIMessageStream) ReasoningEnd(id string) error
- func (s *UIMessageStream) ReasoningStart(id string) error
- func (s *UIMessageStream) Send(event any) error
- func (s *UIMessageStream) SendError(msg string) error
- func (s *UIMessageStream) StartStep() error
- func (s *UIMessageStream) TextDelta(id, delta string) error
- func (s *UIMessageStream) TextEnd(id string) error
- func (s *UIMessageStream) TextStart(id string) error
- func (s *UIMessageStream) ToolInputAvailable(toolCallID, toolName string, input any) error
- func (s *UIMessageStream) ToolInputDelta(toolCallID, inputTextDelta string) error
- func (s *UIMessageStream) ToolInputStart(toolCallID, toolName string) error
- func (s *UIMessageStream) ToolOutputAvailable(toolCallID string, output any) error
- func (s *UIMessageStream) ToolOutputError(toolCallID, errorText string) error
- type Usage
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ChatRequest ¶
type ChatRequest struct {
Messages []UIMessage `json:"messages"`
PageContext json.RawMessage `json:"pageContext,omitempty"`
ClientTools []Tool `json:"clientTools,omitempty"`
}
ChatRequest is the JSON body POSTed by useChat to the chat endpoint. PageContext and ClientTools are extensions a client may add; both are optional, so a plain chat client keeps working unchanged.
type ContentPart ¶ added in v0.2.0
type ContentPart struct {
// Type is "text" or "file".
Type string `json:"type"`
// Text is set when Type is "text".
Text string `json:"text,omitempty"`
// URL, MediaType and Filename describe a file part. URL is remote or a data:
// URL; providers translate both.
URL string `json:"url,omitempty"`
MediaType string `json:"mediaType,omitempty"`
Filename string `json:"filename,omitempty"`
}
ContentPart is one piece of a message's content. It is the general form of ModelMessage.Content: a message that is only text needs none of this, but a message with an attachment has to say what came in which order, because "look at this, then answer that" is not the same prompt as the reverse.
type Logger ¶
type Logger interface {
Debug(msg string, args ...any)
Info(msg string, args ...any)
Warn(msg string, args ...any)
Error(msg string, args ...any)
}
Logger is the whole logging surface this module needs.
The method set deliberately mirrors *slog.Logger, so a plain slog logger satisfies it with no adapter at all. Nothing in the chat backend reaches for a package-global logger: an embedding application injects its own logging stack (a logrus or zap adapter is a handful of lines) and gets every log line in its own format.
type LoggerAware ¶
type LoggerAware interface {
SetLogger(Logger)
}
LoggerAware is implemented by components that can adopt a logger after construction (the providers do). It lets one injection reach the whole request path without every constructor taking a logger.
type MessagePart ¶
type MessagePart struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
ToolCallID string `json:"toolCallId,omitempty"`
ToolName string `json:"toolName,omitempty"`
State string `json:"state,omitempty"`
Input any `json:"input,omitempty"`
Output any `json:"output,omitempty"`
// URL locates a file part's content. It is either a remote URL or a data: URL,
// which is what the client produces for a file picked locally.
URL string `json:"url,omitempty"`
// MediaType is the file part's IANA media type ("image/png").
MediaType string `json:"mediaType,omitempty"`
// Filename is the file part's original name, when the client sent one.
Filename string `json:"filename,omitempty"`
}
MessagePart is a union part inside a UIMessage. Tool parts carry the tool name in Type ("tool-<name>") for static tools, or in ToolName for the "dynamic-tool" type. A completed tool part has a non-nil Output. A "file" part carries URL and MediaType — that is what useChat posts for an attachment.
type ModelMessage ¶
type ModelMessage struct {
Role string `json:"role"`
// Content is the message's text, for a message that is only text.
Content string `json:"content"`
// Parts is the general form: text and files, in the order they arrived. When
// set it is authoritative and Content is ignored.
Parts []ContentPart `json:"parts,omitempty"`
ToolCallID string `json:"toolCallId,omitempty"`
ToolCalls []ToolCall `json:"toolCalls,omitempty"`
}
ModelMessage represents a simplified message for the LLM API call.
Content and Parts are two ways to carry the same thing, and Parts wins: when it is non-empty a provider renders it and ignores Content. Content is the shorthand for the overwhelmingly common case of a message that is only text, so a plain chat never builds a slice it does not need.
func ConvertToModelMessages ¶
func ConvertToModelMessages(msgs []UIMessage) []ModelMessage
ConvertToModelMessages converts UIMessages to role/content messages for LLM APIs. Text parts are concatenated. Completed tool parts (those with an Output) are reconstructed into an assistant message carrying tool_calls plus a following tool-result message — so tool context (including the results of client-executed tools) survives the re-POST that resumes the agent loop. Pending tool parts (no Output) are skipped so we never emit a dangling tool_call the LLM API would reject.
func (ModelMessage) Text ¶ added in v0.2.0
func (m ModelMessage) Text() string
Text is the message's text however it is carried, so a caller that only wants the words does not have to know which form was used. Non-text parts contribute nothing.
type NopLogger ¶
type NopLogger struct{}
NopLogger drops every line. It is the fallback whenever a component was built without a logger, so a missing injection degrades to silence rather than to a nil-pointer panic.
type Tool ¶
type Tool struct {
Type string `json:"type"`
Function ToolFunction `json:"function"`
}
Tool is one tool advertised to the model, in the OpenAI function-calling shape. The Anthropic and ACP providers translate from it, so this stays the single internal tool representation.
type ToolCall ¶ added in v0.2.0
type ToolCall struct {
ID string `json:"id"`
Name string `json:"name"`
Arguments string `json:"arguments"`
}
ToolCall is one tool the model asked for. Arguments stays the raw JSON the model emitted: it is forwarded verbatim rather than decoded and re-encoded, so nothing about the model's own formatting changes underneath it, and a fragment that fails to parse stays diagnosable.
type ToolFunction ¶
type ToolFunction struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Parameters any `json:"parameters"`
}
ToolFunction describes a callable function: its name, its purpose, and its JSON Schema parameters.
type UIMessage ¶
type UIMessage struct {
ID string `json:"id"`
Role string `json:"role"` // "user", "assistant", "system"
Parts []MessagePart `json:"parts"`
}
UIMessage is the shape received from the AI SDK 6 frontend (useChat).
type UIMessageStream ¶
type UIMessageStream struct {
// contains filtered or unexported fields
}
UIMessageStream writes AI SDK 6 Data Stream Protocol events to an http.ResponseWriter. Each event is a Server-Sent Event (SSE) line:
data: {"type":"...","...":"..."}\n\n
The stream ends with:
data: [DONE]\n\n
func NewUIMessageStream ¶
func NewUIMessageStream(w http.ResponseWriter) *UIMessageStream
NewUIMessageStream prepares the ResponseWriter for SSE streaming and returns a stream handle. This is the sole owner of the SSE response headers — callers set only their own (e.g. CORS) before handing the writer over. A writer that already carries a Content-Type is left untouched, so an application that insists on writing the head itself is not overridden.
func (*UIMessageStream) Done ¶
func (s *UIMessageStream) Done()
Done writes the terminal [DONE] marker and marks the stream closed.
func (*UIMessageStream) File ¶ added in v0.2.0
func (s *UIMessageStream) File(url, mediaType string) error
File attaches a file to the message: a generated image, a rendered chart. The URL is either remote or a data: URL, and the client renders it as a file part.
func (*UIMessageStream) Finish ¶
func (s *UIMessageStream) Finish() error
Finish emits the finish event (message complete).
func (*UIMessageStream) FinishStep ¶
func (s *UIMessageStream) FinishStep() error
FinishStep emits a finish-step event.
func (*UIMessageStream) MessageMetadata ¶ added in v0.2.0
func (s *UIMessageStream) MessageMetadata(metadata any) error
MessageMetadata attaches host-defined metadata to the message. The AI SDK merges it into the UIMessage's metadata field, which is where useChat's onFinish reads a turn's token usage from.
The payload is deliberately opaque to this package: the protocol reserves the envelope, not what an application chooses to put in it.
func (*UIMessageStream) MessageStart ¶
func (s *UIMessageStream) MessageStart(messageID string) error
MessageStart emits the start-of-message event.
func (*UIMessageStream) ReasoningDelta ¶
func (s *UIMessageStream) ReasoningDelta(id, delta string) error
ReasoningDelta emits an incremental reasoning chunk.
func (*UIMessageStream) ReasoningEnd ¶
func (s *UIMessageStream) ReasoningEnd(id string) error
ReasoningEnd closes a reasoning block.
func (*UIMessageStream) ReasoningStart ¶
func (s *UIMessageStream) ReasoningStart(id string) error
ReasoningStart begins a reasoning block.
func (*UIMessageStream) Send ¶
func (s *UIMessageStream) Send(event any) error
Send marshals the event to JSON and writes it as an SSE data line.
func (*UIMessageStream) SendError ¶
func (s *UIMessageStream) SendError(msg string) error
SendError writes an error event to the stream.
func (*UIMessageStream) StartStep ¶
func (s *UIMessageStream) StartStep() error
StartStep emits a start-step event.
func (*UIMessageStream) TextDelta ¶
func (s *UIMessageStream) TextDelta(id, delta string) error
TextDelta emits an incremental text chunk.
func (*UIMessageStream) TextEnd ¶
func (s *UIMessageStream) TextEnd(id string) error
TextEnd closes a text block.
func (*UIMessageStream) TextStart ¶
func (s *UIMessageStream) TextStart(id string) error
TextStart begins a text block with the given ID.
func (*UIMessageStream) ToolInputAvailable ¶
func (s *UIMessageStream) ToolInputAvailable(toolCallID, toolName string, input any) error
ToolInputAvailable signals that tool input is fully available.
func (*UIMessageStream) ToolInputDelta ¶
func (s *UIMessageStream) ToolInputDelta(toolCallID, inputTextDelta string) error
ToolInputDelta sends a partial tool input text chunk.
func (*UIMessageStream) ToolInputStart ¶
func (s *UIMessageStream) ToolInputStart(toolCallID, toolName string) error
ToolInputStart begins streaming tool input.
func (*UIMessageStream) ToolOutputAvailable ¶
func (s *UIMessageStream) ToolOutputAvailable(toolCallID string, output any) error
ToolOutputAvailable sends the tool execution result.
func (*UIMessageStream) ToolOutputError ¶ added in v0.2.0
func (s *UIMessageStream) ToolOutputError(toolCallID, errorText string) error
ToolOutputError reports a tool call that failed. It is a distinct event from ToolOutputAvailable on purpose: a failure sent as ordinary output renders as a successful call that happened to return a sentence about an error.
type Usage ¶ added in v0.2.0
type Usage struct {
// InputTokens is the whole prompt, including any part of it served from the
// provider's cache. CachedInputTokens is the subset that was cached, so
// InputTokens - CachedInputTokens is what was billed at full rate.
InputTokens int `json:"inputTokens"`
OutputTokens int `json:"outputTokens"`
TotalTokens int `json:"totalTokens"`
ReasoningTokens int `json:"reasoningTokens"`
CachedInputTokens int `json:"cachedInputTokens"`
}
Usage is the token accounting of one or more model calls, in the AI SDK's LanguageModelUsage shape so a client reads it without translation.
A zero field means "not reported", not "zero": providers differ in what they count, and the ACP path reports nothing at all. Callers that need to tell the two apart should check whether any usage arrived, not whether a field is zero.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package agent is the chat endpoint: an http.Handler that runs an agentic tool loop over a streaming model and renders the result as an AI SDK 6 UIMessage stream.
|
Package agent is the chat endpoint: an http.Handler that runs an agentic tool loop over a streaming model and renders the result as an AI SDK 6 UIMessage stream. |
|
cmd
|
|
|
aisdk-agent
command
Command aisdk-agent is a terminal agent: the same tool loop the HTTP endpoint serves, rendered to a terminal instead of to an AI SDK stream.
|
Command aisdk-agent is a terminal agent: the same tool loop the HTTP endpoint serves, rendered to a terminal instead of to an AI SDK stream. |
|
conformance
|
|
|
server
command
Command conformance-server serves the agent to the real AI SDK client.
|
Command conformance-server serves the agent to the real AI SDK client. |
|
Package llm is one streaming contract over several model APIs.
|
Package llm is one streaming contract over several model APIs. |
|
acp
Package acp drives a local agent process as the model, over the Agent Client Protocol on stdin/stdout.
|
Package acp drives a local agent process as the model, over the Agent Client Protocol on stdin/stdout. |