flyto

package
v0.0.0 Latest Latest
Warning

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

Go to latest
Published: Apr 26, 2026 License: None detected not legal advice Imports: 0 Imported by: 0

Documentation

Overview

Package flyto 是 Flyto Agent 引擎的公共契约包.

这个包只包含接口和类型定义,零实现,零外部依赖. 消费者(TUI,HTTP Server,第三方 SDK)只需 import 这一个包, 不需要了解引擎内部实现细节.

核心原则:

  • 最大公约数:接口只包含所有实现者都必须支持的方法
  • 可选能力:provider 特有功能通过 type assertion 的可选接口暴露
  • 零依赖:只用 Go 标准库,可嵌入任何环境
  • 向后兼容:此包的任何 breaking change 都需要版本升级

包结构:

events.go    - 引擎→消费者的事件流(Event 接口 + 所有具体事件)
observer.go  - 消费者实现的可观测性接口(EventObserver 等)
message.go   - 消息模型(Message,Block,Role)
tool.go      - 工具定义(Tool)
provider.go  - 模型提供商接口(ModelProvider + 可选能力接口)
engine.go    - 引擎接口(Engine,消费者编程的目标)
errors.go    - 结构化错误类型(ErrorCode,EngineError)

API consumption shapes:

Flyto exposes three distinct API shapes to consumers; pick by mechanism, not by domain. See docs/api-reference.md section "API 消费形态 / API Consumption Patterns" for full taxonomy and when to use which.

  • Push (subscribe) — form 1: consumers open a stream or register a callback; the engine notifies asynchronously. Interfaces: Event (via `<-chan flyto.Event`) and EventObserver.
  • Pull — form 2: consumers call a method to read a current snapshot. Example consumers of this package's types: `Session.Stats() SessionStats` and `DenialTracker.Stats() DenialStats` in engine/permission packages.
  • Synchronous callback — form 3: engine blocks for a consumer decision. Interfaces in sibling packages: permission.Handler, engine.ApprovalPolicy, engine.ElicitationHandler, security.AuditSink, hooks.HookHandler.

API 消费形态:

Flyto 对消费者暴露三种独立 API 形态, 按机制选而非按领域选. 完整分类和选型 指引见 docs/api-reference.md "API 消费形态 / API Consumption Patterns" 章节.

  • 订阅 (push) —— 形态一:消费者开流或注册回调, 引擎异步通知. 本包接口: Event (经 `<-chan flyto.Event`) 和 EventObserver.
  • 调取 (pull) —— 形态二:消费者调方法读当前快照. 本包类型在引擎/权限包 的消费例: `Session.Stats() SessionStats`, `DenialTracker.Stats() DenialStats`.
  • 同步回调 (callback) —— 形态三:引擎阻塞等消费者决策. 兄弟包接口: permission.Handler, engine.ApprovalPolicy, engine.ElicitationHandler, security.AuditSink, hooks.HookHandler.

Index

Constants

View Source
const (
	WarnTokenUsageHigh  = "token_usage_high"
	WarnBudgetNearLimit = "budget_near_limit"
	WarnSessionExpiring = "session_expiring"
)

Variables

This section is empty.

Functions

func Float

func Float(v float64) *float64

Float returns a pointer to v. Sugar for setting *float64 fields like Request.Temperature / Request.TopP without a temporary local variable.

Float 返回指向 v 的指针. 给 Request.Temperature / Request.TopP 这类 *float64 字段赋值时省去临时局部变量.

func FormatErrorForDisplay

func FormatErrorForDisplay(err error, verbose bool) string

FormatErrorForDisplay 格式化错误供用户阅读.

func IsRetryable

func IsRetryable(err error) bool

IsRetryable 检查错误是否可重试.

Types

type Block

type Block struct {
	Type BlockType

	// --- TextBlock 字段 ---
	Text string

	// --- ToolUseBlock 字段(模型请求调用工具)---
	ToolUseID string
	ToolName  string
	ToolInput map[string]any

	// --- ToolResultBlock 字段(工具执行结果回传)---
	// ToolUseID 复用上方同名字段(关联请求)
	ResultText string
	IsError    bool

	// ResultBlocks carries tool_result content as an array of blocks when
	// the result includes non-text payloads (e.g. image). Populated by the
	// engine when a tool returns *tools/builtin.ImageResult via Result.Data.
	// Nil when ResultText is sufficient (plain text result). Provider
	// layer emits "content":[...] when non-nil; otherwise falls back to
	// "content":"string" using ResultText.
	//
	// Anthropic API spec (verified 2026-04-21, docs.anthropic.com): a
	// tool_result content field accepts either string or array. Array form
	// supports text + image mixed blocks so the model can ground its
	// response in the returned image.
	//
	// ResultBlocks 以 block 数组形式承载 tool_result 内容, 当结果含非文本
	// 载荷 (如图片) 时填入. 引擎在工具经 Result.Data 返回
	// *tools/builtin.ImageResult 时填. 纯文本结果 ResultText 够用时为 nil.
	// Provider 层据此决定 wire 形态: 非 nil 发 "content":[...] array,
	// 否则用 "content":"string" 字符串 (fallback 到 ResultText).
	//
	// Anthropic spec (2026-04-21 verify): tool_result content 支持 string
	// 或 array. Array 形式允许 text + image 混排, 让模型基于返回图片应答.
	ResultBlocks []Block

	// --- ThinkingBlock 字段(模型扩展思考内容)---
	ThinkingText string // 思考内容文本

	// --- ImageBlock 字段 (BlockImage 类型消息内容) ---
	// ImageSource carries image data in either base64-inline or URL form.
	// Nil for non-image blocks. Populated by engine when the user inlines
	// an image path or a tool returns image data via tools.Result.Data.
	//
	// ImageSource 携带图片数据, base64 内联或 URL 两种形式. 非图片块为 nil.
	// 用户粘贴图片路径或工具经 tools.Result.Data 返图时由引擎填入.
	ImageSource *ImageSource

	// ProviderMetadata 存储 Provider 特有的不透明数据(如签名,ID 等).
	// 引擎不解读此字段,原样回传给 Provider.
	ProviderMetadata map[string]string
}

