aisdk

package module
v0.0.0-...-6e7084f Latest Latest
Warning

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

Go to latest
Published: Feb 26, 2026 License: MIT Imports: 15 Imported by: 0

README

aisdk-go fork supporting the v5 Protocol

Go server implementation for Vercel's AI SDK v5.

The protocol was effectively redone in v5, compared to v4. This is a fork implementing some of the functionality of the v5 protocol, and only for the Anthropic backend. It is very much experimental and the API may change frequently.


Original README Follows

GitHub Release GoDoc CI Status

[!WARNING]
This library is super new and may change a lot.

A Go implementation of Vercel's AI SDK Data Stream Protocol.

  • Supports OpenAI, Google, and Anthropic (with Bedrock support)
  • Examples for integrating useChat
  • Chain tool usage in Go, just like maxSteps
// frontend.tsx

const { messages } = useChat({
    // Points to our Go backend!
    api: "/api/chat",
})
// backend.go

// Accept the POST request...
var req *aisdk.Chat

messages, err := aisdk.MessagesToOpenAI(req.Messages)
if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
}

// Convert the http.ResponseWriter to a Data Stream.
dataStream := aisdk.NewDataStream(w)
stream := openaiClient.Chat.Completions.NewStreaming(...)

aisdk.PipeOpenAIToDataStream(stream, dataStream)

Development

Run tests with go test. Start the useChat demo with:

# any or all of these can be set
export OPENAI_API_KEY=<api-key>
export ANTHROPIC_API_KEY=<api-key>
export GOOGLE_API_KEY=<api-key>

cd demo
bun i
bun dev

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func MessagesToAnthropic

func MessagesToAnthropic(messages []Message) ([]anthropic.MessageParam, []anthropic.TextBlockParam, error)

MessagesToAnthropic converts internal message format to Anthropic's API format. It extracts system messages into a separate slice of TextBlockParams and groups consecutive user/tool and assistant messages according to Anthropic's rules. It handles the case where a single assistant message part contains both the tool call and its result, splitting them into the required assistant tool_use and user tool_result blocks.

func MessagesToGoogle

func MessagesToGoogle(messages []Message) ([]*genai.Content, *genai.Content, error)

MessagesToGoogle converts internal message format to Google's genai.Content slice and extracts system messages into a separate SystemInstruction content.

func MessagesToOpenAI

func MessagesToOpenAI(messages []Message) ([]openai.ChatCompletionMessageParamUnion, error)

MessagesToOpenAI converts internal message format to OpenAI's API format.

func SendSingleDataStreamPart

func SendSingleDataStreamPart(w io.Writer, part DataStreamPart) error

func ToolsToAnthropic

func ToolsToAnthropic(tools []Tool) []anthropic.ToolUnionParam

ToolsToAnthropic converts the tool format to Anthropic's API format.

func ToolsToGoogle

func ToolsToGoogle(tools []Tool) ([]*genai.Tool, error)

func ToolsToOpenAI

func ToolsToOpenAI(tools []Tool) []openai.ChatCompletionToolParam

ToolsToOpenAI converts the tool format to OpenAI's API format.

func WriteDataStreamHeaders

func WriteDataStreamHeaders(w http.ResponseWriter)

func WriteDone

func WriteDone(w io.Writer) error

Types

type AnthropicProviderMetadata

type AnthropicProviderMetadata struct {
	Signature string `json:"signature,omitempty"` // Optional signature for reasoning
}

type Attachment

type Attachment struct {
	Name        string `json:"name,omitempty"`
	ContentType string `json:"contentType,omitempty"`
	URL         string `json:"url"`
}

type Chat

type Chat struct {
	ID       string    `json:"id"`
	Messages []Message `json:"messages"`
}

Chat is the structure sent from `useChat` to the server. This can be extended if you'd like to send additional data with `body`.

type DataPart

type DataPart struct {
	TypeSuffix string `json:"-"` // Not serialized, used to construct type
	Data       any    `json:"data"`
}

DataPart provides custom data with a type suffix.

func (DataPart) Type

func (p DataPart) Type() string

type DataStream

type DataStream iter.Seq2[DataStreamPart, error]

DataStream is a stream of DataStreamParts.

