From 6ef395a7f59b472d76126c8d379fb3c5d373b7f3 Mon Sep 17 00:00:00 2001 From: gozeros Date: Thu, 5 Nov 2026 11:24:29 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20Init=20=E5=89=8D=20AcquireRoundtableRoom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 与 Java 对齐,避免新版 Gateway「会商会话标识缺失」。 Co-authored-by: Cursor --- internal/deerflow/client.go | 63 +++++++++++++++++++++++++++++++++- internal/worker/live_runner.go | 6 ++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/internal/deerflow/client.go b/internal/deerflow/client.go index 496c25f..7368e19 100644 --- a/internal/deerflow/client.go +++ b/internal/deerflow/client.go @@ -86,8 +86,40 @@ type InitMultiAgentOpts struct { RoomSessionID string } +// AcquireRoundtableRoom 占用一步会商房间。新版 Gateway 的 init 只续租不新建, +// 缺 roomSessionId / 未 acquire 时会报「会商会话标识缺失」。 +func (c *Client) AcquireRoundtableRoom(draftID, taskID, roomSessionID string) error { + draftID = strings.TrimSpace(draftID) + roomSessionID = strings.TrimSpace(roomSessionID) + if draftID == "" || roomSessionID == "" { + return fmt.Errorf("缺少会商标识(draftId/roomSessionId),无法占用研讨房间") + } + body := map[string]interface{}{ + "draftId": draftID, + "roomSessionId": roomSessionID, + } + if t := strings.TrimSpace(taskID); t != "" { + body["taskId"] = t + } + raw, err := c.postJSON("/api/roundtable-rooms/acquire", body) + if err != nil { + return err + } + var resp map[string]interface{} + _ = json.Unmarshal(raw, &resp) + if ok, has := resp["ok"].(bool); has && !ok { + msg := fmt.Sprint(resp["message"]) + if msg == "" || msg == "" { + msg = "占用会商房间失败" + } + return fmt.Errorf("%s", msg) + } + logging.L.Infow("DeerFlow 房间已占用", "draftId", draftID, "roomSessionId", roomSessionID) + return nil +} + // InitMultiAgent 建多席线程,返回 agentName → threadId。 -// draft_id 在内网较新 Gateway 上是「会商标识」,缺了会 4xx。 +// draft_id 在内网较新 Gateway 上是「会商标识」,缺了会 4xx。调用前须 AcquireRoundtableRoom。 func (c *Client) InitMultiAgent(agentNames []string, mainAgent, model string, opts InitMultiAgentOpts) (map[string]string, error) { body := map[string]interface{}{ "agent_names": agentNames, @@ -366,6 +398,35 @@ func (c *Client) readSSE( return scanner.Err() } +func (c *Client) postJSON(path string, body map[string]interface{}) ([]byte, error) { + token, err := c.auth.BearerToken() + if err != nil { + return nil, err + } + raw, err := json.Marshal(body) + if err != nil { + return nil, err + } + req, err := http.NewRequest(http.MethodPost, c.cfg.DeerFlowBaseURL+path, bytes.NewReader(raw)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + client := &http.Client{Timeout: 30 * time.Second} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + out, _ := io.ReadAll(resp.Body) + if resp.StatusCode >= 400 { + return nil, fmt.Errorf("DeerFlow %s HTTP %d: %s", path, resp.StatusCode, string(out)) + } + return out, nil +} + func isFinalStatusFrame(v map[string]interface{}) bool { if v == nil { return false diff --git a/internal/worker/live_runner.go b/internal/worker/live_runner.go index 4223f3c..6426745 100644 --- a/internal/worker/live_runner.go +++ b/internal/worker/live_runner.go @@ -88,6 +88,12 @@ func (r *LiveChainRunner) Run(job *domain.AnalysisJob) { if dfTaskID == "" { dfTaskID = job.TaskID } + putProgress(job, 3, "正在占用会商房间…") + r.flush(job) + if err := r.DF.AcquireRoundtableRoom(job.DraftID, dfTaskID, roomSessionID); err != nil { + r.fail(job, err.Error()) + return + } tids, err := r.DF.InitMultiAgent(agentNames, r.Coord, job.Model, deerflow.InitMultiAgentOpts{ DraftID: job.DraftID, TaskID: dfTaskID,