// Package transform 定义出站适配器:IR → Provider 方言的转换层。 // M0 只含回声 stub 适配器;云 Provider adaptor(openai_compatible/anthropic)与 // 本地元炁端点按 rewrite-plan M4 落地(docs/architecture/shenshi-gateway.md §5)。 package transform import ( "context" "hunjing/shenshi/internal/ir" ) // Adaptor 出站适配器契约:消费 IR 请求,产出标准化增量流。 type Adaptor interface { // Stream 产出增量;context 取消时须及时返回。 Stream(ctx context.Context, req *ir.ChatRequest, out chan<- ir.Delta) error // Name 适配器稳定标识(endpoint.type 取值,契约词典 §14.2)。 Name() string } // chunkSize stub 回声切分粒度(与灵台 EchoShenshi 对齐,便于联调对比)。 const chunkSize = 8 // StubAdaptor 回声适配器:把最后一条用户消息加前缀后按固定粒度回流。 // 仅用于 M0 骨架端到端验证,不模拟任何 Provider 行为。 type StubAdaptor struct{} // Name 实现 Adaptor。 func (StubAdaptor) Name() string { return "stub" } // Stream 实现 Adaptor:逐块产出增量并在末帧携带用量。 func (StubAdaptor) Stream(ctx context.Context, req *ir.ChatRequest, out chan<- ir.Delta) error { prompt := req.LastUserMessage() runes := []rune("【神识回声桩】" + prompt) // 按 rune 切分,与灵台回声桩的码点语义对齐 for i := 0; i < len(runes); i += chunkSize { select { case <-ctx.Done(): return ctx.Err() default: } end := min(i+chunkSize, len(runes)) out <- ir.Delta{Delta: string(runes[i:end])} } out <- ir.Delta{ FinishReason: "stop", UsagePromptTokens: max(len([]rune(prompt))/4, 1), UsageCompletionTokens: max(len(runes)/4, 1), } return nil }