func AnthropicToDataStream

func AnthropicToDataStream(stream *ssestream.Stream[anthropic.MessageStreamEventUnion]) (DataStream, func() anthropic.Usage)

AnthropicToDataStream pipes an Anthropic stream to a DataStream.

func GoogleToDataStream

GoogleToDataStream pipes a Google AI stream to a DataStream.

func OpenAIToDataStream

func OpenAIToDataStream(stream *ssestream.Stream[openai.ChatCompletionChunk]) (DataStream, func() openai.CompletionUsage)

OpenAIToDataStream pipes an OpenAI stream to a DataStream.

func (DataStream) Pipe

func (s DataStream) Pipe(w io.Writer) error

Pipe iterates over the DataStream and writes the parts to the writer.

func (DataStream) WithProcessors

func (s DataStream) WithProcessors(processors ...StreamProcessor) DataStream

WithProcessors wraps the DataStream to call processors for each part. Processors observe parts but cannot modify them.

func (DataStream) WithTransformers

func (s DataStream) WithTransformers(transformers ...StreamTransformer) DataStream

WithTransformers wraps the DataStream to transform parts before they reach the consumer.

type DataStreamPart

type DataStreamPart interface {
	Type() string
}

DataStreamPart represents a part of the Vercel AI SDK data stream.

type ErrorPart

type ErrorPart struct {
	ErrorText string `json:"errorText"`
}

ErrorPart indicates an error occurred.

func (ErrorPart) Type

func (p ErrorPart) Type() string

type FilePart

type FilePart struct {
	URL       string `json:"url"`
	MediaType string `json:"mediaType"`
}

FilePart provides file content via URL.

func (FilePart) Type

func (p FilePart) Type() string

type FinishPart

type FinishPart struct {
	FinishReason FinishReason `json:"finishReason,omitzero"`
}

FinishPart indicates the completion of a message.

func (FinishPart) Type

func (p FinishPart) Type() string

type FinishReason

type FinishReason string

FinishReason defines the possible reasons for finishing a step or message.

const (
	FinishReasonStop          FinishReason = "stop"
	FinishReasonLength        FinishReason = "length"
	FinishReasonContentFilter FinishReason = "content-filter"
	FinishReasonToolCalls     FinishReason = "tool-calls"
	FinishReasonError         FinishReason = "error"
	FinishReasonOther         FinishReason = "other"
	FinishReasonUnknown       FinishReason = "unknown"
)

type FinishStepPart

type FinishStepPart struct{}

FinishStepPart indicates the completion of a step.

func (FinishStepPart) Type

func (p FinishStepPart) Type() string

type GoogleProviderMetadata

type GoogleProviderMetadata struct {
	ThoughtSignature []byte `json:"thoughtSignature,omitempty"` // Thought signature for function calls (Gemini 3+)
}

type GoogleStreamIterator

type GoogleStreamIterator interface {
	Next() (*genai.GenerateContentResponse, error)
}

GoogleStreamIterator defines the interface for iterating over Google AI stream responses. This allows for mocking in tests.

type Message

type Message struct {
	ID          string           `json:"id"`
	CreatedAt   *json.RawMessage `json:"createdAt,omitempty"`
	Content     string           `json:"content"`
	Role        string           `json:"role"`
	Parts       []Part           `json:"parts,omitempty"`
	Annotations []any            `json:"annotations,omitempty"`
	Attachments []Attachment     `json:"experimental_attachments,omitempty"`
}

type MessageCollector

type MessageCollector struct {
	// contains filtered or unexported fields
}

MessageCollector accumulates stream parts into a Message compatible with useChat round-trip.

func NewMessageCollector

func NewMessageCollector() *MessageCollector

NewMessageCollector creates a new MessageCollector for accumulating stream parts.

func (*MessageCollector) Message

func (c *MessageCollector) Message() Message

Message returns the accumulated Message.

func (*MessageCollector) Process

func (c *MessageCollector) Process(part DataStreamPart)

Process implements StreamProcessor to accumulate parts into a Message.

type MessageStartPart

type MessageStartPart struct {
	MessageID string `json:"messageId,omitempty"`
}

MessageStartPart indicates the start of a new message.