Block 是消息内容块.

精妙之处(CLEVER): 用单一结构体 + BlockType 判断,而非 interface + 多个子类型-- 避免了消费者写 type switch + 类型断言的样板代码, 同时保持零 interface 分配开销(结构体值语义).

func ImageBlockBase64

func ImageBlockBase64(mediaType, data string) Block

ImageBlockBase64 constructs an image block carrying base64-encoded data. mediaType is required (e.g. "image/png"). data must NOT include the "data:image/...;base64," prefix -- pass raw base64 bytes only.

ImageBlockBase64 构造含 base64 编码数据的图片块. mediaType 必填 (如 "image/png"). data 必须是纯 base64 字节, 不带 "data:image/...;base64," 前缀.

func ImageBlockURL

func ImageBlockURL(url string) Block

ImageBlockURL constructs an image block referencing an HTTPS image URL. Provider layer may fetch or pass through; check provider docs.

ImageBlockURL 构造引用 HTTPS 图片链接的图片块. Provider 层可能抓取或透传, 详见 provider 文档.

func TextBlock

func TextBlock(text string) Block

TextBlock 创建文本内容块.

func ThinkingBlock

func ThinkingBlock(text string, providerMeta map[string]string) Block

ThinkingBlock 创建扩展思考内容块. providerMeta 是 provider 返回的不透明元数据(如签名),回传时必须原样携带. 传 nil 表示无额外元数据.

func ToolResultBlock

func ToolResultBlock(toolUseID, result string, isError bool) Block

ToolResultBlock 创建工具结果块.

func ToolResultBlocks

func ToolResultBlocks(toolUseID string, blocks []Block, isError bool) Block

ToolResultBlocks constructs a tool_result block whose content is an array of nested blocks (typically text + image mixed). Use when the tool returns an image (via Result.Data) that should be surfaced to the model; for plain text results prefer ToolResultBlock.

ToolResultBlocks 构造 content 为 block 数组形式的 tool_result 块 (典型是 text + image 混排). 工具经 Result.Data 返图且要让模型看见时使用; 纯文本 结果优先 ToolResultBlock.

func ToolUseBlock

func ToolUseBlock(id, name string, input map[string]any) Block

ToolUseBlock 创建工具调用块.

type BlockType

type BlockType string

BlockType 标识内容块类型.

const (
	// BlockText 是普通文本内容.
	BlockText BlockType = "text"

	// BlockToolUse 表示模型请求调用一个工具.
	BlockToolUse BlockType = "tool_use"

	// BlockToolResult 表示工具执行结果(回传给模型).
	BlockToolResult BlockType = "tool_result"

	// BlockThinking 表示模型的扩展思考内容(extended thinking).
	BlockThinking BlockType = "thinking"

	// BlockImage carries image data (base64 or URL) for multimodal models.
	// Provider compatibility varies -- Anthropic and compatible endpoints
	// consume this; other providers (openai, gemini, minimax native)
	// currently return an error when encountering BlockImage. Callers
	// routing images must select a vision-capable provider.
	//
	// BlockImage 携带图片数据 (base64 或 URL) 给多模态模型. Provider 兼容性
	// 有差异 -- Anthropic 及兼容端点已支持, 其他 (openai / gemini / minimax
	// native) 目前遇 BlockImage 返 error. 需要传图的调用方应选用有 vision
	// 能力的 provider.
	BlockImage BlockType = "image"
)

type CheckpointEvent

type CheckpointEvent struct {
	ToolCallID string
	ToolName   string
	Input      map[string]any
	Message    string
}

CheckpointEvent 表示引擎在执行不可逆操作前暂停,等待外部确认.

func (*CheckpointEvent) EventType

func (e *CheckpointEvent) EventType() string

type CheckpointSuggestedEvent

type CheckpointSuggestedEvent struct {
	ToolCallID  string         // 触发建议的工具调用 ID
	ToolName    string         // 工具名("Bash" / "FileEdit" / "FileWrite" 等)
	Input       map[string]any // 工具输入(用于消费层展示)
	RiskReason  string         // 高风险原因(英文,方便日志分析)
	RiskPattern string         // 匹配到的风险模式(如 "rm -rf" / "drop table" / "overwrite")
}

CheckpointSuggestedEvent 是引擎的主动建议--检测到高风险操作模式时推送, 但不阻塞执行(与 CheckpointEvent 不同:CheckpointEvent 是工具声明的强制拦截, CheckpointSuggestedEvent 是引擎的静态分析建议,最终决定权仍在消费层).

升华改进(ELEVATED): 早期设计 "Human checkpoint" 仅靠提示词引导模型自主提示用户, 依赖模型遵从,无法覆盖所有 Provider. 我们在引擎层做静态模式匹配:无论底层是哪个模型,只要检测到高风险命令就主动通知消费层. 消费层(TUI/SDK)可选择展示警告,弹出确认框,或忽略(如果用户已在 FLYTO.md 中授权).

