Files
sundynix-agentix/sundynix-gateway/internal/nats/publisher.go
T
Blizzard 2d5fd2fca5 feat: 实时入库监控 + 向量拆分可视化(异步入库 + 进度 SSE)
入库从同步改为异步流水线 + 进度回流(复用 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>
2026-06-11 10:33:36 +08:00

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() }