Help us shape the future of Go! Take the 2026 Go Developer Survey

contextkit

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

README

ContextKit

contextkit is a standalone Go module for context compression. It belongs in the broader goagents workspace, but it does not import goagent. Applications map their runtime messages into contextkit.Message, compress them, and decide how to use the returned projection.

Install

go get github.com/eruca/goagents/contextkit

For local development before publishing:

go mod edit -replace github.com/eruca/goagents/contextkit=/Users/nick/VibeCoding/goagents/contextkit
go get github.com/eruca/goagents/contextkit

Compression Profile

The environment variable is a single deep-compression flag:

CONTEXT_DEEP_COMPRESSION=1

Unset or any value other than 1, true, yes, or on enables levels 1-3. Setting CONTEXT_DEEP_COMPRESSION=1 enables levels 1-5.

CONTEXT_DEEP_COMPRESSION names the behavior directly: the normal path still compresses context, while the flag opts into the deeper, more invasive layers.

Five Levels

standard profile:

  1. Tool observation projection: tool messages become structured observations containing tool name, status, result reference, and bounded result preview.
  2. Message window pruning: system messages and recent conversation are retained.
  3. Projection: the returned message slice is a model-facing view, not a mutation of the caller's original session.

deep profile adds:

  1. Reversible collapse: collapsed messages are recorded with a stable collapse ID, original IDs, original messages, and summary placeholder.
  2. Auto compact: when a Summarizer is configured, deep mode uses it to build a stronger compact summary and places that summary in the model projection.

No LLM dependency is required. Hosts can provide a deterministic summarizer, an LLM summarizer, or no summarizer. Without a summarizer, deep mode still returns collapse and compact metadata using deterministic summaries.

Window Compressor

compressor := window.New(window.Config{
	Budget:       contextkit.Budget{MaxChars: 4000},
	MinRecent:    8,
	MaxToolChars: 1000,
})

result, err := compressor.Compress(ctx, contextkit.Request{
	Messages: messages,
})
if err != nil {
	panic(err)
}

modelMessages := result.Messages

If Profile is omitted from window.Config, the compressor reads CONTEXT_DEEP_COMPRESSION.

Deep Summarization

Deep mode can use a host-owned summarizer:

type summarizer struct{}

func (summarizer) Summarize(ctx context.Context, req contextkit.SummarizeRequest) (*contextkit.SummarizeResult, error) {
	return &contextkit.SummarizeResult{
		Summary: "Primary request: ...\nCurrent state: ...\nPending tasks: ...",
	}, nil
}

compressor := window.New(window.Config{
	Profile:    contextkit.ProfileDeep,
	MinRecent:  8,
	Summarizer: summarizer{},
})

The summarizer receives collapsed messages, recent messages, budget, and metadata. The returned summary replaces the generic collapse placeholder in the model-facing projection:

auto compacted earlier context:
Primary request: ...
Current state: ...
Pending tasks: ...

Result.Collapses still keeps the original collapsed messages, so hosts can recover or inspect the pre-compact history.

Restore A Projection

Deep collapse records are reversible:

restored := contextkit.RestoreProjection(result.Messages, result.Collapses)

This expands collapse summary messages back to their original messages when the projection contains contextkit.collapse_id metadata.

Tool Result Budget

budgeted := toolbudget.Apply(rawToolOutput, toolbudget.Config{MaxChars: 1000})
fmt.Println(budgeted.Content)

Use this at tool boundaries when a host wants explicit level-1 control before messages are assembled.

Tool Observation Projection

toolprojection is the recommended Level 1 primitive for agent traces:

projected := toolprojection.Project(contextkit.Message{
	Role:       contextkit.RoleTool,
	ToolName:   "ocr_document",
	ToolCallID: "call-1",
	Status:     "success",
	Ref:        "ocr:run-1",
	Content:    fullToolResult,
}, toolprojection.Config{MaxResultChars: 1000})

The projected content is shaped for model context:

tool=ocr_document
status=success
tool_call_id=call-1
ref=ocr:run-1
result=...

This removes noisy tool reasoning and raw payloads from the model-facing view while preserving the useful observation.

Use With goagent

Keep the dependency direction at the application boundary:

application
  imports github.com/eruca/goagents/goagent
  imports github.com/eruca/goagents/contextkit
  maps goagent messages into contextkit messages
  uses contextkit output as the model-facing projection