替代方案:<在权限系统中拦截> - 否决:权限系统面向"是否允许执行该类工具"(二元决策), 这里是"建议消费层展示额外确认"(建议而非强制),语义不同,不应混入权限系统.

func (*CheckpointSuggestedEvent) EventType

func (e *CheckpointSuggestedEvent) EventType() string

type CompactEvent

type CompactEvent struct {
	Summary      string
	TokensBefore int
	TokensAfter  int
}

CompactEvent 表示上下文被压缩.

func (*CompactEvent) EventType

func (e *CompactEvent) EventType() string

type DoneEvent

type DoneEvent struct {
	TotalInputTokens  int
	TotalOutputTokens int
	TotalCostUSD      float64
	TurnCount         int
	// Reason 非空表示受控终止(如 "pre_sampling_blocked"),空字符串表示正常结束.
	Reason string
}

DoneEvent 表示 Agent 运行结束.

func (*DoneEvent) EventType

func (e *DoneEvent) EventType() string

type Engine

type Engine interface {
	// Run 在指定会话中执行一轮对话,返回事件流.
	//
	// messages 是本轮输入(用户消息 + 工具结果等).
	// 事件流关闭表示本轮结束,最后一个 *DoneEvent 或 *ErrorEvent 说明结束原因.
	//
	// 精妙之处(CLEVER): 返回 <-chan Event 而非 error--
	// 错误通过 *ErrorEvent 在流中传递,消费者用统一的 for-range 处理所有情况,
	// 不需要双返回值(err + channel)的尴尬.
	Run(ctx context.Context, sessionID string, messages []Message, opts ...RunOption) <-chan Event

	// Close 停止引擎,释放所有资源(goroutine,连接,文件句柄).
	// 幂等:多次调用安全.
	Close() error
}

Engine 是 Flyto Agent 引擎的公共接口.

Shape: push (stream entry). Engine.Run returns `<-chan Event` that consumers range + type-switch on. Close is a pull-side lifecycle call.

形态: 订阅 (流入口). Engine.Run 返回 `<-chan Event`, 消费者 range + type-switch 处理. Close 是 pull 侧生命周期调用.

type EngineError

type EngineError struct {
	Code       ErrorCode
	Message    string
	Detail     string
	Suggestion string
	Cause      error
	Retryable  bool
}

EngineError 是引擎统一错误类型.

func NewEngineError

func NewEngineError(code ErrorCode, message string, cause error) *EngineError

NewEngineError 创建引擎错误(使用默认 Suggestion 和 Retryable).

func WrapError

func WrapError(cause error, code ErrorCode, message string) *EngineError

WrapError 将普通错误包装为 EngineError.

func (*EngineError) Error

func (e *EngineError) Error() string

func (*EngineError) Unwrap

func (e *EngineError) Unwrap() error

type ErrorCode

type ErrorCode string

ErrorCode 是引擎错误码枚举.

const (
	ErrAPIAuth          ErrorCode = "api_auth_error"
	ErrAPIRateLimit     ErrorCode = "api_rate_limit"
	ErrAPIOverloaded    ErrorCode = "api_overloaded"
	ErrAPIBadRequest    ErrorCode = "api_bad_request"
	ErrToolNotFound     ErrorCode = "tool_not_found"
	ErrToolExecution    ErrorCode = "tool_execution_error"
	ErrPermissionDenied ErrorCode = "permission_denied"
	ErrContextOverflow  ErrorCode = "context_overflow"
	ErrBudgetExceeded   ErrorCode = "budget_exceeded"
	ErrMaxTurns         ErrorCode = "max_turns_reached"
	ErrSessionNotFound  ErrorCode = "session_not_found"
	ErrSessionClosed    ErrorCode = "session_closed"
	ErrMCPConnection    ErrorCode = "mcp_connection_error"
	ErrPluginLoad       ErrorCode = "plugin_load_error"
	ErrInternal         ErrorCode = "internal_error"
	ErrStreamTruncated  ErrorCode = "stream_truncated"
)

type ErrorEvent

type ErrorEvent struct {
	Err        error
	Code       string
	Suggestion string
	Retryable  bool
}

ErrorEvent 表示运行出错.

func (*ErrorEvent) Error

func (e *ErrorEvent) Error() string

func (*ErrorEvent) EventType

func (e *ErrorEvent) EventType() string

type Event

type Event interface {
	EventType() string
}

Event is the interface all engine output events implement. Consumed via the `<-chan flyto.Event` channel returned by Engine.Run / Session.Send; consumers type-switch on concrete types (*TextDeltaEvent / *DoneEvent / *CheckpointSuggestedEvent / *InboxMessageEvent / *TeammateMessageReceivedEvent etc.) to dispatch.

Shape: push (stream). The channel delivers events asynchronously; the consumer ranges and does not reply.

Event 是所有引擎输出事件的接口. 消费端从 Engine.Run / Session.Send 返回的 `<-chan flyto.Event` channel 取事件, type-switch 到具体类型 (*TextDeltaEvent / *DoneEvent / *CheckpointSuggestedEvent / *InboxMessageEvent / *TeammateMessageReceivedEvent 等) 分发处理.

形态: 订阅 (stream). channel 异步推事件, 消费者 range 即可, 不回应.

type EventObserver

type EventObserver interface {
	// Event 记录离散事件.
	// name 例如 "tool_result_pairing_repaired",data 是结构化上下文.
	Event(name string, data map[string]any)

	// Error 记录错误(含上下文,用于告警).
	Error(err error, context map[string]any)
}

EventObserver 核心事件接口(消费者必须实现以接收引擎内部事件).

