Skip to main content

Usage Types

Types for tracking token usage and costs across API calls with detailed breakdowns for multimodal inputs, caching, and reasoning.

Usage​

type Usage struct {
InputTokens *int64 // Total input tokens (prompt)
OutputTokens *int64 // Total output tokens (completion)
TotalTokens *int64 // Total tokens (input + output)

InputDetails *InputTokenDetails // Detailed input token breakdown
OutputDetails *OutputTokenDetails // Detailed output token breakdown

Raw map[string]interface{} // Provider-specific raw usage data
}

Token usage information for language model calls with v6.0 detailed tracking.

Fields​

FieldTypeDescription
InputTokens*int64Total tokens in the input (prompt)
OutputTokens*int64Total tokens in the output (completion)
TotalTokens*int64Total tokens (input + output)
InputDetails*InputTokenDetailsDetailed breakdown of input tokens (cache, text/image)
OutputDetails*OutputTokenDetailsDetailed breakdown of output tokens (text/reasoning)
Rawmap[string]interfaceProvider-specific usage data

Methods​

func (u Usage) Add(other Usage) Usage

Adds two usage objects together, merging all detailed breakdowns.

func (u Usage) GetInputTokens() int64
func (u Usage) GetOutputTokens() int64
func (u Usage) GetTotalTokens() int64

Helper methods that return 0 if the pointer is nil.

InputTokenDetails​

type InputTokenDetails struct {
NoCacheTokens *int64 // Tokens not served from cache
CacheReadTokens *int64 // Tokens read from cache
CacheWriteTokens *int64 // Tokens written to cache
TextTokens *int64 // Text input tokens (for multimodal)
ImageTokens *int64 // Image input tokens (for multimodal)
}

Detailed breakdown of input token usage, particularly useful for:

  • Tracking prompt caching benefits (cost savings)
  • Differentiating text vs image costs in multimodal models

Fields​

FieldTypeDescription
NoCacheTokens*int64Input tokens processed normally (not from cache)
CacheReadTokens*int64Input tokens read from cache (cheaper)
CacheWriteTokens*int64Input tokens written to cache for future use
TextTokens*int64Text input tokens (for multimodal cost tracking)
ImageTokens*int64Image input tokens (for multimodal cost tracking)

OutputTokenDetails​

type OutputTokenDetails struct {
TextTokens *int64 // Tokens for regular text generation
ReasoningTokens *int64 // Tokens for internal reasoning (o1/o3)
}

Detailed breakdown of output token usage for models with reasoning capabilities.

Fields​

FieldTypeDescription
TextTokens*int64Tokens used for regular text generation
ReasoningTokens*int64Tokens used for internal reasoning (not shown in output)

Other Usage Types​

EmbeddingUsage​

type EmbeddingUsage struct {
InputTokens int
TotalTokens int
}

ImageUsage​

type ImageUsage struct {
ImageCount int
}

TranscriptionUsage​

type TranscriptionUsage struct {
DurationSeconds float64
}

VideoUsage​

type VideoUsage struct {
VideoCount int
TotalDurationSeconds float64
}

Examples​

Basic Usage Tracking​

package main

import (
"context"
"fmt"
"log"

"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)

func main() {
provider := openai.New(openai.Config{APIKey: "your-api-key"})
model, err := provider.LanguageModel("gpt-4")
if err != nil {
log.Fatal(err)
}

result, err := ai.GenerateText(context.Background(), ai.GenerateTextOptions{
Model: model,
Prompt: "Hello, world!",
})
if err != nil {
log.Fatal(err)
}

usage := result.Usage
fmt.Printf("Input tokens: %d\n", usage.GetInputTokens())
fmt.Printf("Output tokens: %d\n", usage.GetOutputTokens())
fmt.Printf("Total tokens: %d\n", usage.GetTotalTokens())
}

Track Text vs Image Tokens (Multimodal)​

result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Messages: []types.Message{
{
Role: types.RoleUser,
Content: []types.ContentPart{
types.TextContent{Text: "Describe this image:"},
types.ImageContent{URL: imageURL},
},
},
},
})
if err != nil {
log.Fatal(err)
}

// Check if provider supports text/image breakdown
if result.Usage.InputDetails != nil {
if result.Usage.InputDetails.TextTokens != nil {
fmt.Printf("Text input tokens: %d\n", *result.Usage.InputDetails.TextTokens)
}
if result.Usage.InputDetails.ImageTokens != nil {
fmt.Printf("Image input tokens: %d\n", *result.Usage.InputDetails.ImageTokens)
}
}

