跳转至

核心数据流(源码增强版)

覆盖范围: 5 条关键数据路径,每条含实际源码追踪 新增: 账户获取流、模型解析流、OAuth 登录流

1. Chat Completions 请求生命周期

Client (OpenAI SDK)        代理 api-routes.ts       代理 task-runner.ts          MonkeyCode 后端
  │                           │                        │                           │
  │ POST /v1/chat/completions │                        │                           │
  ├─────────────────────────►│                        │                           │
  │                           │                        │                           │
  │                           │ 1. 验证:messages 非空 │                           │
  │                           │ 2. 模型解析(6 层回退) │                           │
  │                           │   modelManager.resolveModel(modelId)               │
  │                           ├──────────────────────────────────────────────────►│
  │                           │◄──── { models: [...] } ──────────────────────────│
  │                           │                        │                           │
  │                           │ 3. 检查对话复用        │                           │
  │                           │   conversationManager?.get(conversationId)         │
  │                           │                        │                           │
  │                           │ 4. 获取账号(号池模式)│                           │
  │                           │   accountPool?.acquireWs()                         │
  │                           │   accountPool?.acquireHttp()   ← 回退              │
  │                           │                        │                           │
  │                           │ 5. 转换 prompt 格式     │                           │
  │                           │   messagesToPrompt()   │                           │
  │                           │                        │                           │
  │                           │ 6. 创建任务             │                           │
  │                           ├──────────────────────►│                           │
  │                           │   createTask()         │ POST /api/v1/users/tasks  │
  │                           │                        ├─────────────────────────►│
  │                           │                        │◄── { task_id } ─────────│
  │                           │◄── taskId ────────────│                           │
  │                           │                        │                           │
  │                           │ 7. 流式接收             │                           │
  │                           ├──────────────────────►│                           │
  │                           │   streamTask()         │ WS connect                │
  │                           │                        ├─────────────────────────►│
  │                           │                        │◄── opened ──────────────│
  │                           │                        │                           │
  │                           │                        │ send: auto-approve        │
  │                           │                        │ send: user-input          │
  │                           │                        │                           │
  │                           │ 8. ACP → SSE           │◄── task-started ─────────│
  │ ◄── SSE: chunk ─────────│◄── 事件转换 ───────────│◄── agent_message_chunk ──│
  │ ◄── SSE: chunk ─────────│◄── 事件转换 ───────────│◄── agent_thought_chunk ──│
  │ ◄── SSE: chunk ─────────│◄── 事件转换 ───────────│◄── tool_call ────────────│
  │                           │                        │◄── usage_update ─────────│
  │ ◄── SSE: [DONE] ────────│◄── task-ended ─────────│◄── task-ended ───────────│
  │                           │                        │                           │
  │                           │ 9. 释放账号(号池模式)│                           │
  │                           │   accountPool?.releaseWs(auth)                     │

数据流关键代码(1→6 步)

// api-routes.ts — 第 2~6 步
const model = await modelManager.resolveModel(body.model || "")

let accountAuth = accountPool?.acquireWs() || accountPool?.acquireHttp() || null

const systemMsg = body.messages.find((m) => m.role === "system")
const prompt = body.messages.filter((m) => m.role !== "system")
  .map((m) => `[${m.role === "user" ? "User" : "Assistant"}]\n${m.content}`).join("\n\n")

const taskId = await taskRunner.createTask(model, prompt, {
  authOverride: accountAuth || undefined,
  systemPrompt: systemMsg?.content,
})

数据流关键代码(7→9 步)

// api-routes.ts — 第 7~9 步(流式分支)
const sendSSE = (data: object) => {
  if (res.writableEnded) return
  res.write(`data: ${JSON.stringify(data)}\n\n`)
}

await taskRunner.streamTask(taskId, prompt, (chunk) => {
  sendSSE(chunk)                            // ACP→SSE 分块转发
}, abortController.signal, auth || undefined)

sendSSE({ object: "done" })
res.write("data: [DONE]\n\n")
res.end()
pool?.releaseWs(auth)                       // 释放 WS 锁

2. Responses API 数据流

Client                          代理 api-routes.ts               MonkeyCode 后端
  │ POST /v1/responses              │                               │
  ├───────────────────────────────►│                               │
  │                                │ 1. 模型解析 + 任务创建(同 Chat) │
  │                                │                               │
  │                                │ 2. Responses SSE 模式          │
  │                                │ sendEvent("response.created") │
  │◄── event: response.created ──│                               │
  │                                │                               │
  │                                │ 3. streamTaskRaw() 接收 ACP    │
  │                                │   agent_message_chunk →        │
  │◄── event: response.output_text.delta ──│                     │
  │                                │   tool_call →                  │
  │◄── event: response.output_item.added ──│                    │
  │                                │   tool_call_update →           │
  │◄── event: response.function_call_arguments.delta ──│        │
  │                                │                               │
  │                                │ 4. task-ended → 完成           │
  │◄── event: response.completed ─│                               │

3. 账户获取流(号池模式)