注意:这里的"事件"是引擎内部运行事件(tool_result_pairing_repaired 等), 与 Event 接口(引擎输出事件流)是两个不同的概念.

Shape: push (subscribe). Consumers register an implementation via engine.Config.Observer; the engine calls back asynchronously on state changes, no consumer response expected.

形态: 订阅 (push). 消费者经 engine.Config.Observer 注入实现, 引擎在状态 变更时异步回调, 不等消费者回应.

type ImageSource

type ImageSource struct {
	// SourceType is "base64" or "url".
	// SourceType 为 "base64" 或 "url".
	SourceType string

	// MediaType is the IANA media type (e.g. "image/png", "image/jpeg").
	// Required when SourceType is "base64".
	//
	// MediaType 是 IANA 媒体类型 (如 "image/png" / "image/jpeg"). SourceType
	// 为 "base64" 时必填.
	MediaType string

	// Data is the base64-encoded image bytes (no data-URL prefix). Required
	// when SourceType is "base64".
	//
	// Data 是图片 bytes 的 base64 编码 (不带 data-URL 前缀). SourceType 为
	// "base64" 时必填.
	Data string

	// URL points to an image served over HTTPS. Required when SourceType is
	// "url".
	//
	// URL 是 HTTPS 图片链接. SourceType 为 "url" 时必填.
	URL string
}

ImageSource carries a single image as either base64-inline data or a URL. Mirrors Anthropic's image source shape (provider layer reshapes per API).

ImageSource 携带单张图片, base64 内联数据或 URL 二选一. shape 对齐 Anthropic image source, provider 层按具体 API 适配.

type InboxMessageEvent

type InboxMessageEvent struct {
	Type      string // "progress" / "log" / "result"
	ToolUseID string
	Data      string
	Meta      string // JSON 格式的额外元数据
}

InboxMessageEvent 表示工具子进程通过 UDS 发来的消息.

func (*InboxMessageEvent) EventType

func (e *InboxMessageEvent) EventType() string

type Message

type Message struct {
	Role   Role
	Blocks []Block // 一条消息可包含多个内容块
}

Message 是对话消息(用户或助手发出).

func AssistantText

func AssistantText(text string) Message

AssistantText 创建纯文本助手消息的便捷函数.

func UserText

func UserText(text string) Message

UserText 创建纯文本用户消息的便捷函数.

type MetricObserver

type MetricObserver interface {
	// Metric 记录数值指标.
	// 例如:name="api_latency_ms", value=123.4, tags={"model":"claude-sonnet-4-6"}
	Metric(name string, value float64, tags map[string]string)
}

MetricObserver 数值指标接口(可选,通过 type assertion 检测).

Shape: push (subscribe). Engine emits numeric metric samples; consumer forwards to Prometheus / StatsD / OpenTelemetry etc.

形态: 订阅 (push). 引擎发数值指标样本, 消费者转给 Prometheus / StatsD / OpenTelemetry 等.

type ModelInfo

type ModelInfo struct {
	ID          string // API 使用的模型 ID,如 "claude-sonnet-4-6"
	DisplayName string // 展示名称,如 "Claude Sonnet 4.6"
	Provider    string // provider 标识

	ContextWindow   int // 上下文窗口(tokens)
	MaxOutputTokens int // 最大输出(tokens)

	// 定价(USD / 1M tokens,0 = 免费或未知)
	InputPricePer1M      float64
	OutputPricePer1M     float64
	CacheReadPricePer1M  float64 // 缓存读取价格(美元/百万 token)
	CacheWritePricePer1M float64 // 缓存写入价格(美元/百万 token)

	// 能力标志(provider 填写).
	// 升华改进(ELEVATED): 早期仅作展示元数据,新版同时驱动引擎自动决策--
	// SupportsCaching=true + CachingMinTokens > 0 → 引擎自动检查 system 长度并注入 cache_control(已实现,2026-04)
	// SupportsThinking=true → 消费者可用 Request.NeedsThinking 触发自动 budget 注入(已实现,2026-04)
	// 替代方案:<把所有能力逻辑放在消费者侧> - 否决:每个消费者都得手动处理阈值/header/格式差异.
	//
	// SupportsCaching 已知支持(2026-04):
	//   anthropic claude-opus-4-6 / claude-sonnet-4-6 : 1024t(官方文档)
	//   anthropic claude-haiku-4-5                    : 4096t(官方文档)
	//   minimax MiniMax-M2.7/M2.5/M2.1/M2            : 1024t(probe 实测)
	//   openrouter → anthropic 路径                   : ✗(probe 确认 cr=0@7200t)
	SupportsCaching  bool
	SupportsBatch    bool
	SupportsThinking bool
	SupportsVision   bool

	// CachingMinTokens 是触发 prompt caching 的最低系统提示 token 数.
	// 数据来源:官方文档 + 实测探测(2026-04).
	// 0 = 不支持或未知.
	//
	// 已知阈值(2026-04):
	//   anthropic claude-opus-4-6 / claude-sonnet-4-6 : 1024t(官方文档)
	//   anthropic claude-haiku-4-5                    : 4096t(官方文档;probe 确认需要 ~7200t 才触发,文档值 4096 在范围内)
	//   minimax MiniMax-M2.x                          : 1024t(probe 实测 cr=1110 @~1000t 系统提示)
	//
	// 历史包袱(LEGACY): OpenRouter 路径 cache_control 不被转发给上游后端
	// (probe 确认 cr=0@7200t),OpenRouter 路由的模型应设 SupportsCaching=false.
	CachingMinTokens int

	// MaxTools 是单次请求允许的最大工具数(0 = 未知/无限制).
	//
	// 已知值(2026-04):
	//   OpenAI Chat API  : 128(OpenAPI spec 明确记录)
	//   Anthropic strict : 20(官方文档;普通模式无明确文档上限,此处填 0)
	//   MiniMax          : 0(probe 实测 @256 未发现上限,待后续验证)
	//   OpenRouter       : 0(透传底层模型,自身无额外限制)
	//
	// 精妙之处(CLEVER): 用 0 表示"未知/不限制"而非 MaxInt--
	// 0 是 Go 零值,静态表不填此字段即表示"不限制",无需显式声明;
	// MaxInt 在各层传递时容易溢出或被误用为"极大数"参与比较运算.
	MaxTools int

	// MaxToolsExhaustive 表示 MaxTools 是否是穷尽测试得到的真上限.
	//
	// 升华改进(ELEVATED): 与 cmd/capability-probe 输出的 max_tools.exhaustive
	// schema 对应.区分两种语义:
	//   true  = MaxTools 是确认上限,provider 可硬执行(len(tools) > MaxTools 即报错)
	//   false = MaxTools 是已知下界(probe 测到这个数没出错,但没找到真上限),
	//           provider 应软处理(继续发请求让 API 自己拒),不应客户端硬拒
	//
	// 默认零值 false 是保守选择:静态表不显式填写时按"已知下界"对待,避免误伤.
	// 替代方案:<*bool 三态> - 否决:MaxTools=0 已是哨兵语义(无上限),
	// Exhaustive 仅在 MaxTools > 0 时有意义,bool 零值刚好对应"保守软处理".
	MaxToolsExhaustive bool
}