Estimate Cost with Multimodal Pricing​

// Example pricing (OpenAI GPT-4o)
const (
textInputCost = 0.0000025 // $2.50 per 1M tokens
imageInputCost = 0.0000075 // $7.50 per 1M tokens (approx)
outputCost = 0.0000100 // $10.00 per 1M tokens
)

usage := result.Usage
var cost float64

// Calculate input cost (text + image)
if usage.InputDetails != nil && usage.InputDetails.TextTokens != nil && usage.InputDetails.ImageTokens != nil {
// Accurate multimodal cost
cost += float64(*usage.InputDetails.TextTokens) * textInputCost
cost += float64(*usage.InputDetails.ImageTokens) * imageInputCost
} else {
// Fallback to average rate if breakdown not available
cost += float64(usage.GetInputTokens()) * textInputCost
}

// Add output cost
cost += float64(usage.GetOutputTokens()) * outputCost

fmt.Printf("Estimated cost: $%.6f\n", cost)

Track Cached Tokens​

result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: longPrompt,
})
if err != nil {
log.Fatal(err)
}

if result.Usage.InputDetails != nil && result.Usage.InputDetails.CacheReadTokens != nil {
cacheRead := *result.Usage.InputDetails.CacheReadTokens
if cacheRead > 0 {
total := result.Usage.GetInputTokens()
savings := float64(cacheRead) / float64(total) * 100
fmt.Printf("Cache hit! %d tokens from cache (%.1f%% savings)\n", cacheRead, savings)
}
}

Track Reasoning Tokens (o1/o3 Models)​

model, _ := openaiProvider.LanguageModel("o3-mini") // OpenAI reasoning model

result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "Solve this complex problem...",
})
if err != nil {
log.Fatal(err)
}

if result.Usage.OutputDetails != nil && result.Usage.OutputDetails.ReasoningTokens != nil {
reasoning := *result.Usage.OutputDetails.ReasoningTokens
text := *result.Usage.OutputDetails.TextTokens

fmt.Printf("Text tokens: %d\n", text)
fmt.Printf("Reasoning tokens: %d (hidden)\n", reasoning)
fmt.Printf("Reasoning overhead: %.1f%%\n", float64(reasoning)/float64(text)*100)
}

Accumulate Usage Across Calls​

var totalUsage types.Usage

for i := 0; i < 5; i++ {
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: fmt.Sprintf("Question %d", i),
})
if err != nil {
log.Printf("Error on call %d: %v", i, err)
continue
}

totalUsage = totalUsage.Add(result.Usage)
}

fmt.Printf("Total usage across all calls:\n")
fmt.Printf(" Input tokens: %d\n", totalUsage.GetInputTokens())
fmt.Printf(" Output tokens: %d\n", totalUsage.GetOutputTokens())
fmt.Printf(" Total tokens: %d\n", totalUsage.GetTotalTokens())

Provider-Specific Usage Data​

result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "Hello",
})
if err != nil {
log.Fatal(err)
}

// Access raw provider-specific data
if result.Usage.Raw != nil {
if promptDetails, ok := result.Usage.Raw["prompt_tokens_details"]; ok {
fmt.Printf("Provider details: %+v\n", promptDetails)
}
}

Usage Budget Enforcement​

const maxTokens = 10000
var usedTokens int64

for _, task := range tasks {
if usedTokens >= maxTokens {
fmt.Println("Token budget exceeded")
break
}

result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: task,
})
if err != nil {
log.Printf("Error: %v", err)
continue
}

usedTokens += result.Usage.GetTotalTokens()
fmt.Printf("Used %d/%d tokens\n", usedTokens, maxTokens)
}

Provider Support​

Different providers support different levels of usage detail:

ProviderText/Image TokensCache TrackingReasoning Tokens
OpenAI✅ Yes✅ Yes✅ Yes (o1/o3)
XAI✅ Yes✅ Yes✅ Yes
Google✅ Yes✅ Yes✅ Yes (thinking)
Anthropic❌ No✅ Yes❌ No
Azure✅ Yes✅ Yes✅ Yes
Groq⚠️ Partial⚠️ Partial⚠️ Partial
DeepSeek✅ Yes✅ Yes✅ Yes
Together✅ Yes✅ Yes✅ Yes
Fireworks✅ Yes✅ Yes✅ Yes
OthersVariesVariesVaries

When detailed fields are not available from a provider, the pointers will be nil.

See Also​