Core Functions
This page documents every public function in the goai package.
Import path: github.com/zendev-sh/goai
GenerateText
Performs a non-streaming text generation. When tools with Execute functions are provided and MaxSteps > 1, it automatically runs a tool loop: generate, execute tools, re-generate.
func GenerateText(ctx context.Context, model provider.LanguageModel, opts ...Option) (*TextResult, error)Parameters:
| Name | Type | Description |
|---|---|---|
ctx | context.Context | Request context for cancellation and deadlines. |
model | provider.LanguageModel | The language model to use. |
opts | ...Option | Configuration options (system prompt, messages, tools, etc.). |
Returns: *TextResult containing generated text, tool calls, step history, and usage. Returns an error on API failure or context cancellation.
Behavior:
- Builds request parameters from the provided options.
- Calls
model.DoGeneratewith automatic retry on transient errors. - If the model returns tool calls and executable tools are registered, executes them and appends results to the conversation.
- Repeats up to
MaxStepstimes (default 1 = single model step; if that step requests executable tools, they can still be executed before returning). - Fires telemetry hooks (
OnRequest,OnResponse,OnStepFinish,OnToolCall) at appropriate points.
Example:
model := google.Chat("gemini-2.0-flash") // auto-reads GOOGLE_GENERATIVE_AI_API_KEY or GEMINI_API_KEY
result, err := goai.GenerateText(context.Background(), model,
goai.WithSystem("You are a helpful assistant. Be concise."),
goai.WithPrompt("What is the capital of France?"),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Text)
fmt.Printf("Tokens: %d in, %d out\n", result.TotalUsage.InputTokens, result.TotalUsage.OutputTokens)StreamText
Performs a streaming text generation, returning a TextStream for incremental consumption.
func StreamText(ctx context.Context, model provider.LanguageModel, opts ...Option) (*TextStream, error)Parameters: Same as GenerateText.
Returns: *TextStream for consuming the response incrementally. Returns an error if the initial API call fails.
Tool Loop Support:
When WithMaxSteps is set > 1 and tools with Execute functions are provided, StreamText runs an automatic tool loop. All steps stream through a single unified channel. Step boundaries are marked by ChunkStepFinish chunks. The initial DoStream failure returns (nil, error). Subsequent step errors flow through the stream as ChunkError chunks — check stream.Err() after consuming.
Example (basic):
stream, err := goai.StreamText(context.Background(), model,
goai.WithPrompt("Write a haiku about Go programming."),
)
if err != nil {
log.Fatal(err)
}
for text := range stream.TextStream() {
fmt.Print(text)
}
fmt.Println()
result := stream.Result()
fmt.Printf("Tokens: %d in, %d out\n", result.TotalUsage.InputTokens, result.TotalUsage.OutputTokens)Example (streaming with tools):
stream, err := goai.StreamText(ctx, model,
goai.WithPrompt("What's the weather in Tokyo?"),
goai.WithTools(weatherTool),
goai.WithMaxSteps(5),
)
if err != nil {
log.Fatal(err)
}
for chunk := range stream.Stream() {
switch chunk.Type {
case provider.ChunkText:
fmt.Print(chunk.Text)
case provider.ChunkStepFinish:
fmt.Println("\n[step complete]")
}
}
if err := stream.Err(); err != nil {
log.Fatal("stream error:", err)
}TextStream
TextStream provides three consumption modes. Stream() and TextStream() are mutually exclusive - only call one. Result() can always be called, including after a streaming method, to get the accumulated final result.
TextStream.Stream
Returns a channel that emits raw provider.StreamChunk values from the provider.
func (ts *TextStream) Stream() <-chan provider.StreamChunkUse this when you need access to all chunk types (text, tool calls, reasoning, finish events).
TextStream.TextStream
Returns a channel that emits only text content strings, filtering out non-text chunks.
func (ts *TextStream) TextStream() <-chan stringUse this when you only need the generated text tokens.
TextStream.Result
Blocks until the stream completes and returns the final accumulated result.
func (ts *TextStream) Result() *TextResultCan be called after Stream() or TextStream() to get usage, finish reason, and the complete text. Can also be called without any streaming method to silently consume the stream and return the result.
TextStream.Err
Returns the first error encountered during streaming, or nil if the stream completed successfully. Follows the bufio.Scanner.Err() pattern: must be called after the stream is fully consumed (after Result(), or after the Stream()/TextStream() channel is drained). Blocks until the stream is done.
func (ts *TextStream) Err() errorGenerateObject
Performs a non-streaming structured output generation. The type parameter T determines the output schema.
func GenerateObject[T any](ctx context.Context, model provider.LanguageModel, opts ...Option) (*ObjectResult[T], error)Parameters: Same as GenerateText, plus structured output options (WithExplicitSchema, WithSchemaName).
Returns: *ObjectResult[T] containing the parsed object, usage, and metadata. Returns an error on API failure, JSON parse failure, or if MaxSteps is exhausted before a stop step occurs.
Behavior:
- Auto-generates a JSON Schema from
TusingSchemaFrom[T](), unless overridden withWithExplicitSchema. - Sets
ResponseFormaton the provider request to enable native JSON mode. - Parses the model's JSON response into the target type
T.
When tools with Execute functions are provided and MaxSteps > 1, GenerateObject runs a tool loop identical to GenerateText. ResponseFormat is set on every step, and the model decides when to call tools vs produce the final JSON output. Structured output is parsed from the step that returns finishReason "stop".
Example:
type Recipe struct {
Name string `json:"name" jsonschema:"description=Recipe name"`
Ingredients []string `json:"ingredients" jsonschema:"description=List of ingredients"`
Steps []string `json:"steps" jsonschema:"description=Cooking steps"`
Difficulty string `json:"difficulty" jsonschema:"enum=easy|medium|hard"`
}
result, err := goai.GenerateObject[Recipe](ctx, model,
goai.WithPrompt("Give me a recipe for chocolate chip cookies"),
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Recipe: %s\n", result.Object.Name)
fmt.Printf("Difficulty: %s\n", result.Object.Difficulty)StreamObject
Performs a streaming structured output generation, returning partial objects as JSON accumulates.
func StreamObject[T any](ctx context.Context, model provider.LanguageModel, opts ...Option) (*ObjectStream[T], error)Parameters: Same as GenerateObject[T].
Returns: *ObjectStream[T] for consuming partial and final results. Returns an error if the initial API call fails.
Note: Unlike
GenerateObject,StreamObjectis intentionally single-step — it does not support tool loops. UseGenerateObjectwhen you need tools and multi-step behaviour.
ObjectStream.PartialObjectStream
Returns a channel that emits progressively populated partial objects as JSON tokens arrive.
func (os *ObjectStream[T]) PartialObjectStream() <-chan *TEach emitted value has more fields populated than the previous one. Fields not yet received have their zero values.
ObjectStream.Result
Blocks until the stream completes and returns the final validated object.
func (os *ObjectStream[T]) Result() (*ObjectResult[T], error)Returns an error if JSON parsing of the accumulated text fails.
ObjectStream.Err
Returns the first error encountered during streaming, or nil if the stream completed successfully. Follows the bufio.Scanner.Err() pattern: must be called after the stream is fully consumed (after Result(), or after the PartialObjectStream() channel is drained). Blocks until the stream is done.
func (os *ObjectStream[T]) Err() errorExample:
stream, err := goai.StreamObject[Recipe](ctx, model,
goai.WithPrompt("Give me a recipe for pancakes"),
)
if err != nil {
log.Fatal(err)
}
for partial := range stream.PartialObjectStream() {
if partial.Name != "" {
fmt.Printf("\rStreaming: %s (%d ingredients)", partial.Name, len(partial.Ingredients))
}
}
fmt.Println()
final, err := stream.Result()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Usage: %d input, %d output tokens\n", final.Usage.InputTokens, final.Usage.OutputTokens)Embed
Generates an embedding vector for a single text value.
func Embed(ctx context.Context, model provider.EmbeddingModel, value string, opts ...Option) (*EmbedResult, error)Parameters:
| Name | Type | Description |
|---|---|---|
ctx | context.Context | Request context. |
model | provider.EmbeddingModel | The embedding model to use. |
value | string | The text to embed. |
opts | ...Option | Options (WithTimeout, WithMaxRetries, WithEmbeddingProviderOptions). |
Returns: *EmbedResult containing the embedding vector, usage, and provider response metadata (Response.Model when available).
Example:
model := google.Embedding("text-embedding-004", google.WithAPIKey(apiKey))
result, err := goai.Embed(ctx, model, "The quick brown fox jumps over the lazy dog")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Dimensions: %d\n", len(result.Embedding))EmbedMany
Generates embedding vectors for multiple text values. Auto-chunks when values exceed the model's MaxValuesPerCall limit and processes chunks in parallel.
func EmbedMany(ctx context.Context, model provider.EmbeddingModel, values []string, opts ...Option) (*EmbedManyResult, error)Parameters:
| Name | Type | Description |
|---|---|---|
ctx | context.Context | Request context. |
model | provider.EmbeddingModel | The embedding model to use. |
values | []string | The texts to embed. |
opts | ...Option | Options (WithMaxParallelCalls, WithTimeout, WithMaxRetries, WithEmbeddingProviderOptions). |
Returns: *EmbedManyResult containing one embedding vector per input value, aggregated usage, and provider response metadata (Response.Model when available). When EmbedMany auto-chunks a large batch, ProviderMetadata is merged from all chunks using last-write-wins semantics per namespace key; Response is taken from the first chunk.
Example:
texts := []string{
"I love programming",
"Software engineering is great",
"The weather is nice today",
}
result, err := goai.EmbedMany(ctx, model, texts)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Generated %d embeddings\n", len(result.Embeddings))GenerateImage
Generates images from a text prompt.
func GenerateImage(ctx context.Context, model provider.ImageModel, opts ...ImageOption) (*ImageResult, error)Parameters:
| Name | Type | Description |
|---|---|---|
ctx | context.Context | Request context. |
model | provider.ImageModel | The image model to use. |
opts | ...ImageOption | Image-specific options (prompt, count, size, aspect ratio, max retries, timeout). |
Note: GenerateImage uses ImageOption instead of Option. See the Options page for image-specific options.
Returns: *ImageResult containing the generated images as byte data.
Example:
result, err := goai.GenerateImage(ctx, model,
goai.WithImagePrompt("A sunset over mountains, oil painting style"),
goai.WithImageSize("1024x1024"),
goai.WithImageCount(1),
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Generated %d image(s)\n", len(result.Images))Message Builders
Convenience functions for constructing provider.Message values.
SystemMessage
func SystemMessage(text string) provider.MessageCreates a system message with text content (role: system).
UserMessage
func UserMessage(text string) provider.MessageCreates a user message with text content (role: user).
AssistantMessage
func AssistantMessage(text string) provider.MessageCreates an assistant message with text content (role: assistant).
ToolMessage
func ToolMessage(toolCallID, toolName, output string) provider.MessageCreates a tool result message (role: tool) containing the output of a tool execution.
Example:
msgs := []provider.Message{
goai.SystemMessage("You are a helpful assistant."),
goai.UserMessage("Hello!"),
goai.AssistantMessage("Hi there! How can I help?"),
goai.UserMessage("What time is it?"),
}
result, err := goai.GenerateText(ctx, model,
goai.WithMessages(msgs...),
)SchemaFrom
Generates a JSON Schema from a Go type using reflection. The schema is compatible with OpenAI strict mode: all properties are required, pointer types become nullable, and additionalProperties is set to false on all objects.
func SchemaFrom[T any]() json.RawMessageSupported struct tags:
| Tag | Example | Description |
|---|---|---|
json:"name" | json:"city" | Sets the property name in the schema. |
json:"-" | json:"-" | Excludes the field from the schema. |
jsonschema:"description=..." | jsonschema:"description=City name" | Adds a description to the property. |
jsonschema:"enum=a|b|c" | jsonschema:"enum=easy|medium|hard" | Restricts values to an enum. |
Supported types: string, bool, int (all sizes), uint (all sizes), float32/64, slices, maps with string keys, structs, time.Time (string with date-time format), json.RawMessage (any type), and recursive types. Embedded structs are flattened. Pointer types produce nullable schemas (type: ["<base>", "null"]).
Limitation: mutually recursive named slice types (for example
type A []B; type B []A) are not supported and can overflow the stack. Use struct wrappers instead.
Example:
type City struct {
Name string `json:"name" jsonschema:"description=City name"`
Population int `json:"population"`
Country string `json:"country" jsonschema:"enum=US|UK|FR|DE"`
Nickname *string `json:"nickname"` // nullable
}
schema := goai.SchemaFrom[City]()
// Produces: {"type":"object","properties":{...},"required":["name","population","country","nickname"],"additionalProperties":false}SchemaFrom is called automatically by GenerateObject and StreamObject. Use it directly when you need the schema for other purposes (validation, documentation, passing to WithExplicitSchema).
Error Utility Functions
See Errors for IsOverflow, ParseHTTPError, ParseHTTPErrorWithHeaders, ParseStreamError, ClassifyStreamError, ErrUnknownTool, and error type documentation.
Tool Call Context Utility
ToolCallIDFromContext
Returns the provider tool call ID from a tool execution context.
func ToolCallIDFromContext(ctx context.Context) stringThis is useful inside a tool Execute function when you need to correlate logs or telemetry with the provider's tool call identifier.