Documentation
¶
Overview ¶
Package convcontext provides context window management and message pruning for conversations.
Package convcontext provides context window management and message pruning for conversations. ABOUTME: Message summarization using Claude API ABOUTME: Reduces token usage by summarizing old conversation context
Index ¶
- func CreateSummaryMessage(summary string) core.Message
- func EstimateMessageTokens(msg core.Message) int
- func EstimateMessagesTokens(messages []core.Message) int
- func EstimateTokens(text string) int
- func PruneContext(messages []core.Message, maxTokens int) []core.Message
- func SummarizeToolResult(toolName, content string) string
- type ContextUsage
- type Manager
- type PruneStrategy
- type Summarizer
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CreateSummaryMessage ¶
CreateSummaryMessage creates a system message containing a summary
func EstimateMessageTokens ¶
EstimateMessageTokens estimates tokens for a single message
func EstimateMessagesTokens ¶
EstimateMessagesTokens estimates total tokens for a slice of messages
func EstimateTokens ¶
EstimateTokens estimates tokens in a string using a simple heuristic This is a rough estimate: actual token count depends on tokenizer
func PruneContext ¶
PruneContext prunes messages to fit within maxTokens Strategy: - Always keep first message if it's a system message - Keep most recent messages - Preserve messages with tool calls - Remove middle messages if needed
Example ¶
ExamplePruneContext demonstrates context pruning preserving important messages
package main
import (
"fmt"
"github.com/2389-research/hex/internal/convcontext"
"github.com/2389-research/hex/internal/core"
)
func main() {
messages := []core.Message{
{Role: "system", Content: "You are a helpful assistant."},
{Role: "user", Content: "Old message 1"},
{Role: "assistant", Content: "Old response 1"},
{Role: "user", Content: "Old message 2"},
{Role: "assistant", Content: "Old response 2"},
{Role: "user", Content: "Use the read tool"},
{Role: "assistant", Content: "Reading file", ToolCalls: []core.ToolUse{{Name: "read_file", ID: "1"}}},
{Role: "user", Content: "Recent message"},
{Role: "assistant", Content: "Recent response"},
}
pruned := convcontext.PruneContext(messages, 100)
fmt.Printf("Original: %d messages\n", len(messages))
fmt.Printf("Pruned: %d messages\n", len(pruned))
fmt.Printf("Kept system message: %v\n", pruned[0].Role == "system")
hasToolCall := false
for _, msg := range pruned {
if len(msg.ToolCalls) > 0 {
hasToolCall = true
break
}
}
fmt.Printf("Kept tool call message: %v\n", hasToolCall)
fmt.Printf("Kept recent messages: %v\n", pruned[len(pruned)-1].Content == "Recent response")
}
Output: Original: 9 messages Pruned: 9 messages Kept system message: true Kept tool call message: true Kept recent messages: true
func SummarizeToolResult ¶ added in v1.11.0
SummarizeToolResult creates a brief summary of a tool result for context pruning
Types ¶
type ContextUsage ¶
ContextUsage provides information about context token usage
type Manager ¶
type Manager struct {
MaxTokens int
Strategy PruneStrategy
}
Manager handles context pruning and token estimation
Example (TokenSavings) ¶
ExampleManager_tokenSavings demonstrates the token savings from context pruning
package main
import (
"fmt"
"github.com/2389-research/hex/internal/convcontext"
"github.com/2389-research/hex/internal/core"
)
func main() {
// Simulate a long conversation (500 messages with substantial content)
messages := make([]core.Message, 500)
messages[0] = core.Message{Role: "system", Content: "You are a helpful coding assistant with extensive knowledge of Go, Python, JavaScript, and software architecture."}
for i := 1; i < 500; i++ {
if i%2 == 1 {
messages[i] = core.Message{
Role: "user",
Content: fmt.Sprintf("This is user message #%d asking a detailed question about coding in Go and Python. "+
"I need help understanding how to implement a feature with proper error handling, testing, and documentation. "+
"Can you provide a complete example with best practices?", i),
}
} else {
messages[i] = core.Message{
Role: "assistant",
Content: fmt.Sprintf("This is assistant response #%d providing a detailed explanation of code concepts with examples. "+
"Here's how you implement that feature: First, you need to set up the proper structure, then handle errors appropriately, "+
"write comprehensive tests, and document your code thoroughly. Let me show you a complete example...", i),
}
}
}
// Without context management
tokensWithoutPruning := convcontext.EstimateMessagesTokens(messages)
// With context management (1000 token limit for demonstration)
manager := convcontext.NewManager(1000)
prunedMessages := manager.Prune(messages)
tokensWithPruning := convcontext.EstimateMessagesTokens(prunedMessages)
// Calculate savings
tokensSaved := tokensWithoutPruning - tokensWithPruning
percentSaved := float64(tokensSaved) / float64(tokensWithoutPruning) * 100
// Cost calculation (Sonnet 4.5 pricing: $3/million input tokens)
costWithout := float64(tokensWithoutPruning) * 3.0 / 1_000_000
costWith := float64(tokensWithPruning) * 3.0 / 1_000_000
costSaved := costWithout - costWith
fmt.Printf("Original conversation: %d messages, ~%d tokens\n", len(messages), tokensWithoutPruning)
fmt.Printf("After pruning: %d messages, ~%d tokens\n", len(prunedMessages), tokensWithPruning)
fmt.Printf("Tokens saved: %d (%.1f%%)\n", tokensSaved, percentSaved)
fmt.Printf("Cost saved per request: $%.4f\n", costSaved)
fmt.Printf("Cost saved over 100 requests: $%.2f\n", costSaved*100)
}
Output: Original conversation: 500 messages, ~37400 tokens After pruning: 14 messages, ~995 tokens Tokens saved: 36405 (97.3%) Cost saved per request: $0.1092 Cost saved over 100 requests: $10.92
func (*Manager) GetUsage ¶
func (m *Manager) GetUsage(messages []core.Message) ContextUsage
GetUsage returns current context usage information
type PruneStrategy ¶
type PruneStrategy int
PruneStrategy defines how to handle context pruning
const ( // StrategyKeepAll preserves all messages without pruning StrategyKeepAll PruneStrategy = iota // StrategyPrune removes old messages when context limit is reached StrategyPrune // StrategySummarize summarizes old messages to save tokens StrategySummarize )
type Summarizer ¶
type Summarizer struct {
// contains filtered or unexported fields
}
Summarizer creates summaries of conversation history
func NewSummarizer ¶
func NewSummarizer(client *core.Client) *Summarizer
NewSummarizer creates a new summarizer
func (*Summarizer) ClearCache ¶
func (s *Summarizer) ClearCache()
ClearCache clears the summary cache
func (*Summarizer) SummarizeMessages ¶
func (s *Summarizer) SummarizeMessages(ctx context.Context, messages []core.Message) (string, error)
SummarizeMessages creates a concise summary of messages using Claude