adapters

package
v0.11.0 Latest Latest
Warning

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

Go to latest
Published: Nov 9, 2026 License: Apache-2.0 Imports: 9 Imported by: 3

Documentation

Overview

Package adapters provides adapters for genai providers and realtime sessions.

Index

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{}

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{}

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{}

func WrapReasoning

func WrapReasoning(c genai.Provider) genai.Provider

WrapReasoning wraps a Provider and processes its output to extract reasoning blocks ONLY if needed.

Types

type ProviderAppend

type ProviderAppend struct {
	genai.Provider

	Append genai.Request
}

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

type ProviderUsage struct {
	genai.Provider
	// contains filtered or unexported fields
}

ProviderUsage wraps a Provider and accumulates Usage values across multiple requests to track total token consumption.

func (*ProviderUsage) Embed added in v0.10.2

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

SystemOne implements genai.Provider and accumulates decision token usage.

func (*ProviderUsage) Unwrap

func (c *ProviderUsage) Unwrap() genai.Provider

Jump to

Keyboard shortcuts

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