func (MessageStartPart) Type

func (p MessageStartPart) Type() string

type Part

type Part struct {
	Type PartType `json:"type"`

	// Type: "text"
	Text string `json:"text,omitempty"`

	// Type: "reasoning"
	Reasoning string            `json:"reasoning,omitempty"`
	Details   []ReasoningDetail `json:"details,omitempty"`

	// Type: "tool-invocation"
	ToolCallID string              `json:"toolCallId"`
	ToolName   string              `json:"toolName"`
	Input      any                 `json:"input"`
	Output     any                 `json:"output,omitempty"`
	State      ToolInvocationState `json:"state,omitempty"`
	ErrorText  string              `json:"errorText,omitempty"`

	// Type: "source"
	Source *SourceInfo `json:"source,omitempty"`

	// Type: "file"
	MimeType string `json:"mimeType,omitempty"`
	Data     []byte `json:"data,omitempty"`

	ProviderMetadata *ProviderMetadata `json:"providerMetadata,omitzero"`
}

func MergeParts

func MergeParts(existing, incoming []Part) []Part

MergeParts merges incoming parts with existing parts. Tool invocation parts are merged by ToolCallID (updating existing ones). Step-start parts are filtered out. Other parts are deduplicated by content.

func (Part) MarshalJSON

func (p Part) MarshalJSON() ([]byte, error)

func (*Part) UnmarshalJSON

func (p *Part) UnmarshalJSON(data []byte) error

type PartType

type PartType string
const (
	PartTypeText           PartType = "text"
	PartTypeReasoning      PartType = "reasoning"
	PartTypeToolInvocation PartType = "tool-invocation"
	PartTypeSource         PartType = "source"
	PartTypeFile           PartType = "file"
	PartTypeStepStart      PartType = "step-start"
)

type ProviderMetadata

type ProviderMetadata struct {
	Anthropic *AnthropicProviderMetadata `json:"anthropic,omitzero"`
	Google    *GoogleProviderMetadata    `json:"google,omitzero"`
}

type ReasoningDeltaPart

type ReasoningDeltaPart struct {
	ID               string           `json:"id"`
	Delta            string           `json:"delta"`
	ProviderMetadata ProviderMetadata `json:"providerMetadata,omitzero"`
}

ReasoningDeltaPart contains incremental reasoning content.

func (ReasoningDeltaPart) Type

func (p ReasoningDeltaPart) Type() string

type ReasoningDetail

type ReasoningDetail struct {
	Type      string `json:"type"`
	Text      string `json:"text,omitempty"`
	Signature string `json:"signature,omitempty"`
	Data      string `json:"data,omitempty"`
}

type ReasoningEndPart

type ReasoningEndPart struct {
	ID string `json:"id"`
}

ReasoningEndPart indicates the end of a reasoning segment.

func (ReasoningEndPart) Type

func (p ReasoningEndPart) Type() string

type ReasoningStartPart

type ReasoningStartPart struct {
	ID string `json:"id"`
}

ReasoningStartPart indicates the start of a reasoning segment.

func (ReasoningStartPart) Type

func (p ReasoningStartPart) Type() string

type Schema

type Schema struct {
	Required   []string       `json:"required"`
	Properties map[string]any `json:"properties"`
}

type SourceDocumentPart

type SourceDocumentPart struct {
	SourceID  string `json:"sourceId"`
	MediaType string `json:"mediaType"`
	Title     string `json:"title"`
}

SourceDocumentPart provides document metadata for a source.

func (SourceDocumentPart) Type

func (p SourceDocumentPart) Type() string

type SourceInfo

type SourceInfo struct {
	URI         string         `json:"uri,omitempty"`
	ContentType string         `json:"contentType,omitempty"`
	Data        string         `json:"data,omitempty"`
	Metadata    map[string]any `json:"metadata,omitempty"`
}

type SourceUrlPart

type SourceUrlPart struct {
	SourceID string `json:"sourceId"`
	URL      string `json:"url"`
}

SourceUrlPart provides a URL reference for a source.

func (SourceUrlPart) Type

func (p SourceUrlPart) Type() string

type StartStepStreamPart

type StartStepStreamPart struct {
}

StartStepStreamPart corresponds to TYPE_ID 'f'.

