package model import ( "context" "errors" ) // model 包返回的错误。向外传递时一律用 %w 包装, // 以便调用方既能按类别判定,又能保留底层原因。 var ( // 无法解析出任何模型名时返回 ErrNoModel。 ErrNoModel = errors.New("model: no model configured") // 降级链没有任何步骤时返回 ErrNoSteps。 ErrNoSteps = errors.New("model: empty fallback chain") // 提供商请求失败(网络、状态码、解码)或降级链的 // 每一步都失败时,返回 ErrUpstream。 ErrUpstream = errors.New("model: upstream request failed") // 请求无法编码为线格式时返回 ErrBadRequest。 ErrBadRequest = errors.New("model: invalid request") // 流在完成前就结束时返回 ErrStream。 ErrStream = errors.New("model: stream closed before completion") ) // Recorder 在一次成功完成的 LLM 调用之后接收 CallRecord。 // 它由各适配器调用,好让运行时(M9 监控/前端)收集用量, // 而不必与任何存储后端耦合。 type Recorder func(CallRecord) // Adapter 抽象单个 LLM 提供商。各实现面向具体厂商, // 但都说归一化的 Request/Response 词汇;降级 Chain 或 // Router 都能组合它们,无需知道每个背后是哪家提供商。 type Adapter interface { // Name 返回提供商/适配器的稳定标识。 Name() string // Chat 执行一次非流式补全并返回完整响应。 Chat(ctx context.Context, req Request, opts Options) (Response, error) // ChatStream 通过 onEvent 流出结构化事件,并返回聚合后的 // 响应(提供商上报用量时一并带上)。onEvent 可为 nil, // 此时仍照常聚合、只是丢弃事件。提供商支持的每个片段 // 都被成对包裹(text_start/delta/end、tool_call_start/delta/end), // 消费者因此可以独立渲染各片段;适配器尚无法区分的片段 // 以 text_delta 事件投递。 ChatStream(ctx context.Context, req Request, onEvent func(StreamEvent)) (Response, error) }