github.com/eruca/goagents/goagent does not import github.com/eruca/goagents/contextkit
github.com/eruca/goagents/contextkit does not import github.com/eruca/goagents/goagent

Until goagent has a native context compression port, use contextkit in host code around memory or model-request preparation. A future goagent stage can call the same compressor before ThinkStage without moving the algorithms into core.

Typical mapping:

func toContextKit(messages []agentcore.Message) []contextkit.Message {
	out := make([]contextkit.Message, 0, len(messages))
	for _, msg := range messages {
		out = append(out, contextkit.Message{
			Role:    contextkit.Role(msg.Role),
			Content: msg.Content,
		})
	}
	return out
}

For large tools such as OCR or retrieval, pair contextkit with bounded tool results:

  • return a preview in tools.Result.ForLLM
  • keep full output in tools.Result.ForUser, object storage, or a retrieval index
  • expose bounded read/search tools for follow-up access

Verify

go test ./...

Documentation

Index

Constants

View Source
const EnvDeepCompression = "CONTEXT_DEEP_COMPRESSION"

Variables

This section is empty.

Functions

This section is empty.

Types

type Budget

type Budget struct {
	MaxChars int `json:"max_chars"`
}

type Collapse

type Collapse struct {
	ID          string    `json:"id"`
	StartIndex  int       `json:"start_index"`
	EndIndex    int       `json:"end_index"`
	Summary     Message   `json:"summary"`
	OriginalIDs []string  `json:"original_ids"`
	Originals   []Message `json:"originals,omitempty"`
}

type Compact

type Compact struct {
	Summary  string         `json:"summary"`
	Metadata map[string]any `json:"metadata,omitempty"`
}

type Compressor

type Compressor interface {
	Compress(ctx context.Context, req Request) (*Result, error)
}

type Level

type Level int
const (
	LevelToolResultBudget   Level = 1
	LevelWindowPruning      Level = 2
	LevelProjection         Level = 3
	LevelReversibleCollapse Level = 4
	LevelAutoCompact        Level = 5
)

func LevelsForProfile

func LevelsForProfile(profile Profile) []Level

type Message

type Message struct {
	ID         string         `json:"id,omitempty"`
	Role       Role           `json:"role"`
	Content    string         `json:"content"`
	ToolName   string         `json:"tool_name,omitempty"`
	ToolCallID string         `json:"tool_call_id,omitempty"`
	Status     string         `json:"status,omitempty"`
	Ref        string         `json:"ref,omitempty"`
	Metadata   map[string]any `json:"metadata,omitempty"`
}

func RestoreProjection

func RestoreProjection(messages []Message, collapses []Collapse) []Message

func (Message) CharLen

func (m Message) CharLen() int

type Profile

type Profile string
const (
	ProfileStandard Profile = "standard"
	ProfileDeep     Profile = "deep"
)

func ProfileFromEnv

func ProfileFromEnv() Profile

func ProfileFromLookup

func ProfileFromLookup(lookup func(string) (string, bool)) Profile

type Request

type Request struct {
	Messages []Message      `json:"messages"`
	Budget   Budget         `json:"budget"`
	Metadata map[string]any `json:"metadata,omitempty"`
}

type Result

type Result struct {
	Messages    []Message      `json:"messages"`
	Profile     Profile        `json:"profile"`
	Levels      []Level        `json:"levels"`
	Summary     string         `json:"summary,omitempty"`
	Dropped     int            `json:"dropped"`
	Collapses   []Collapse     `json:"collapses,omitempty"`
	AutoCompact *Compact       `json:"auto_compact,omitempty"`
	Metadata    map[string]any `json:"metadata,omitempty"`
}

type Role

type Role string
const (
	RoleSystem    Role = "system"
	RoleUser      Role = "user"
	RoleAssistant Role = "assistant"
	RoleTool      Role = "tool"
)

type SummarizeRequest

type SummarizeRequest struct {
	Collapsed []Message      `json:"collapsed"`
	Recent    []Message      `json:"recent"`
	Budget    Budget         `json:"budget"`
	Metadata  map[string]any `json:"metadata,omitempty"`
}

type SummarizeResult

type SummarizeResult struct {
	Summary  string         `json:"summary"`
	Metadata map[string]any `json:"metadata,omitempty"`
}

type Summarizer

type Summarizer interface {
	Summarize(ctx context.Context, req SummarizeRequest) (*SummarizeResult, error)
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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