ModelInfo 描述一个模型的规格和能力.

用途:token 进度条(ContextWindow),费用估算(Price), 模型选择 UI(DisplayName),能力过滤(Supports*).

type ModelProvider

type ModelProvider interface {
	// Name 返回 provider 标识,如 "openai","ollama".
	Name() string

	// Stream 向模型发送请求,返回事件流.
	//
	// 精妙之处(CLEVER): channel 而非回调--
	// channel 天然背压(consumer 慢则 provider 等待),
	// 与 Go 的 for-range 习惯完美契合,支持 context 取消.
	//
	// provider 负责将 API 响应转换为 flyto.Event 事件序列.
	// channel 关闭表示流结束,最后一个事件为 *ErrorEvent 表示出错.
	Stream(ctx context.Context, req *Request) (<-chan Event, error)

	// Models 返回此 provider 可用的模型列表.
	// 用于模型选择 UI,合法性验证,定价展示,token 进度条等.
	Models(ctx context.Context) ([]ModelInfo, error)
}

ModelProvider 是模型提供商的核心接口(最大公约数).

已有实现:

  • pkg/providers/anthropic - Anthropic 原生
  • pkg/providers/openai - OpenAI 原生
  • pkg/providers/openrouter - OpenRouter 聚合(OpenAI 兼容)
  • pkg/providers/minimax - MiniMax 原生
  • pkg/providers/gemini - Google Gemini 原生(AI Studio + Vertex AI 双模式)[待 probe 验证]
  • pkg/providers/ollama - Ollama 本地部署(OpenAI 兼容)
  • pkg/providers/lmstudio - LM Studio 本地部署(OpenAI 兼容)

Shape: push (stream) from engine's perspective. Engine calls Stream(ctx, req) and ranges the returned channel; the provider fans out upstream API chunks as flyto.Event sequence. Consumers wanting to plug a new model backend implement this interface.

形态: 引擎视角 push (流). 引擎调 Stream(ctx, req), range 返回的 channel; provider 将上游 API chunks 分发为 flyto.Event 序列. 要接新模型后端的 消费者实现此接口.

type PermissionLearnEvent

type PermissionLearnEvent struct {
	Rules []PermissionLearnRule
}

PermissionLearnEvent 建议添加永久权限规则(用户反复批准同类操作时触发).

func (*PermissionLearnEvent) EventType

func (e *PermissionLearnEvent) EventType() string

type PermissionLearnRule

type PermissionLearnRule struct {
	RuleString  string
	Description string
}

PermissionLearnRule 是一条建议的权限规则.

type PermissionRequestEvent

type PermissionRequestEvent struct {
	ID       string
	ToolName string
	Input    map[string]any
	Message  string
}

PermissionRequestEvent 表示工具需要用户批准. 消费层收到此事件后展示权限 UI,通过 Session.ResolvePermission() 回复.

func (*PermissionRequestEvent) EventType

func (e *PermissionRequestEvent) EventType() string

type Request

