Skip to content

How to

Generate Text and Structured Output

One-shot text, typed objects, and streamed completions with pkg/pi

Read this when
  • Making your first generation call
  • Getting a typed Go value back instead of prose

Set OPENAI_API_KEY, then run the first program.

pkg/catalog · pi
fig. 01 — One prompt, three ways to take the answer

The prompt and the model spec are the same in all three calls. Only the shape of the answer changes: a message, a typed value, or a stream of deltas.

Generate text

This is the whole program. Every other block on this page is a fragment.

package main
import (
"context"
"fmt"
"log"
"github.com/sonnes/pi-go/pkg/ai"
"github.com/sonnes/pi-go/pkg/pi"
)
func main() {
prompt := pi.Prompt{
Messages: []pi.Message{
ai.UserMessage("Write one sentence about durable agents."),
},
}
msg, err := pi.GenerateText(
context.Background(),
"openai-completions/gpt-5-mini",
prompt,
ai.WithMaxTokens(120),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.JoinText(""))
}

pi.GenerateText resolves the model spec, runs the stream, and returns the final assistant message.

Get a typed object back

type recipe struct {
Title string `json:"title"`
Ingredients []string `json:"ingredients"`
Minutes int `json:"minutes"`
}
result, err := pi.GenerateObject[recipe](ctx, "openai-completions/gpt-5-mini", prompt)
fmt.Println(result.Object.Title, result.Object.Minutes)

pi.GenerateObject builds a JSON Schema from the Go type. The provider must implement object generation.

Stream instead of waiting

stream := pi.StreamText(ctx, "openai-completions/gpt-5-mini", prompt)
for event, err := range stream.Events() {
if event.Type == ai.EventTextDelta {
fmt.Print(event.Delta)
}
// ... thinking_delta, tool_delta, text_end
}
msg, err := stream.Wait() // the same final message, after the deltas
fmt.Println(msg.StopReason)

Read EventTextDelta for UI text. Call Wait after the range to get the final message.

Pick a model

  • Use a full spec when more than one provider is available.
  • openai-completions/gpt-5-mini uses OPENAI_API_KEY.
  • openai-responses/gpt-5-mini uses OPENAI_OAUTH_TOKEN.
  • anthropic-messages/claude-haiku-4-5 uses Anthropic credentials.
  • A bare model ID works only when one registered provider serves it.

Next: Authenticate Providers.