Documentation
¶
Overview ¶
错误分类器 -- Provider Adapter 模式实现.
升华改进(ELEVATED): 早期方案把 Anthropic 特定的 header 解析,消息匹配硬编码在通用错误处理中, 导致无法支持其他供应商(OpenAI / Bedrock / 本地模型).
本设计:ErrorClassifier 接口定义分类契约,每个供应商实现自己的 Classifier. 引擎只依赖 ErrorCategory 枚举,不依赖任何供应商特定的字符串.
替代方案:<原方案所有供应商的逻辑混在一个 500 行 if-else 中>
API 客户端 -- 封装与 Messages API 的 HTTP 通信(纯 transport 层).
这是引擎与 Anthropic Messages API 之间的 HTTP 传输桥梁. 负责构建 HTTP 请求,鉴权,发送请求,处理非 2xx 错误. SSE 协议解析已迁移至 internal/wire/anthropic.go.
升华改进(ELEVATED): 早期方案将 HTTP transport + SSE 解析混杂在本文件中, 导致单元测试需要 mock HTTP 客户端.现在 transport 和解析分离:
- client.go: 纯 HTTP transport,职责是"把字节发出去,把响应体拿回来"
- wire/anthropic.go: 纯 SSE 解析,职责是"把字节流变成 flyto.Event"
好处:wire 包可以独立测试(传入 strings.NewReader 即可).
历史包袱(LEGACY): StreamEvent / StreamEventType / UsageInfo 类型仍保留-- engine.go / subagent.go / classifier_ai.go 等尚未迁移到 flyto.Event. 待 Phase 5(engine.go 全面迁移)完成后,这些类型将随之删除.
连接诊断系统 -- SSL 错误码目录 + 用户可操作提示.
精妙之处(CLEVER): 企业用户背后往往有 TLS 拦截代理(Zscaler,Palo Alto 等), 拿到 "UNABLE_TO_VERIFY_LEAF_SIGNATURE" 这种 OpenSSL 错误码根本不知道怎么办. 把 19 个高频 SSL 错误码映射为可操作的诊断提示,一条消息省一轮技术支持.
升华改进(ELEVATED): 不只 SSL--扩展为通用的连接诊断, 涵盖 DNS,超时,连接拒绝等所有网络层错误. 仓储场景同样需要:PLC 连接超时,MQTT broker 不可达,OPC-UA 证书过期.
替代方案:<原方案只处理 SSL,其他连接错误返回 "Connection error">
API 错误分类系统 -- 一次分类,多处消费.
升华改进(ELEVATED): 早期方案有三套平行的 if-else 链(classifyAPIError / getAssistantMessageFromError / categorizeRetryableAPIError)各自独立做字符串匹配,改一个忘另一个就是 bug. 早期方案注释甚至承认 "Patterns MUST stay in sync"--需要注释来保证同步说明结构就是错的.
本设计:解析 HTTP 响应时一次性创建结构化 APIError(含 Category + RetryInfo + TokenGap + Hint), 所有消费者(分析,用户消息,重试决策)直接读字段,不再各自做 string matching.
替代方案:<原方案三套独立分类器 + 字符串匹配>
API 预连接 -- TCP+TLS 握手预热 + HTTP Transport 优化配置.
精妙之处(CLEVER): 首次 API 调用前发一个 fire-and-forget HEAD 请求, TCP+TLS 握手(100-400ms)与初始化逻辑并行完成, 正式请求直接复用 keep-alive 连接池中的热连接.
升华改进(ELEVATED): Go 的 http.Transport 是统一抽象-- 不管有没有代理/mTLS,都通过同一个 Transport 走,连接池自然共享. 不需要像早期方案那样检查 6 个环境变量决定是否跳过预连接.
替代方案:<原方案 Node.js 全局 fetch + SDK 自定义 dispatcher 是两个池, 需要检查 proxy/mTLS/Unix socket 场景跳过预连接>
SSE 流状态守卫 -- 边界情况检测 + 空闲看门狗 + 停顿诊断.
精妙之处(CLEVER): parseAnthropicSSE 是裸解析器(收到什么推什么),StreamGuard 叠加 状态追踪和边界防御.两层职责清晰--解析器负责"解析正确", StreamGuard 负责"检测异常".
覆盖的生产边界情况:
- 空响应:200 OK 但无 SSE 事件(代理故障,返回 HTML/空体)
- 部分流:有内容事件但未收到 UsageEvent(网络中断)
- 空闲挂起:流中间长时间无数据(代理/防火墙静默断开)
- 停顿:两次事件间隔过长(网络抖动诊断)
- Scanner 错误:行过长或 I/O 错误
升华改进(ELEVATED): 从 StreamEvent(Anthropic 专有中间类型)改为 flyto.Event-- StreamGuard 现在对所有 provider 通用,不绑定 Anthropic 语义. 替代方案:<每个 provider 实现自己的流守卫> - 否决:重复代码, 且 Gemini / OpenAI 的可靠性检测逻辑与 Anthropic 完全相同.
Index ¶
- Constants
- func IsSSLErrorCode(code string) bool
- func NewTransport(cfg *TransportConfig) *http.Transport
- func ParseAPIErrorBody(body []byte) (errorType, message string)
- func ParseRetryAfter(value string) time.Duration
- func ParseShouldRetry(value string) *bool
- func ParseTokenGap(message string) int
- func SanitizeErrorHTML(message string) string
- type APIError
- func (e *APIError) AnalyticsTag() string
- func (e *APIError) Category() string
- func (e *APIError) Error() string
- func (e *APIError) Headers() http.Header
- func (e *APIError) IsRetryable() bool
- func (e *APIError) Message() string
- func (e *APIError) RetryDelay() time.Duration
- func (e *APIError) RetryInfo() *RetryInfo
- func (e *APIError) Unwrap() error
- type AnthropicClassifier
- type BetaFeatures
- type CacheControl
- type Client
- type ClientOption
- func WithAPIVersion(version string) ClientOption
- func WithBearerAuth() ClientOption
- func WithClassifier(c ErrorClassifier) ClientOption
- func WithHTTPClient(hc *http.Client) ClientOption
- func WithMessagePath(path string) ClientOption
- func WithOverflowHandler(h *retry.ContextOverflowHandler) ClientOption
- func WithResponseHeaderTimeout(d time.Duration) ClientOption
- func WithRetryPolicy(p retry.RetryPolicy) ClientOption
- func WithStreamGuard(cfg *StreamGuardConfig) ClientOption
- func WithTransport(t *http.Transport) ClientOption
- type CompositeClassifier
- type CompositeHinter
- type ContentBlock
- type DNSCache
- type DefaultClassifier
- type DefaultHinter
- type DiagnosticHinter
- type ErrorCategory
- type ErrorClassifier
- type ImageSource
- type MessageRequest
- type Preconnector
- type RequestMessage
- type ResponseFormat
- type RetryInfo
- type StreamEvent
- type StreamEventType
- type StreamGuard
- type StreamGuardConfig
- type StreamStats
- type SystemContentBlock
- type ThinkingConfig
- type ToolDef
- type TransportConfig
- type UsageInfo
Constants ¶
const DefaultResponseHeaderTimeout = 60 * time.Second
DefaultResponseHeaderTimeout is the safety net applied to the internal default http.Client when no WithResponseHeaderTimeout option is supplied. Provider packages (anthropic, openai, ...) override this explicitly via their own Config.Timeout field; this constant only matters for direct transport.NewClient callers (internal tests, experimentation).
精妙之处(CLEVER): We target http.Transport.ResponseHeaderTimeout, NOT http.Client.Timeout. The latter caps TOTAL request duration including the streaming body read - which silently kills long SSE responses. The former only caps "time from request send to first response byte", leaving long streams alive. Setting http.Client.Timeout=60s on a streaming LLM provider is a classic way to break prod in a subtle, hard-to-debug manner.
反向思维 (2026-04-13): Should this be mutable (var) for global override? Rejected - encourages process-global tuning which violates Provider 必填 principle (see memory project_architecture_decisions.md). Per-instance tuning belongs in provider Config.Timeout.
Variables ¶
This section is empty.
Functions ¶
func IsSSLErrorCode ¶
IsSSLErrorCode 检查给定的错误码或消息片段是否为 SSL/TLS 相关.
func NewTransport ¶
func NewTransport(cfg *TransportConfig) *http.Transport
NewTransport 根据配置创建 http.Transport.
精妙之处(CLEVER): 返回的 Transport 应被 Client 和 Preconnector 共享-- 同一个 Transport = 同一个连接池 = 预连接的热连接被正式请求复用.
func ParseAPIErrorBody ¶
ParseAPIErrorBody 从 API JSON 响应体中提取错误类型和消息.
API 错误响应格式:
{"type":"error","error":{"type":"invalid_request_error","message":"..."}}
精妙之处(CLEVER): 不做完整 JSON 反序列化--只提取两个字段, 避免为错误路径引入复杂的类型定义.手动 JSON 解析虽然"丑",但错误路径 需要最大的容错能力,半格式化的 JSON 也要尽量提取信息.
func ParseRetryAfter ¶
ParseRetryAfter 从 retry-after header 值解析等待时间. 支持秒数格式("30").
func ParseShouldRetry ¶
ParseShouldRetry 从 x-should-retry header 解析服务端重试建议. 返回 nil 表示服务端未表态.
func ParseTokenGap ¶
ParseTokenGap 从错误消息中提取 prompt_too_long 的 token 溢出量. 返回 0 表示无法解析.
func SanitizeErrorHTML ¶
SanitizeErrorHTML 清理可能包含 HTML 的错误消息.
精妙之处(CLEVER): CloudFlare,AWS ALB 等网关在故障时返回 HTML 错误页(而非 JSON). 这些 HTML 如果原样传给 LLM 会浪费几千 token.提取 <title> 标签文本作为简洁消息. 如果没有 HTML 则原样返回.
Types ¶
type APIError ¶
type APIError struct {
// ErrCategory 是错误的语义分类
ErrCategory ErrorCategory
// StatusCode 是 HTTP 状态码(连接错误时为 0)
StatusCode int
// Msg 是原始错误消息(可能来自 API JSON body 或网络错误)
Msg string
// Hint 是用户可操作的诊断提示(如 "检查企业代理的 SSL 证书")
Hint string
// Retry 是重试建议(nil 表示使用 ErrCategory 默认行为)
Retry *RetryInfo
// TokenGap 是 prompt_too_long 时溢出的 token 数(用于响应式压缩跳步).
// 精妙之处(CLEVER): 从 "137500 tokens > 135000 maximum" 中提取差值 2500,
// 让压缩模块一步跳过 2500 token 的消息组,而非逐个尝试.
// 仅在 ErrCategory == ErrPromptTooLong 时有意义.
TokenGap int
// RespHeaders 是保留的响应头(用于下游消费者提取供应商特定信息)
RespHeaders http.Header
// Body 是原始响应体(用于调试和日志)
Body string
// Cause 是底层错误(网络错误时保留原始 error 链)
Cause error
}
APIError 是结构化的 API 错误,实现 error 接口.
升华改进(ELEVATED): 所有错误信息在创建时一次性解析填充-- Category(分类),RetryInfo(重试),TokenGap(压缩跳步),Hint(用户提示). 消费者只读字段,不做二次解析.
替代方案:<原方案每个消费者各自 instanceof + string includes 做分类>
func (*APIError) AnalyticsTag ¶
AnalyticsTag 返回用于分析系统的标准化标签字符串.
func (*APIError) Error ¶
Error implements the error interface. The output line includes every structured field populated at construction time -- Hint, TokenGap, and a truncated Body preview. Previous revisions read only StatusCode / ErrCategory / Msg; the other three were filled by the classifier but silently dropped, so each log line showed half the diagnostic that the struct carried. Body is truncated to 256 bytes to keep lines log-friendly; the full body stays on the APIError and can be read directly by debug tooling when needed.
Previous implementation retained for reference:
if e.StatusCode > 0 {
return fmt.Sprintf("api: HTTP %d [%s]: %s", e.StatusCode, e.ErrCategory, e.Msg)
}
return fmt.Sprintf("api: [%s]: %s", e.ErrCategory, e.Msg)
Error 实现 error 接口. 输出行包含构造时填充的所有结构字段 -- Hint / TokenGap / Body 截断预览. 旧版本只读 StatusCode / ErrCategory / Msg, 其他三个字段由 classifier 填了但被静默丢弃, 每条日志只能看到结构体 携带一半的诊断信息. Body 截到 256 字节保持日志可读; 完整 body 仍挂 在 APIError 上, debug 工具需要时直接读字段.
原实现保留供参照, 见上方 godoc.
func (*APIError) IsRetryable ¶
IsRetryable 返回是否建议重试. 优先使用 Retry 的精确判断,fallback 到 ErrCategory 默认行为.
type AnthropicClassifier ¶
type AnthropicClassifier struct {
// Hinter 提供连接诊断提示(可选)
Hinter DiagnosticHinter
}
AnthropicClassifier 在 DefaultClassifier 基础上增加 Anthropic 特定的分类逻辑:
- 解析 anthropic-ratelimit-* header
- 检测 overloaded_error(SDK 有时丢失 529 状态码)
- 解析 x-should-retry header
- SSL 证书错误诊断
精妙之处(CLEVER): 先调 DefaultClassifier 做基础分类,再用 Anthropic 特定信息增强. 这样即使 Anthropic header 格式变了,基础分类仍然正确(降级而非崩溃).
type BetaFeatures ¶
type BetaFeatures struct {
// PromptCaching 启用 prompt caching
PromptCaching bool
// PromptCachingScope 缓存范围 ("global" 或 "org")
PromptCachingScope string
// ExtendedThinking 启用 extended thinking
ExtendedThinking bool
// FastMode 启用快速模式
FastMode bool
// Effort 努力级别 ("low"/"medium"/"high")
Effort string
// ContextManagement 启用上下文管理
ContextManagement bool
// StructuredOutput 启用结构化输出
StructuredOutput bool
// TaskBudgets 启用任务预算
TaskBudgets bool
}
BetaFeatures 控制要启用的 Beta 功能. 各功能对应特定的 anthropic-beta header 值.
type CacheControl ¶
type CacheControl struct {
Type string `json:"type"` // "ephemeral"
}
CacheControl 是缓存控制配置.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client 是 Messages API 的客户端.
func NewClient ¶
func NewClient(apiKey, baseURL string, opts ...ClientOption) *Client
NewClient 创建一个新的 API 客户端. 默认使用 DefaultClassifier + DefaultHinter,无重试策略. 调用方必须传入 baseURL(不再默认指向任何供应商). 供应商特有配置(messagePath,apiVersion,retryPolicy)通过 ClientOption 注入.
func (*Client) CreateMessageStream ¶
func (c *Client) CreateMessageStream(ctx context.Context, req *MessageRequest) (<-chan flyto.Event, error)
CreateMessageStream 发起流式 Messages API 调用,返回 flyto.Event channel.
升华改进(ELEVATED): 早期方案返回 <-chan StreamEvent(Anthropic 专有中间类型), 消费者(provider 层)还需要二次转换为 flyto.Event. 现在直接返回 flyto.Event,消费者零转换成本,且 StreamEvent 类型从公共 API 消失. 替代方案:<保留 StreamEvent 减少改动> - 否决:这正是架构不一致的根源.
func (*Client) HTTPClient ¶
HTTPClient 返回底层 *http.Client,用于测试,introspection 或需要直接发请求的场景. 升华改进(ELEVATED): 暴露这个 getter 是为了让 provider 包的单元测试能断言超时配置 是否正确传递 (通过 .Transport.(*http.Transport).ResponseHeaderTimeout). 同时也为未来可能的 introspection 场景 (比如 metrics observer 读取 transport 配置) 预留接口.
type ClientOption ¶
type ClientOption func(*Client)
ClientOption 是 Client 的配置选项.
func WithAPIVersion ¶
func WithAPIVersion(version string) ClientOption
WithAPIVersion 设置 API 版本 header 值(如 "2023-06-01"). 空字符串表示不发送 "anthropic-version" header.
func WithBearerAuth ¶
func WithBearerAuth() ClientOption
WithBearerAuth 切换为 "Authorization: Bearer <key>" 鉴权格式. 适用于使用 Bearer Token 的兼容端点.
func WithClassifier ¶
func WithClassifier(c ErrorClassifier) ClientOption
WithClassifier 设置自定义错误分类器.
func WithHTTPClient ¶
func WithHTTPClient(hc *http.Client) ClientOption
WithHTTPClient 设置自定义 HTTP 客户端(用于代理,超时等配置).
注意: WithHTTPClient 会替换整个 httpClient,包括 Transport.如果同时使用 WithResponseHeaderTimeout,options 的调用顺序决定最终结果:
- WithHTTPClient 在后: 最终使用消费者的 client, WithResponseHeaderTimeout 被覆盖
- WithResponseHeaderTimeout 在后: 会尝试修改消费者的 transport (如果是 *http.Transport)
推荐: provider.New() 应二选一,不混用.消费者给了 HTTPClient 就完全交出超时控制权.
func WithMessagePath ¶
func WithMessagePath(path string) ClientOption
WithMessagePath 设置 API 消息路径(如 "/v1/messages"). 空字符串表示 baseURL 已包含完整路径,不需要拼接.
func WithOverflowHandler ¶
func WithOverflowHandler(h *retry.ContextOverflowHandler) ClientOption
WithOverflowHandler 设置 max_tokens 溢出修正器.
func WithResponseHeaderTimeout ¶
func WithResponseHeaderTimeout(d time.Duration) ClientOption
WithResponseHeaderTimeout 覆盖默认 http.Client 的 ResponseHeaderTimeout.
这是 "从请求发出到收到响应首字节" 的时间上限,**不影响** SSE 流式响应的后续 body 读取. LLM provider 的正确超时语义: 捕捉服务端不响应的死等,放行正常的长流式输出.
精妙之处(CLEVER): 不要误用 http.Client.Timeout (它会砍死 SSE 流). 详见 DefaultResponseHeaderTimeout 注释的反向思维段.
安全兜底: 如果 httpClient.Transport 不是 *http.Transport (消费者用了自定义 RoundTripper 或先调用了 WithHTTPClient 替换了整个 client),此 option silent no-op 而不是 panic. provider.New() 约定二选一使用,此 no-op 只在 transport 包被其他路径滥用时触发.
func WithRetryPolicy ¶
func WithRetryPolicy(p retry.RetryPolicy) ClientOption
WithRetryPolicy 设置自定义重试策略. nil 表示不重试(首次失败即返回).
func WithStreamGuard ¶
func WithStreamGuard(cfg *StreamGuardConfig) ClientOption
WithStreamGuard 设置自定义 SSE 流守卫配置.
func WithTransport ¶
func WithTransport(t *http.Transport) ClientOption
WithTransport 设置共享 Transport(用于预连接 + 正式请求共享连接池).
type CompositeClassifier ¶
type CompositeClassifier struct {
// contains filtered or unexported fields
}
CompositeClassifier 按优先级组合多个分类器. 第一个返回非 ErrUnknown 分类的 Classifier 胜出.
升华改进(ELEVATED): 支持运行时动态添加分类器-- 例如仓储场景可以 Add 一个识别 PLC 连接错误的分类器, 而不需要修改核心代码.
func NewCompositeClassifier ¶
func NewCompositeClassifier(classifiers ...ErrorClassifier) *CompositeClassifier
NewCompositeClassifier 创建组合分类器.
func (*CompositeClassifier) Add ¶
func (c *CompositeClassifier) Add(classifier ErrorClassifier)
Add 添加分类器(追加到末尾,优先级最低).
type CompositeHinter ¶
type CompositeHinter struct {
// contains filtered or unexported fields
}
CompositeHinter 组合多个 Hinter,第一个返回非空提示的胜出.
func NewCompositeHinter ¶
func NewCompositeHinter(hinters ...DiagnosticHinter) *CompositeHinter
NewCompositeHinter 创建组合提示器.
type ContentBlock ¶
type ContentBlock struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Input map[string]any `json:"input,omitempty"`
ToolUseID string `json:"tool_use_id,omitempty"`
Content string `json:"content,omitempty"`
IsError bool `json:"is_error,omitempty"`
Signature string `json:"signature,omitempty"` // thinking block 的签名(Anthropic API 要求)
// Source 携带 type=="image" 块的图片数据, 对齐 Anthropic image block
// source spec (base64 内联或 url). 非 image 块留 nil (omitempty).
//
// Source carries image data for type=="image" blocks, matching
// Anthropic's image block source spec (base64 inline or url). Nil
// for non-image blocks (omitempty on the wire).
Source *ImageSource `json:"source,omitempty"`
// ContentItems carries array-form tool_result content (text + image
// mixed). MarshalJSON picks between Content (string) and ContentItems
// (array) for the "content" wire field. Non-tool_result blocks leave
// it nil.
//
// ContentItems 承载 array 形式的 tool_result 内容 (text + image 混排).
// MarshalJSON 在 Content 字符串 / ContentItems 数组间选一个做 "content"
// wire 字段. 非 tool_result 块留 nil.
ContentItems []ContentBlock `json:"-"`
}
ContentBlock 是消息中的内容块(用于构建请求体).
func (ContentBlock) MarshalJSON ¶
func (c ContentBlock) MarshalJSON() ([]byte, error)
MarshalJSON overrides the default for tool_use blocks: the Anthropic spec requires tool_use to always carry an "input" object, even when the tool takes no arguments. The default map[string]any + omitempty drops nil/empty maps, producing {"type":"tool_use","id":...,"name":...} with no input key. Real Anthropic endpoints are lenient (auto-substitute {}), but the MiniMax Anthropic-compat endpoint rejects it with:
"invalid params, invalid function arguments json string, tool_call_id: ..."
Round 1 returns a valid tool_use → Round 2 re-sends with input dropped → MiniMax 400 → engine wraps as "API 调用在 1 次尝试后失败". All three wire call sites (pkg/providers/anthropic, pkg/providers/minimax, pkg/engine's query.Content → api.ContentBlock compaction conversion) hit this, so the fix lives on the type rather than being duplicated in each caller.
Non-tool_use blocks fall through to the default alias marshaler -- omitempty is the correct behavior for text/thinking/tool_result (their optional fields really are optional on the wire).
MarshalJSON 覆盖 tool_use 块的默认序列化: Anthropic spec 要求 tool_use 永远 包含 "input" 对象, 即使工具无参数. 默认 map[string]any + omitempty 组合会把 nil/空 map 丢掉, 产出 {"type":"tool_use","id":...,"name":...} 无 input. 真 Anthropic 端宽容 (自动补 {}), 但 MiniMax Anthropic-compat 端严格拒绝:
"invalid params, invalid function arguments json string, tool_call_id: ..."
Round 1 返有效 tool_use → Round 2 重发时 input 被丢 → MiniMax 400 → engine 包成 "API 调用在 1 次尝试后失败". 三处 wire 调用点 (anthropic / minimax / engine 的 query.Content → api.ContentBlock 压缩转换) 都中招, 修在类型上而不 在每个 caller 里重复.
非 tool_use 块 fall through 到默认 alias 序列化 -- omitempty 对 text/thinking/tool_result 是正确行为 (它们的可选字段在 wire 上真的可选).
type DNSCache ¶
type DNSCache struct {
// contains filtered or unexported fields
}
DNSCache 是简单的 DNS 解析缓存.
精妙之处(CLEVER): 企业内网 DNS 可能很慢(递归查询 100-500ms), 提前解析并缓存,后续连接直接用 IP. 缓存时间较短(5 分钟),避免 DNS 变更后长时间用旧 IP.
type DefaultClassifier ¶
type DefaultClassifier struct{}
DefaultClassifier 是基于 HTTP 状态码的默认分类器. 不解析任何供应商特定的 header 或 body 内容,作为兜底分类器使用.
type DiagnosticHinter ¶
DiagnosticHinter 为 API 错误提供用户可操作的诊断提示.
升华改进(ELEVATED): 接口化而非硬编码--不同部署环境可以注册不同的 Hinter. 例如企业内网环境注册一个知道内部代理地址的 Hinter, 云环境注册一个检查安全组/防火墙的 Hinter.
type ErrorCategory ¶
type ErrorCategory = apierror.ErrorCategory
ErrorCategory 是 API 错误的语义分类(使用 apierror 包的定义).
const ( ErrUnknown ErrorCategory = apierror.ErrUnknown ErrAborted ErrorCategory = apierror.ErrAborted ErrTimeout ErrorCategory = apierror.ErrTimeout ErrRateLimit ErrorCategory = apierror.ErrRateLimit ErrOverloaded ErrorCategory = apierror.ErrOverloaded ErrPromptTooLong ErrorCategory = apierror.ErrPromptTooLong ErrMediaTooLarge ErrorCategory = apierror.ErrMediaTooLarge ErrRequestTooLarge ErrorCategory = apierror.ErrRequestTooLarge ErrInvalidRequest ErrorCategory = apierror.ErrInvalidRequest ErrAuthentication ErrorCategory = apierror.ErrAuthentication ErrModelNotFound ErrorCategory = apierror.ErrModelNotFound ErrBilling ErrorCategory = apierror.ErrBilling ErrServerError ErrorCategory = apierror.ErrServerError ErrConnection ErrorCategory = apierror.ErrConnection ErrSSL ErrorCategory = apierror.ErrSSL ErrToolMismatch ErrorCategory = apierror.ErrToolMismatch ErrUnexpectedTool ErrorCategory = apierror.ErrUnexpectedTool ErrDuplicateToolID ErrorCategory = apierror.ErrDuplicateToolID ErrInvalidModel ErrorCategory = apierror.ErrInvalidModel ErrContentPolicy ErrorCategory = apierror.ErrContentPolicy )
以下常量与 apierror.Err* 对应,保持向后兼容.
type ErrorClassifier ¶
type ErrorClassifier interface {
// Classify 分类一个 API 错误.
// statusCode: HTTP 状态码(连接错误时为 0)
// headers: 响应头(连接错误时为 nil)
// body: 响应体(连接错误时为 nil)
// cause: 底层错误(网络错误时非 nil)
Classify(statusCode int, headers http.Header, body []byte, cause error) *APIError
}
ErrorClassifier 将原始 HTTP 响应或连接错误分类为结构化的 APIError.
精妙之处(CLEVER): 接口只有一个方法--简单就是最好的抽象. 不同供应商实现不同的 Classify 逻辑,但返回统一的 *APIError. 支持 CompositeClassifier 叠加(宪法第8条:叠加而非替换).
type ImageSource ¶
type ImageSource struct {
Type string `json:"type"` // "base64" 或 "url"
MediaType string `json:"media_type,omitempty"` // "image/png" 等, base64 时必填
Data string `json:"data,omitempty"` // base64 编码字节, base64 时必填
URL string `json:"url,omitempty"` // HTTPS URL, url 时必填
}
ImageSource 是 Anthropic image block 的 source 子对象.
ImageSource is the source sub-object of an Anthropic image block.
type MessageRequest ¶
type MessageRequest struct {
Model string `json:"model"`
MaxTokens int `json:"max_tokens"`
System json.RawMessage `json:"system,omitempty"` // 支持字符串或 SystemContentBlock 数组
Messages []RequestMessage `json:"messages"`
Tools []ToolDef `json:"tools,omitempty"`
Stream bool `json:"stream"`
Thinking *ThinkingConfig `json:"thinking,omitempty"` // extended thinking 配置
// 升华改进(ELEVATED): stop_sequences 是 API 的基础能力,引擎应完整支持.
// 不应因为"当前只有分类器用"就砍掉--跨场景谁知道哪个场景需要.
// 例如仓储场景可能需要模型生成到 "---订单结束---" 就停.
// 分类器 Stage 1 用 stop_sequences=["</block>"] 可以从 64 token 省到 5 token.
// 替代方案:不支持,靠 max_tokens 兜底(能用但浪费 token).
StopSequences []string `json:"stop_sequences,omitempty"`
// Beta 功能配置(不序列化到请求体,通过 header 传递)
Beta *BetaFeatures `json:"-"`
ResponseFormat *ResponseFormat `json:"response_format,omitempty"` // 结构化输出格式
// Temperature is the per-request sampling temperature; nil omits the
// field on the wire so the upstream uses its default. Anthropic accepts
// [0, 1]; anthropic provider also enforces extended-thinking mode's
// hard constraint of temperature=1.0 before reaching this point.
//
// Temperature 是本次请求的采样温度; nil 时 wire 上不传, 上游用默认.
// Anthropic 接受 [0, 1]; anthropic provider 在 extended thinking 模式
// 下会在到达此处前强制覆盖为 1.0 (服务端硬约束).
Temperature *float64 `json:"temperature,omitempty"`
// TopP is the per-request nucleus sampling cutoff; nil omits the field.
// Anthropic accepts [0, 1]; in thinking mode the API restricts to
// [0.95, 1.0] (anthropic provider pre-handles the override).
//
// TopP 是本次请求的 nucleus 采样阈值; nil 时 wire 上不传.
// Anthropic 接受 [0, 1]; thinking 模式下 API 限制 [0.95, 1.0]
// (anthropic provider 提前覆盖).
TopP *float64 `json:"top_p,omitempty"`
}
MessageRequest 是 Messages API 的请求体.
func (*MessageRequest) SetSystemBlocks ¶
func (r *MessageRequest) SetSystemBlocks(blocks []SystemContentBlock)
SetSystemBlocks 设置带缓存控制的系统提示内容块.
func (*MessageRequest) SetSystemString ¶
func (r *MessageRequest) SetSystemString(text string)
SetSystemString 设置纯文本系统提示(向后兼容).
type Preconnector ¶
type Preconnector struct {
// contains filtered or unexported fields
}
Preconnector 负责 API 连接预热.
用法:
transport := api.NewTransport(nil)
client := api.NewClient(key, url, api.WithHTTPClient(&http.Client{Transport: transport}))
preconn := api.NewPreconnector(url, transport)
preconn.Warmup(ctx) // fire-and-forget,不阻塞
func NewPreconnector ¶
func NewPreconnector(baseURL string, transport *http.Transport) *Preconnector
NewPreconnector 创建预连接器. transport 必须与 Client 共享同一个实例,否则预热的连接不会被复用.
func (*Preconnector) Warmup ¶
func (p *Preconnector) Warmup(ctx context.Context)
Warmup 异步预热 TCP+TLS 连接.
精妙之处(CLEVER): fire-and-forget 模式-- 启动一个 goroutine 发 HEAD 请求,不阻塞调用者. HEAD 请求无响应体,连接完成 TLS 握手后立即进入 keep-alive 池. 失败静默忽略(预连接是优化不是功能,失败了正式请求照常握手).
sync.Once 确保只预热一次,多次调用幂等.
type RequestMessage ¶
type RequestMessage struct {
Role string `json:"role"`
Content json.RawMessage `json:"content"`
}
RequestMessage 是请求中的消息.
func NewBlockMessage ¶
func NewBlockMessage(role string, blocks []ContentBlock) RequestMessage
NewBlockMessage 创建一个包含多个 content block 的消息.
func NewTextMessage ¶
func NewTextMessage(role, text string) RequestMessage
NewTextMessage 创建一个纯文本消息.
type ResponseFormat ¶
type ResponseFormat struct {
Type string `json:"type"` // "json_schema"
JSONSchema json.RawMessage `json:"json_schema,omitempty"` // JSON Schema 定义
}
ResponseFormat 是结构化输出的格式配置.
type StreamEvent ¶
type StreamEvent struct {
Type StreamEventType
Index int // content block 的索引
Delta string // text / thinking 增量内容
// content_block_start 时携带完整的 block 信息
BlockType string // "text", "thinking", "tool_use"
BlockID string // tool_use block 的 ID
BlockName string // tool_use block 的工具名称
// tool_use delta 时累积的 JSON 片段
PartialJSON string
// message_start / message_delta 时携带的 usage 信息
Usage *UsageInfo
// message_delta 时携带的 stop_reason
StopReason string
}
StreamEvent 是从 SSE 流中解析出的结构化事件.
type StreamEventType ¶
type StreamEventType string
StreamEventType 是流式事件类型枚举.
const ( EventMessageStart StreamEventType = "message_start" EventContentBlockStart StreamEventType = "content_block_start" EventContentBlockDelta StreamEventType = "content_block_delta" EventContentBlockStop StreamEventType = "content_block_stop" EventMessageDelta StreamEventType = "message_delta" EventMessageStop StreamEventType = "message_stop" EventPing StreamEventType = "ping" EventError StreamEventType = "error" )
type StreamGuard ¶
type StreamGuard struct {
// contains filtered or unexported fields
}
StreamGuard 包装 flyto.Event channel,添加边界检测和空闲看门狗.
func NewStreamGuard ¶
func NewStreamGuard(cfg *StreamGuardConfig) *StreamGuard
NewStreamGuard 创建流守卫.
type StreamGuardConfig ¶
type StreamGuardConfig struct {
// IdleTimeout 空闲超时:流中间多久无事件视为挂起(默认 90s).
// 精妙之处(CLEVER): SDK 的 request timeout 只管初始连接,
// 不管流中间断了.没有看门狗,静默断开的连接会让进程永远挂起.
IdleTimeout time.Duration
// IdleWarningAt 空闲警告时间点(默认 IdleTimeout/2).
IdleWarningAt time.Duration
// StallThreshold 停顿阈值(默认 30s).
StallThreshold time.Duration
// OnIdleWarning 空闲警告回调(可选)
OnIdleWarning func(elapsed time.Duration)
// OnIdleTimeout 空闲超时回调(可选)
OnIdleTimeout func()
// OnStall 停顿检测回调(可选)
OnStall func(gap time.Duration, stallCount int, totalStallTime time.Duration)
// OnStreamEnd 流结束回调(可选)
OnStreamEnd func(stats *StreamStats)
}
StreamGuardConfig 配置流守卫的行为.
func DefaultStreamGuardConfig ¶
func DefaultStreamGuardConfig() *StreamGuardConfig
DefaultStreamGuardConfig 返回默认配置.
type StreamStats ¶
type StreamStats struct {
// HasContent 是否收到过内容事件(TextDelta / ToolUse / ThinkingDelta)
HasContent bool
// HasUsage 是否收到 UsageEvent(流正常结束的标志)
HasUsage bool
// StopReason 最终的 stop_reason(来自 UsageEvent)
StopReason string
// ContentBlockCount 完成的内容块数量(Text + ToolUse)
ContentBlockCount int
// EventCount 总事件数量
EventCount int
// StallCount 停顿次数
StallCount int
// TotalStallTime 累计停顿时间
TotalStallTime time.Duration
// Duration 流的总持续时间
Duration time.Duration
// IdleAborted 是否因空闲超时被中止
IdleAborted bool
}
StreamStats 是流结束时的统计信息.
func (*StreamStats) IsIncomplete ¶
func (s *StreamStats) IsIncomplete() bool
IsIncomplete 检查流是否不完整(有内容但未正常结束).
type SystemContentBlock ¶
type SystemContentBlock struct {
Type string `json:"type"` // "text"
Text string `json:"text"`
CacheControl *CacheControl `json:"cache_control,omitempty"` // 缓存控制标记
}
SystemContentBlock 是系统提示中的内容块. 支持 prompt caching:通过 CacheControl 标记静态内容为可缓存.
type ThinkingConfig ¶
type ThinkingConfig struct {
Type string `json:"type"` // "enabled" 或 "disabled"
BudgetTokens int `json:"budget_tokens,omitempty"` // thinking token 预算(0=不限制)
}
ThinkingConfig 是 extended thinking 配置.
type ToolDef ¶
type ToolDef struct {
Name string `json:"name"`
Description string `json:"description"`
InputSchema json.RawMessage `json:"input_schema"`
CacheControl *CacheControl `json:"cache_control,omitempty"`
}
ToolDef 是工具定义(提供给 API 的 JSON Schema).
CacheControl 是可选的缓存控制标记. 升华改进(ELEVATED): 工具列表也可以按 cache_control 分段缓存-- 把稳定工具排在前面,在最后一个稳定工具处加 cache_control, 不稳定工具排在后面(不带 cache_control),则稳定工具缓存不受不稳定工具影响. 早期实现 只在系统提示词上加 cache_control,工具列表整体无分段保护. 替代方案:<只缓存全部工具或不缓存> - 否决:任何工具变化都让全部工具缓存失效, 大量稳定工具的 token 费用浪费在一个不稳定工具身上.
type TransportConfig ¶
type TransportConfig struct {
// MaxIdleConnsPerHost 每个 host 最大空闲连接数(默认 2)
MaxIdleConnsPerHost int
// MaxIdleConns 全局最大空闲连接数(默认 10)
MaxIdleConns int
// IdleConnTimeout 空闲连接超时时间(默认 90s)
IdleConnTimeout time.Duration
// TLSHandshakeTimeout TLS 握手超时(默认 10s)
TLSHandshakeTimeout time.Duration
// ResponseHeaderTimeout 等待响应头的超时(默认 0=不限制,由 context 控制)
ResponseHeaderTimeout time.Duration
// DisableKeepAlives 禁用 keep-alive(stale 连接自愈时使用)
DisableKeepAlives bool
// TLSConfig 自定义 TLS 配置(mTLS 客户端证书等)
TLSConfig *tls.Config
// DialTimeout TCP 连接超时(默认 30s)
DialTimeout time.Duration
// DNSResolver 自定义 DNS 解析器(可选,用于 DNS 预解析)
DNSResolver *net.Resolver
}
TransportConfig 集中管理 HTTP Transport 配置.
精妙之处(CLEVER): 所有连接池参数集中在此,不散落在各处. 默认值针对 LLM API 场景优化:
- MaxIdleConnsPerHost=2: API 调用是顺序的(流式),同时最多 2 个连接够用
- IdleConnTimeout=90s: 用户思考时间内保持热连接
- TLSHandshakeTimeout=10s: 企业代理可能慢,给足时间
func DefaultTransportConfig ¶
func DefaultTransportConfig() *TransportConfig
DefaultTransportConfig 返回针对 LLM API 优化的默认配置.