api-routes.ts                      account-pool.ts
  │                                   │
  │ acquireWs() / acquireHttp()       │
  ├─────────────────────────────────►│
  │                                   │ 1. 过滤 ACTIVE 且 !lockedByWs
  │                                   │ 2. 按 lastUsedAt 升序排序
  │                                   │ 3. 取最久未用的账号
  │                                   │    └── acquireWs: 设置 lockedByWs=true, lockedAt=Date.now()
  │                                   │    └── acquireHttp: roundRobinIndex++
  │                                   │ 4. 返回 AuthManager 实例
  │◄──── auth ──────────────────────│
  │                                   │
  │ 使用 auth 创建任务 + WS 流        │
  │                                   │
  │ finally: releaseWs(auth)          │
  ├─────────────────────────────────►│
  │                                   │ lockedByWs=false, lockedAt=null
// account-pool.ts — acquireWs 源码
acquireWs(): AuthManager | null {
  const candidates = this.accounts
    .filter((a) => a.status === "ACTIVE" && !a.lockedByWs)
    .sort((a, b) => a.lastUsedAt - b.lastUsedAt)
  if (candidates.length === 0) return null
  const chosen = candidates[0]
  chosen.lockedByWs = true
  chosen.lockedAt = Date.now()
  chosen.lastUsedAt = Date.now()
  return chosen.auth
}

4. 会话认证流

AuthManager                    MonkeyCode 后端              Redis
  │                               │                         │
  │ getSessionCookie()            │                         │
  ├─ 检查缓存: Date.now() - TTL?  │                         │
  ├─ 过期?→ login()              │                         │
  │      │                        │                         │
  │      │ POST /password-login   │                         │
  │      ├──────────────────────►│                         │
  │      │ 验证密码 bcrypt        │                         │
  │      │ 创建 Session          │── SET Lookup Key ──────►│
  │      │                       │── SET Hash Key ────────►│
  │      │◄── Set-Cookie + 200 ─│                         │
  │      │                        │                         │
  │ 缓存 Cookie + 更新时间戳      │                         │
  │                              │                         │
  │ return Cookie                │                         │
  │                              │                         │
  │ authHeaders()                │                         │
  ├─ getSessionCookie()          │                         │
  ├─ 构造 {Cookie, Content-Type} │                         │
  │ return headers               │                         │
// auth.ts — Session 缓存与刷新
async getSessionCookie(): Promise<string> {
  if (this.sessionCookie && Date.now() - this.lastAuthTime < this.sessionTTL) {
    return this.sessionCookie            // 24h 缓存命中
  }
  await this.login()                      // 过期→重新登录
  return this.sessionCookie
}

async authHeaders(): Promise<Record<string, string>> {
  const cookie = await this.getSessionCookie()
  return {
    Cookie: `${this.sessionCookieName}=${cookie}`,
    "Content-Type": "application/json",
  }
}

5. 模型解析流(6 层回退)

modelManager.resolveModel(modeId)
  │ await fetchModels()
  │   └─ 缓存命中?→返回
  │   └─ 未命中?→ GET /api/v1/users/models → 缓存 5 分钟
  │ 6 层回退匹配:
  ├── 第 1 层:精确匹配 "monkeycode/{provider}/{model}"
  ├── 第 2 层:匹配 "{provider}/{model}" 格式
  ├── 第 3 层:匹配 model 名称
  ├── 第 4 层:匹配 display_name
  ├── 第 5 层:回退到 is_default 模型
  └── 第 6 层:回退到 models[0]
// 用户输入解析示例
// 用户输入 "gpt-4o"
// 第 3 层命中 → model === "gpt-4o"
// 返回 MonkeyCodeModel { provider: "openai", model: "gpt-4o", interface_type: "openai_chat" }

// 用户输入 "monkeycode/siliconflow/Qwen/Qwen3.5-Plus"
// 第 1 层命中 → 精确匹配完整路径

6. OAuth 登录流(6 步)

server.ts                    admin-login.ts                 百智云/MonkeyCode
  │                              │                              │
  │ POST /admin/login/send-code   │                              │
  ├────────────────────────────►│                              │
  │                              │ 1. startOAuthLogin()         │
  │                              │   GET /api/v1/users/login    │
  │                              ├─────────────────────────────►│
  │                              │◄── 302 + state/clientId ───│
  │                              │                              │
  │                              │ 2. getSCaptchaToken()        │
  │                              │   POST *.s-captcha-r1.com    │
  │                              │◄── { token: "sc_xxx" } ────│
  │                              │                              │
  │                              │ 3. sendSmsCode(phone, token) │
  │                              │   POST baizhi.cloud/phone_code
  │                              ├─────────────────────────────►│
  │                              │◄── { code: 0 } ────────────│
  │◄── { state, msg } ─────────│                              │
  │                              │                              │
  │ POST /admin/login/verify     │                              │
  ├────────────────────────────►│                              │
  │                              │ 4. baizhiPhoneLogin(code)    │
  │                              │   POST baizhi.cloud/login/phone
  │                              ├─────────────────────────────►│
  │                              │◄── baizhi cookies + user   │
  │                              │                              │
  │                              │ 5. baizhiOAuthAuthorize()    │
  │                              │   GET baizhi.cloud/oauth/authorize
  │                              ├─────────────────────────────►│
  │                              │◄── 302 + code ─────────────│
  │                              │                              │
  │                              │ 6. monkeycodeCallback()      │
  │                              │   GET callback?code=xxx      │
  │                              ├─────────────────────────────►│
  │                              │◄── Set-Cookie: session ────│
  │                              │                              │
  │◄── { sessionCookie,        │                              │
  │       imageId, models }     │                              │

相关章节