type Request struct {
	Model     string    // 模型 ID,如 "claude-sonnet-4-6"
	Messages  []Message // 对话历史(含工具调用/结果)
	System    string    // 系统提示(空 = 不使用)
	MaxTokens int       // 最大输出 token 数
	Tools     []Tool    // 可用工具列表(空 = 不使用工具)

	// ResponseFormat 约束输出格式(nil = 文本,不限制).
	// 仅 "json_object" 类型在所有主流 provider 中通用.
	// Provider 特有的 json_schema + 额外 header 通过 provider Config 配置.
	ResponseFormat *ResponseFormat

	// NeedsThinking: 消费者声明需要扩展思考(thinking 是有感知的,消费者主动声明).
	// 引擎无法判断业务复杂度,因此 thinking 必须由消费者显式开启,而非自动决策.
	// Provider 自动注入 ThinkingBudget 或 reasoning 参数.
	// 若模型不支持 thinking,silently skip(不报错).
	// 对比 Config 级别的 ThinkingBudget:Config 是全局开关,NeedsThinking 是 per-request 开关.
	NeedsThinking bool

	// FastMode 启用快速模式(影响 max_tokens 默认值 + provider 专有 beta header).
	// 仅部分 provider 支持,不支持的 provider 应忽略此字段.
	FastMode bool

	// Effort 努力级别("low"/"medium"/"high"),空字符串表示不设置.
	// 仅部分 provider 支持,不支持的 provider 应忽略此字段.
	Effort string

	// Temperature controls per-request sampling temperature. Nil = use the
	// provider/model default (do not transmit a temperature field on the
	// wire). Non-nil = use this value; each provider passes it through to
	// its native API and lets the upstream service validate (Anthropic
	// 0-1, OpenAI/Gemini/Ollama 0-2, MiniMax (0,1], OpenRouter per-model,
	// LMStudio backend-defined). Out-of-range values surface as the
	// provider's natural 4xx ErrorEvent rather than client-side clamp --
	// this matches industry consensus (Vercel AI SDK / LangChain /
	// instructor passthrough; only litellm tries drop_params and is
	// empirically buggy). One in-Request deterministic conflict gets
	// pre-handled: Anthropic + NeedsThinking + Temperature != 1.0 →
	// silent override to 1.0 + WarningEvent (server otherwise 400s).
	//
	// Temperature 控制本次请求的采样温度. nil = 用 provider/模型默认
	// (wire 上不传 temperature 字段); 非 nil = 用该值, 每个 provider 直接
	// 透传到原生 API 由上游服务校验 (Anthropic 0-1, OpenAI/Gemini/Ollama
	// 0-2, MiniMax (0,1], OpenRouter 按 model 各异, LMStudio 由 backend
	// 决定). 越界一律不在 flyto 层 clamp, 由上游 4xx 自然冒泡为
	// ErrorEvent -- 与业界共识一致 (Vercel AI SDK / LangChain /
	// instructor 全 passthrough; 只有 litellm 尝试 drop_params 且 bug
	// 频发). 仅一个 wire 时已知冲突预拦: Anthropic + NeedsThinking +
	// Temperature != 1.0 → silent override 1.0 + WarningEvent (否则
	// 服务端 400).
	//
	// CLEVER: nullable *float64 而非 float64 + sentinel -- Go 零值 0
	// 在采样语义里是合法的 deterministic, 不能复用作 "未设". helper
	// flyto.Float() 简化指针字段构造.
	Temperature *float64

	// TopP controls nucleus sampling cutoff (1.0 = disabled). Nil = use
	// the provider/model default. Non-nil = use this value; same
	// passthrough policy as Temperature -- upstream validates, out-of-range
	// surfaces as 4xx ErrorEvent. One pre-handled conflict: Anthropic +
	// NeedsThinking restricts top_p to [0.95, 1.0]; values below 0.95
	// silent-override to 1.0 + WarningEvent.
	//
	// TopP 控制 nucleus 采样阈值 (1.0 = 不启用). nil = 用 provider/
	// 模型默认; 非 nil = 用该值. 与 Temperature 同 passthrough 策略,
	// 上游校验, 越界 4xx 自然冒泡. 仅一个预拦特例: Anthropic +
	// NeedsThinking 限制 top_p 在 [0.95, 1.0], 低于 0.95 silent override
	// 1.0 + WarningEvent.
	TopP *float64

	// SystemBlocks 分段系统提示词(支持 per-block 缓存策略).
	// 如果非 nil 且非空,Provider 应优先使用此字段而非 System string.
	// 每个 block 有 Text 和 CacheScope 字段.
	SystemBlocks []SystemBlock

	// Capabilities 是本次请求关联的模型能力快照(由 engine 在调用 provider 之前注入).
	//
	// 升华改进(ELEVATED): data-driven-capabilities RFC 的核心机制--
	// engine 每次调用 provider.Stream 之前从 ModelRegistry 取出当前模型的 ModelInfo,
	// 塞进这个字段.Provider 优先读取这里的字段(registry 数据驱动),
	// 缺失时降级到 provider 包内的硬编码常量(向后兼容兜底).
	//
	// 设计要点:
	//  - nil = engine 未注入(单元测试 / mock 场景 / model 不在 registry 中),
	//    provider 必须降级到包内常量,行为完全等同于现状(零回归)
	//  - 非 nil = engine 已注入快照,provider 优先使用此字段
	//  - 这是只读快照--provider 不应修改它的字段,registry 后续修改也不影响
	//    进行中的请求(值的指针,但 ModelInfo 字段都是值类型)
	//
	// 替代方案:<provider 持有 ModelRegistry 引用> - 否决:
	// 会让 provider 包 import config 包,引入依赖循环风险;
	// 而 Request 字段注入让 provider 完全无感知 registry 的存在.
	// 替代方案:<让 engine 全部预先解析完成后只传 maxTools/supportsThinking 等扁平字段> - 否决:
	// flyto.Request 字段会膨胀,且每加一个能力都要改 Request schema.
	Capabilities *ModelInfo
}

Request 是发给 ModelProvider 的请求(最大公约数字段).

升华改进(ELEVATED): 只包含所有 provider 通用的字段. provider 特有参数(Thinking budget,cache breakpoints,beta flags 等) 在 provider 工厂的 Config 里配置,不污染公共 Request 类型.

Auto-caching 行为:当 system prompt 超过模型阈值时,引擎自动注入 cache_control, 消费者无需声明.阈值来自 ModelInfo.CachingMinTokens(官方文档 + probe 实测).

type ResponseFormat

