Documentation
¶
Overview ¶
Package adapters provides adapters for genai providers and realtime sessions.
Index ¶
- func GenStreamWithToolCallLoop(ctx context.Context, p genai.Provider, msgs genai.Messages, ...) (iter.Seq[genai.Reply], func() (genai.Messages, genai.Usage, error))
- func GenSyncWithToolCallLoop(ctx context.Context, p genai.Provider, msgs genai.Messages, ...) (genai.Messages, genai.Usage, error)
- func RealtimeWithToolCallLoop(s genai.RealtimeSession, tools []genai.ToolDef) genai.RealtimeSession
- func WrapReasoning(c genai.Provider) genai.Provider
- type ProviderAppend
- func (c *ProviderAppend) GenStream(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (iter.Seq[genai.Reply], func() (genai.Result, error))
- func (c *ProviderAppend) GenSync(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (genai.Result, error)
- func (c *ProviderAppend) Unwrap() genai.Provider
- type ProviderReasoning
- func (c *ProviderReasoning) GenStream(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (iter.Seq[genai.Reply], func() (genai.Result, error))
- func (c *ProviderReasoning) GenSync(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (genai.Result, error)
- func (c *ProviderReasoning) Unwrap() genai.Provider
- type ProviderUsage
- func (c *ProviderUsage) Embed(ctx context.Context, in *genai.EmbeddingRequest) (*genai.EmbeddingResponse, error)
- func (c *ProviderUsage) GenStream(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (iter.Seq[genai.Reply], func() (genai.Result, error))
- func (c *ProviderUsage) GenSync(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (genai.Result, error)
- func (c *ProviderUsage) GetAccumulatedUsage() genai.Usage
- func (c *ProviderUsage) SystemOne(ctx context.Context, req *genai.SystemOneRequest) (*genai.SystemOneResponse, error)
- func (c *ProviderUsage) Unwrap() genai.Provider
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GenStreamWithToolCallLoop ¶
func GenStreamWithToolCallLoop(ctx context.Context, p genai.Provider, msgs genai.Messages, opts ...genai.GenOption) (iter.Seq[genai.Reply], func() (genai.Messages, genai.Usage, error))
GenStreamWithToolCallLoop runs a conversation loop with an LLM that handles tool calls via streaming until there are no more. It will repeatedly call GenStream(), collect fragments into a complete message, process tool calls with DoToolCalls(), and continue the conversation until the LLM response has no more tool calls.
The function will return early if any error occurs. The returned Messages will include all the messages including the original ones, the LLM's responses, and the tool call result messages.
Warning: If opts.Force == ToolCallRequired, it will be mutated to ToolCallAny after the first tool call.
No need to process the tool calls or accumulate the Reply fragments.
Example ¶
package main
import (
"context"
"log"
"os"
"time"
"github.com/maruel/genai"
"github.com/maruel/genai/adapters"
"github.com/maruel/genai/providers/gemini"
)
func main() {
// Supported by Anthropic, Cerebras, Cloudflare, Cohere, DeepSeek, Gemini, Groq, HuggingFace, Mistral,
// Ollama, OpenAI, TogetherAI.
// Using a free small model for testing.
// See https://ai.google.dev/gemini-api/docs/models/gemini?hl=en
ctx := context.Background()
c, err := gemini.New(ctx, genai.ProviderOptionModel("gemini-2.5-flash"))
if c != nil {
defer func() {
if err := c.Close(); err != nil {
log.Printf("Close: %v", err)
}
}()
}
if err != nil {
log.Print(err)
return
}
msgs := genai.Messages{genai.NewTextMessage("What season are we in?")}
opts := genai.GenOptionTools{
// GetTodayClockTime returns the current time and day in a format that the LLM
// can understand. It includes the weekend.
Tools: []genai.ToolDef{GetTodayClockTime},
// Force the LLM to do a tool call first.
Force: genai.ToolCallRequired,
}
fragments, finish := adapters.GenStreamWithToolCallLoop(ctx, c, msgs, &opts)
for f := range fragments {
_, _ = os.Stdout.WriteString(f.Text)
}
if _, _, err = finish(); err != nil {
log.Print(err)
return
}
}
var GetTodayClockTime = genai.ToolDef{
Name: "get_today_date_current_clock_time",
Description: "Get the current clock time and today's date.",
Callback: func(ctx context.Context, e *empty) (string, error) {
return time.Now().Format("Monday 2006-01-02 15:04:05"), nil
},
}
type empty struct{}
Output:
func GenSyncWithToolCallLoop ¶
func GenSyncWithToolCallLoop(ctx context.Context, p genai.Provider, msgs genai.Messages, opts ...genai.GenOption) (genai.Messages, genai.Usage, error)
GenSyncWithToolCallLoop runs a conversation with the LLM, handling tool calls in a loop until there are no more tool calls.
It calls the provided Provider.GenSync() method, processes any tool calls using Message.DoToolCalls(), and continues the conversation in a loop until the LLM's response has no more tool calls.
Warning: If opts.Force == ToolCallRequired, it will be mutated to ToolCallAny after the first tool call.
It returns the messages to accumulate to the thread. The last message is the LLM's response.
Example ¶
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/maruel/genai"
"github.com/maruel/genai/adapters"
"github.com/maruel/genai/providers/gemini"
)
func main() {
// Supported by Anthropic, Cerebras, Cloudflare, Cohere, DeepSeek, Gemini, Groq, HuggingFace, Mistral,
// Ollama, OpenAI, TogetherAI.
// Using a free small model for testing.
// See https://ai.google.dev/gemini-api/docs/models/gemini?hl=en
ctx := context.Background()
c, err := gemini.New(ctx, genai.ProviderOptionModel("gemini-2.5-flash"))
if c != nil {
defer func() {
if err := c.Close(); err != nil {
log.Printf("Close: %v", err)
}
}()
}
if err != nil {
log.Print(err)
return
}
msgs := genai.Messages{genai.NewTextMessage("What season are we in?")}
opts := genai.GenOptionTools{
// GetTodayClockTime returns the current time and day in a format that the LLM
// can understand. It includes the weekend.
Tools: []genai.ToolDef{GetTodayClockTime},
// Force the LLM to do a tool call first.
Force: genai.ToolCallRequired,
}
newMsgs, _, err := adapters.GenSyncWithToolCallLoop(ctx, c, msgs, &opts)
if err != nil {
log.Print(err)
return
}
fmt.Printf("%s\n", newMsgs[len(newMsgs)-1].String())
}
var GetTodayClockTime = genai.ToolDef{
Name: "get_today_date_current_clock_time",
Description: "Get the current clock time and today's date.",
Callback: func(ctx context.Context, e *empty) (string, error) {
return time.Now().Format("Monday 2006-01-02 15:04:05"), nil
},
}
type empty struct{}
Output:
func RealtimeWithToolCallLoop ¶ added in v0.11.0
func RealtimeWithToolCallLoop(s genai.RealtimeSession, tools []genai.ToolDef) genai.RealtimeSession
RealtimeWithToolCallLoop wraps a realtime session and executes tool calls in a loop. The caller still owns the event loop and decides when to stop.
It updates its tool declarations after a successful RealtimeUpdate, so later tool calls use the currently configured tools. Tools without a callback are rejected when called.
Example ¶
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/maruel/genai"
"github.com/maruel/genai/adapters"
"github.com/maruel/genai/providers/openaichat"
)
func main() {
ctx := context.Background()
c, err := openaichat.New(ctx, genai.ProviderOptionModel("gpt-realtime-2.1"))
if err != nil {
log.Print(err)
return
}
defer func() {
if err := c.Close(); err != nil {
log.Printf("Close: %v", err)
}
}()
tools := []genai.ToolDef{GetTodayClockTime}
s, err := c.ConnectRealtime(ctx, &genai.RealtimeOptionTools{Tools: tools}, genai.RealtimeTurnManual)
if err != nil {
log.Print(err)
return
}
s = adapters.RealtimeWithToolCallLoop(s, tools)
defer func() {
if err := s.Close(); err != nil {
log.Printf("Close: %v", err)
}
}()
// The adapter uses these tools. Send RealtimeUpdate with new Tools to
// replace the active set.
if err := s.Send(ctx, genai.RealtimeInputContent{Text: "What time is it?", Generate: true}); err != nil {
log.Print(err)
return
}
for e, err := range s.Receive(ctx) {
if err != nil {
log.Print(err)
return
}
switch e.Kind {
case genai.RealtimeEventContentText:
fmt.Print(e.Content.Text)
case genai.RealtimeEventError:
log.Printf("Provider rejected a command: %v", e.Error)
case genai.RealtimeEventTurnDone:
return
default:
// Audio and transcription events are ignored in this example.
}
}
}
var GetTodayClockTime = genai.ToolDef{
Name: "get_today_date_current_clock_time",
Description: "Get the current clock time and today's date.",
Callback: func(ctx context.Context, e *empty) (string, error) {
return time.Now().Format("Monday 2006-01-02 15:04:05"), nil
},
}
type empty struct{}
Output:
Types ¶
type ProviderAppend ¶
ProviderAppend wraps a Provider and appends a Request before processing when the messages end with a user message.
Useful to inject a "/think" for Qwen3 models.
func (*ProviderAppend) GenStream ¶
func (c *ProviderAppend) GenStream(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (iter.Seq[genai.Reply], func() (genai.Result, error))
GenStream implements genai.Provider.
func (*ProviderAppend) GenSync ¶
func (c *ProviderAppend) GenSync(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (genai.Result, error)
GenSync implements genai.Provider.
func (*ProviderAppend) Unwrap ¶
func (c *ProviderAppend) Unwrap() genai.Provider
type ProviderReasoning ¶
type ProviderReasoning struct {
genai.Provider
// ReasoningTokenStart is the start reasoning token. It is often "<think>\n" but there are cases when it can
// be never output, like "qwen-3-235b-a22b-thinking-2507".
ReasoningTokenStart string
// ReasoningTokenEnd is the end reasoning token, where the explicit answer lies after. It is often
// "\n</think>\n".
ReasoningTokenEnd string
// contains filtered or unexported fields
}
ProviderReasoning wraps a Provider and processes its output to extract reasoning blocks.
It looks for content within tags ReasoningTokenStart and ReasoningTokenEnd and places it in Reasoning Content blocks instead of Text.
It requires the starting reasoning tag. Otherwise, the content is assumed to be text. This is necessary for JSON formatted responses.
func (*ProviderReasoning) GenStream ¶
func (c *ProviderReasoning) GenStream(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (iter.Seq[genai.Reply], func() (genai.Result, error))
GenStream implements the Provider interface for streaming by delegating to the wrapped provider and processing each fragment to extract reasoning blocks. If no reasoning tags are present, the first part of the message is assumed to be reasoning.
func (*ProviderReasoning) GenSync ¶
func (c *ProviderReasoning) GenSync(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (genai.Result, error)
GenSync implements the Provider interface by delegating to the wrapped provider and processing the result to extract reasoning blocks.
func (*ProviderReasoning) Unwrap ¶
func (c *ProviderReasoning) Unwrap() genai.Provider
type ProviderUsage ¶
ProviderUsage wraps a Provider and accumulates Usage values across multiple requests to track total token consumption.
func (*ProviderUsage) Embed ¶ added in v0.10.2
func (c *ProviderUsage) Embed(ctx context.Context, in *genai.EmbeddingRequest) (*genai.EmbeddingResponse, error)
Embed implements genai.Provider and accumulates embedding token usage.
func (*ProviderUsage) GenStream ¶
func (c *ProviderUsage) GenStream(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (iter.Seq[genai.Reply], func() (genai.Result, error))
GenStream implements the Provider interface and accumulates usage statistics.
func (*ProviderUsage) GenSync ¶
func (c *ProviderUsage) GenSync(ctx context.Context, msgs genai.Messages, opts ...genai.GenOption) (genai.Result, error)
GenSync implements the Provider interface and accumulates usage statistics.
func (*ProviderUsage) GetAccumulatedUsage ¶
func (c *ProviderUsage) GetAccumulatedUsage() genai.Usage
GetAccumulatedUsage returns the current accumulated usage values.
func (*ProviderUsage) SystemOne ¶ added in v0.10.0
func (c *ProviderUsage) SystemOne(ctx context.Context, req *genai.SystemOneRequest) (*genai.SystemOneResponse, error)
SystemOne implements genai.Provider and accumulates decision token usage.
func (*ProviderUsage) Unwrap ¶
func (c *ProviderUsage) Unwrap() genai.Provider