feat(gateway): 消息mode落库(A3) — 持久化真实写入渲染模式
- POST /api/v1/chat 与 ws.chat 上行新增可选 mode(行为模式 design/01 §3/design/16 §5.1) - Web路径经ctx透传本轮mode到编排器持久化(persistUserMessages/persistAssistantReply),缺省回落chat - pendingMsg记录mode,恢复/续接路径沿用发起轮次mode - IM路径(persistToMain/persistIsolated)恒为chat - 新增/扩充测试:REST/WS/orchestrator/channelbridge 覆盖mode写入 - Docs/api-client.md v0.20 同步mode字段
This commit is contained in:
1 parent
fe5dbcddba
commit
b686d5fec8
9 files changed
+199
-41
No files matched your search
@@ -348,6 +348,33 @@ func TestChatStreamMode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestChatRequestPersistsMode(t *testing.T) {
|
||||
t.Parallel()
|
||||
hist := &fakeHistory{}
|
||||
_, ts, jwt := buildEnv(t, cfgDefault(), Deps{
|
||||
Loop: &stubRunner{res: &loop.Result{Text: "回复", StopReason: "stop"}},
|
||||
History: hist,
|
||||
})
|
||||
tok := signAny(t, jwt, "acct", auth.RoleOwner)
|
||||
// The REST body carries the client's behavior mode (design/16 §5.1); the
|
||||
// orchestrator persists both the user turn and the assistant reply under it.
|
||||
resp, body := doReq(t, http.MethodPost, ts.URL+"/api/v1/chat",
|
||||
map[string]any{"sessionId": "web", "text": "改代码", "mode": "code"}, tok)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("status = %d, want 200 (body=%s)", resp.StatusCode, body)
|
||||
}
|
||||
recs := hist.records()
|
||||
if len(recs) != 2 {
|
||||
t.Fatalf("appends = %d, want 2 (user + assistant)", len(recs))
|
||||
}
|
||||
if recs[0].Role != history.RoleUser || recs[0].Mode != "code" {
|
||||
t.Fatalf("user record = %+v, want role=user mode=code", recs[0])
|
||||
}
|
||||
if recs[1].Role != history.RoleAssistant || recs[1].Mode != "code" {
|
||||
t.Fatalf("assistant record = %+v, want role=assistant mode=code", recs[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestChatDefaultsSessionToWeb(t *testing.T) {
|
||||
t.Parallel()
|
||||
cr := &captureRunner{res: &loop.Result{Text: "ok", Steps: 1, StopReason: "stop"}}
|
||||
@@ -882,6 +909,37 @@ func TestHubStreamChat(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHubStreamChatPersistsMode(t *testing.T) {
|
||||
t.Parallel()
|
||||
hist := &fakeHistory{}
|
||||
hb := newTestHub(&stubRunner{res: &loop.Result{Text: "hi", StopReason: "stop"}}, nil)
|
||||
hb.orchestrator = NewOrchestrator(OrchestratorOptions{
|
||||
Run: func(context.Context, string, []model.Message, loop.SessionEnv) (*loop.Result, error) {
|
||||
return &loop.Result{Text: "hi", StopReason: "stop"}, nil
|
||||
},
|
||||
History: hist,
|
||||
})
|
||||
// The ws.chat payload carries the client's behavior mode (design/16 §5.1);
|
||||
// streamChat threads it into the orchestrator, which persists both the user
|
||||
// turn and the assistant reply under it.
|
||||
hb.streamChat(context.Background(), map[string]any{"sessionId": "web", "text": "改代码", "mode": "code"})
|
||||
|
||||
deadline := time.Now().Add(2 * time.Second)
|
||||
for time.Now().Before(deadline) && len(hist.records()) < 2 {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
recs := hist.records()
|
||||
if len(recs) != 2 {
|
||||
t.Fatalf("appends = %d, want 2 (user + assistant)", len(recs))
|
||||
}
|
||||
if recs[0].Role != history.RoleUser || recs[0].Mode != "code" {
|
||||
t.Fatalf("user record = %+v, want role=user mode=code", recs[0])
|
||||
}
|
||||
if recs[1].Role != history.RoleAssistant || recs[1].Mode != "code" {
|
||||
t.Fatalf("assistant record = %+v, want role=assistant mode=code", recs[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestHubBroadcastStream(t *testing.T) {
|
||||
t.Parallel()
|
||||
hb := newTestHub(nil, nil)
|
||||
|
||||
Reference in new issue
Block a user