func (StartStepStreamPart) Type

func (p StartStepStreamPart) Type() string

type StreamProcessor

type StreamProcessor func(DataStreamPart)

StreamProcessor observes stream parts as they flow through. Processors cannot modify parts, only observe them.

type StreamTransformer

type StreamTransformer func(DataStreamPart) DataStreamPart

StreamTransformer transforms stream parts as they flow through. It can modify or replace parts before they reach the consumer.

func ReplyToMessageID

func ReplyToMessageID(messageID string) StreamTransformer

ReplyToMessageID returns a transformer that sets the message ID on MessageStartPart. Use this when continuing/updating an existing message so useChat updates it in place.

type TextDeltaPart

type TextDeltaPart struct {
	ID    string `json:"id"`
	Delta string `json:"delta"`
}

TextDeltaPart contains incremental text content.

func (TextDeltaPart) Type

func (p TextDeltaPart) Type() string

type TextEndPart

type TextEndPart struct {
	ID string `json:"id"`
}

TextEndPart indicates the end of a text segment.

func (TextEndPart) Type

func (p TextEndPart) Type() string

type TextStartPart

type TextStartPart struct {
	ID string `json:"id"`
}

TextStartPart indicates the start of a text segment.

func (TextStartPart) Type

func (p TextStartPart) Type() string

type Tool

type Tool struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Schema      Schema `json:"schema"`
}

type ToolCall

type ToolCall struct {
	ID   string         `json:"id"`
	Name string         `json:"name"`
	Args map[string]any `json:"args"`
}

ToolCall represents a tool call *request*.

type ToolCallResult

type ToolCallResult interface {
	Part | []Part | any
}

type ToolInputAvailablePart

type ToolInputAvailablePart struct {
	ToolCallID       string           `json:"toolCallId"`
	ToolName         string           `json:"toolName"`
	Input            map[string]any   `json:"input"`
	ProviderMetadata ProviderMetadata `json:"providerMetadata,omitzero"`
}

ToolInputAvailablePart provides complete tool input.

func (ToolInputAvailablePart) Type

func (p ToolInputAvailablePart) Type() string

type ToolInputDeltaPart

type ToolInputDeltaPart struct {
	ToolCallID     string `json:"toolCallId"`
	InputTextDelta string `json:"inputTextDelta"`
}

ToolInputDeltaPart contains incremental tool input.

func (ToolInputDeltaPart) Type

func (p ToolInputDeltaPart) Type() string

type ToolInputStartPart

type ToolInputStartPart struct {
	ToolCallID string `json:"toolCallId"`
	ToolName   string `json:"toolName"`
}

ToolInputStartPart indicates the start of tool input.

func (ToolInputStartPart) Type

func (p ToolInputStartPart) Type() string

type ToolInvocationState

type ToolInvocationState string
const (
	// useChat tool states
	ToolStateInputStreaming  ToolInvocationState = "input-streaming"
	ToolStateInputAvailable  ToolInvocationState = "input-available"
	ToolStateOutputAvailable ToolInvocationState = "output-available"
	ToolStateOutputError     ToolInvocationState = "output-error"

	// Text/reasoning states (same type, different values)
	StateStreaming ToolInvocationState = "streaming"
	StateDone      ToolInvocationState = "done"

	// Legacy states for backward compatibility
	ToolInvocationStateCall            ToolInvocationState = "call"
	ToolInvocationStatePartialCall     ToolInvocationState = "partial-call"
	ToolInvocationStateResult          ToolInvocationState = "result"
	ToolInvocationStateOutputAvailable ToolInvocationState = "output-available"
	ToolInvocationStateOutputError     ToolInvocationState = "output-error"
)

type ToolOutputAvailablePart

type ToolOutputAvailablePart struct {
	ToolCallID string `json:"toolCallId"`
	Output     any    `json:"output"`
}

ToolOutputAvailablePart provides tool output.

func (ToolOutputAvailablePart) Type

type Usage

type Usage struct {
	PromptTokens     *int64 `json:"promptTokens"`
	CompletionTokens *int64 `json:"completionTokens"`
}

Usage details the token usage.

Jump to

Keyboard shortcuts

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