type ResponseFormat struct {
	// Type 是格式类型:
	//   "json_object" - 约束输出为合法 JSON 对象(所有主流 provider 支持)
	//   "json_schema" - 按指定 schema 约束(OpenAI/OpenRouter/MiniMax 原生支持;
	//                    不支持的 provider 降级为 fence strip,不传 schema)
	Type string

	// JSONSchema 是 json_schema 类型的 schema 定义(json_schema 时必填,其他类型忽略)
	JSONSchema json.RawMessage `json:"json_schema,omitempty"`
}

ResponseFormat 控制模型的输出格式约束(跨 provider 最大公约数).

精妙之处(CLEVER): 只放真正跨 provider 通用的格式-- "json_object" 几乎所有现代 provider 都原生支持(OpenAI/OpenRouter/MiniMax/Gemini). 部分 provider 的结构化输出需要特殊 header + json_schema,属于 provider 特有能力, 通过 provider Config 配置,不出现在此通用类型中. 替代方案:<把 json_schema + 特殊 flag 都塞进来> - 否决: 绑定了特定 provider 实现细节,其他 provider 无法使用这些字段, 造成"通用"接口实际上只有一个 provider 能完整支持.

type Role

type Role string

Role 是消息发送方角色.

const (
	RoleUser      Role = "user"
	RoleAssistant Role = "assistant"
)

type RunOption

type RunOption interface {
	// contains filtered or unexported methods
}

RunOption 是单次 Run 调用的选项(不透明类型).

精妙之处(CLEVER): interface 而非 func(*runConfig)-- 外部包无法实现此接口(unexported method),只能使用引擎提供的 WithXxx 工厂函数. 这样引擎能在不破坏 API 的前提下修改内部 runConfig 结构.

type SessionInfoEvent

type SessionInfoEvent struct {
	SessionID    string
	Title        string
	TurnCount    int
	InputTokens  int
	OutputTokens int
	CostUSD      float64
}

SessionInfoEvent 通知消费层更新会话统计(token 用量,花费等).

func (*SessionInfoEvent) EventType

func (e *SessionInfoEvent) EventType() string

type SlashCommandEvent

type SlashCommandEvent struct {
	Name string
	Args string
}

SlashCommandEvent 表示检测到斜杠命令(引擎不处理,通知消费层).

func (*SlashCommandEvent) EventType

func (e *SlashCommandEvent) EventType() string

type SystemBlock

type SystemBlock struct {
	Text       string // 文本内容
	CacheScope string // "", "session", "global" - 非空表示需要缓存
}

SystemBlock 是分段系统提示词的一块.

type TeammateMessageReceivedEvent

type TeammateMessageReceivedEvent struct {
	From        string // 发送方 agent 名称
	To          string // 接收方 agent 名称 (自己)
	Type        string // Message.Type (task_assignment / idle_notification 等)
	MessageID   string // Message.ID
	PayloadSize int    // payload 字节数
}

TeammateMessageReceivedEvent 表示 Agent Teams 通讯中收到来自同伴的消息.

升华改进(ELEVATED): 复用 flyto.EventObserver 统一事件总线, 不再新建 hook 系统. 对标 Anthropic Claude Code Agent Teams v2.1.32 的 TeammateIdle/TaskCreated/TaskCompleted 三个独立 shell hook -- 我们用单一事件总线 (类型字段区分) 覆盖其超集:

  • 可编程性: Observer 实现任意 Go 逻辑 (调 DB / 发 Slack / 更新 UI), 不限于 shell
  • 跨进程: SaaS 场景订阅 Event 的不必是本机, shell hook 做不到
  • 结构化: Data 字段是 struct, 解析无歧义; shell 拿到字符串参数

替代方案: <仿 Anthropic 三个独立 shell hook> - 否决: L1326 刚把 hooks/context/evolve 三包 Observer 收敛到 flyto.EventObserver, 再拆回去是架构回退.

func (*TeammateMessageReceivedEvent) EventType

func (e *TeammateMessageReceivedEvent) EventType() string

type TextDeltaEvent

type TextDeltaEvent struct {
	Text string
}

TextDeltaEvent 是流式文本增量(最频繁的事件).

func (*TextDeltaEvent) EventType

func (e *TextDeltaEvent) EventType() string

type TextEvent

type TextEvent struct {
	Text string
}

TextEvent 是完整的文本块(一个 content block 结束时发出).

func (*TextEvent) EventType

func (e *TextEvent) EventType() string

type ThinkingDeltaEvent

type ThinkingDeltaEvent struct {
	Text string
}

ThinkingDeltaEvent 是流式思考增量.

func (*ThinkingDeltaEvent) EventType

func (e *ThinkingDeltaEvent) EventType() string

type ThinkingEvent

type ThinkingEvent struct {
	Text string
}

ThinkingEvent 是完整的思考块.

func (*ThinkingEvent) EventType

func (e *ThinkingEvent) EventType() string

type Tool

type Tool struct {
	Name        string          // 工具名称,如 "Bash"
	Description string          // 工具描述(给模型看的自然语言说明)
	InputSchema json.RawMessage // 输入参数的 JSON Schema(object 类型)
}

Tool 是工具定义(JSON Schema 格式的输入规格).

type ToolProgressEvent

type ToolProgressEvent struct {
	ID       string
	ToolName string
	Progress float64 // 0.0-1.0
	Detail   string
}

ToolProgressEvent 表示工具执行中的进度更新(长时间运行的工具).

func (*ToolProgressEvent) EventType

func (e *ToolProgressEvent) EventType() string

type ToolResultEvent

