Documentation
¶
Overview ¶
Package context - bundle.go 定义系统提示词的分段装配基础设施.
核心概念:
- Section - 系统提示词的一个命名片段,携带缓存语义(静态/会话级/每轮重算).
- SectionRegistry - Engine 实例绑定的 Section 计算缓存,/clear 或 /compact 后 Reset.
- PromptBundle - 一组 Section 的命名集合,按 (ModelFamily, Scenario) 调优.
- BundleRegistry - 持有所有已注册 Bundle,精确匹配 + 默认回退.
- SystemPromptBlock - 带缓存语义的 API 块,与 internal/api 包解耦.
设计决策:
- M+N 而非 M×N:ModelFamily 和 Scenario 两个维度独立组合,避免组合爆炸.
- 实例绑定而非全局:SectionRegistry 和 BundleRegistry 绑定到 Engine 实例, 支持 SaaS 多租户下每个工作区独立的提示词配置.
- 静态/动态分离:静态 sections 全局可缓存,动态 sections 会话级缓存, volatile sections 每轮重算--直接对应 Anthropic prompt caching 的三种语义.
Package context - bundle_overlay.go 提供 BundleOverlay 类型.
BundleOverlay 让 SDK 用户以"最小改动"适配新模型或新场景, 而不必从头实现完整的 PromptBundle 接口(那需要了解全部 14 个 section 的语义).
典型用法:
// 接入 Qwen 模型:只需覆盖行为准则和工具说明两个 section,其余继承 DefaultBundle
qwenBundle := context.NewBundleOverlay(context.NewDefaultBundle()).
OverrideStatic("intro", "你是 Flyto,一个智能助手,帮助用户完成软件工程任务.").
OverrideStatic("using_tools", "使用工具时优先选择专用工具而非 Bash...").
OverrideDynamic("env_info", func(ctx context.Context) string {
return "# 运行环境\n..." // 用中文写环境描述
})
eng.RegisterPromptBundle(
context.BundleKey{ModelFamily: "qwen", Scenario: "programming"},
qwenBundle,
)
设计决策:
一层 Overlay,不支持嵌套.嵌套 Overlay(Overlay 套 Overlay)会导致调用链难以 追踪,且实际需求从未出现.如果真的需要深度定制,直接实现 PromptBundle 接口.
以 section Name 为键.Name 是 section 在 Bundle 中的语义标识符, 用它覆盖而非用下标,让覆盖代码可读("我在覆盖 'intro' 段落"而非"第 0 个 section").
不修改 SectionRegistry 的行为.被覆盖的 section 走自己的 Compute 函数, base bundle 中同名 section 的缓存条目在第一次 Overlay.Compute 时被新值覆盖. 这是 SectionRegistry 的 double-check 写入语义的自然行为,无需额外处理.
Package context - chinese_bundle.go 定义中文系统提示词 Bundle.
NewChineseBundle 返回一个全中文静态段落的 PromptBundle, 动态段落(env_info,tool_descs,instructions,append_prompt 等)继承自 DefaultBundle.
适用场景:
- 接入中文语言模型(Qwen,Deepseek,Baidu ERNIE 等)
- 用户语言偏好为中文的部署环境
- 需要验证"中文指令 vs 英文指令"效果差异的 A/B 实验
注册示例:
eng.RegisterPromptBundle(
engine.BundleKeyFor("qwen", "programming"),
context.NewChineseBundle(),
)
// 或通过 RunOption per-request 切换:
eng.Run(ctx, prompt, engine.WithBundleKey(engine.BundleKeyFor("qwen", "programming")))
设计决策:
- 静态段落全部替换为中文版本(prompts_zh.go),语义与英文版一字不差.
- 动态段落(env_info 读取 cwd/platform,instructions 读取 FLYTO.md, tool_descs 从注册表生成)继承 DefaultBundle--这些段落的内容由运行时 注入值决定,与语言无关.
- 不修改 DefaultBundle--中文 Bundle 是独立注册的新 Bundle, 不影响已验证的英文 claude+programming Bundle 的稳定性.
Package context - compact.go 实现上下文压缩功能.
对应原项目中同名模块的功能. 当对话消息的 token 总量接近模型上下文窗口时,自动触发压缩:
- 调用轻量模型(Haiku)生成对话摘要
- 用摘要替换旧消息,保留最近几轮
- MicroCompact 则是轻量修剪:截断旧的工具结果内容
改进:
- 使用更准确的 token 估算(基于 tokenizer 包)
- 压缩后自动注入 PostCompactContext(最近文件列表,git diff 摘要)
- 压缩提示词改进(保留文件路径,函数名,关键决策)
- MicroCompact 智能截断(保留头尾而不只是头部)
- 工具错误输出保留完整内容(错误信息通常更重要)
- 区分部分压缩和完全压缩
- 支持可插拔的 CompactionPolicy 和 PostCompactRestorer
- 消息按 API 往返分组,压缩边界对齐到组边界
- 多策略支持(full / partial / reactive)
Package context - composite.go 实现多策略叠加的 CompositePolicy.
宪法第 8 条「叠加而非替换」的核心实现. 现实中一个 Agent 可能同时处理编程和仓储任务, 编程策略保留"文件路径,函数名",仓储策略保留"订单号,SKU", CompositePolicy 合并两者,确保跨场景切换时不丢关键信息.
使用示例:
codePolicy := &DefaultCodePolicy{}
warehousePolicy := &WarehousePolicy{}
combined := NewCompositePolicy(codePolicy, warehousePolicy)
compressor.SetPolicy(combined)
// 压缩时同时保留文件路径和订单号
叠加规则:
- PreserveKeywords: 合并所有策略的关键词,去重
- ScoreMessageImportance: 取所有策略的最高分(宁可多保留不可多丢弃)
- MaxRecentRoundsToKeep: 取最大值(保留更多上下文)
- PreprocessForCompaction: 依次应用所有策略的预处理
升华改进(ELEVATED): 多策略叠加而非单策略替换. 替代方案:Config 中只传一个 Policy(原始设计,锁定单场景).
Package context 管理 Agent 的上下文构建和压缩.
核心职责:
- 构建完整的系统提示词(角色定义 + 工具指南 + 环境信息 + 用户追加)
- 检测当前环境信息(Git 状态,操作系统,shell 等)
- 管理上下文窗口(自动压缩,微压缩)
设计要点:
- 零 UI 依赖,纯逻辑
- 环境检测通过 os/exec 调用系统命令,不引入外部库
- 系统提示词是可组合的,每个模块独立定义
- Bundle + SectionRegistry 支持静态/动态分离缓存(模块 15)
Package context - default_bundle.go 定义 claude+programming 的默认 PromptBundle.
这是引擎内置的唯一 Bundle.内容来自早期方案,语义和逻辑一字未改.
设计决策:
静态 sections:7 个角色/行为/工具指南段落,取自 prompts.go 的已有常量. 这些内容在引擎生命周期内不变,可以安全地走 global cache scope.
动态 sections:env_info(运行时环境),instructions(FLYTO.md 文件), tool_descriptions(动态注册工具),summarize_tool_results,evolve_fragment,append_prompt. 这些内容每次会话或每次调用后可能变化,走 ephemeral cache scope.
FLYTO.md instructions 用 DynamicSection(会话级缓存)而非 VolatileSection-- 文件内容在一次会话中不会实时变化,不需要每轮重读.
注意:不要改变 defaultClaudeProgrammingBundle 中的静态文字内容-- 这些是针对 claude 模型 + 编程场景深度优化的结果,改一个字都可能影响模型行为.
Package context - grouping.go 将消息按 API 往返分组.
精妙之处(CLEVER): 按 API 往返分组保证压缩边界在完整对话轮次之间, 不会出现"保留了 user 消息但丢了 assistant 回复"的破碎状态.
Package context - instructions.go 实现 FLYTO.md 项目指令加载.
FLYTO.md 是项目级指令文件,让用户可以为特定项目定义 自定义的行为规则,代码风格,工具偏好等.
加载优先级(按顺序搜索,所有找到的文件合并):
- ~/.flyto/FLYTO.md - 用户全局指令
- <project_root>/FLYTO.md - 项目根目录指令
- <project_root>/.flyto/FLYTO.md - 项目 .flyto 目录指令
- <cwd>/FLYTO.md - 当前工作目录指令(如果不同于项目根)
自定义指令加载机制.
Package context - policy.go 定义压缩策略接口和编程场景的默认实现.
升华改进(ELEVATED): 策略可插拔.编程场景 PreserveKeywords 返回 "file paths, function names",仓储场景返回 "order numbers, SKU codes". 不同场景不改引擎代码,只换策略. 替代方案:硬编码编程关键词(原始设计,简单但锁死在编程场景).
Package context - prompts.go 定义完整的系统提示词.
定义完整的系统提示词. 所有提示词内容保持英文原文,每段用中文注释解释其作用.
组装顺序:
- 角色定义 + 行为准则 + 安全准则
- 工具使用指南(详细的)
- Git 安全协议
- 代码质量准则
- 输出风格准则
- FLYTO.md 项目指令(如果有)
- 工具描述列表(动态)
- 环境信息(cwd, platform, git status)
- 进化能力提示(如果启用)
10. 用户追加提示(如果有)
Package context - prompts_zh.go 定义系统提示词的中文版本.
内容与 prompts.go 中的英文版本语义完全一致,逐段直译, 供接入中文语言模型(Qwen,Deepseek,Baidu 等)时使用.
翻译原则:
- 语义忠实--不改变任何行为约束的含义
- 技术术语保留英文(Bash,Glob,Grep,git,PR 等)
- 工具名称保留英文(Read,Edit,Write,Glob,Grep,Bash)
- 命令和路径保留原样(git add,--no-verify 等)
注意:不要修改这些常量中任何约束性文字-- 即使是"不得","必须"等措辞,改动都可能影响模型行为.
Package context - restorer.go 定义压缩后恢复器接口和内置恢复器实现.
升华改进(ELEVATED): 恢复器是可插拔的.编程场景恢复"最近读的文件", 仓储场景可以注册"当前订单状态恢复器".引擎不关心恢复什么, 只负责按优先级调用恢复器并控制总 token 预算. 替代方案:硬编码 5 种恢复逻辑(原始设计,简单但无法扩展).
Index ¶
- Constants
- Variables
- func AppendPromptFromCtx(ctx context.Context) string
- func BlocksToString(blocks []SystemPromptBlock) string
- func BuildDefaultSystemPrompt() string
- func CwdFromCtx(ctx context.Context) string
- func DetectOrphanedToolResults(messages []CompactMessage) []string
- func EstimateTokens(messages []CompactMessage) int
- func EvolveFragmentFromCtx(ctx context.Context) string
- func LoadInstructions(cwd string) string
- func ModelIDFromCtx(ctx context.Context) string
- func PromptLanguageFromCtx(ctx context.Context) string
- func RegisterChineseBundle(r *BundleRegistry)
- func SetCompactModelProvider(fn CompactModelFunc)
- func SetContextWindowProvider(fn ContextWindowFunc)
- func WithAppendPrompt(ctx context.Context, prompt string) context.Context
- func WithCwd(ctx context.Context, cwd string) context.Context
- func WithEvolveFragment(ctx context.Context, frag string) context.Context
- func WithMCPServerStatuses(ctx context.Context, statuses []MCPServerStatus) context.Context
- func WithModelID(ctx context.Context, modelID string) context.Context
- func WithPromptLanguage(ctx context.Context, lang string) context.Context
- func WithToolDescriptions(ctx context.Context, descs []ToolDescription) context.Context
- type AgentRestorer
- type BreakerState
- type Builder
- func (b *Builder) BuildSystemPrompt() string
- func (b *Builder) BuildSystemPromptBlocks(ctx context.Context) []SystemPromptBlock
- func (b *Builder) SetAppendPrompt(prompt string)
- func (b *Builder) SetBundleKey(key BundleKey)
- func (b *Builder) SetBundleRegistry(r *BundleRegistry)
- func (b *Builder) SetEnableCaching(enable bool)
- func (b *Builder) SetEvolveFragment(fragment string)
- func (b *Builder) SetMCPServerStatuses(statuses []MCPServerStatus)
- func (b *Builder) SetModelID(modelID string)
- func (b *Builder) SetSectionRegistry(r *SectionRegistry)
- func (b *Builder) SetSystemPrompt(prompt string)
- func (b *Builder) SetToolDescriptions(descs []ToolDescription)
- type BundleKey
- type BundleOverlay
- func (o *BundleOverlay) DynamicSections() []*Section
- func (o *BundleOverlay) OverrideDynamic(name string, compute ComputeFn) *BundleOverlay
- func (o *BundleOverlay) OverrideSection(s *Section) *BundleOverlay
- func (o *BundleOverlay) OverrideStatic(name, text string) *BundleOverlay
- func (o *BundleOverlay) OverrideVolatile(name string, compute ComputeFn, reason string) *BundleOverlay
- func (o *BundleOverlay) StaticSections() []*Section
- type BundleRegistry
- type CircuitBreakerPersister
- type CompactCircuitBreaker
- type CompactMessage
- type CompactModelFunc
- type CompactOption
- type CompactResult
- type CompactState
- type CompactStrategy
- type CompactionPolicy
- type CompositePolicy
- func (cp *CompositePolicy) Add(p CompactionPolicy)
- func (cp *CompositePolicy) Len() int
- func (cp *CompositePolicy) MaxRecentRoundsToKeep() int
- func (cp *CompositePolicy) Name() string
- func (cp *CompositePolicy) PreprocessForCompaction(msgs []CompactMessage) []CompactMessage
- func (cp *CompositePolicy) PreserveKeywords() string
- func (cp *CompositePolicy) Remove(name string) bool
- func (cp *CompositePolicy) ScoreMessageImportance(role string, content string) float64
- type Compressor
- func (c *Compressor) CircuitBreaker() *CompactCircuitBreaker
- func (c *Compressor) CompactTiered(ctx context.Context, messages []CompactMessage, policy CompactionPolicy, ...) (*CompactResult, error)
- func (c *Compressor) CompactWithStrategy(ctx context.Context, messages []CompactMessage, strategy CompactStrategy, ...) (*CompactResult, error)
- func (c *Compressor) DoCompact(messages []CompactMessage) (*CompactResult, error)
- func (c *Compressor) DoCompactWithHint(messages []CompactMessage, opts ...CompactOption) (*CompactResult, error)
- func (c *Compressor) DoMicroCompact(messages []CompactMessage) []CompactMessage
- func (c *Compressor) SetCompactModelFn(fn CompactModelFunc)
- func (c *Compressor) SetContextWindowFn(fn ContextWindowFunc)
- func (c *Compressor) SetObserver(obs flyto.EventObserver)
- func (c *Compressor) SetPersister(p CircuitBreakerPersister)
- func (c *Compressor) SetPolicy(p CompactionPolicy)
- func (c *Compressor) SetProvider(p flyto.ModelProvider)
- func (c *Compressor) SetRestoreManager(rm *RestoreManager)
- func (c *Compressor) ShouldCompact(messages []CompactMessage) bool
- func (c *Compressor) Threshold() int
- type ComputeFn
- type ContextWindowFunc
- type DefaultCodePolicy
- func (p *DefaultCodePolicy) MaxRecentRoundsToKeep() int
- func (p *DefaultCodePolicy) Name() string
- func (p *DefaultCodePolicy) PreprocessForCompaction(msgs []CompactMessage) []CompactMessage
- func (p *DefaultCodePolicy) PreserveKeywords() string
- func (p *DefaultCodePolicy) ScoreMessageImportance(role string, content string) float64
- type EnvInfo
- type FilePersister
- type FileRestorer
- type FileStateCacheReader
- type MCPRestorer
- type MCPServerStatus
- type MessageGroup
- type NoopPersister
- type PlanRestorer
- type PostCompactRestorer
- type PromptBundle
- type RestoreItem
- type RestoreManager
- type Section
- type SectionRegistry
- type SkillInfo
- type SkillProvider
- type SkillRestorer
- type SystemPromptBlock
- type ToolDescription
Constants ¶
const DefaultAgentPrompt = `` /* 1910-byte string literal not displayed */
DefaultAgentPrompt 是子代理(Agent)的默认系统提示词. 当 Flyto 派生子代理执行任务时使用此提示词.
const DefaultContextWindow = 200000
DefaultContextWindow 是默认的上下文窗口大小(token 数). 当通过 ModelRegistry 查询不到时使用此默认值.
Variables ¶
var DefaultBundleKey = BundleKey{ModelFamily: "claude", Scenario: "programming"}
DefaultBundleKey 是系统内置的默认 Bundle key(claude + programming).
Functions ¶
func AppendPromptFromCtx ¶
AppendPromptFromCtx 从 context 读取用户追加提示.
func BlocksToString ¶
func BlocksToString(blocks []SystemPromptBlock) string
BlocksToString 将 SystemPromptBlock 列表合并为单个字符串. 用于不支持多块缓存的场景(降级路径,调试,测试断言等).
func BuildDefaultSystemPrompt ¶
func BuildDefaultSystemPrompt() string
BuildDefaultSystemPrompt 组装完整的默认系统提示词. 不包含动态部分(工具描述,环境信息,FLYTO.md 等), 这些由 Builder.BuildSystemPrompt() 负责注入.
func DetectOrphanedToolResults ¶
func DetectOrphanedToolResults(messages []CompactMessage) []string
DetectOrphanedToolResults 检测孤立的 tool_result(无对应 tool_use). 返回孤立 tool_result 的 tool_use_id 列表.
孤立 tool_result 可能在压缩时因截断位置不当产生-- 比如 assistant 的 tool_use 被压缩了但对应的 user tool_result 保留了.
func EstimateTokens ¶
func EstimateTokens(messages []CompactMessage) int
EstimateTokens 估算消息列表的 token 数. 使用改进的估算策略:
- 对英文文本:按空格分词,每词约 1.3 token
- 对代码/JSON:按结构特征估算
- 对 CJK 字符:每字符约 1.5 token
比旧的 4 chars/token 估算准确 2-3 倍.
func EvolveFragmentFromCtx ¶
EvolveFragmentFromCtx 从 context 读取进化能力提示片段.
func LoadInstructions ¶
LoadInstructions 加载所有 FLYTO.md 项目指令文件并合并.
按优先级搜索以下路径的 FLYTO.md 文件:
- ~/.flyto/FLYTO.md - 用户全局配置
- <project_root>/FLYTO.md - 项目根目录(Git 仓库根或 cwd)
- <project_root>/.flyto/FLYTO.md - 项目 .flyto 子目录
- <cwd>/FLYTO.md - 当前工作目录(仅当不同于项目根时)
所有找到的文件内容用 "\n\n" 合并. 如果没有找到任何 FLYTO.md 文件,返回空字符串(不报错).
func ModelIDFromCtx ¶
ModelIDFromCtx 从 context 读取模型 ID.
func PromptLanguageFromCtx ¶
PromptLanguageFromCtx 从 context 读取语言偏好(可选,P2 功能预留).
历史包袱(LEGACY): 当前未被任何 section 使用--语言本地化是 P2 特性, 此函数是为将来的本地化 Bundle 提前埋下的 context key 接入点. 一旦 P2 实现,删除此注释,添加使用示例.
func RegisterChineseBundle ¶
func RegisterChineseBundle(r *BundleRegistry)
RegisterChineseBundle 将中文 Bundle 批量注册到指定的 BundleRegistry.
升华改进(ELEVATED): 提供一键注册函数,降低 SDK 用户的接入成本-- 不需要了解 ChineseBundleKeys() 列表,也不需要手动循环注册. 与 NewDefaultBundleRegistry 的设计一致(工厂函数 vs 手动注册). 替代方案:<要求调用方手动循环注册> - 否决原因:样板代码重复,且当支持的模型族列表变化时, 每个调用方都要手动更新,维护成本分散.
func SetCompactModelProvider ¶
func SetCompactModelProvider(fn CompactModelFunc)
SetCompactModelProvider 设置获取压缩用模型 ID 的回调函数. 典型用法:注入 ModelRegistry 的 RoleFast 查询.
context.SetCompactModelProvider(func() string {
return cfg.ModelForRole(config.RoleFast)
})
func SetContextWindowProvider ¶
func SetContextWindowProvider(fn ContextWindowFunc)
SetContextWindowProvider 设置全局的上下文窗口查询函数. 典型用法:在引擎初始化时注入 ModelRegistry 的查询能力.
context.SetContextWindowProvider(func(model string) int {
return registry.ContextWindow(model)
})
func WithAppendPrompt ¶
WithAppendPrompt 将用户追加提示注入 context.
func WithEvolveFragment ¶
WithEvolveFragment 将进化能力提示片段注入 context.
func WithMCPServerStatuses ¶
func WithMCPServerStatuses(ctx context.Context, statuses []MCPServerStatus) context.Context
WithMCPServerStatuses injects a snapshot of MCP server connection state into ctx, consumed by the mcp_servers volatile section.
WithMCPServerStatuses 将 MCP server 连接状态快照注入 ctx, 由 mcp_servers volatile section 消费.
func WithModelID ¶
WithModelID 将模型 ID 注入 context,供 env_info section 构建模型描述.
func WithPromptLanguage ¶
WithPromptLanguage 将语言偏好注入 context(P2 功能预留).
func WithToolDescriptions ¶
func WithToolDescriptions(ctx context.Context, descs []ToolDescription) context.Context
WithToolDescriptions 将工具描述列表注入 context.
Types ¶
type AgentRestorer ¶
type AgentRestorer struct{}
AgentRestorer 异步代理状态恢复.
func (*AgentRestorer) Name ¶
func (r *AgentRestorer) Name() string
func (*AgentRestorer) Priority ¶
func (r *AgentRestorer) Priority() int
func (*AgentRestorer) Restore ¶
func (r *AgentRestorer) Restore(_ context.Context, state *CompactState) ([]RestoreItem, error)
Restore 恢复异步代理状态.
func (*AgentRestorer) TokenBudget ¶
func (r *AgentRestorer) TokenBudget() int
type BreakerState ¶
type BreakerState struct {
Failures int `json:"failures"`
LastFailedAt time.Time `json:"last_failed_at"`
}
BreakerState 是断路器的可序列化状态. 精妙之处(CLEVER): 只持久化需要跨进程传递的最小状态-- failures 和 lastFailedAt.maxFailures 是配置,不需要持久化.
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder 构建发送给 API 的上下文(系统提示 + 用户上下文 + 工具描述).
将系统提示构建逻辑收敛到一个结构体中.
升华改进(ELEVATED): 在早期方案字符串拼接基础上增加 Bundle + SectionRegistry 支持--
- BuildSystemPromptBlocks() 返回 []SystemPromptBlock(带缓存语义)
- BuildSystemPrompt() 向后兼容,内部调用 BuildSystemPromptBlocks 后 join 为字符串
替代方案:<废弃 BuildSystemPrompt,只保留 BuildSystemPromptBlocks> - 否决原因:其他调用方(测试,子模块)还依赖字符串形式,激进废弃代价高.
func NewBuilder ¶
NewBuilder 创建上下文构建器. 默认使用 DefaultBundleKey(claude+programming)和内置 DefaultBundle.
func (*Builder) BuildSystemPrompt ¶
BuildSystemPrompt 组装完整的系统提示词,返回字符串.
向后兼容方法:内部调用 BuildSystemPromptBlocks 后合并为字符串. 新代码应优先使用 BuildSystemPromptBlocks 以获得分块缓存语义.
func (*Builder) BuildSystemPromptBlocks ¶
func (b *Builder) BuildSystemPromptBlocks(ctx context.Context) []SystemPromptBlock
BuildSystemPromptBlocks 组装完整的系统提示词,返回带缓存语义的 API 块列表.
静态 sections(角色定义,行为准则等)→ CacheScope="ephemeral"(全局可缓存) 动态 sections(环境信息,FLYTO.md 等)→ CacheScope="ephemeral"(会话级缓存) volatile sections(MCP 连接等)→ CacheScope=""(不缓存)
如果设置了自定义 systemPrompt(覆盖模式),返回单块(不走 Bundle). ctx 用于 Section 的 Compute 函数读取注入值(cwd,modelID 等).
func (*Builder) SetAppendPrompt ¶
SetAppendPrompt 设置追加到系统提示末尾的额外内容.
func (*Builder) SetBundleKey ¶
SetBundleKey 设置使用的 Bundle 标识符. 零值(BundleKey{})等价于 DefaultBundleKey(claude+programming).
func (*Builder) SetBundleRegistry ¶
func (b *Builder) SetBundleRegistry(r *BundleRegistry)
SetBundleRegistry 设置 Bundle 注册表(替换默认注册表). 通常不需要调用--消费层向引擎注册 Bundle,引擎把注册表传入 Builder.
func (*Builder) SetEnableCaching ¶
SetEnableCaching 设置是否启用分块缓存语义(影响 BuildSystemPromptBlocks 返回的 CacheScope).
func (*Builder) SetEvolveFragment ¶
SetEvolveFragment 设置进化能力提示片段.
func (*Builder) SetMCPServerStatuses ¶
func (b *Builder) SetMCPServerStatuses(statuses []MCPServerStatus)
SetMCPServerStatuses injects the per-build MCP server connection snapshot consumed by the mcp_servers volatile section. Pass an empty slice (or leave unset) to indicate no MCP servers configured — the section then yields an empty string and is dropped.
SetMCPServerStatuses 注入 per-build 的 MCP server 连接快照, 由 mcp_servers volatile section 消费. 传空 slice (或不设) 表示未配置任何 MCP server -- section 返回空串被过滤.
func (*Builder) SetModelID ¶
SetModelID 设置当前使用的模型 ID(注入到 env_info section).
func (*Builder) SetSectionRegistry ¶
func (b *Builder) SetSectionRegistry(r *SectionRegistry)
SetSectionRegistry 设置 Section 缓存(替换每次 build 都重新分配的默认行为). Engine 实例应当把自己持有的 SectionRegistry 传入,使缓存跨 build 调用复用.
func (*Builder) SetSystemPrompt ¶
SetSystemPrompt 设置自定义系统提示(覆盖默认).
func (*Builder) SetToolDescriptions ¶
func (b *Builder) SetToolDescriptions(descs []ToolDescription)
SetToolDescriptions 设置工具描述列表.
type BundleKey ¶
type BundleKey struct {
ModelFamily string // "claude", "gpt", "gemini", "local", ...
Scenario string // "programming", "warehouse", "medical", ...
}
BundleKey 按 (模型族, 场景) 唯一标识一个 PromptBundle.
精妙之处(CLEVER): M+N 而非 M×N-- ModelFamily 描述模型侧的调优(工具调用格式,指令遵循风格); Scenario 描述任务侧的调优(编程/仓储/金融). 二者独立:3 个 ModelFamily × 4 个 Scenario 在理论上有 12 个 Bundle, 但每个维度的调优只需维护 M+N=7 个变体(通过组合 base + overlay 实现), 不是每种组合都要完整实现. BundleRegistry.Resolve 先精确匹配,再回退到默认 Bundle.
func ChineseBundleKeys ¶
func ChineseBundleKeys() []BundleKey
ChineseBundleKeys 返回中文 Bundle 推荐注册的 BundleKey 列表.
当前包含主流中文语言模型的模型族标识符. 调用方可以用此列表批量注册,也可以自行选择注册子集.
用法:
for _, key := range context.ChineseBundleKeys() {
eng.RegisterPromptBundle(key, context.NewChineseBundle())
}
func (BundleKey) String ¶
String formats the BundleKey as "<family>/<scenario>" for use in logs, error messages, and observer event payloads. Without this method, code that prints a BundleKey (via fmt.Sprintf %v or similar) emits the raw struct literal "{claude programming}", which is unfriendly for operators grepping through production logs. Empty fields render as the literal "<empty>" so zero-value keys are still distinguishable.
Design note (CLEVER): this also makes BundleKey.ModelFamily / BundleKey.Scenario load-bearing at the type level — without a method reading them, they are only used for struct hashing as map keys (which the dead-field scanner treats as unread, a known struct-as-map-key false positive). A real String() method gives operators human output AND serves as the syntactic read site that makes the field's purpose statically inspectable.
String 将 BundleKey 格式化为 "<family>/<scenario>", 用于日志/错误 消息/observer 事件 payload. 无此方法时, 打印 BundleKey (fmt.Sprintf %v 等) 产出原生 struct 字面 "{claude programming}", 运维 grep 生产 日志不友好. 空字段渲染为字面 "<empty>" 让零值 key 仍可区分.
设计说明 (CLEVER): 此方法也让 BundleKey.ModelFamily / BundleKey.Scenario 在类型层面承载 -- 没有读它们的方法时, 它们仅被 struct-as-map-key 哈希使用 (dead-field scanner 视其为未读, struct- as-map-key 已知假阳性). 真的 String() 方法给运维人类可读输出 + 作为让字段用途静态可验的 syntactic read site.
type BundleOverlay ¶
type BundleOverlay struct {
// contains filtered or unexported fields
}
BundleOverlay 在 base PromptBundle 基础上覆盖指定 section,其余继承.
升华改进(ELEVATED): 早期实现 没有任何机制让外部覆盖提示词 section-- 早期方案是一个大函数,所有内容硬编码,外部无法插入. 我们设计了 BundleOverlay,让 SDK 用户只需声明"我要覆盖哪个段落", 引擎自动把被覆盖的段落替换为新内容,其余段落继承 base Bundle 不变. 对于 CLI/SDK 用户:DefaultBundle 继续工作,零影响. 对于第三方模型接入:只需覆盖 1-3 个 section,即可适配新模型的指令风格. 替代方案:<要求外部完整实现 PromptBundle 接口> - 否决原因:需要了解全部 14 个 section 的语义,门槛过高,且 base 内容无法复用.
func NewBundleOverlay ¶
func NewBundleOverlay(base PromptBundle) *BundleOverlay
NewBundleOverlay 创建一个基于 base 的 Overlay. base 不得为 nil(使用 NewDefaultBundle() 作为最常见的基础).
func (*BundleOverlay) DynamicSections ¶
func (o *BundleOverlay) DynamicSections() []*Section
DynamicSections 返回动态 section 列表,被覆盖的 section 用 override 替换.
func (*BundleOverlay) OverrideDynamic ¶
func (o *BundleOverlay) OverrideDynamic(name string, compute ComputeFn) *BundleOverlay
OverrideDynamic 覆盖指定名称的 section,用动态计算函数替换. compute 函数从 context 读取运行时注入值(CwdFromCtx,ModelIDFromCtx 等). 返回空字符串表示跳过此 section(不注入到提示词).
func (*BundleOverlay) OverrideSection ¶
func (o *BundleOverlay) OverrideSection(s *Section) *BundleOverlay
OverrideSection 直接覆盖整个 Section 对象(最大灵活度). 适合需要精细控制 CacheBreak / NoCacheReason 等字段的场景.
func (*BundleOverlay) OverrideStatic ¶
func (o *BundleOverlay) OverrideStatic(name, text string) *BundleOverlay
OverrideStatic 覆盖指定名称的 section,用静态文字替换.
精妙之处(CLEVER): 返回 *BundleOverlay 自身,支持链式调用-- 这是 Builder 模式的惯用法,让覆盖代码紧凑可读:
overlay.OverrideStatic("intro", "...").OverrideStatic("using_tools", "...")
替代方案:<每次覆盖都返回新的 BundleOverlay 副本(不可变风格)> - 否决原因:每次分配新对象,在 section 较多时有不必要的 GC 压力; BundleOverlay 在构建阶段(引擎启动时)完成,不是并发修改的热路径.
func (*BundleOverlay) OverrideVolatile ¶
func (o *BundleOverlay) OverrideVolatile(name string, compute ComputeFn, reason string) *BundleOverlay
OverrideVolatile 覆盖指定名称的 section,用每轮重算的函数替换. reason 说明为什么此 section 必须每轮重算(用于代码审查和文档).
func (*BundleOverlay) StaticSections ¶
func (o *BundleOverlay) StaticSections() []*Section
StaticSections 返回静态 section 列表,被覆盖的 section 用 override 替换.
精妙之处(CLEVER): applyOverrides 统一处理静态和动态 section 的覆盖逻辑-- 不区分 section 原来是静态还是动态,只按 Name 匹配. 这意味着可以用动态 override 替换静态 base section(反之亦然), 给 SDK 用户提供最大灵活度. 如果用 index 匹配(如 sections[0] = override),就无法跨静态/动态替换.
type BundleRegistry ¶
type BundleRegistry struct {
// contains filtered or unexported fields
}
BundleRegistry 持有所有已注册的 PromptBundle,按 BundleKey 索引.
升华改进(ELEVATED): 与 SkillRegistry / AgentRegistry 设计一致--实例绑定到 Engine, SaaS 多租户场景下每个工作区有独立的 Bundle 集合,互不干扰. 替代方案:<全局注册表 sync.Map> - 否决原因:多租户下不同租户可能需要不同 Bundle,全局变量无法隔离.
func NewBundleRegistry ¶
func NewBundleRegistry() *BundleRegistry
NewBundleRegistry 创建 Bundle 注册表,默认 key 为 claude+programming.
func NewDefaultBundleRegistry ¶
func NewDefaultBundleRegistry() *BundleRegistry
NewDefaultBundleRegistry 创建已注册默认 Bundle 的 BundleRegistry.
升华改进(ELEVATED): 提供工厂函数而非要求调用方手动 Register-- 这样 engine.New() 只需一行即可获得完整可用的 Bundle 基础设施,不会因为忘记 Register 而运行时 nil panic. 替代方案:<让调用方手动注册> - 否决原因:用 BundleRegistry.Resolve 返回 nil,后续调用方必须 nil 检查,出错路径更多.
func (*BundleRegistry) Register ¶
func (r *BundleRegistry) Register(key BundleKey, bundle PromptBundle)
Register 注册或覆盖一个 Bundle. 消费层(SDK 用户,平台层)通过此方法添加行业特化 Bundle. key 相同时覆盖已有 Bundle(支持热更新).
func (*BundleRegistry) Resolve ¶
func (r *BundleRegistry) Resolve(key BundleKey) PromptBundle
Resolve 按 BundleKey 查找 Bundle,找不到则回退到默认 Bundle.
精妙之处(CLEVER): 两级回退策略,保证引擎在任何配置下都不返回 nil--
- 精确匹配 (ModelFamily, Scenario)
- 回退到注册表的 defaultKey(通常是 claude+programming)
不会 panic 或返回 nil,引擎可以安全地用 Resolve 结果直接调用. 如果注册表为空(未注册任何 Bundle),返回 nil(调用方必须自行检查).
func (*BundleRegistry) SetDefault ¶
func (r *BundleRegistry) SetDefault(key BundleKey)
SetDefault 设置未精确匹配时使用的默认 Bundle key. 通常不需要调用(默认是 claude+programming), 但允许专注非编程场景的部署覆盖默认值.
type CircuitBreakerPersister ¶
type CircuitBreakerPersister interface {
// Save 将断路器状态持久化.
// 在 RecordFailure / Reset 后调用.
Save(state BreakerState) error
// Load 加载上次持久化的状态.
// 返回 (nil, nil) 表示无历史状态(首次启动或状态过期).
Load() (*BreakerState, error)
}
CircuitBreakerPersister 是断路器状态持久化的接口.
升华改进(ELEVATED): 接口驱动设计--
默认实现:FilePersister(JSON 文件,per-project by cwd hash) 扩展实现:Redis 适配器(多副本共享,P2 TODO) 测试替代:NoopPersister(不写文件,测试无副作用)
Save/Load 都是幂等操作:失败时静默返回 error(不影响压缩主流程), 因为持久化是增强功能,不是核心路径.
type CompactCircuitBreaker ¶
type CompactCircuitBreaker struct {
// contains filtered or unexported fields
}
CompactCircuitBreaker 是压缩操作的电路断路器. 连续失败 maxFailures 次后停止尝试,避免反复调用失败的 API. 一旦成功,重置失败计数.
升华改进(ELEVATED): 加 mutex 保护--断路器模式源自微服务架构(Netflix Hystrix), 在任何多线程环境(不限于编程)都可能被并发访问:多个压缩请求同时检查/更新状态. 原方案无锁在单线程 Engine 中无问题,但断路器作为独立类型应自带线程安全保证, 遵循"对象管理自身一致性"原则. 替代方案:<原方案无 mutex,依赖外部调用者保证单线程访问>
升华改进(ELEVATED): 断路器区分错误类型 + 时间重置.
改进 1:rate limit (429/529) 不计入失败次数. 反向思考:早期方案不区分看似有道理(rate limit 时重试也没用). 但问题是:rate limit 通常 30 秒恢复,断路器关闭后要重启才能重试. 不计入的话,rate limit 过了自然能压缩.
改进 2:时间重置(5 分钟后自动 Reset). 替代方案:半开状态 + 探测请求(更精细但更复杂,需要后台定时器). 反向思考后选择时间重置:简单,不需要后台 goroutine, 5 分钟足以让大多数临时问题恢复.
func NewCompactCircuitBreaker ¶
func NewCompactCircuitBreaker(maxFailures int) *CompactCircuitBreaker
NewCompactCircuitBreaker 创建一个新的断路器,maxFailures 是最大连续失败次数.
func (*CompactCircuitBreaker) Failures ¶
func (cb *CompactCircuitBreaker) Failures() int
Failures 返回当前连续失败次数.
func (*CompactCircuitBreaker) RecordFailure ¶
func (cb *CompactCircuitBreaker) RecordFailure(isRateLimit bool)
RecordFailure 记录一次失败.
升华改进(ELEVATED): isRateLimit=true 时不计入失败次数. 反向思考:rate limit (429/529) 是临时性限流,通常 30 秒后恢复. 如果计入失败,3 次 rate limit 就会关闭断路器, 导致限流恢复后仍然无法压缩,必须重启才行. 不计入的话,rate limit 过了自然恢复,无需重启.
func (*CompactCircuitBreaker) Reset ¶
func (cb *CompactCircuitBreaker) Reset()
Reset 重置断路器(压缩成功时调用).
func (*CompactCircuitBreaker) ShouldAttempt ¶
func (cb *CompactCircuitBreaker) ShouldAttempt() bool
ShouldAttempt 判断是否应该尝试压缩. 如果连续失败次数已达上限,检查时间重置:超过 resetAfter 自动恢复.
升华改进(ELEVATED): 时间重置机制--超过 resetAfter 后自动清零失败计数. 反向思考:半开状态(只允许一个探测请求)更精细,但需要后台 goroutine 和额外状态管理.时间重置在单次检查中完成,无后台开销.
type CompactMessage ¶
type CompactMessage struct {
Role string `json:"role"`
Content json.RawMessage `json:"content"`
}
CompactMessage 是压缩模块使用的通用消息格式. 与 api.RequestMessage 解耦,避免循环依赖.
func MicroCompact ¶
func MicroCompact(messages []CompactMessage) []CompactMessage
MicroCompact 执行轻量级上下文修剪. 改进版:
- 智能截断:保留头尾而不只是头部(尾部通常有结论/错误信息)
- 工具错误输出保留完整内容(错误信息通常更重要)
- 区分 text 和 tool_result 类型的截断策略
策略:
- 只修剪距离最近轮次较远的消息(保留最近 recentTurnsToKeep*2 条不动)
- 只修剪 tool_result 类型的内容块
- 截断超过 microCompactMaxLen 字符的内容(保留头尾)
- 标记为错误的 tool_result 不截断(错误信息通常更重要)
func StripImages ¶
func StripImages(messages []CompactMessage) []CompactMessage
StripImages 压缩 API 调用前剥离图像块. 精妙之处(CLEVER): 图像对摘要无帮助但可能占 >50K tokens(一张截图). 剥离后压缩请求的 token 预算全部留给文本内容.
type CompactOption ¶
type CompactOption func(*compactOptions)
CompactOption is a functional option for CompactTiered. Added 2026-04-19 so callers can hand the compressor a precise token gap parsed from a PromptTooLong API error (see internal/transport.APIError.TokenGap), which lets truncateAndRetryCompact jump straight to the right stride instead of shaving one group at a time. Older callers that don't have the gap continue to omit the option; behavior is unchanged when no option is passed.
CompactOption 是 CompactTiered 的 functional option. 2026-04-19 新加, 让调用方把从 PromptTooLong API 错误解出的精确 token gap (见 internal/transport.APIError.TokenGap) 传给压缩器, truncateAndRetryCompact 一步跳到正确的步长, 不用一组一组砍. 老调用方不传此 option 行为不变.
func WithTokenGap ¶
func WithTokenGap(n int) CompactOption
WithTokenGap supplies the precise excess-token count from the last PromptTooLong error to CompactTiered. If > 0, truncateAndRetryCompact accumulates the oldest groups' tokens until it meets or exceeds the gap and drops them in one pass, then retries compactFull. If that still returns PromptTooLong, the existing incremental retry loop takes over.
WithTokenGap 把最近一次 PromptTooLong 错误报出的精确溢出 token 数传进 CompactTiered. > 0 时 truncateAndRetryCompact 从最旧的组开始累积 token, 一旦累积量 >= gap 就一次性丢掉, 再试一次 compactFull. 那次还 PromptTooLong 就 fall through 到原来的逐组重试 loop.
type CompactResult ¶
type CompactResult struct {
// Messages 是压缩后的消息列表
Messages []CompactMessage
// Summary 是生成的对话摘要
Summary string
// KeptMessages 保留的最近消息
KeptMessages []CompactMessage
// RestoredItems 恢复的内容
RestoredItems []RestoreItem
// Strategy 使用的策略
Strategy CompactStrategy
// TokensBefore 压缩前的估算 token 数
TokensBefore int
// TokensAfter 压缩后的估算 token 数
TokensAfter int
// DurationMs 压缩耗时(毫秒)
DurationMs int64
}
CompactResult 是压缩操作的结果.
func Compact ¶
func Compact(messages []CompactMessage, provider flyto.ModelProvider, model string) (*CompactResult, error)
Compact 执行上下文压缩(向后兼容的旧入口). 历史包袱(LEGACY): 早期方案使用 apiKey/baseURL 直连 Anthropic HTTP API. 已改为要求 provider 非 nil,调用方应迁移到 Compressor.CompactTiered().
type CompactState ¶
type CompactState struct {
// RecentFiles 压缩前的文件缓存快照
RecentFiles []string
// ActiveSkills 活跃技能列表
ActiveSkills []string
// MCPServers MCP 服务器状态
MCPServers []string
// ActiveAgents 异步代理状态
ActiveAgents []string
// CustomData 通用:场景自定义数据
CustomData map[string]any
}
CompactState 保存压缩前的状态快照,供恢复器使用.
type CompactStrategy ¶
type CompactStrategy string
CompactStrategy 压缩策略类型.
const ( // StrategyFull 完整压缩--生成摘要替换所有旧消息 StrategyFull CompactStrategy = "full" // StrategyPartial 部分压缩--保留前缀,只压缩中间部分 StrategyPartial CompactStrategy = "partial" // StrategyReactive 反应式压缩--API 413 后紧急裁剪 StrategyReactive CompactStrategy = "reactive" )
type CompactionPolicy ¶
type CompactionPolicy interface {
// Name 返回策略的唯一标识名称(用于日志和动态移除).
// 升华改进(ELEVATED): 新增方法,支持 CompositePolicy 按名称移除策略.
// 替代方案:用指针比较来识别策略(不直观且不可序列化).
Name() string
// PreserveKeywords 压缩摘要中必须保留的关键信息描述
PreserveKeywords() string
// ScoreMessageImportance 评估单条消息的重要性(0.0-1.0)
// 低分消息优先被摘要化,高分消息尽量保留原文
ScoreMessageImportance(role string, content string) float64
// MaxRecentRoundsToKeep 保留最近多少轮完整对话
MaxRecentRoundsToKeep() int
// PreprocessForCompaction 压缩前预处理(裁剪大响应,移除重复等)
PreprocessForCompaction(msgs []CompactMessage) []CompactMessage
}
CompactionPolicy 定义特定场景的压缩策略. 编程场景提供默认实现,其他场景(仓储,法律等)注册自己的实现.
Shape: synchronous callback. Engine calls the policy's methods during compression decisions; consumers inject per-scenario implementations via engine.Config.CompactionPolicies (stackable, multiple policies coexist).
形态: 同步回调. 引擎在压缩决策时调策略方法; 消费者经 engine.Config.CompactionPolicies 注入场景专用实现 (可叠加, 多策略并存).
type CompositePolicy ¶
type CompositePolicy struct {
// contains filtered or unexported fields
}
CompositePolicy 将多个 CompactionPolicy 叠加为一个.
使用示例:
code := &DefaultCodePolicy{}
warehouse := &WarehousePolicy{} // 自定义实现
composite := NewCompositePolicy(code, warehouse)
// 关键词合并:
// composite.PreserveKeywords() →
// "file paths, function names, ..., order numbers, SKU codes"
// 重要性评分取最高:
// code 给 0.3, warehouse 给 0.9 → 最终 0.9
// 上下文轮数取最大:
// code 返回 5, warehouse 返回 8 → 最终 8
// 预处理依次执行:
// code 先移除图像 → warehouse 再移除过期订单
func NewCompositePolicy ¶
func NewCompositePolicy(policies ...CompactionPolicy) *CompositePolicy
NewCompositePolicy 创建叠加策略. 至少传一个策略,否则兜底使用 DefaultCodePolicy.
使用示例:
// 单策略退化--行为与直接使用该策略一致
cp := NewCompositePolicy(&DefaultCodePolicy{})
// 多策略叠加--编程 + 仓储
cp := NewCompositePolicy(&DefaultCodePolicy{}, &WarehousePolicy{})
// 零策略兜底--自动使用 DefaultCodePolicy
cp := NewCompositePolicy()
func (*CompositePolicy) Add ¶
func (cp *CompositePolicy) Add(p CompactionPolicy)
Add 动态添加策略(运行时场景切换).
使用示例:
composite := NewCompositePolicy(&DefaultCodePolicy{})
// 用户开始处理仓储任务
composite.Add(&WarehousePolicy{})
// 后续压缩将同时保留编程和仓储关键词
Add 动态添加策略(运行时场景切换). 如果已有同名策略,替换(upsert 语义).两个同名策略是 bug 不是 feature.
func (*CompositePolicy) MaxRecentRoundsToKeep ¶
func (cp *CompositePolicy) MaxRecentRoundsToKeep() int
MaxRecentRoundsToKeep 取所有策略的最大值. 不同场景需要不同的上下文深度,取最大确保不遗漏.
func (*CompositePolicy) Name ¶
func (cp *CompositePolicy) Name() string
Name 返回叠加策略的名称,由所有子策略名称组合而成.
func (*CompositePolicy) PreprocessForCompaction ¶
func (cp *CompositePolicy) PreprocessForCompaction(msgs []CompactMessage) []CompactMessage
PreprocessForCompaction 依次应用所有策略的预处理.
精妙之处(CLEVER): 顺序执行而非并行,因为前一个策略的裁剪 可能影响后一个策略的判断(例如裁掉了图像后文本变短).
func (*CompositePolicy) PreserveKeywords ¶
func (cp *CompositePolicy) PreserveKeywords() string
PreserveKeywords 合并所有策略的关键词,用 ", " 连接,去重.
编程策略: "file paths, function names, error messages" 仓储策略: "order numbers, SKU codes, error messages" 叠加结果: "file paths, function names, error messages, order numbers, SKU codes"
func (*CompositePolicy) Remove ¶
func (cp *CompositePolicy) Remove(name string) bool
Remove 按名称移除策略(场景卸载时). 返回是否成功移除.
使用示例:
composite.Remove("warehouse")
// 后续压缩只保留编程关键词
func (*CompositePolicy) ScoreMessageImportance ¶
func (cp *CompositePolicy) ScoreMessageImportance(role string, content string) float64
ScoreMessageImportance 取所有策略的最高分.
精妙之处(CLEVER): 取最高分而非平均分. 如果编程策略给 0.3(普通文本),但仓储策略给 0.9(含订单号), 最终 0.9 -- 这条消息对仓储场景很重要,不应该被压缩掉. 替代方案:加权平均(更"公平",但会稀释某个场景的高重要性消息).
type Compressor ¶
type Compressor struct {
// contains filtered or unexported fields
}
Compressor 负责上下文压缩. 对应原项目中 autoCompact / microCompact / sessionMemoryCompact.
Compressor 包装了 Compact 和 MicroCompact 函数, 提供有状态的压缩管理(追踪阈值,决定何时触发).
升华改进(ELEVATED): 内嵌断路器实例,CompactTiered 主流程自动管理断路器状态. 替代方案:断路器外置,由调用者管理(早期方案设计,断路器和压缩器分离增加调用复杂度).
func NewCompressor ¶
func NewCompressor(threshold int, provider flyto.ModelProvider) *Compressor
NewCompressor 创建压缩器. threshold 是触发自动压缩的 token 阈值;传入 0 则使用默认阈值(200000 - 13000). provider 是模型调用接口;传入 nil 则退化为仅支持微压缩(无摘要生成).
升华改进(ELEVATED): 签名从 (threshold, apiKey, baseURL, bearerAuth) 简化为 (threshold, provider). 旧签名将 Anthropic 特有认证字段泄漏给所有消费方(OpenAI/Vertex/本地模型无 x-api-key 概念). 新签名通过 flyto.ModelProvider 接口统一所有 provider,调用方不感知底层协议. 替代方案(原方案): 构造函数直接持有 apiKey/baseURL/bearerAuth,provider 通过 SetProvider 注入-- 遗留了"旧路径 vs Provider 路径"的双重代码分支,在每个摘要生成点都要 if/else 分叉.
func (*Compressor) CircuitBreaker ¶
func (c *Compressor) CircuitBreaker() *CompactCircuitBreaker
CircuitBreaker 返回内嵌的断路器(供外部检查状态).
func (*Compressor) CompactTiered ¶
func (c *Compressor) CompactTiered( ctx context.Context, messages []CompactMessage, policy CompactionPolicy, opts ...CompactOption, ) (*CompactResult, error)
CompactTiered 执行三层压缩降级. 这是压缩的主入口,依次尝试三层策略,并自动管理断路器状态.
升华改进(ELEVATED): 三层降级确保从普通会话到极端长会话都能处理, 同时保持 95% 场景走最简单的路径. 替代方案:只有单次压缩(早期方案,极端长会话卡死).
func (*Compressor) CompactWithStrategy ¶
func (c *Compressor) CompactWithStrategy( ctx context.Context, messages []CompactMessage, strategy CompactStrategy, policy CompactionPolicy, ) (*CompactResult, error)
CompactWithStrategy 使用指定策略和策略接口执行压缩. 升华改进(ELEVATED): 三种策略各有场景--
- Full: 常规压缩,生成完整摘要替换旧消息
- Partial: 只压缩中间部分,保留首尾(适合长对话中间有大量工具输出)
- Reactive: API 返回 413 后紧急裁剪,不调用摘要 API,直接丢弃最旧的组
替代方案:只有 Full 一种策略(原始设计,无法处理 413 紧急情况和部分压缩需求).
func (*Compressor) DoCompact ¶
func (c *Compressor) DoCompact(messages []CompactMessage) (*CompactResult, error)
DoCompact 执行压缩操作. 优先走 CompactTiered(provider 路径 + 三层降级),无 provider 时退化为 MicroCompact 降级.
升华改进(ELEVATED): 原实现调用 Compact(msgs, apiKey, baseURL)-- 绕过了 provider 抽象,始终走 Anthropic HTTP 直连,无法与 OpenAI/Vertex 等 Provider 协同. 替代方案(原方案): 保留 Compact(apiKey,baseURL) 调用,provider 路径在 CompactTiered 里另起炉灶-- 两条路径并存,调用方需要知道"用哪个入口",复杂度增加.
func (*Compressor) DoCompactWithHint ¶
func (c *Compressor) DoCompactWithHint(messages []CompactMessage, opts ...CompactOption) (*CompactResult, error)
DoCompactWithHint is DoCompact plus an opts pipe for callers that have extra information (currently: precise token gap from a PromptTooLong API error). engine.forceCompact uses this variant after a ctx-too-long error so the compressor's truncateAndRetryCompact can take a precise stride instead of shaving one group at a time. The plain DoCompact stays for reflex-path callers (maybeCompact) that have no hint.
DoCompactWithHint 是 DoCompact 加一个 opts 管道, 给有额外信息的调用方用 (目前: PromptTooLong API 错误解出的精确 token gap). engine.forceCompact 在 ctx-too-long 错误后走这个 variant, 压缩器的 truncateAndRetryCompact 就能精确跳步, 不用一组一组砍. 纯 DoCompact 留给 reflex-path 调用方 (maybeCompact) -- 它们没有 hint.
func (*Compressor) DoMicroCompact ¶
func (c *Compressor) DoMicroCompact(messages []CompactMessage) []CompactMessage
DoMicroCompact 执行微压缩操作.
func (*Compressor) SetCompactModelFn ¶
func (c *Compressor) SetCompactModelFn(fn CompactModelFunc)
SetCompactModelFn 设置实例级压缩用模型查询函数. 优先于全局 SetCompactModelProvider,用于同进程多 Engine 场景.
func (*Compressor) SetContextWindowFn ¶
func (c *Compressor) SetContextWindowFn(fn ContextWindowFunc)
SetContextWindowFn 设置实例级上下文窗口查询函数. 优先于全局 SetContextWindowProvider,用于同进程多 Engine 场景. 旧的全局 API 保留向后兼容,单 Engine 场景无需迁移.
func (*Compressor) SetObserver ¶
func (c *Compressor) SetObserver(obs flyto.EventObserver)
SetObserver 设置可观测性接口. 升华改进(ELEVATED): Setter 注入而非构造函数参数-- 因为 NewCompressor 已有三个参数且在多处调用,加参数会破坏所有调用点. Setter 注入让现有代码零改动即可工作(observer 为 nil 时自动用 noop 兜底). 替代方案:修改 NewCompressor 签名(破坏所有现有调用点).
func (*Compressor) SetPersister ¶
func (c *Compressor) SetPersister(p CircuitBreakerPersister)
SetPersister 设置断路器状态持久化接口,并立即加载历史状态(如果有).
升华改进(ELEVATED): Setter 注入与 SetObserver 模式一致,不破坏 NewCompressor 调用点. SetPersister 被调用时立即执行一次 Load(),将历史失败计数注入内存断路器. 这样进程重启后断路器从上次离开的状态继续,而不是从零开始.
fail-open 设计:如果 Load() 失败(文件损坏,权限问题), 记录 observer event 但继续运行,断路器从零开始(不影响功能).
func (*Compressor) SetProvider ¶
func (c *Compressor) SetProvider(p flyto.ModelProvider)
SetProvider 更新模型 Provider(支持运行时热切换). NewCompressor 构造时已通过参数注入 provider,此方法用于构造后替换(如插件热加载场景). 传入 nil 时无效(防止意外清除已注入的 provider).
func (*Compressor) SetRestoreManager ¶
func (c *Compressor) SetRestoreManager(rm *RestoreManager)
SetRestoreManager 设置恢复管理器.
func (*Compressor) ShouldCompact ¶
func (c *Compressor) ShouldCompact(messages []CompactMessage) bool
ShouldCompact 检查是否需要触发自动压缩.
type ComputeFn ¶
ComputeFn 是 Section 的动态计算函数. 返回空字符串表示该 Section 在本次调用中应被跳过(不注入提示词). ctx 携带运行时注入值,通过 With* 系列帮助函数写入,在 Compute 内读出.
type ContextWindowFunc ¶
ContextWindowFunc 是获取模型上下文窗口大小的回调函数类型. 允许外部注入 ModelRegistry 的查询能力,避免循环依赖.
type DefaultCodePolicy ¶
type DefaultCodePolicy struct{}
DefaultCodePolicy 编程场景的默认压缩策略.
func (*DefaultCodePolicy) MaxRecentRoundsToKeep ¶
func (p *DefaultCodePolicy) MaxRecentRoundsToKeep() int
MaxRecentRoundsToKeep 编程场景保留最近 5 轮对话.
func (*DefaultCodePolicy) PreprocessForCompaction ¶
func (p *DefaultCodePolicy) PreprocessForCompaction(msgs []CompactMessage) []CompactMessage
PreprocessForCompaction 编程场景的压缩预处理. 1. 移除图像块(图像对摘要无帮助但占大量 token) 2. 截断超长工具结果(>8K 只保留头尾)
func (*DefaultCodePolicy) PreserveKeywords ¶
func (p *DefaultCodePolicy) PreserveKeywords() string
PreserveKeywords 编程场景需要保留的关键信息.
func (*DefaultCodePolicy) ScoreMessageImportance ¶
func (p *DefaultCodePolicy) ScoreMessageImportance(role string, content string) float64
ScoreMessageImportance 评估编程场景中单条消息的重要性. 含错误信息,文件路径,决策语言的消息更重要.
type EnvInfo ¶
type EnvInfo struct {
// Cwd 当前工作目录
Cwd string
// Platform 操作系统平台(linux/darwin/windows)
Platform string
// Shell 用户 shell(bash/zsh/fish 等)
Shell string
// Hostname 主机名
Hostname string
// GitBranch 当前 Git 分支(如果在 Git 仓库中)
GitBranch string
// GitStatus Git 工作区状态摘要
GitStatus string
// IsGitRepo 是否在 Git 仓库中
IsGitRepo bool
// OSVersion 操作系统版本信息
OSVersion string
}
EnvInfo 是运行时环境信息. 注入到系统提示词中,让模型了解当前工作环境.
func CollectEnvInfo ¶
CollectEnvInfo 收集当前运行时环境信息. 通过系统命令和 Go 标准库获取各种环境参数.
type FilePersister ¶
type FilePersister struct {
// contains filtered or unexported fields
}
FilePersister 将断路器状态写入 JSON 文件.
文件路径:`{baseDir}/{cwdHash}.json`
baseDir 默认为 `~/.flyto/compact_breaker/` cwdHash = SHA-256(cwd)[:16](16 个 hex 字符,防止路径冲突)
精妙之处(CLEVER): 用 cwd 的 SHA-256 前缀而非 cwd 本身做文件名, 避免路径中的斜杠,空格等特殊字符导致文件名不合法. 16 hex 字符 = 64 位熵,碰撞概率极低(生日悖论:10^6 个 cwd 碰撞概率 < 0.001%).
func NewFilePersister ¶
func NewFilePersister(baseDir, cwd string) (*FilePersister, error)
NewFilePersister 创建 FilePersister.
baseDir:持久化文件目录,空字符串时使用默认路径 `~/.flyto/compact_breaker/`. cwd:当前工作目录,用于 per-project 隔离(传入 os.Getwd() 的结果).
func (*FilePersister) Load ¶
func (f *FilePersister) Load() (*BreakerState, error)
Load 从文件加载状态,并检查 TTL.
以下情况返回 (nil, nil)(视为"无历史状态"):
- 文件不存在(首次启动)
- 状态已过期(LastFailedAt 超过 breakerStateTTL)
- Failures == 0(成功后 Reset 写入的清零状态)
以下情况返回 (nil, error)(IO 或解析失败,调用方 fail-open 忽略):
- 文件读取失败
- JSON 解析失败(如截断文件,理论上不应发生因为有原子写入)
func (*FilePersister) Save ¶
func (f *FilePersister) Save(state BreakerState) error
Save 将状态原子写入文件(write-then-rename 防止写一半的文件被读到).
升华改进(ELEVATED): atomic write = 写临时文件 → rename. 直接写文件(os.WriteFile)在进程崩溃时会产生截断的 JSON, 下次 Load 会 json.Unmarshal 失败并返回 error. rename 是 POSIX 原子操作,要么旧文件要么新文件,没有中间态.
type FileRestorer ¶
type FileRestorer struct {
// contains filtered or unexported fields
}
FileRestorer 恢复最近读过的文件. 最多 5 个文件,每个 5K token,总预算 50K.
func NewFileRestorer ¶
func NewFileRestorer(fc FileStateCacheReader) *FileRestorer
NewFileRestorer 创建文件恢复器.
func (*FileRestorer) Name ¶
func (r *FileRestorer) Name() string
func (*FileRestorer) Priority ¶
func (r *FileRestorer) Priority() int
func (*FileRestorer) Restore ¶
func (r *FileRestorer) Restore(_ context.Context, state *CompactState) ([]RestoreItem, error)
Restore 从 CompactState 中恢复最近读过的文件信息.
func (*FileRestorer) TokenBudget ¶
func (r *FileRestorer) TokenBudget() int
type FileStateCacheReader ¶
FileStateCacheReader 文件缓存只读接口,避免循环依赖.
type MCPRestorer ¶
type MCPRestorer struct{}
MCPRestorer MCP 指令增量恢复.
func (*MCPRestorer) Name ¶
func (r *MCPRestorer) Name() string
func (*MCPRestorer) Priority ¶
func (r *MCPRestorer) Priority() int
func (*MCPRestorer) Restore ¶
func (r *MCPRestorer) Restore(_ context.Context, state *CompactState) ([]RestoreItem, error)
Restore 恢复 MCP 服务器状态.
func (*MCPRestorer) TokenBudget ¶
func (r *MCPRestorer) TokenBudget() int
type MCPServerStatus ¶
type MCPServerStatus struct {
Name string // Server 配置名 (e.g. "filesystem", "git").
Connected bool // True 表示本轮可调用其工具; false 表示断连或未连上.
}
MCPServerStatus is a snapshot of one MCP server's connection state at prompt build time. The mcp_servers volatile section renders this into a short bulleted line so the model knows which MCP-backed tools are live this turn.
MCPServerStatus 是一次 prompt 构建时某个 MCP server 的连接状态快照. mcp_servers volatile section 将其渲染为简短列表, 让模型知道本轮哪些 MCP-backed 工具可用.
func MCPServerStatusesFromCtx ¶
func MCPServerStatusesFromCtx(ctx context.Context) []MCPServerStatus
MCPServerStatusesFromCtx reads the MCP server status snapshot from ctx. Returns nil if not injected (volatile section then yields empty string and the block drops out).
MCPServerStatusesFromCtx 从 ctx 读取 MCP server 状态快照. 未注入时返回 nil (volatile section 返回空串, 对应 block 被过滤).
type MessageGroup ¶
type MessageGroup struct {
Index int // 分组编号(0 = 前言)
Messages []CompactMessage // 这一轮的所有消息
Tokens int // 估算 token 数
}
MessageGroup 是按 API 往返分组的消息组.
func GroupByAPIRound ¶
func GroupByAPIRound(messages []CompactMessage) []MessageGroup
GroupByAPIRound 将消息按 API 往返分组. Group 0: 前言(系统消息,初始附件--即第一个 assistant 之前的所有 user 消息) Group 1+: 每轮 assistant + 后续 user(tool_results 等)
分组逻辑:
- 遇到 assistant 消息开始新组
- 同一组内包含 assistant 消息和紧随其后的 user 消息(通常是 tool_result)
- 这样保证每组是一个完整的 API 往返
type NoopPersister ¶
type NoopPersister struct{}
NoopPersister 不做任何持久化. 用于测试(避免测试污染文件系统)或明确禁用持久化的场景.
func (*NoopPersister) Load ¶
func (n *NoopPersister) Load() (*BreakerState, error)
func (*NoopPersister) Save ¶
func (n *NoopPersister) Save(_ BreakerState) error
type PlanRestorer ¶
type PlanRestorer struct{}
PlanRestorer 恢复当前计划.
func (*PlanRestorer) Name ¶
func (r *PlanRestorer) Name() string
func (*PlanRestorer) Priority ¶
func (r *PlanRestorer) Priority() int
func (*PlanRestorer) Restore ¶
func (r *PlanRestorer) Restore(_ context.Context, state *CompactState) ([]RestoreItem, error)
Restore 恢复当前计划信息.
func (*PlanRestorer) TokenBudget ¶
func (r *PlanRestorer) TokenBudget() int
type PostCompactRestorer ¶
type PostCompactRestorer interface {
Name() string
Priority() int // 越小越先执行
TokenBudget() int
Restore(ctx context.Context, state *CompactState) ([]RestoreItem, error)
}
PostCompactRestorer 压缩后恢复器接口. 每个恢复器负责一类上下文的恢复,有独立的 token 预算.
type PromptBundle ¶
type PromptBundle interface {
// StaticSections 返回静态部分(边界前,全局可缓存).
// 所有返回的 Section 的 Static 字段应为 true.
// 返回顺序即组装顺序.
StaticSections() []*Section
// DynamicSections 返回动态部分(边界后,会话级缓存).
// 包括 volatile(CacheBreak=true)和普通动态 section.
// 返回顺序即组装顺序.
DynamicSections() []*Section
}
PromptBundle 是一组系统提示词 Section 的命名集合, 按 (ModelFamily, Scenario) 组合调优.
升华改进(ELEVATED): 早期实现 只有一套提示词(对 claude+编程场景深度优化). 我们设计 Bundle 机制支持多模型/多行业-- 引擎内置默认 Bundle(claude+programming,内容一字不改), 平台层或 SDK 用户通过 BundleRegistry.Register 注册行业 Bundle,互不干扰. 不同模型和行业的踩坑改动彼此隔离,不会影响已验证的默认 Bundle. 替代方案:<单一全局提示词,按模型/场景 if-else 分支> - 否决原因:所有场景耦合在一起,行业 bundle 的实验改动会影响编程场景稳定性.
Shape: pull (consumer-registered). Consumers register industry-specific PromptBundle implementations via engine.RegisterPromptBundle(key, bundle); the engine pulls StaticSections() / DynamicSections() during prompt assembly at every turn.
形态: 调取 (消费者注册). 消费者经 engine.RegisterPromptBundle(key, bundle) 注册行业专用 PromptBundle; 引擎在每轮拼 prompt 时 pull StaticSections() / DynamicSections().
func NewBundleFromFunc ¶
func NewBundleFromFunc(staticFn, dynamicFn func() []*Section) PromptBundle
NewBundleFromFunc 从静态/动态函数构建 PromptBundle.
func NewChineseBundle ¶
func NewChineseBundle() PromptBundle
NewChineseBundle 创建中文版 PromptBundle 实例.
静态段落(角色定义,任务准则,操作安全,工具指南,Git 协议等) 全部使用 prompts_zh.go 中的中文常量. 动态段落继承 DefaultBundle 的实现(env_info,tool_descs,instructions 等).
func NewDefaultBundle ¶
func NewDefaultBundle() PromptBundle
NewDefaultBundle 创建 claude+programming 的默认 Bundle 实例.
type RestoreItem ¶
type RestoreItem struct {
Type string // "file" / "skill" / "state" / 自定义
Name string // 资源名(文件路径,技能名等)
Content string // 恢复的内容
Tokens int // 估算 token 数
}
RestoreItem 是单个恢复条目.
type RestoreManager ¶
type RestoreManager struct {
// contains filtered or unexported fields
}
RestoreManager 管理所有恢复器,按优先级执行,控制总预算.
func NewRestoreManager ¶
func NewRestoreManager(totalBudget int) *RestoreManager
NewRestoreManager 创建恢复管理器. totalBudget 为 0 时使用默认值 80000.
func (*RestoreManager) Execute ¶
func (m *RestoreManager) Execute(ctx context.Context, state *CompactState) ([]RestoreItem, error)
Execute 按优先级执行所有恢复器,控制总 token 预算. 精妙之处(CLEVER): 按优先级排序后逐个执行,每个恢复器的结果立即计入已用预算. 如果某个恢复器的结果超过剩余预算,则截断该恢复器的结果. 这保证了高优先级恢复器始终能获得足够的预算.
func (*RestoreManager) Register ¶
func (m *RestoreManager) Register(r PostCompactRestorer)
Register 注册一个恢复器.
type Section ¶
type Section struct {
// Name Section 的唯一标识符,用于 SectionRegistry 的缓存 key.
// 同一 Bundle 内应唯一;不同 Bundle 之间允许重名(各自独立缓存).
Name string
// Static marks whether this Section's content is globally invariant
// (role definitions, behavior rules) and thus a candidate for a long-lived
// cache scope.
//
// true = globally invariant — suitable for "global" cache scope once
// the Anthropic beta stabilizes (currently assembled as
// "ephemeral" in BuildPromptBlocks, see LEGACY note there).
// false = may vary per session/turn (env_info, FLYTO.md, volatile
// sections) — assembled as "ephemeral" or uncached.
//
// Field is read at three points, making it a load-bearing descriptor,
// not a redundant self-description:
//
// (a) Runtime invariant check: BuildPromptBlocks asserts that every
// section returned by StaticSections() has Static=true, and every
// non-Volatile section returned by DynamicSections() has
// Static=false. Violations fire a `section_contract_violation`
// observer event so SDK consumers who hand-build &Section{...}
// and place it in the wrong bucket see the bug at wire time, not
// via a cache-behavior regression weeks later.
// (b) Future global cache-scope branching: once the Anthropic beta
// header stabilizes, BuildPromptBlocks' static-block CacheScope
// will switch from "ephemeral" to "global" gated on Static=true.
// Keeping the field explicit (rather than inferred from the
// interface method) makes that upgrade a one-line flip.
// (c) SectionRegistry cache-benefit: Static=true sections still go
// through the registry cache to avoid per-call string allocation
// even though their content would be cheap to recompute.
//
// Static 标记此 Section 是否为全局不变内容 (角色定义/行为规则), 从而
// 是长寿命 cache scope 的候选.
//
// true = 全局不变 -- 适合 Anthropic beta 稳定后的 "global" cache scope
// (当前 BuildPromptBlocks 统一组装为 "ephemeral", 见 LEGACY 注释).
// false = 可能逐会话/每轮变化 (env_info, FLYTO.md, volatile section)
// -- 组装为 "ephemeral" 或不缓存.
//
// 字段在三处被读, 是承载性描述, 不是冗余 self-description:
//
// (a) 运行时 invariant check: BuildPromptBlocks 断言 StaticSections()
// 返回的 section 必须 Static=true, DynamicSections() 返回的非
// Volatile section 必须 Static=false. 违反会发
// `section_contract_violation` observer 事件, SDK 消费者手搓
// &Section{...} 放错 bucket 时立即在 wire time 发现 bug, 而不是
// 数周后通过 cache 行为回归暴露.
// (b) 未来 global cache-scope 分支: Anthropic beta header 稳定后,
// BuildPromptBlocks 的 static-block CacheScope 会从 "ephemeral"
// 切到 "global", gate 在 Static=true. 显式字段 (而非 interface
// method 推断) 让此升级只需改一行.
// (c) SectionRegistry cache 收益: Static=true section 仍走 registry
// 缓存以避免每次调用的字符串分配, 即便重算开销低.
Static bool
// Text 静态文字内容.
// Static=true 且内容已知时,直接填此字段,Compute 留 nil.
// Compute 不为 nil 时,Text 字段被忽略.
Text string
// Compute 动态计算函数(可选).
// nil 时直接使用 Text 字段.
// 非 nil 时:SectionRegistry.Compute 调用此函数,结果缓存(除非 CacheBreak=true).
Compute ComputeFn
// CacheBreak 为 true 时,此 Section 每轮强制重算,完全绕过缓存.
//
// 历史包袱(LEGACY): 名字和语义沿用早期方案 DANGEROUS_uncachedSystemPromptSection 的设计--
// 用于 MCP server 连接状态等在会话中途可能变化的内容.
// 早期方案用前缀 DANGEROUS 标记此类 section,以提示开发者"这会打碎 prompt cache".
// 我们保留相同语义,用 CacheBreak bool + NoCacheReason string 替代命名约定,
// 更容易静态分析和 lint.
// 理想状态:用 event-driven invalidation(section 订阅特定事件)替代,
// 但需要更多基础设施,暂时保持简单.
CacheBreak bool
// NoCacheReason explains why this Section must be recomputed every turn.
// Only meaningful when CacheBreak=true. Consumed by three audiences:
// 1. Documentation and code review (grep for VolatileSection call sites).
// 2. Runtime diagnostics: SectionRegistry.Compute emits a
// `section_cache_break` observer event carrying this string whenever
// a CacheBreak section is computed, so operators tracing a
// prompt-cache miss can see *which* section invalidated and why.
// 3. Future event-driven invalidation: a registry that subscribes to
// a reason taxonomy can selectively invalidate rather than per-turn recompute.
//
// NoCacheReason 说明为什么此 Section 必须每轮重算.
// 仅在 CacheBreak=true 时有意义, 三个消费者:
// 1. 文档与代码审查 (grep VolatileSection 调用点).
// 2. 运行时诊断: SectionRegistry.Compute 每次计算 CacheBreak section
// 时, 经 observer 发 `section_cache_break` 事件携带此字符串,
// 运维追踪 prompt-cache miss 可看到 *哪个* section 打碎 cache 以及原因.
// 3. 未来事件驱动失效: 订阅 reason 分类的 registry 可精确失效
// 而不必每轮重算.
NoCacheReason string
}
Section 是系统提示词的一个命名片段,可单独缓存和管理.
升华改进(ELEVATED): 早期实现用 JS 对象 {name, compute, cacheBreak} + 全局 state 做缓存(Map<string, string>,进程级全局变量). 我们将缓存状态移入 SectionRegistry 实例,绑定到 Engine-- 同一进程中多个 Engine(多用户,多工作区)各有独立缓存,不会互相污染. CLI 单用户场景行为等价;SaaS 多租户场景获得隔离性. 替代方案:<沿用全局 sync.Map> - 否决原因:多 Engine 实例会互相污染缓存, Reset() 时要么清掉别人的缓存要么无法精确清除.
func DynamicSection ¶
DynamicSection 是创建动态(会话级缓存)Section 的便捷函数.
func StaticSection ¶
StaticSection 是创建静态 Section 的便捷函数. 用于不需要运行时计算的 Section(角色定义,行为准则等常量文本).
type SectionRegistry ¶
type SectionRegistry struct {
// contains filtered or unexported fields
}
SectionRegistry 是会话级的 Section 计算缓存,绑定到 Engine 实例.
生命周期:
- New(): 随 Engine 创建
- Compute(): 首次计算后缓存,后续命中直接返回
- Reset(): 在 /clear 或 /compact 后清空,让动态 section 下一轮重新计算
- Invalidate(name): 精确使某个 section 失效(如 MCP 连接状态变化时)
线程安全:读多写少场景用 RWMutex,Compute 路径用 RLock 快速读,仅 miss 时升级 Lock.
func NewSectionRegistry ¶
func NewSectionRegistry() *SectionRegistry
NewSectionRegistry 创建空的 Section 缓存.
func NewSectionRegistryWithObserver ¶
func NewSectionRegistryWithObserver(obs flyto.EventObserver) *SectionRegistry
NewSectionRegistryWithObserver creates an empty Section cache that emits `section_cache_break` diagnostic events to obs whenever a CacheBreak Section is computed. obs may be nil (equivalent to NewSectionRegistry).
NewSectionRegistryWithObserver 创建空的 Section 缓存, 并在每次计算 CacheBreak Section 时经 obs 发 `section_cache_break` 诊断事件. obs 可为 nil (等价于 NewSectionRegistry).
func (*SectionRegistry) Compute ¶
func (r *SectionRegistry) Compute(ctx context.Context, s *Section) string
Compute 返回 Section 的文字内容,优先使用缓存.
精妙之处(CLEVER): CacheBreak=true 的 Section 完全跳过缓存-- 不读也不写缓存,保证每轮拿到实时值. 普通 Section(静态或动态)首次调用后缓存结果,后续直接返回, 避免重复执行 IO 操作(git status,FLYTO.md 读取等).
func (*SectionRegistry) Invalidate ¶
func (r *SectionRegistry) Invalidate(name string)
Invalidate 使特定 Section 的缓存条目失效. 用于已知某个 Section 内容变化时的精确失效(如 MCP server 连接/断开).
func (*SectionRegistry) Reset ¶
func (r *SectionRegistry) Reset()
Reset 清空所有缓存条目. 在 /clear 或 /compact 后调用,让动态 Section 在下一轮重新计算.
type SkillProvider ¶
type SkillProvider interface {
ActiveSkills() []SkillInfo
}
SkillProvider 技能提供者接口,避免循环依赖.
type SkillRestorer ¶
type SkillRestorer struct {
// contains filtered or unexported fields
}
SkillRestorer 恢复活跃技能. 每个 5K token,总预算 25K.
func NewSkillRestorer ¶
func NewSkillRestorer(sp SkillProvider) *SkillRestorer
NewSkillRestorer 创建技能恢复器.
func (*SkillRestorer) Name ¶
func (r *SkillRestorer) Name() string
func (*SkillRestorer) Priority ¶
func (r *SkillRestorer) Priority() int
func (*SkillRestorer) Restore ¶
func (r *SkillRestorer) Restore(_ context.Context, state *CompactState) ([]RestoreItem, error)
Restore 恢复活跃技能.
func (*SkillRestorer) TokenBudget ¶
func (r *SkillRestorer) TokenBudget() int
type SystemPromptBlock ¶
type SystemPromptBlock struct {
// Text 是此块的文字内容.
Text string
// CacheScope 控制此块的缓存行为:
// "global" - 全局可缓存(跨会话/跨用户),对应 Anthropic beta cache_scope='global'
// "ephemeral" - 会话级缓存,对应 cache_control: {type: "ephemeral"}
// "" - 不缓存(每次请求都发送,无 cache_control)
CacheScope string
}
SystemPromptBlock 是一个带缓存语义的系统提示词 API 块.
升华改进(ELEVATED): 早期实现 buildSystemPromptBlocks 直接生成 Anthropic API 结构体 (anthropic.TextBlockParam with cache_control). 我们用中间层 SystemPromptBlock 解耦--context 包生成 Block(纯逻辑), engine 层负责将 Block 转换为 api.SystemContentBlock(API 序列化). 好处:context 包不需要 import internal/api,避免循环依赖; 也更容易测试(不需要对 API 结构体做断言). 替代方案:<Builder 直接返回 api.SystemContentBlock> - 否决原因:context 包会循环依赖 internal/api 包.
func BuildPromptBlocks ¶
func BuildPromptBlocks(ctx context.Context, bundle PromptBundle, registry *SectionRegistry, enableCaching bool) []SystemPromptBlock
BuildPromptBlocks 将 Bundle 的所有 Section 转换为带缓存语义的 API 块.
组装策略(enableCaching=true 时):
- 静态 sections → 合并为一个 "ephemeral" 块(将来升级为 "global",当 beta 可用)
- 非 volatile 动态 sections → 合并为一个 "ephemeral" 块(会话级命中)
- volatile(CacheBreak=true)动态 sections → 每个单独的 "" 块(不缓存)
组装策略(enableCaching=false 时):
- 所有内容合并为单个无缓存块(向后兼容,与旧 buildAPIRequest 行为一致)
精妙之处(CLEVER): 静态和动态各自合并为单块而非逐 section 分块-- Anthropic API 的 cache_control breakpoint 限额为 4 个. 把同类 sections 合并可以节约 breakpoint 预算,留给工具列表等其他可缓存位置. 替代方案:<每个 Section 独立成块> - 否决原因:轻易超过 4 个 breakpoint 限额.
type ToolDescription ¶
ToolDescription 是工具的简要描述,用于注入到系统提示中.
func ToolDescriptionsFromCtx ¶
func ToolDescriptionsFromCtx(ctx context.Context) []ToolDescription
ToolDescriptionsFromCtx 从 context 读取工具描述列表.