2d5fd2fca5
入库从同步改为异步流水线 + 进度回流(复用 token 流 NATS streaming)。 UI 实时看到 解析→切块→向量化(分批)→写入 各阶段 + 拆分块预览。 - shared: contract.IngestEvent(stage/done/total/chunks/error) - mcp-go: rag.Ingest 加 onProgress + 分批向量化(10/批)逐批回报;kb_ingest 带 job_id 把进度发到 sundynix.streams.<job_id> + CompleteStream - gateway: 入库异步返回 job_id,后台 runIngest 发进度;GET /kb/ingest/:id/stream SSE - frontend: streamIngest(EventSource);KbView 实时进度面板(阶段徽标+进度条+拆分列表) - 验证: build✓+e2e PASS; 浏览器 12 行→6 阶段点亮+进度条 12/12+拆分 12 块逐条 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
75 lines
2.4 KiB
Go
75 lines
2.4 KiB
Go
// Package nats 是网关对共享 bus 的薄封装(发布任务 / 订阅 Token 回流)。
|
|
package nats
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"log"
|
|
|
|
sharedbus "github.com/sundynix/sundynix-shared/bus"
|
|
"github.com/sundynix/sundynix-shared/contract"
|
|
)
|
|
|
|
// Bus 包装共享 bus,向网关其余代码暴露发布能力。
|
|
type Bus struct {
|
|
inner *sharedbus.Bus
|
|
}
|
|
|
|
// MustConnect 接入 NATS 并确保任务流存在。
|
|
func MustConnect(url string) *Bus {
|
|
inner, err := sharedbus.Connect(url)
|
|
if err != nil {
|
|
log.Fatalf("[nats] connect: %v", err)
|
|
}
|
|
if err := inner.EnsureTaskStream(context.Background()); err != nil {
|
|
log.Fatalf("[nats] ensure stream: %v", err)
|
|
}
|
|
log.Printf("[nats] connected %s, task stream ready", url)
|
|
return &Bus{inner: inner}
|
|
}
|
|
|
|
// PublishTask 把组装后的 Task 发布到 sundynix.tasks.<id>。
|
|
func (b *Bus) PublishTask(ctx context.Context, t *contract.Task) error {
|
|
seq, err := b.inner.PublishTask(ctx, t)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Printf("[nats] published task %s (seq=%d)", t.ID, seq)
|
|
return nil
|
|
}
|
|
|
|
// SubscribeTokens 订阅 sundynix.streams.<taskID> 的 Token 回流,
|
|
// 每个 Token 触发 onToken,流结束触发 onDone,返回 unsub。
|
|
func (b *Bus) SubscribeTokens(taskID string, onToken func([]byte), onDone func()) (func() error, error) {
|
|
return b.inner.SubscribeTokens(taskID, onToken, onDone)
|
|
}
|
|
|
|
// CallTool 经 NATS 同步调用一个 MCP 工具(用于网关侧写偏好记忆等)。
|
|
func (b *Bus) CallTool(ctx context.Context, subject string, call *contract.ToolCall) (*contract.ToolResult, error) {
|
|
return b.inner.CallTool(ctx, subject, call)
|
|
}
|
|
|
|
// ServeConfig 让网关作为配置控制面,响应某 kind 的配置请求。
|
|
func (b *Bus) ServeConfig(kind string, provide func() *contract.ModelConfig) (func() error, error) {
|
|
return b.inner.ServeConfig(kind, provide)
|
|
}
|
|
|
|
// PublishConfigUpdated 广播某 kind 的配置变更。
|
|
func (b *Bus) PublishConfigUpdated(kind string, cfg *contract.ModelConfig) error {
|
|
return b.inner.PublishConfigUpdated(kind, cfg)
|
|
}
|
|
|
|
// PublishIngest 把一条入库进度事件发到 sundynix.streams.<jobID>。
|
|
func (b *Bus) PublishIngest(jobID string, ev *contract.IngestEvent) error {
|
|
data, err := json.Marshal(ev)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return b.inner.PublishToken(jobID, data)
|
|
}
|
|
|
|
// CompleteStream 发送入库流结束信号。
|
|
func (b *Bus) CompleteStream(jobID string) error { return b.inner.CompleteStream(jobID) }
|
|
|
|
func (b *Bus) Close() { b.inner.Close() }
|