type ToolResultEvent struct {
	ID       string // 对应 ToolUseEvent.ID
	ToolName string
	Output   string
	IsError  bool

	// Truncated marks that Output is a short summary and the full tool
	// result has been persisted to StoredPath. Consumer UIs use this to
	// render "result truncated -- click to open full content".
	//
	// Truncated 标记 Output 是短摘要, 完整结果已经落盘到 StoredPath. 消费层
	// UI 据此渲染 "结果已截断 -- 点击打开完整内容".
	Truncated bool

	// StoredPath is where the full tool result was persisted (by the
	// orchestrator's pluggable ResultProcessor). Empty when Truncated is
	// false. Path shape is consumer-layer defined (local filesystem path,
	// sandbox-internal path, object-storage key, ...); callers parse per
	// the ResultProcessor they installed.
	//
	// SECURITY: the path may carry sandbox-internal structure or caller-
	// specific details. Downstream observers / SSE bridges MUST treat it
	// as untrusted data (e.g. avoid logging to shared destinations without
	// review).
	//
	// StoredPath 是完整工具结果的持久化位置 (由 orchestrator 的可插拔
	// ResultProcessor 决定). Truncated=false 时为空串. Path shape 由消费层
	// 定义 (本地文件路径 / sandbox 内部路径 / 对象存储 key / ...); 调用方按
	// 自己装的 ResultProcessor 解析.
	//
	// 安全: path 可能携带 sandbox 内部结构或调用方特定细节. 下游 observer /
	// SSE bridge 必须把它当作不可信数据 (例如未审查前不写入共享目的地).
	StoredPath string
}

ToolResultEvent 表示工具执行完成.

Truncated / StoredPath surface the orchestrator's large-result handling to consumers: when a tool emits an oversized output, the orchestrator replaces Output with a short summary and persists the full content via the consumer-installed ResultProcessor. Without these fields on the event, UIs / SSE bridges see only the summary and cannot render a "click to open full content" affordance or audit the full result.

Truncated / StoredPath 把 orchestrator 的大结果处理透传给消费层: 工具产 生超大输出时, orchestrator 用短摘要替换 Output 并经消费层装的 ResultProcessor 把完整内容落盘. 事件不带这两个字段时, UI / SSE bridge 只看得到摘要, 无法渲染 "点击打开完整内容" 入口, 也无法审计完整结果.

func (*ToolResultEvent) EventType

func (e *ToolResultEvent) EventType() string

type ToolSummaryEvent

type ToolSummaryEvent struct {
	ID       string
	ToolName string
	Summary  string // 5-20 字
}

ToolSummaryEvent 表示工具执行摘要已异步生成(用于 UI 展示).

func (*ToolSummaryEvent) EventType

func (e *ToolSummaryEvent) EventType() string

type ToolUseEvent

type ToolUseEvent struct {
	ID       string         // 工具调用 ID
	ToolName string         // 工具名称
	Input    map[string]any // 工具输入参数
}

ToolUseEvent 表示模型请求调用工具.

func (*ToolUseEvent) EventType

func (e *ToolUseEvent) EventType() string

type TraceObserver

type TraceObserver interface {
	SpanStart(name string, tags map[string]string) string // 返回 span ID
	SpanEnd(spanID string, err error)
}

TraceObserver 调用链接口(可选,通过 type assertion 检测).

Shape: push (subscribe). Engine emits span-start / span-end events for distributed tracing consumers (Jaeger / Zipkin / Tempo).

形态: 订阅 (push). 引擎发 span-start / span-end 事件给分布式追踪消费者 (Jaeger / Zipkin / Tempo).

type TurnEndEvent

type TurnEndEvent struct {
	TurnNumber   int
	InputTokens  int
	OutputTokens int
	CostUSD      float64
	MaxTokens    int
}

TurnEndEvent 表示对话轮次结束(含本轮 token 用量).

func (*TurnEndEvent) EventType

func (e *TurnEndEvent) EventType() string

type TurnStartEvent

type TurnStartEvent struct {
	TurnNumber          int
	Model               string
	ContextWindowTokens int // 由 provider.Models() 提供,消费层无需硬编码
}

TurnStartEvent 表示新对话轮次开始.

func (*TurnStartEvent) EventType

func (e *TurnStartEvent) EventType() string

type UsageEvent

type UsageEvent struct {
	InputTokens         int
	OutputTokens        int
	CacheReadTokens     int    // prompt caching 命中的 token 数(仅支持缓存的 provider)
	CacheCreationTokens int    // prompt caching 写入的 token 数(仅支持缓存的 provider)
	StopReason          string // "end_turn"/"max_tokens"/"tool_use"/"stop_sequence"/"length"
}

UsageEvent 由 ModelProvider 推送,携带本轮原始 token 用量.

精妙之处(CLEVER): provider 只汇报原始数字,不计算费用-- 费用计算需要模型定价表,而定价表属于引擎层(通过 Models() 获取). 分层清晰:provider 知道 token 数,引擎知道单价,两者在引擎层合并. 如果 provider 自己计费,定价表就得维护两份,数据来源单一原则被破坏.

消费者不应依赖此事件--引擎会将其转换为 TurnEndEvent. 直接使用 provider(不经过引擎)时才需要读取此事件.

func (*UsageEvent) EventType

func (e *UsageEvent) EventType() string

type WarningEvent

type WarningEvent struct {
	Code    string
	Message string
	Detail  string
}

WarningEvent 表示非致命警告(token 接近上限,花费接近预算等).

func (*WarningEvent) EventType

func (e *WarningEvent) EventType() string

Jump to

Keyboard shortcuts

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