Skip to content

Feat/xiaomimo web#115

Open
aurelius1688 wants to merge 6 commits intolinuxhsj:mainfrom
aurelius1688:feat/xiaomimo-web
Open

Feat/xiaomimo web#115
aurelius1688 wants to merge 6 commits intolinuxhsj:mainfrom
aurelius1688:feat/xiaomimo-web

Conversation

@aurelius1688
Copy link

@aurelius1688 aurelius1688 commented Mar 19, 2026

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem:
  • Why it matters:
  • What changed:
  • What did NOT change (scope boundary):

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #

User-visible / Behavior Changes

List user-visible changes (including defaults/config).
If none, write None.

Security Impact (required)

  • New permissions/capabilities? (Yes/No)
  • Secrets/tokens handling changed? (Yes/No)
  • New/changed network calls? (Yes/No)
  • Command/tool execution surface changed? (Yes/No)
  • Data access scope changed? (Yes/No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS:
  • Runtime/container:
  • Model/provider:
  • Integration/channel (if any):
  • Relevant config (redacted):

Steps

Expected

Actual

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios:
  • Edge cases checked:
  • What you did not verify:

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No)
  • Config/env changes? (Yes/No)
  • Migration needed? (Yes/No)
  • If yes, exact upgrade steps:

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly:
  • Files/config to restore:
  • Known bad symptoms reviewers should watch for:

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk:
    • Mitigation:

Summary by CodeRabbit

发布说明

  • 新功能

    • 在产品中新增 Xiaomi MiMo(MiMo Web)模型支持:可在 Web UI 与 CLI 中进行对话、流式输出与工具调用兼容。
    • 添加用于 MiMo 的浏览器登录与授权流程(Playwright 支持)及 CLI 授权命令,便于在本地完成认证并保存凭据。
  • 文档

    • 新增认证汇总文档,列出已支持 Web 模型的认证状态、配置路径与使用示例。

- Add xiaomimo-web-client-browser.ts with browser-based API client
- Add xiaomimo-web-auth.ts for browser authentication
- Add xiaomimo-web-stream.ts for SSE response parsing
- Update models-config.providers.ts with xiaomimo-web provider
- Update onboard-web-auth.ts with xiaomimo-web option
- Add xiaomimo-web to MODEL_APIS types
- Add xiaomimo-web to web-models extension
- Add prompt truncation for API length limits (3000 chars)

API format uses query/msgId/conversationId/modelConfig/multiMedias
Response format uses SSE events: dialogId, message, usage
- Fix conversationId persistence from dialogId response
- Add tool instruction injection and tool call parsing
- Reduce prompt to 2500 chars with recent message history
- Support multi-turn conversations
- Parse tool_call XML tags from response
- Pass systemPrompt to client for context
- Combine system prompt with user message
- Fix variable name errors
@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2567560b-d397-43dd-8964-bb3c17c5067f

📥 Commits

Reviewing files that changed from the base of the PR and between dcfd8dd and 406e04c.

📒 Files selected for processing (1)
  • auth-summary.md
✅ Files skipped from review due to trivial changes (1)
  • auth-summary.md

📝 Walkthrough

Walkthrough

此次变更添加对 Xiaomi MiMo / MiMo Web 的提供商、客户端与流处理支持;大量代码风格/引号统一化调整;新增认证与文档条目并微调若干脚本与 UI 导入。仅格式化与新增 MiMo 功能,无其他行为变更说明。

Changes

Cohort / File(s) Summary
配置与文档
\.openclaw-state.example/openclaw.json, README.zh-CN.md, auth-summary.md
修正 JSON 结构小问题,调整 Markdown 表格格式并新增认证汇总文档。
字符串/样式规范化(AskOnce 与主库)
extensions/askonce/src/askonce/adapters/*, extensions/askonce/src/askonce/*, extensions/askonce/src/*, src/**/*
将大量单引号改为双引号、重排导入、格式化函数签名与日志调用,均为风格/格式化变更,无逻辑修改。
新增 MiMo / Xiaomi MiMo 支持 — 提供商与认证
src/providers/mimo-web-auth.ts, src/providers/xiaomimo-web-auth.ts, src/commands/auth-choice.apply.mimo-web.ts, src/commands/auth-choice.apply.mimo-web.ts
新增基于 Playwright 的 MiMo / Xiaomi MiMo 浏览器认证流程与命令行子命令。
新增 MiMo 客户端实现(服务端与浏览器两套)
src/providers/mimo-web-client.ts, src/providers/mimo-web-client-browser.ts, src/providers/xiaomimo-web-client.ts, src/providers/xiaomimo-web-client-browser.ts
新增 MiMo / Xiaomi 客户端模块,包含模型发现、chat/completions 请求与流式响应处理。
新增 MiMo 流处理适配器
src/agents/mimo-web-stream.ts, src/agents/xiaomimo-web-stream.ts
新增流工厂与转换器,支持将 MiMo SSE/行式输出规范化为内部流事件(包含思考/工具调用解析)。
Web 模型插件与配置扩展
extensions/web-models/index.ts, src/agents/models-config.providers.ts, src/config/types.models.ts, src/providers/index.ts
在 WEB 提供商列表与模型映射中加入 xiaomimo-web / mimo-web 条目并导出相应提供商,更新模型 API 类型与 provider 构建逻辑。
嵌入式运行与集成点
src/agents/pi-embedded-runner/compact.ts, src/agents/pi-embedded-runner/run/attempt.ts, src/commands/onboard-web-auth.ts
在运行时/尝试逻辑与 onboarding 流中接入 MiMo 流工厂与授权白名单。
导出/注册调整
src/providers/index.ts, extensions/askonce/src/askonce/adapters/index.ts, extensions/askonce/src/askonce/formatters/index.ts
新增/调整对 MiMo 提供商的导出与若干 re-export 的字符串引号样式。
脚本更新
scripts/bundle-a2ui.sh
动态解析 Node 可执行路径以增强跨平台哈希脚本的健壮性。
大量现有提供商/客户端/命令格式化
src/providers/*-web-auth.ts, src/providers/*-web-client*.ts, src/commands/auth-choice.apply.*.ts
对现有各类提供商与认证命令进行格式化、导入重排与小范围语法微调,保持行为不变。
UI 视图与类型注解轻微调整
ui/src/ui/views/*
导入重排与 Lit 状态类型注解格式化,无功能变动。

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Browser as Playwright<br/>(Browser)
    participant OpenClaw as OpenClaw<br/>(Auth Capture)
    participant MiMoAPI as MiMo<br/>(Auth/API)

    User->>Browser: 打开登录页面 (openUrl)
    Browser->>MiMoAPI: 浏览器加载 /login 等页面
    User->>MiMoAPI: 完成登录交互
    MiMoAPI-->>Browser: 返回 Set-Cookie / Authorization header
    Browser->>OpenClaw: 拦截 request/response (Cookie/Authorization)
    OpenClaw->>Browser: 读取 document.cookie / localStorage / userAgent
    Browser-->>OpenClaw: 返回凭证 (cookie, bearer, sessionId, userAgent)
    OpenClaw-->>User: 持久化认证配置 (保存 profile)
Loading
sequenceDiagram
    participant Client
    participant OpenClaw as Orchestrator
    participant MimoStream as MiMo Stream
    participant MimoClient as MiMo Client
    participant MiMoAPI as MiMo Server

    Client->>OpenClaw: 发起 query(messages, model)
    OpenClaw->>MimoStream: createMimoWebStreamFn(credentials)
    MimoStream->>MimoClient: chatCompletions({messages, stream:true})
    MimoClient->>MiMoAPI: POST /chat (流式)
    MiMoAPI-->>MimoClient: SSE / 行式流响应
    MimoClient-->>MimoStream: ReadableStream
    MimoStream->>MimoStream: 解析并规范化事件 (text_delta, thinking, toolCall)
    MimoStream-->>OpenClaw: 逐步推送流事件
    OpenClaw-->>Client: 汇总并返回最终响应
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 我是小白兔,跳入代码坑,
新增 MiMo 如花绽放,忙碌不惊慌。
引号整齐排成行,认证凭证藏框中,
流式对话细如丝,兔子为你鼓掌♪

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning PR 描述是一个空的模板,所有必需部分都未填写,包括摘要、变更类型、作用域、用户可见的变化、安全影响和验证信息。 请完整填写 PR 描述模板,包括摘要、变更类型、作用域、用户可见的变化、安全影响评估和验证步骤。
Docstring Coverage ⚠️ Warning Docstring coverage is 11.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed 标题 'Feat/xiaomimo web' 清楚地指向了主要变化:添加 Xiaomi MiMo Web 支持。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Important

Merge conflicts detected (Beta)

  • Resolve merge conflict in branch feat/xiaomimo-web
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/agents/grok-web-stream.ts (1)

370-376: ⚠️ Potential issue | 🟡 Minor

复制粘贴错误:日志标签不正确

错误日志中使用了 [Qwen Stream] 标签,但这是 GrokWebStream 模块。这会导致调试时产生混淆。

🔧 建议修复
                   } catch (e) {
                     part.arguments = { raw: argStr };
                     console.error(
-                      `[Qwen Stream] Failed to parse JSON for tool call ${currentToolName}:`,
+                      `[GrokWebStream] Failed to parse JSON for tool call ${currentToolName}:`,
                       argStr,
                       "\nError:",
                       e,
                     );
                   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/grok-web-stream.ts` around lines 370 - 376, The error log in
GrokWebStream incorrectly uses the "[Qwen Stream]" tag; update the console.error
call in GrokWebStream (the block that references currentToolName, argStr, and e)
to use the correct module tag (e.g., "[GrokWebStream]" or "[Grok Web Stream]")
so logs accurately reflect the source and avoid confusion when debugging.
🟡 Minor comments (16)
src/providers/xiaomimo-web-client.ts-59-102 (1)

59-102: ⚠️ Potential issue | 🟡 Minor

返回类型与实际返回值不一致

方法签名声明返回 ReadableStream<Uint8Array> | null,但 res.body 在某些情况下可能为 null(即使 res.oktrue)。建议添加 null 检查或调整返回类型处理:

🛡️ 建议的修复
    console.log(
      `[XiaomiMimoWebClient] Chat completion response OK (status: ${res.status}). Content-Type: ${res.headers.get("content-type")}`,
    );

-   return res.body;
+   if (!res.body) {
+     throw new Error("XiaomiMimo response body is null");
+   }
+   return res.body;
  }

同时可以将返回类型简化为 Promise<ReadableStream<Uint8Array>>

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/xiaomimo-web-client.ts` around lines 59 - 102, The method
chatCompletions declares Promise<ReadableStream<Uint8Array> | null> but returns
res.body which can be null even when res.ok is true; update chatCompletions to
ensure a non-null ReadableStream is always returned by checking res.body after
the success response and throwing a descriptive Error if it's null (or
alternatively construct/pipe an empty ReadableStream), and then tighten the
method signature to Promise<ReadableStream<Uint8Array>>; refer to the
chatCompletions function and the res.body use to locate where to add the
null-check and signature change.
src/providers/xiaomimo-web-client.ts-104-125 (1)

104-125: ⚠️ Potential issue | 🟡 Minor

模型配置中 api 属性缺失导致客户端实现不一致

xiaomimo-web-client.tsdiscoverModels() 返回的模型配置缺少 api 属性。虽然 ModelDefinitionConfigapi 字段是可选的,但其他 web 客户端(如 chatgpt-web-client-browser.tsqwen-web-client-browser.ts)都包含此属性。doubao-web-client.ts 也存在同样问题。建议为一致性添加 api: "xiaomimo-web" 属性。

🔧 建议的修复
  async discoverModels(): Promise<ModelDefinitionConfig[]> {
    return [
      {
        id: "xiaomimo-chat",
        name: "MiMo Chat",
+       api: "xiaomimo-web",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 128000,
        maxTokens: 4096,
      },
      {
        id: "mimo-v2-pro",
        name: "MiMo V2 Pro",
+       api: "xiaomimo-web",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 128000,
        maxTokens: 8192,
      },
    ];
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/xiaomimo-web-client.ts` around lines 104 - 125, discoverModels
currently returns model objects missing the optional api field, causing
inconsistency with other web clients; update the discoverModels method in
xiaomimo-web-client.ts to add api: "xiaomimo-web" to each ModelDefinitionConfig
object (the entries with id "xiaomimo-chat" and "mimo-v2-pro") so the model
definitions match other clients like chatgpt-web-client-browser and
qwen-web-client-browser.
src/providers/xiaomimo-web-client-browser.ts-124-125 (1)

124-125: ⚠️ Potential issue | 🟡 Minor

signal 入参未被使用,调用方无法可靠中断请求

函数签名接收了 AbortSignal,但整个请求流程没有中断检查,超时/取消场景下可观测性与控制性较差。

💡 建议修复
   async chatCompletions(params: {
@@
   }): Promise<ReadableStream<Uint8Array>> {
+    if (params.signal?.aborted) {
+      throw new Error("XiaomiMimo request aborted");
+    }
     const { page } = await this.ensureBrowser();
@@
     const result = await page.evaluate(
@@
     );
+    if (params.signal?.aborted) {
+      throw new Error("XiaomiMimo request aborted");
+    }

Also applies to: 126-227

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/xiaomimo-web-client-browser.ts` around lines 124 - 125,
该函数声明接收了参数 signal 并返回 Promise<ReadableStream<Uint8Array>>,但实现未使用该
AbortSignal;请在该函数(接受 signal 的那个方法)中把 signal 传递给底层的 fetch 请求(即在调用 fetch 时将 {
signal } 作为选项),在开始读取流前检查 signal.aborted 并在 signal 的 'abort' 事件触发时调用
reader.cancel() / response.body.cancel() 来停止流处理,同时将 fetch 的错误/AbortError
正确向外抛出或映射为拒绝的 Promise;若函数内部创建了自己的 AbortController(例如用于超时),确保将其与传入的 signal
联合(当任一中止时取消整体操作)。
src/commands/auth-choice.apply.mimo-web.ts-35-37 (1)

35-37: ⚠️ Potential issue | 🟡 Minor

错误处理中缺少类型守卫。

error.message 访问未经类型检查,如果 error 不是 Error 实例会导致运行时错误。

🐛 建议的修复
     } catch (error) {
-      console.error("? MiMo-Web authentication failed:", error.message);
+      console.error("? MiMo-Web authentication failed:", error instanceof Error ? error.message : String(error));
       process.exit(1);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/auth-choice.apply.mimo-web.ts` around lines 35 - 37, The catch
block currently assumes "error" is an Error and reads error.message; add a type
guard to safely extract message (e.g., check if error instanceof Error or typeof
error === 'object' && 'message' in error) and fall back to String(error) or
JSON.stringify for non-Error values before calling console.error in the catch of
the MiMo-Web auth flow; ensure the log uses the computed message and keep the
existing process.exit(1) behavior.
src/providers/mimo-web.ts-64-160 (1)

64-160: ⚠️ Potential issue | 🟡 Minor

setInterval 资源泄漏:超时或请求处理器成功时未清理定时器。

timeout 触发(第 66-70 行)或 requestHandler 成功捕获凭证(第 89-98 行)时,第 153 行创建的 setInterval 没有被清理。虽然下次定时器回调时会检测到 resolved=true 并自行清理,但这仍然是一个小的资源泄漏。

🛠️ 建议修复:将 interval 提升到外层作用域并在所有退出路径清理
   private async waitForLogin(
     page: Page,
     onProgress: (msg: string) => void,
   ): Promise<typeof this.credentials | null> {
     return new Promise((resolve) => {
       let resolved = false;
+      let interval: ReturnType<typeof setInterval> | undefined;
+
+      const cleanup = () => {
+        resolved = true;
+        clearTimeout(timeout);
+        if (interval) clearInterval(interval);
+        page.removeListener("request", requestHandler);
+      };
+
       const timeout = setTimeout(() => {
         if (!resolved) {
-          resolved = true;
+          cleanup();
           resolve(null);
         }
       }, 300000);

       const requestHandler = async (request: any) => {
         if (resolved) return;
         // ... existing logic ...
         if (headers["authorization"] || headers["cookie"]) {
           onProgress("检测到认证信息,正在保存...");
           const cookies = await page.context().cookies();
           const cookieStr = cookies.map((c) => `${c.name}=${c.value}`).join("; ");
-          resolved = true;
-          clearTimeout(timeout);
-          page.removeListener("request", requestHandler);
+          cleanup();
           resolve({ /* ... */ });
         }
       };

       // ... checkLogin function ...

-      const interval = setInterval(() => {
+      interval = setInterval(() => {
         if (resolved) {
           clearInterval(interval);
           return;
         }
         checkLogin();
       }, 2000);
     });
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web.ts` around lines 64 - 160, The interval started at the
bottom is not cleared on all exit paths causing a resource leak; move the
interval variable into the outer scope and ensure you call
clearInterval(interval) whenever you resolve (in the timeout handler, in
requestHandler when you capture credentials, and in the checkLogin success
branch), and also clearTimeout(timeout) and remove the "request" listener in
those same exit paths (requestHandler, checkLogin success, and timeout) so every
early/normal exit cleans interval, timeout and the listener (references:
timeout, interval, requestHandler, checkLogin).
src/providers/xiaomimo-web-auth.ts-161-251 (1)

161-251: ⚠️ Potential issue | 🟡 Minor

事件监听器未清理

page.on("request")page.on("response")page.on("framenavigated") 的事件监听器在凭据捕获成功或超时后从未被移除。这与 src/providers/mimo-web-auth.ts 中的问题相同。

建议提取监听器处理函数,并在 tryResolve 成功解析时调用清理函数移除所有监听器。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/xiaomimo-web-auth.ts` around lines 161 - 251, Event listeners
registered with page.on("request"), page.on("response") and
page.on("framenavigated") are never removed after capturedToken is set or
tryResolve completes; extract each listener into named handler functions (e.g.,
requestHandler, responseHandler, frameNavigatedHandler), add a cleanup function
that calls page.off(...) (or page.removeListener) to remove those handlers, and
invoke that cleanup inside tryResolve when it successfully resolves or on the
timeout/failure path so handlers are not left attached; ensure capturedToken and
tryResolve remain referenced so cleanup runs exactly when a token is captured or
the operation ends.
src/providers/mimo-web-client.ts-128-128 (1)

128-128: ⚠️ Potential issue | 🟡 Minor

避免使用 any 类型

多个方法参数和返回值使用了 any 类型:

  • 第 128 行:body?: any
  • 第 159 行:parseModels(data: any)
  • 第 182 行:createStreamFromResponse(data: any)

As per coding guidelines: "Maintain strict TypeScript typing - avoid using any type."

Also applies to: 159-159, 182-182

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web-client.ts` at line 128, 方法签名中使用了 any(makeRequest 的
body?: any,parseModels(data: any),createStreamFromResponse(data:
any));请替换为严格类型:为请求体定义具体接口或使用 Record<string, unknown> / unknown
并在函数体内做显式类型缩小/验证;为 parseModels 返回值和输入创建一个明确的 ModelResponse 接口并在
parseModels(data: unknown) 中做运行时校验;为 createStreamFromResponse 输入定义 StreamPayload
或类似类型并在函数内部转换/校验后再使用。更新 makeRequest、parseModels、createStreamFromResponse
的签名以使用这些新接口,确保任何 JSON.parse 或外部数据入口处都有类型守卫或转换函数以保持类型安全。
src/agents/mimo-web-stream.ts-37-37 (1)

37-37: ⚠️ Potential issue | 🟡 Minor

避免使用 any 类型

多处使用了 any 类型,违反了编码规范:

  • 第 37 行:messages as any
  • 第 102 行:transformMimoChunk(mimoChunk: any): any
  • 第 139 行:formatMimoTools(tools: any[]): any[]
♻️ 建议为 transformMimoChunk 添加类型
+interface MimoChunk {
+  id?: string;
+  object?: string;
+  created?: number;
+  model?: string;
+  content?: string;
+  text?: string;
+  response?: string;
+  message?: { content?: string };
+  choices?: Array<{ index: number; delta: { role?: string; content?: string }; finish_reason?: string | null }>;
+  finish_reason?: string;
+  done?: boolean;
+}

-function transformMimoChunk(mimoChunk: any): any {
+function transformMimoChunk(mimoChunk: MimoChunk): MimoChunk {

As per coding guidelines: "Maintain strict TypeScript typing - avoid using any type."

Also applies to: 102-102, 139-139

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/mimo-web-stream.ts` at line 37, Replace all uses of `any` by
introducing proper TypeScript interfaces and updating function signatures:
define a MimoMessage (or Message) interface and use it instead of `messages as
any` (e.g., messages: MimoMessage[]), create a MimoChunk (or RawMimoChunk) and
ProcessedChunk (or TransformedMimoChunk) interfaces and change the signature of
transformMimoChunk from `transformMimoChunk(mimoChunk: any): any` to
`transformMimoChunk(mimoChunk: MimoChunk): ProcessedChunk`, and define
RawTool/FormattedTool types and change `formatMimoTools(tools: any[]): any[]` to
`formatMimoTools(tools: RawTool[]): FormattedTool[]`; update all internal
property accesses in transformMimoChunk and formatMimoTools to match the new
interfaces so callers (including where `messages` is passed) get strict typing.
src/agents/xiaomimo-web-stream.ts-37-37 (1)

37-37: ⚠️ Potential issue | 🟡 Minor

避免使用 any 类型

根据编码规范,应避免使用 any 类型。以下位置使用了 any

  • 第 37 行:(context as any).sessionId
  • 第 435 行:currentMode = "error" as any
  • 第 544 行:} as any);

建议扩展类型定义以包含所需的属性,或使用更具体的类型断言。

♻️ 针对第 37 行的建议

考虑扩展 context 类型或使用类型守卫:

-const sessionKey = model.id + ((context as any).sessionId ? `:${(context as any).sessionId}` : '');
+const contextWithSession = context as typeof context & { sessionId?: string };
+const sessionKey = model.id + (contextWithSession.sessionId ? `:${contextWithSession.sessionId}` : '');

As per coding guidelines: "Maintain strict TypeScript typing - avoid using any type."

Also applies to: 435-435, 544-544

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/xiaomimo-web-stream.ts` at line 37, The code uses `any` in three
places—building sessionKey, assigning currentMode, and a final object cast—so
add/extend proper TypeScript types and replace the unsafe casts: declare or
extend an interface (e.g., AgentContext { sessionId?: string }) and use that
type for the `context` parameter or a local typed variable to access `sessionId`
instead of `(context as any).sessionId`; change `currentMode = "error" as any`
to use the correct union/enum type or a properly typed variable (e.g.,
CurrentMode = "idle" | "running" | "error") and assign `"error"` without `any`;
and replace the final `} as any` cast with the actual interface/type for that
object so the compiler can verify properties—update function signatures or local
type assertions to these specific types rather than using `any`.
src/agents/xiaomimo-web-stream.ts-91-92 (1)

91-92: ⚠️ Potential issue | 🟡 Minor

模板字符串中的换行符

模板字符串中的换行符可能导致输出格式异常(</think> 标签前有额外的换行)。

♻️ 建议的修复
                 } else if (part.type === "thinking") {
-                  content += `<think>\n${part.thinking}\n
-</think>\n`;
+                  content += `<think>\n${part.thinking}\n</think>\n`;
                 } else if (part.type === "toolCall") {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/xiaomimo-web-stream.ts` around lines 91 - 92, 在
xiaomimo-web-stream.ts 中构建 content 的模板字面量在插入 part.thinking 后多出一个换行,导致 </think>
前有额外空行;修复方法:修改生成模板的位置(涉及变量 content 和 part.thinking)去掉多余的换行,例如将模板从在 </think>
前留空行的写法改为直接闭合(或对 part.thinking 使用 trimEnd())以确保没有多余的换行。
src/providers/xiaomimo-web-auth.ts-253-258 (1)

253-258: ⚠️ Potential issue | 🟡 Minor

页面关闭时的清理不完整

当页面关闭时,reject 被调用但 timeout 未被清除,且 resolved 未设置为 true。这意味着超时处理器仍可能触发,导致在 Promise 已拒绝后再次调用 reject(虽然第二次调用不会有影响,但逻辑不完整)。

🛡️ 建议的修复
       page.on("close", () => {
+        if (resolved) return;
+        resolved = true;
+        clearTimeout(timeout);
         if (checkInterval) clearInterval(checkInterval);
         reject(new Error("Browser window closed before login was captured."));
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/xiaomimo-web-auth.ts` around lines 253 - 258, When handling the
page "close" event, ensure full cleanup by clearing the timeout and interval and
marking the operation resolved to prevent the timeout/tryResolve from firing
after reject; specifically, inside the page.on("close") handler (the callback
that currently clears checkInterval and calls reject), also clear the timeout
variable (clearTimeout(timeout)), set resolved = true, and ensure checkInterval
is cleared (clearInterval(checkInterval)) so tryResolve cannot run after the
Promise has been rejected.
src/agents/xiaomimo-web-stream.ts-26-43 (1)

26-43: ⚠️ Potential issue | 🟡 Minor

未使用的客户端实例和变量遮蔽

第 26 行创建了一个 client 实例,但在第 39 行又声明了一个同名的 let client 变量,这会遮蔽外部的 client。实际上,第 26 行创建的 client 从未被使用。

♻️ 建议的修复
 export function createXiaomiMimoWebStreamFn(cookieOrJson: string): StreamFn {
   let options: XiaomiMimoWebClientOptions;
   try {
     const parsed = JSON.parse(cookieOrJson);
     options = { cookie: parsed.cookie || cookieOrJson };
   } catch {
     options = { cookie: cookieOrJson };
   }
-  const client = new XiaomiMimoWebClientBrowser(options);

   return (model, context, streamOptions) => {
     const stream = createAssistantMessageEventStream();

     const run = async () => {
       try {
         console.log('[XiaomiMimoWebStream] context keys:', Object.keys(context).join(', '));
         const messages = context.messages;
         const systemPrompt = context.systemPrompt || "";
         const tools = context.tools || [];
         const sessionKey = model.id + ((context as any).sessionId ? `:${(context as any).sessionId}` : '');
         const sessionId = sessionMap.get(sessionKey);
-        let client = clientMap.get(sessionKey);
+        const client = clientMap.get(sessionKey) ?? new XiaomiMimoWebClientBrowser(options);
         if (!client) {
-          client = new XiaomiMimoWebClientBrowser(options);
           clientMap.set(sessionKey, client);
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/xiaomimo-web-stream.ts` around lines 26 - 43, The top-level
creation of client using XiaomiMimoWebClientBrowser is unused and is shadowed by
a later local "let client" inside the returned function; remove the unused outer
"const client = new XiaomiMimoWebClientBrowser(options)" (or rename/repurpose
it) and ensure the function uses the client obtained from clientMap (the local
"client" tied to sessionKey) so there is no variable shadowing; update any
references to "client" to consistently use the client from clientMap and keep
only one client creation point related to sessionKey/sessionMap.
src/agents/xiaomimo-web-stream.ts-149-149 (1)

149-149: ⚠️ Potential issue | 🟡 Minor

变量名遮蔽

第 149 行的 messages 变量遮蔽了第 34 行从 context.messages 获取的 messages。这可能导致混淆。

♻️ 建议的修复
-            const messages = prompt.split(/\n\n(?=User:|Assistant:)/);
+            const promptParts = prompt.split(/\n\n(?=User:|Assistant:)/);
             let accumulated = "";
-            for (let i = messages.length - 1; i >= 0; i--) {
-              const candidate = messages[i] + (accumulated ? "\n\n" + accumulated : "");
+            for (let i = promptParts.length - 1; i >= 0; i--) {
+              const candidate = promptParts[i] + (accumulated ? "\n\n" + accumulated : "");
               if (candidate.length > MAX_PROMPT_LENGTH) {
                 break;
               }
               accumulated = candidate;
             }
             if (!accumulated) {
-              const lastMessage = messages[messages.length - 1];
+              const lastMessage = promptParts[promptParts.length - 1];
               accumulated = lastMessage.slice(-MAX_PROMPT_LENGTH);
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/xiaomimo-web-stream.ts` at line 149, The local variable named
messages created by const messages = prompt.split(/\n\n(?=User:|Assistant:)/)
shadows the earlier messages obtained from context.messages (around where
context.messages is read); rename the local variable (e.g., promptMessages or
parsedMessages) and update all subsequent uses in this scope to that new name so
there is no shadowing and the original context.messages remains unambiguous.
src/providers/mimo-web-auth.ts-63-118 (1)

63-118: ⚠️ Potential issue | 🟡 Minor

事件监听器未清理 - 潜在内存泄漏

page.on("request")page.on("load") 事件监听器在凭据捕获成功或超时后从未被移除。这可能导致:

  1. 内存泄漏(如果页面对象长期存在)
  2. 在凭据已捕获后仍然执行多余的处理逻辑

建议在 resolve 之前使用 page.off()page.removeListener() 移除监听器。

🛡️ 建议的修复方向
 async function captureMimoCredentials(
   page: Page,
   onProgress: (msg: string) => void,
 ): Promise<MimoAuthCredentials | null> {
   return new Promise((resolve) => {
     let captured = false;
+    
+    const requestHandler = async (request: any) => {
+      // ... existing request handling logic
+    };
+    
+    const loadHandler = async () => {
+      // ... existing load handling logic  
+    };
+    
+    const cleanup = () => {
+      page.off("request", requestHandler);
+      page.off("load", loadHandler);
+    };
+
     const timeout = setTimeout(() => {
       if (!captured) {
+        cleanup();
         onProgress("Timeout waiting for MiMo login");
         resolve(null);
       }
     }, 300000);

-    page.on("request", async (request) => {
+    page.on("request", requestHandler);
+    page.on("load", loadHandler);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web-auth.ts` around lines 63 - 118, The page request and
load event handlers (the page.on("request") listener in this snippet and the
page.on("load") listener used elsewhere) are never removed, causing potential
memory leaks and extra work after credentials are captured or on timeout; update
the capture flow so that before calling resolve(...) or on timeout/reject you
remove both listeners (use page.off or page.removeListener for the same handler
references), clear the timeout, and ensure you stop further processing (e.g.,
check captured flag) — specifically remove the request handler defined for
page.on("request") and the corresponding load handler wherever it is registered,
then call resolve/reject.
src/providers/mimo-web-auth.ts-93-93 (1)

93-93: ⚠️ Potential issue | 🟡 Minor

变量名遮蔽

循环变量 cookie 遮蔽了外部作用域中第 75 行定义的 cookie 变量(请求头中的 cookie 字符串)。这会导致混淆且容易出错。

♻️ 建议的修复
-            for (const cookie of cookies) {
+            for (const c of cookies) {
               if (
-                cookie.name.includes("session") ||
-                cookie.name.includes("token") ||
-                cookie.name.includes("auth")
+                c.name.includes("session") ||
+                c.name.includes("token") ||
+                c.name.includes("auth")
               ) {
-                sessionId = cookie.value;
+                sessionId = c.value;
                 break;
               }
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web-auth.ts` at line 93, The loop variable "cookie" in the
for (const cookie of cookies) statement shadows the outer "cookie" variable
defined earlier (request header cookie string) — rename the loop variable (e.g.,
cookiePair or parsedCookie) and update all usages inside that loop (the for...of
block) to the new name so the outer "cookie" variable is not shadowed; ensure
any comparisons or assignments that previously referenced the inner "cookie" now
use the new identifier.
src/providers/mimo-web-client.ts-146-150 (1)

146-150: ⚠️ Potential issue | 🟡 Minor

移除冗余的 credentials: "include" 选项

credentials: "include" 是浏览器 fetch 选项,虽然 Node.js 的 fetch(18+)在语法上接受此选项,但在 Node.js 中它没有任何实际效果。由于代码已经通过 Cookie 请求头(第 135 行)手动管理 cookies,此选项是冗余的,会造成代码混淆。建议移除此选项以明确代码意图仅针对 Node.js 环境。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web-client.ts` around lines 146 - 150, Remove the
redundant browser-specific credentials: "include" entry from the RequestInit
object named options in the function where you build the request (const options:
RequestInit = { method, headers, ... }). The Node.js fetch call already manages
cookies via the manually-set Cookie header (see headers variable), so delete the
credentials property from options and ensure no other code relies on it before
committing.
🧹 Nitpick comments (24)
src/agents/grok-web-stream.ts (1)

510-512: 避免使用 as any 类型断言

根据编码规范,应避免使用 any 类型。此处的 as any 类型断言绕过了 TypeScript 的类型检查。

♻️ 建议修复

考虑为错误事件定义正确的类型,或使用更精确的类型断言:

-        } as any);
+        } as Parameters<typeof stream.push>[0]);

或者定义一个明确的错误事件类型接口。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/grok-web-stream.ts` around lines 510 - 512, Replace the unsafe "as
any" cast on the emitted error payload with a proper typed shape: define an
interface (e.g., ErrorEventPayload) matching the object fields (including
timestamp) and use that type where the object is passed instead of "as any";
alternatively, if an existing event type exists in this module, cast to that
specific type. Update the function/method that constructs/emits the event (the
spot creating the object with timestamp: Date.now()) to return/accept the
concrete type so TypeScript checks the payload structure rather than bypassing
it with "any".
src/providers/gemini-web-client-browser.ts (1)

231-231: 可选改进:提取长度阈值常量

代码中使用了多个长度阈值(20、30、40、50 字符),它们分别用于不同的过滤场景。虽然当前实现功能正常,但可以考虑将这些"魔法数字"提取为命名常量以提升代码可读性:

const UI_ELEMENT_MIN_LENGTH = 20;  // isSkip 使用
const MODEL_RESPONSE_MIN_LENGTH = 30;  // 模型响应选择器策略
const FINAL_RESPONSE_MIN_LENGTH = 40;  // 最终有效响应
const TEXT_BLOCK_MIN_LENGTH = 50;  // 文本块候选

当前分层过滤逻辑是合理的,此项为代码可维护性的细微优化。

Also applies to: 270-270, 284-284, 299-300

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/gemini-web-client-browser.ts` at line 231, The code uses
multiple magic numeric length thresholds (e.g., 20, 30, 40, 50) in filtering
expressions such as the skip check (skipTexts.some((s) => t.includes(s)) ||
isGreeting(t) || t.length < 20) and other selection logic; extract these
literals into clearly named constants (e.g., UI_ELEMENT_MIN_LENGTH,
MODEL_RESPONSE_MIN_LENGTH, FINAL_RESPONSE_MIN_LENGTH, TEXT_BLOCK_MIN_LENGTH) and
replace the raw numeric comparisons in the functions/expressions that reference
skipTexts, isGreeting, and the response selection logic so the intent is
explicit and maintainable.
auth-summary.md (1)

86-88: 补充跨平台启动说明

当前仅提供了 Windows 的 Chrome 启动命令。考虑到 README 中提到项目支持 macOS/Linux/Windows(WSL2),建议补充其他平台的启动方式或引用现有的 start-chrome-debug.sh 脚本。

💡 建议的改进方案
 ## 注意事项
 
 1. **Chrome 调试模式**: 确保 Chrome 已启动调试模式
-   - Windows: `chrome.exe --remote-debugging-port=9222`
+   ```bash
+   # macOS/Linux
+   ./start-chrome-debug.sh
+   
+   # Windows (如果不使用脚本)
+   chrome.exe --remote-debugging-port=9222
+   ```
 2. **认证有效期**: Web 模型认证通常有有效期,需要定期重新认证
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@auth-summary.md` around lines 86 - 88, 在“Chrome 调试模式”项补充跨平台启动说明:在现有只列出
Windows 的 chrome.exe --remote-debugging-port=9222 之外,加入 macOS/Linux
的启动方法或明确引用现有脚本 start-chrome-debug.sh(例如说明可运行 ./start-chrome-debug.sh 来启动带远程调试端口的
Chrome),并保留 Windows 的手动命令作为备用说明;确保文本简洁、与 README 中声明的 macOS/Linux/Windows(WSL2)
支持一致并示例化如何在各平台启动调试模式。
src/agents/pi-embedded-runner/run/attempt.ts (1)

1258-1357: 建议把 Web provider 分发提取为映射表,减少重复分支

这次新增 xiaomimo-web 分支与既有分支完全同构;继续沿用长链 else if 会让后续 provider 接入和回归测试成本持续上升。

💡 可选重构方向
+const WEB_STREAM_FACTORIES: Record<string, (cookie: string) => StreamFn> = {
+  "deepseek-web": createDeepseekWebStreamFn as unknown as (cookie: string) => StreamFn,
+  "claude-web": createClaudeWebStreamFn as unknown as (cookie: string) => StreamFn,
+  "doubao-web": createDoubaoWebStreamFn as unknown as (cookie: string) => StreamFn,
+  "chatgpt-web": createChatGPTWebStreamFn as unknown as (cookie: string) => StreamFn,
+  "qwen-web": createQwenWebStreamFn as unknown as (cookie: string) => StreamFn,
+  "kimi-web": createKimiWebStreamFn as unknown as (cookie: string) => StreamFn,
+  "gemini-web": createGeminiWebStreamFn as unknown as (cookie: string) => StreamFn,
+  "grok-web": createGrokWebStreamFn as unknown as (cookie: string) => StreamFn,
+  "glm-web": createGlmWebStreamFn as unknown as (cookie: string) => StreamFn,
+  "glm-intl-web": createGlmIntlWebStreamFn as unknown as (cookie: string) => StreamFn,
+  "xiaomimo-web": createXiaomiMimoWebStreamFn as unknown as (cookie: string) => StreamFn,
+};
@@
-      } else if (params.model.api === "xiaomimo-web") {
-        const cookie = (await params.authStorage.getApiKey("xiaomimo-web")) || "";
-        if (cookie) {
-          activeSession.agent.streamFn = createXiaomiMimoWebStreamFn(cookie) as StreamFn;
-          ensureCustomApiRegistered(params.model.api, activeSession.agent.streamFn);
-        } else {
-          log.warn(`[web-stream] no API key for xiaomimo-web`);
-          activeSession.agent.streamFn = streamSimple;
-        }
+      } else if (params.model.api && WEB_STREAM_FACTORIES[params.model.api]) {
+        const api = params.model.api;
+        const cookie = (await params.authStorage.getApiKey(api)) || "";
+        if (cookie) {
+          activeSession.agent.streamFn = WEB_STREAM_FACTORIES[api](cookie);
+          ensureCustomApiRegistered(api, activeSession.agent.streamFn);
+        } else {
+          log.warn(`[web-stream] no API key for ${api}`);
+          activeSession.agent.streamFn = streamSimple;
+        }
       }

As per coding guidelines: Keep files concise; extract helpers instead of "V2" copies. Use existing patterns for CLI options and dependency injection via createDefaultDeps.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/pi-embedded-runner/run/attempt.ts` around lines 1258 - 1357, The
long chain of else-if blocks setting activeSession.agent.streamFn for each web
provider (checking params.model.api, calling create*WebStreamFn and
ensureCustomApiRegistered or defaulting to streamSimple) should be replaced with
a mapping-driven helper to remove duplication: create a map from provider key
(e.g., "chatgpt-web", "xiaomimo-web") to the corresponding factory function
(createChatGPTWebStreamFn, createXiaomiMimoWebStreamFn, etc.), then implement a
helper like getWebStreamFnFor(provider, authStorage) that looks up the factory,
fetches the cookie via params.authStorage.getApiKey(provider), returns the
created streamFn (or streamSimple when missing) and calls
ensureCustomApiRegistered when present; replace the entire else-if sequence with
a single call that assigns activeSession.agent.streamFn = await
getWebStreamFnFor(params.model.api, params.authStorage) so future providers only
need a map entry and follow existing createDefaultDeps patterns.
src/commands/onboard-auth.config-core.ts (1)

618-618: 括号分组改进是正确的。

existingProvider?.models as any[] || [] 改为 (existingProvider?.models as any[]) || [] 使类型断言的作用范围更加明确,提高了代码可读性。

注意:这些行使用了 as any[] 类型断言,这与项目的严格类型规范有冲突。建议在后续重构中为 existingProvider?.models 定义更精确的类型。

Also applies to: 647-647, 676-676, 705-705, 734-734, 763-763, 792-792, 821-821, 850-850, 879-879

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/onboard-auth.config-core.ts` at line 618, Wrap the type
assertion so it applies to the optional property before the fallback: change the
occurrences where `existingProvider?.models as any[] || []` is used (notably the
`defaultModels` assignment in onboard-auth.config-core and the similar lines
mentioned) to use a grouped assertion `(existingProvider?.models as any[]) ||
[]`; update all listed occurrences (lines referenced in the review) to the same
pattern to ensure the type assertion scope is correct and keep a note to replace
`any[]` with a precise type in future refactors.
extensions/askonce/src/askonce/adapters/gemini.ts (1)

5-8: LGTM!

引号风格统一从单引号改为双引号。适配器元数据、凭证类型检查和响应状态字符串的格式化保持一致。

注意:Line 94 中的 as any 类型断言是既有代码,建议在后续重构中为 modelcontext 参数提供更精确的类型定义,以符合严格类型规范。

Also applies to: 10-17, 33-33, 46-51, 59-81, 88-89, 94-94, 96-96, 99-123

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/askonce/src/askonce/adapters/gemini.ts` around lines 5 - 8,
Summary: remove the loose "as any" assertion for the Gemini adapter and add
precise types for the model and context parameters. Fix: locate the
function/method in this file that currently casts model and/or context with "as
any" (used when calling createGeminiWebStreamFn or inside the adapter
implementation that extends BaseAdapter), replace the assertion by declaring
concrete parameter types (e.g., create/consume specific GeminiModel and
GeminiContext types or reuse ModelResponse/AdapterQueryOptions where
appropriate), update imports to include any new types, and adjust call sites to
satisfy the stricter types; also ensure the file continues to use double-quote
string style consistently. Reference symbols: createGeminiWebStreamFn,
BaseAdapter, ModelResponse, AdapterQueryOptions, and the local model/context
parameters that are currently cast "as any".
extensions/askonce/src/index.ts (1)

70-70: 建议使用严格类型替代 any

options: any 使用了 any 类型,这违反了编码规范中关于避免 any 的要求。建议定义具体的选项接口类型。

♻️ 建议的类型定义
interface AskOnceOptions {
  models?: string;
  timeout?: string;
  output?: string;
  file?: string;
  stream?: boolean;
  list?: boolean;
}

然后将 options: any 改为 options: AskOnceOptions

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/askonce/src/index.ts` at line 70, Replace the use of the unsafe
any type for the CLI options in runAskOnce by declaring a concrete interface
(e.g., AskOnceOptions) that lists the expected properties (models?: string,
timeout?: string, output?: string, file?: string, stream?: boolean, list?:
boolean) and change the function signature from options: any to options:
AskOnceOptions; update any internal references or destructuring in runAskOnce to
rely on the typed properties so the compiler can check usage.
extensions/web-models/index.ts (1)

312-312: as any 类型断言可能隐藏类型问题。

api: provider.id as any 的类型断言表明 provider.id 的类型与期望的 api 字段类型不兼容。考虑扩展 api 类型定义以包含新的提供商 ID。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/web-models/index.ts` at line 312, The code uses a blanket
assertion "api: provider.id as any" which hides a real type mismatch; update the
types so provider.id matches the api property's declared type instead of using
any — locate the assignment of api (the object where api: provider.id as any is
set) and either widen the api field's type union to include the provider.id
values or cast provider.id to the correct specific type (e.g., the api
enum/type) and adjust the provider id definition accordingly (references:
provider.id and the api property in the object in
extensions/web-models/index.ts).
src/commands/auth-choice.apply.glm-web.ts (1)

33-39: 格式化可简化。

openUrl 回调的显式包装略显冗余,但功能正确。如果 openUrl 已经返回 Promise<boolean> 或兼容类型,可以直接使用简写形式。

♻️ 可选的简化形式
-        openUrl: async (url) => {
-          await openUrl(url);
-          return true;
-        },
+        openUrl,

注意:仅当 openUrl 函数本身返回符合预期的类型时适用。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/auth-choice.apply.glm-web.ts` around lines 33 - 39, 简短:loginZWeb
的 openUrl 回调显式包裹成 async (url) => { await openUrl(url); return true; } 冗余;如果外部
openUrl 已返回 Promise<boolean>(或兼容类型),请直接传入该函数以简化代码:在调用 loginZWeb 时将 openUrl
作为回调(而保留 onProgress: (msg) => spin.update(msg) 不变),并删除多余的 async 包装器,确保
loginZWeb、openUrl 和 spin.update 的预期返回类型仍然匹配。
extensions/askonce/src/askonce/adapters/grok.ts (1)

93-93: 避免使用 as any 类型断言。

根据编码规范,应保持严格的 TypeScript 类型,避免使用 any。这里使用了两次 as any 断言来绕过类型检查。

建议为 streamFn 的参数创建合适的类型定义,或者在 grok-web-stream.ts 中导出相应的类型以便复用。

♻️ 建议的类型改进方向
+// 在 grok-web-stream.ts 或 types.ts 中定义
+interface StreamModel {
+  id: string;
+  api: string;
+  provider: string;
+}
+
+interface StreamContext {
+  messages: Array<{ role: string; content: string }>;
+  systemPrompt: string;
+  tools: unknown[];
+  sessionId: string;
+}

-const stream = streamFn(model as any, context as any, { signal: options?.signal });
+const stream = streamFn(model as StreamModel, context as StreamContext, { signal: options?.signal });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/askonce/src/askonce/adapters/grok.ts` at line 93, The call to
streamFn currently uses two unsafe `as any` assertions; replace them by
importing or defining proper TypeScript types for the stream function signature
and the model/context objects (e.g. export the StreamFn type from
grok-web-stream.ts or declare ModelType/ContextType there), update the streamFn
variable to be typed as StreamFn and the parameters `model` and `context` to
their concrete types, and then call streamFn(model, context, { signal:
options?.signal }) without `as any` casts so the call is fully type-checked.
extensions/askonce/src/askonce/adapters/qwen-cn.ts (1)

93-93: 与其他适配器相同的 as any 问题。

建议在重构时统一处理所有适配器中的类型断言问题,创建共享的类型定义。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/askonce/src/askonce/adapters/qwen-cn.ts` at line 93, The call to
streamFn in qwen-cn.ts uses broad "as any" casts (streamFn(model as any, context
as any, { signal: options?.signal })) which hides typing errors; replace these
ad-hoc casts by introducing or importing a shared adapter type for Model,
Context, and StreamOptions used across adapters and update the call to use those
concrete types (e.g., ensure streamFn, model, context, and options are typed to
the new shared interfaces) so you can remove the "as any" assertions and keep
type-safety consistent with other adapters.
src/commands/onboard-web-auth.ts (1)

53-92: 建议为新提供商添加模型别名映射。

modelAliases 对象中没有为 xiaomimo-web 定义别名映射。虽然代码会回退到使用原始 modelId,但为保持一致性,建议添加相应的别名。

♻️ 建议添加 xiaomimo-web 别名
     "qwen-cn-web": {
       "qwen-turbo": "Qwen CN Web",
     },
+    "xiaomimo-web": {
+      "xiaomimo-chat": "Xiaomi MiMo Chat",
+    },
   };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/onboard-web-auth.ts` around lines 53 - 92, Add an entry for
"xiaomimo-web" inside the existing modelAliases mapping so the onboarding flow
uses friendly names instead of raw modelId for that provider; update the
modelAliases object (the variable named modelAliases in this file) to include a
"xiaomimo-web" key mapping its known model IDs to display names (e.g., map the
xiaomimo model IDs to appropriate human-friendly aliases consistent with the
other provider entries).
extensions/askonce/src/askonce/adapters/deepseek.ts (1)

94-94: 与其他适配器相同的 as any 问题。

此处与 grok.ts 存在相同的类型断言问题。建议在统一修复时,为所有适配器创建共享的流函数参数类型定义。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/askonce/src/askonce/adapters/deepseek.ts` at line 94, The current
cast "as any" used when calling streamFn in deepseek.ts (const stream =
streamFn(model as any, context as any, { signal: options?.signal });) mirrors
the same unsafe typing in grok.ts; replace these ad-hoc casts by introducing a
shared StreamFunction parameter type (e.g., StreamFnParams or StreamInvokeArgs)
used across adapters and update streamFn's signature to consume that type so you
can call streamFn(model, context, { signal: options?.signal }) without casts;
apply the same shared type to other adapters (grok.ts and any similar files) and
adjust their streamFn declarations/consumers accordingly.
src/commands/auth-choice.apply.mimo-web.ts (1)

9-10: 改进类型安全性。

  1. argv 参数未指定类型
  2. globalThis as any 绕过了类型检查

建议定义适当的类型来描述 __openclaw_browser__ 的结构。

♻️ 建议的类型改进
+import type { Browser, Page } from "playwright-core";
+
+interface OpenClawBrowserContext {
+  browser: Browser;
+  page: Page;
+}
+
+declare global {
+  var __openclaw_browser__: Promise<OpenClawBrowserContext> | undefined;
+}
+
 export const mimoWebAuthCommand: CommandModule = {
   command: "mimo-web",
   describe: "Authenticate with Xiaomi MiMo-Web via browser login",
-  handler: async (argv) => {
-    const { browser, page } = await (globalThis as any).__openclaw_browser__;
+  handler: async (_argv) => {
+    if (!globalThis.__openclaw_browser__) {
+      throw new Error("Browser context not initialized");
+    }
+    const { browser, page } = await globalThis.__openclaw_browser__;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/auth-choice.apply.mimo-web.ts` around lines 9 - 10, The
handler's signature and use of globalThis.__openclaw_browser__ are currently
untyped (handler: async (argv) and globalThis as any), so add proper TypeScript
types: declare an interface describing the runtime object (e.g., an
OpenClawBrowser shape containing browser and page) and augment globalThis (or
add a global.d.ts) so __openclaw_browser__ has that type; then update the
handler parameter to a concrete type (or unknown/Record if appropriate) and
replace the any cast with a typed access to (globalThis as unknown as {
__openclaw_browser__: OpenClawBrowser }). This ensures the references to browser
and page inside handler are type-checked and documents the expected structure
for __openclaw_browser__.
extensions/askonce/src/cli.ts (2)

101-106: 进度回调中的 event 参数使用了 any 类型。

应使用 ProgressEvent 类型(已在 types.ts 中定义)。

♻️ 建议的修复
+import type { ProgressEvent } from "../askonce/types.js";
+
-  const onProgress = (event: any) => {
+  const onProgress = (event: ProgressEvent) => {
     if (options.stream) {
       process.stdout.write(`\r[${event.modelId}] ${event.type}...`);
     }
   };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/askonce/src/cli.ts` around lines 101 - 106, The onProgress
callback currently types its parameter as any; replace that with the defined
ProgressEvent type from types.ts so the signature becomes onProgress(event:
ProgressEvent) and update any imports to pull ProgressEvent from the module;
ensure references to event.modelId and event.type remain valid with the
ProgressEvent shape in types.ts (function name: onProgress, parameter: event,
type: ProgressEvent).

46-49: options 参数使用了 any 类型。

根据编码规范应避免使用 any。建议定义具体的选项接口类型。

♻️ 建议的类型定义
+interface AskOnceCliOptions {
+  list?: boolean;
+  models?: string;
+  output?: "console" | "markdown" | "json";
+  timeout?: string;
+  stream?: boolean;
+  file?: string;
+}
+
 export async function registerAskOnceCli(
   program: Command,
-  options: any,
+  options: AskOnceCliOptions,
   question?: string[],
 ): Promise<void> {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/askonce/src/cli.ts` around lines 46 - 49, 函数 registerAskOnceCli
的参数 options 使用了 any,应改为具体类型以遵守编码规范:定义一个接口(例如
AskOnceCliOptions)列出所有可能的选项字段和类型(可选字段用 ? 标注),将 registerAskOnceCli(program:
Command, options: AskOnceCliOptions, question?: string[])
的签名更新为使用该接口,导出该接口供外部使用,并在函数体内/调用处修复因类型更改引入的任何属性访问或默认值处理(如用可选链和默认值赋值);同时更新相关调用点和测试以匹配新类型。
src/providers/mimo-web.ts (3)

1-1: 应使用 import type 导入仅用于类型的 Playwright 类型。

BrowserPage 仅用于方法签名中的类型标注,应使用 import type 以符合编码规范并优化打包体积。

♻️ 建议修复
-import { Browser, Page } from "playwright";
+import type { Browser, Page } from "playwright";

As per coding guidelines: "Use import type { X } for type-only imports in TypeScript files."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web.ts` at line 1, The Playwright types Browser and Page
are used only for type annotations—change the import to a type-only import by
replacing the current import of Browser and Page with an import type for those
symbols (i.e., use import type { Browser, Page } from "playwright") so
TypeScript treats them as type-only and bundlers can tree-shake appropriately;
update the import statement that currently references Browser and Page to use
import type and leave any runtime imports unchanged.

200-242: chat 方法静默吞掉错误,可能导致调试困难。

第 236-238 行的 catch (e) { continue; } 会静默忽略所有错误。建议至少记录错误信息,或者累积错误以便在所有端点都失败时提供更有用的诊断信息。

💡 建议:记录或累积错误信息
+    const errors: string[] = [];
     for (const endpoint of endpoints) {
       try {
         const response = await fetch(endpoint, {
           // ...
         });

         if (response.ok) {
           return await response.json();
         }
+        errors.push(`${endpoint}: HTTP ${response.status}`);
       } catch (e) {
+        errors.push(`${endpoint}: ${e instanceof Error ? e.message : String(e)}`);
         continue;
       }
     }

-    throw new Error("无法连接到 MiMo API");
+    throw new Error(`无法连接到 MiMo API: ${errors.join("; ")}`);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web.ts` around lines 200 - 242, The chat method currently
swallows all exceptions in the for-loop catch (e) { continue; }, making failures
hard to diagnose; update chat to record/log each error (e.g., push error
messages into an errors array and/or call this.logger.error/console.error inside
the catch) and also capture non-OK responses (include response.status/text) so
that when all endpoints fail you throw a new Error that includes the accumulated
error details (instead of the opaque "无法连接到 MiMo API"); reference the chat
function, the endpoints array, the catch block and the final throw so you
collect and surface useful diagnostics.

74-74: 避免使用 any 类型以保持类型安全。

第 74 行的 request: any 和第 179 行的 cookies: any[] 使用了 any 类型,违反了严格类型检查规范。

♻️ 建议使用具体类型
-      const requestHandler = async (request: any) => {
+      const requestHandler = async (request: import("playwright").Request) => {

-  private extractSessionId(cookies: any[]): string | undefined {
+  private extractSessionId(cookies: Array<{ name: string; value: string }>): string | undefined {

As per coding guidelines: "Maintain strict TypeScript typing - avoid using any type."

Also applies to: 179-179

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web.ts` at line 74, Replace the use of the unsafe any
types by defining and using concrete types: change the request param type in
requestHandler to a specific request interface (e.g. MimoRequest or the
framework's Request type) and replace cookies: any[] with a typed array (e.g.
Cookie[] or string[]), creating a Cookie interface if needed; update the
function signature for requestHandler and any other functions referencing
cookies to use these new types and import framework request types where
appropriate (symbols to edit: requestHandler and the cookies parameter).
src/providers/xiaomimo-web-auth.ts (1)

125-127: 生产环境中的调试日志

代码中包含多个 console.log 语句用于调试。考虑在生产环境中使用结构化日志记录器,或确保这些日志在正常情况下不会过于频繁地输出。

Also applies to: 144-144, 151-153, 156-156

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/xiaomimo-web-auth.ts` around lines 125 - 127, Replace all
console.log calls in src/providers/xiaomimo-web-auth.ts (the debug prints that
show cookie counts and related messages at the locations referenced) with the
project's structured logger and appropriate log level (e.g., logger.debug or
processLogger.debug) and/or guard them behind an environment or debug flag so
they don't spam production; update each occurrence (the console.log at the
cookies map and the other occurrences noted) to call the shared logger instance
and include the same message text and contextual fields rather than raw console
output.
src/providers/mimo-web-auth.ts (1)

1-3: 移除未使用的导入并使用类型导入

EventEmitter 被导入但从未使用。另外,BrowserPage 仅用作类型注解,应使用 import type

♻️ 建议的修复
-import { EventEmitter } from "events";
-// src/providers/mimo-web-auth.ts
-import { Browser, Page } from "playwright";
+// src/providers/mimo-web-auth.ts
+import type { Browser, Page } from "playwright";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web-auth.ts` around lines 1 - 3, Remove the unused
EventEmitter import and change the Playwright type imports to type-only imports:
replace the current import of Browser and Page with an `import type` for Browser
and Page and delete the EventEmitter import so only needed type imports remain;
target the imports referencing EventEmitter, Browser, and Page in
mimo-web-auth.ts.
src/agents/xiaomimo-web-stream.ts (1)

15-16: 模块级缓存无清理机制

sessionMapclientMap 是模块级 Map,会随着不同会话的使用而持续增长,但没有清理机制。在长时间运行的进程中,这可能导致内存泄漏。

考虑实现以下方案之一:

  • 设置最大缓存大小,使用 LRU 策略淘汰旧条目
  • 提供显式的清理函数
  • 使用 WeakMap(如果适用)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/xiaomimo-web-stream.ts` around lines 15 - 16, sessionMap and
clientMap are module-level Maps that can grow without bound; add a bounded cache
or explicit cleanup to avoid leaks: replace or wrap these Maps with an
LRU-capable structure (e.g., an LRUMap) or implement size checks on set to evict
oldest entries, and expose an explicit API like clearSessionCache() and
removeClient(sessionId: string) to allow callers to drop entries; alternatively
evaluate using WeakMap for clientMap if keys are objects and lifecycle matches.
Update usages of sessionMap and clientMap in XiaomiMimoWebClientBrowser-related
code to use the new cache API (get/set/delete/clear) so eviction and explicit
cleanup are honored.
src/providers/mimo-web-client.ts (1)

54-56: 空的 catch 块吞噬错误信息

空的 catch 块会吞噬错误信息,使调试变得困难。至少应该记录警告或保留错误信息。

♻️ 建议的修复
     } catch (error) {
-      console.warn("Failed to fetch MiMo models via API, using defaults");
+      console.warn("Failed to fetch MiMo models via API, using defaults:", error instanceof Error ? error.message : error);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web-client.ts` around lines 54 - 56, The catch block that
handles failures when fetching MiMo models via API currently swallows the error;
update the catch after the API fetch (the try/catch handling "Failed to fetch
MiMo models via API, using defaults") to log the caught error details (e.g.,
include the error object or its message/stack) instead of discarding it so
debugging info is preserved; keep the existing fallback behavior but change the
console.warn call to include the error information (or use the project's logger
if available).
src/agents/mimo-web-stream.ts (1)

45-47: 错误处理丢失堆栈信息

当前错误处理将原始错误转换为字符串,丢失了堆栈跟踪信息,这会使调试变得困难。

♻️ 建议的修复
     } catch (error) {
-      throw new Error(`MiMo stream error: ${error}`);
+      const message = error instanceof Error ? error.message : String(error);
+      const wrappedError = new Error(`MiMo stream error: ${message}`);
+      if (error instanceof Error && error.stack) {
+        wrappedError.stack = error.stack;
+      }
+      throw wrappedError;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/mimo-web-stream.ts` around lines 45 - 47, The catch block in
mimo-web-stream.ts currently replaces the original error with a new Error
containing only the stringified error, losing the original stack; update the
catch to preserve the original error (either by throwing a new Error that uses
the native "cause" option with the original error as cause, or by attaching the
original error.stack to the new error before throwing) so the stack trace and
original error metadata are retained; locate the catch handling the "MiMo stream
error" and modify it accordingly (preserve original error object instead of
interpolating it into a string).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cefef7c9-ee7a-4861-ba78-d449e9dc6070

📥 Commits

Reviewing files that changed from the base of the PR and between 403dda0 and dcfd8dd.

📒 Files selected for processing (92)
  • .openclaw-state.example/openclaw.json
  • README.zh-CN.md
  • auth-summary.md
  • extensions/askonce/src/askonce/adapters/base.ts
  • extensions/askonce/src/askonce/adapters/chatgpt.ts
  • extensions/askonce/src/askonce/adapters/claude.ts
  • extensions/askonce/src/askonce/adapters/deepseek.ts
  • extensions/askonce/src/askonce/adapters/doubao.ts
  • extensions/askonce/src/askonce/adapters/gemini.ts
  • extensions/askonce/src/askonce/adapters/glm.ts
  • extensions/askonce/src/askonce/adapters/grok.ts
  • extensions/askonce/src/askonce/adapters/index.ts
  • extensions/askonce/src/askonce/adapters/kimi.ts
  • extensions/askonce/src/askonce/adapters/qwen-cn.ts
  • extensions/askonce/src/askonce/adapters/qwen.ts
  • extensions/askonce/src/askonce/adapters/registry.ts
  • extensions/askonce/src/askonce/concurrent-engine.ts
  • extensions/askonce/src/askonce/constants.ts
  • extensions/askonce/src/askonce/formatters/console.ts
  • extensions/askonce/src/askonce/formatters/index.ts
  • extensions/askonce/src/askonce/formatters/json.ts
  • extensions/askonce/src/askonce/formatters/markdown.ts
  • extensions/askonce/src/askonce/index.ts
  • extensions/askonce/src/askonce/query-orchestrator.ts
  • extensions/askonce/src/askonce/types.ts
  • extensions/askonce/src/cli.ts
  • extensions/askonce/src/index.ts
  • extensions/web-models/index.ts
  • scripts/bundle-a2ui.sh
  • src/agents/chatgpt-web-stream.ts
  • src/agents/claude-web-stream.ts
  • src/agents/doubao-web-stream.ts
  • src/agents/gemini-web-stream.ts
  • src/agents/glm-intl-web-stream.ts
  • src/agents/glm-web-stream.ts
  • src/agents/grok-web-stream.ts
  • src/agents/kimi-web-stream.ts
  • src/agents/mimo-web-stream.ts
  • src/agents/models-config.providers.ts
  • src/agents/pi-embedded-runner/compact.ts
  • src/agents/pi-embedded-runner/run/attempt.ts
  • src/agents/qwen-cn-web-stream.ts
  • src/agents/qwen-web-stream.ts
  • src/agents/xiaomimo-web-stream.ts
  • src/browser/chrome.ts
  • src/commands/auth-choice.apply.chatgpt-web.ts
  • src/commands/auth-choice.apply.claude-web.ts
  • src/commands/auth-choice.apply.deepseek-web.ts
  • src/commands/auth-choice.apply.doubao-web.ts
  • src/commands/auth-choice.apply.gemini-web.ts
  • src/commands/auth-choice.apply.glm-intl-web.ts
  • src/commands/auth-choice.apply.glm-web.ts
  • src/commands/auth-choice.apply.grok-web.ts
  • src/commands/auth-choice.apply.kimi-web.ts
  • src/commands/auth-choice.apply.manus-api.ts
  • src/commands/auth-choice.apply.mimo-web.ts
  • src/commands/auth-choice.apply.qwen-web.ts
  • src/commands/onboard-auth.config-core.ts
  • src/commands/onboard-web-auth.ts
  • src/config/types.models.ts
  • src/providers/chatgpt-web-auth.ts
  • src/providers/chatgpt-web-client-browser.ts
  • src/providers/claude-web-auth.ts
  • src/providers/claude-web-client.ts
  • src/providers/deepseek-web-auth.ts
  • src/providers/doubao-web-auth.ts
  • src/providers/doubao-web-client-browser.ts
  • src/providers/doubao-web-client.ts
  • src/providers/gemini-web-client-browser.ts
  • src/providers/glm-intl-web-auth.ts
  • src/providers/glm-intl-web-client-browser.ts
  • src/providers/glm-web-auth.ts
  • src/providers/glm-web-client-browser.ts
  • src/providers/grok-web-auth.ts
  • src/providers/grok-web-client-browser.ts
  • src/providers/index.ts
  • src/providers/kimi-web-auth.ts
  • src/providers/kimi-web-client-browser.ts
  • src/providers/manus-api-client.ts
  • src/providers/mimo-web-auth.ts
  • src/providers/mimo-web-client.ts
  • src/providers/mimo-web.ts
  • src/providers/qwen-cn-web-auth.ts
  • src/providers/qwen-cn-web-client-browser.ts
  • src/providers/qwen-web-auth.ts
  • src/providers/qwen-web-client-browser.ts
  • src/providers/xiaomimo-web-auth.ts
  • src/providers/xiaomimo-web-client-browser.ts
  • src/providers/xiaomimo-web-client.ts
  • ui/src/ui/views/app-render.ts
  • ui/src/ui/views/app-view-state.ts
  • ui/src/ui/views/app.ts

sessionId,
};

const stream = streamFn(model as any, context as any, { signal: options?.signal });
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 检查 createKimiWebStreamFn 的类型定义
ast-grep --pattern 'export function createKimiWebStreamFn($_): $_ {
  $$$
}'

Repository: linuxhsj/openclaw-zero-token

Length of output: 36142


🏁 Script executed:

find . -path "*extensions/askonce/src/askonce/adapters/kimi.ts" -type f

Repository: linuxhsj/openclaw-zero-token

Length of output: 121


🏁 Script executed:

# Search for StreamFn type definition
rg -n "type StreamFn|interface StreamFn" --type typescript --type tsx

Repository: linuxhsj/openclaw-zero-token

Length of output: 106


🏁 Script executed:

# Check if askonce adapter exists and view its content around potential line 93
fd "kimi.ts" --path "*/askonce/*" -x wc -l {}

Repository: linuxhsj/openclaw-zero-token

Length of output: 287


🏁 Script executed:

# Read the kimi.ts file to see the actual code
cat -n ./extensions/askonce/src/askonce/adapters/kimi.ts | head -150

Repository: linuxhsj/openclaw-zero-token

Length of output: 4489


🏁 Script executed:

# Search for StreamFn type definition with correct syntax
rg "type StreamFn|interface StreamFn" -t ts -t tsx

Repository: linuxhsj/openclaw-zero-token

Length of output: 99


🏁 Script executed:

# Also search for where StreamFn is imported or defined
rg "StreamFn" -B 2 -A 2 -t ts -t tsx | head -100

Repository: linuxhsj/openclaw-zero-token

Length of output: 99


🏁 Script executed:

# Search for StreamFn definition without specifying file type
rg "type StreamFn|interface StreamFn" -B 2 -A 5

Repository: linuxhsj/openclaw-zero-token

Length of output: 784


🏁 Script executed:

# Also search in all files for StreamFn
rg "StreamFn" -B 1 -A 1 | head -200

Repository: linuxhsj/openclaw-zero-token

Length of output: 13872


🏁 Script executed:

# Check what types are exported from kimi-web-stream.ts
cat -n ./src/agents/kimi-web-stream.ts | head -50

Repository: linuxhsj/openclaw-zero-token

Length of output: 2232


避免使用 as any 类型断言,应显式定义参数类型。

model as anycontext as any 绕过了 TypeScript 类型检查。由于 modelcontext 对象已在调用前构造完成(包含 idapiprovidermessagessystemPrompttoolssessionId 等属性),可以为其定义具体的类型接口,而不是使用 any

建议为 modelcontext 定义明确的类型,然后在调用 streamFn 时移除 as any 断言,以保持类型安全。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/askonce/src/askonce/adapters/kimi.ts` at line 93, The call to
streamFn currently uses unsafe assertions (model as any, context as any);
instead define explicit interfaces/types for the objects passed (e.g., ModelType
with id, api, provider, messages, systemPrompt, tools, sessionId, etc., and
ContextType for the streaming context) and update the streamFn signature to
accept those types so you can replace the casted call const stream =
streamFn(model as any, context as any, { signal: options?.signal }); with a
type-safe call const stream = streamFn(model, context, { signal: options?.signal
});; ensure any helper functions that construct model/context (the factory or
callers) are updated to return the new ModelType/ContextType so TypeScript
enforces correctness.

Comment on lines +270 to 279
"xiaomimo-web": [
{
id: "xiaomimo-chat",
name: "MiMo Chat",
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128000,
maxTokens: 4096,
},
],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Xiaomi MiMo AI model context window limit

💡 Result:

  • MiMo‑7B: 32,768 tokens context window. [1]
  • MiMo‑V2‑Flash: up to 256k tokens context window (commonly implemented as 262,144 tokens). [2][3]

Sources:
[1] The Decoder (MiMo‑7B) (the-decoder.com)
[2] arXiv: MiMo‑V2‑Flash Technical Report (arxiv.org)
[3] Hugging Face README (MiMo‑V2‑Flash) (huggingface.co)

Citations:


🏁 Script executed:

# 在代码库中搜索 xiaomimo 相关的配置或注释
rg "xiaomimo" -i -A 5 -B 5

Repository: linuxhsj/openclaw-zero-token

Length of output: 21161


🌐 Web query:

Xiaomi MiMo Chat API specifications maxTokens context window

💡 Result:

For Xiaomi MiMo (MiMo‑V2‑Flash) Chat API:

  • Context window: 262,144 tokens (~256K) for mimo-v2-flash. (docs.openclaw.ai)
  • Max output tokens (maxTokens / max_tokens): integrator configs for Xiaomi MiMo commonly cap generation at 8,192 tokens (i.e., you can request up to 8192 output tokens, subject to the overall context limit). (docs.openclaw.ai)
  • Rule of thumb: input_tokens + requested_output_tokens ≤ context_window (so long prompts reduce the available completion tokens). (docs.siliconflow.com)

Citations:


更新 Xiaomi MiMo Chat 的实际规格参数。

根据官方文档,MiMo-V2-Flash 模型支持 262,144 tokens 上下文窗口和 8,192 tokens 最大输出,但代码中配置为 contextWindow: 128000maxTokens: 4096,约为实际限制的 50%。需要将这两个值更正为:

  • contextWindow: 262144
  • maxTokens: 8192

注意:同一代码库中的 mimo-v2-pro 已正确配置 maxTokens: 8192,应保持一致。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/web-models/index.ts` around lines 270 - 279, Update the Xiaomi
MiMo Chat spec under the "xiaomimo-web" array for the entry with id
"xiaomimo-chat": change the contextWindow property from 128000 to 262144 and
change maxTokens from 4096 to 8192 to match the MiMo-V2-Flash official limits
(ensure consistency with the existing "mimo-v2-pro" maxTokens setting).

Comment on lines +47 to +52
# Try to find node via Windows PATH (useful if running in WSL or MinGW)
if command -v cmd.exe >/dev/null 2>&1; then
node_path=$(cmd.exe //c where node 2>/dev/null | head -n 1 | tr -d '\r')
if [ -n "$node_path" ] && [ -x "$node_path" ]; then
node_cmd="$node_path"
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

f="$(fd 'bundle-a2ui\.sh$' | head -n1)"
echo "Checking: $f"
nl -ba "$f" | sed -n '34,62p'

echo
echo "[verify] cmd.exe fallback present:"
rg -n 'cmd\.exe\s*//c\s*where node' "$f"

echo
echo "[verify] path conversion present (expect wslpath/cygpath after fix):"
rg -n 'wslpath|cygpath' "$f" || true

echo
echo "[verify] where-node failure tolerant (expect || true after fix):"
rg -n 'where node.*\|\|\s*true' "$f" || true

Repository: linuxhsj/openclaw-zero-token

Length of output: 164


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the file
f=$(find . -name 'bundle-a2ui.sh' -type f | head -n1)
echo "Checking: $f"
echo

# Show lines 34-62 with line numbers
echo "[Section: Lines 34-62]"
sed -n '34,62p' "$f" | cat -n -v

echo
echo "[verify] cmd.exe fallback present:"
grep -n 'cmd\.exe.*where node' "$f" || echo "Not found"

echo
echo "[verify] path conversion (wslpath/cygpath):"
grep -n 'wslpath\|cygpath' "$f" || echo "Not found"

echo
echo "[verify] where node failure handling (|| true):"
grep -n 'where node.*|| *true' "$f" || echo "Not found"

echo
echo "[verify] set -euo pipefail present:"
grep -n 'set -euo pipefail' "$f" || echo "Not found"

Repository: linuxhsj/openclaw-zero-token

Length of output: 1692


🏁 Script executed:

#!/bin/bash
set -euo pipefail

f="./scripts/bundle-a2ui.sh"

echo "[1] 查看完整 compute_hash 函数:"
sed -n '34,62p' "$f"

echo
echo "[2] 检查 pipefail 行为:cmd.exe where node 是否有容错"
grep -A 3 "cmd.exe.*where node" "$f"

echo
echo "[3] 检查 -x 检查对 Windows 路径的有效性:"
echo "   如果 node_path 是 Windows 格式路径(如 C:\... 或 /c/...),"
echo "   Bash 的 [ -x ... ] 检查会失败。来源:Bash 手册,-x 测试本地文件可执行性。"

Repository: linuxhsj/openclaw-zero-token

Length of output: 1523


🏁 Script executed:

#!/bin/bash
# 验证 [ -x ] 对 Windows 路径的行为
echo "Testing [ -x ] with Windows-style paths:"
test_path="/c/Program Files/nodejs/node.exe"
if [ -x "$test_path" ]; then
  echo "  Path $test_path is executable (unlikely in WSL)"
else
  echo "  Path $test_path failed -x check (expected in WSL)"
fi

test_path2="C:\\Program Files\\nodejs\\node.exe"
if [ -x "$test_path2" ]; then
  echo "  Path $test_path2 is executable (unlikely)"
else
  echo "  Path $test_path2 failed -x check (expected)"
fi

Repository: linuxhsj/openclaw-zero-token

Length of output: 253


cmd.exe where node 返回的 Windows 路径格式与 Bash 的 [ -x ] 检查不兼容,导致此回退分支在 WSL/MinGW 下失效。

第 49 行中 cmd.exe //c where node 可能返回 Windows 格式路径(如 C:\.../c/Program Files/...),但第 50 行的 [ -x "$node_path" ] 在 WSL 环境中无法正确验证此类路径的可执行性,从而导致即使 where 命令成功,也会因路径检查失败而被拒绝。此外,代码中缺少 wslpath/cygpath 路径转换逻辑和显式的容错处理(如 || true),使得这个备选方案在目标环境中完全不可用。

建议添加路径格式转换,将 Windows 路径转换为 POSIX 格式,并增强命令失败的容错能力。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/bundle-a2ui.sh` around lines 47 - 52, The Windows path returned by
`cmd.exe //c where node` can be in Windows format and fail the POSIX file test
`[ -x "$node_path" ]`; update the fallback block that sets
`node_path`/`node_cmd` to (1) tolerate command failures with `|| true`, (2)
convert returned Windows paths to POSIX using `wslpath -a` (and fall back to
`cygpath -u` if `wslpath` is unavailable) before testing, and (3) only perform
the `[ -x "$node_path" ]` check on the converted POSIX path; reference the
`cmd.exe //c where node`, `node_path`, `node_cmd`, `[ -x "$node_path" ]`,
`wslpath`, and `cygpath` symbols when making these changes.

Comment on lines +20 to +46
return new Promise(async (resolve, reject) => {
try {
onProgress("Starting MiMo-Web authentication...");

// Navigate to MiMo AI Studio
const loginUrl = "https://aistudio.xiaomimimo.com/";
onProgress(`Opening ${loginUrl}...`);
await page.goto(loginUrl, { waitUntil: "networkidle" });

// Wait for user to login manually (scan QR code or enter credentials)
onProgress("Please login to MiMo AI Studio in the browser...");
onProgress("Waiting for login completion...");

// Monitor network requests to capture authentication tokens
const credentials = await captureMimoCredentials(page, onProgress);

if (!credentials) {
throw new Error("Failed to capture MiMo credentials");
}

onProgress("MiMo authentication successful!");
resolve(credentials);
} catch (error) {
onProgress(`MiMo authentication failed: ${error}`);
reject(error);
}
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

修复异步 Promise 执行器反模式

使用 async 函数作为 Promise 执行器是一个反模式(由静态分析工具 noAsyncPromiseExecutor 标记)。如果在第一个 await 之前抛出异常,该异常不会被 Promise 的 reject 捕获,而是会变成未处理的 Promise 拒绝。

由于函数本身已经是 async,完全不需要包装在 new Promise 中。

🐛 建议的修复
 export async function loginMimoWeb(params: {
   onProgress: (msg: string) => void;
   openUrl: (url: string) => Promise<boolean>;
   browser: Browser;
   page: Page;
 }): Promise<MimoAuthCredentials> {
   const { onProgress, openUrl, browser, page } = params;

-  return new Promise(async (resolve, reject) => {
-    try {
-      onProgress("Starting MiMo-Web authentication...");
+  onProgress("Starting MiMo-Web authentication...");

-      // Navigate to MiMo AI Studio
-      const loginUrl = "https://aistudio.xiaomimimo.com/";
-      onProgress(`Opening ${loginUrl}...`);
-      await page.goto(loginUrl, { waitUntil: "networkidle" });
+  // Navigate to MiMo AI Studio
+  const loginUrl = "https://aistudio.xiaomimimo.com/";
+  onProgress(`Opening ${loginUrl}...`);
+  await page.goto(loginUrl, { waitUntil: "networkidle" });

-      // Wait for user to login manually (scan QR code or enter credentials)
-      onProgress("Please login to MiMo AI Studio in the browser...");
-      onProgress("Waiting for login completion...");
+  // Wait for user to login manually
+  onProgress("Please login to MiMo AI Studio in the browser...");
+  onProgress("Waiting for login completion...");

-      // Monitor network requests to capture authentication tokens
-      const credentials = await captureMimoCredentials(page, onProgress);
+  // Monitor network requests to capture authentication tokens
+  const credentials = await captureMimoCredentials(page, onProgress);

-      if (!credentials) {
-        throw new Error("Failed to capture MiMo credentials");
-      }
+  if (!credentials) {
+    throw new Error("Failed to capture MiMo credentials");
+  }

-      onProgress("MiMo authentication successful!");
-      resolve(credentials);
-    } catch (error) {
-      onProgress(`MiMo authentication failed: ${error}`);
-      reject(error);
-    }
-  });
+  onProgress("MiMo authentication successful!");
+  return credentials;
 }
🧰 Tools
🪛 Biome (2.4.7)

[error] 20-46: Promise executor functions should not be async.

(lint/suspicious/noAsyncPromiseExecutor)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web-auth.ts` around lines 20 - 46, The code wraps async
logic in a new Promise which is an anti-pattern; refactor the function to be
async and remove the new Promise wrapper: make the enclosing function async (if
it isn't already), move the try/catch out of the Promise executor, directly
await captureMimoCredentials(page, onProgress), and return the credentials
instead of resolve; on errors throw or rethrow inside the catch after calling
onProgress. Update references to captureMimoCredentials, onProgress and page in
this block so no new Promise(...) is used.

Comment on lines +112 to +113
if (stream) {
return response.body as unknown as Readable;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if Readable.fromWeb is available in the project's Node.js version
node -e "console.log('Node.js version:', process.version); console.log('Readable.fromWeb available:', typeof require('stream').Readable.fromWeb === 'function')"

Repository: linuxhsj/openclaw-zero-token

Length of output: 129


🏁 Script executed:

cat -n src/providers/mimo-web-client.ts | head -200

Repository: linuxhsj/openclaw-zero-token

Length of output: 6557


修复 Web ReadableStream 与 Node.js Readable 的类型不兼容问题

第 113 行的类型断言 response.body as unknown as Readable 存在严重的类型安全问题。response.body 是 Web Streams API 的 ReadableStream<Uint8Array>,而返回类型声明为 Node.js 的 Readable。这两个类型的 API 完全不兼容:

  • ReadableStream 使用 getReader()read() 方法
  • Readable 使用事件 ('data', 'end') 和 pipe() 方法

该类型断言会导致运行时错误,因为消费者将尝试调用 Node.js Readable 的 API。

使用 Readable.fromWeb() 进行正确转换(Node.js 17+ 已支持,项目使用 v24.3.0):

  if (stream) {
-   return response.body as unknown as Readable;
+   return Readable.fromWeb(response.body!);
  }

同时修复代码指南违规:

  • 第 128 行:将 body?: any 改为 body?: Record<string, unknown>
  • 第 159 行:将 data: any 改为 data: unknown
  • 第 182 行:将 data: any 改为 data: unknown
  • 第 149 行:移除浏览器专用的 credentials: "include" 选项
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/mimo-web-client.ts` around lines 112 - 113, The code
incorrectly asserts a Web ReadableStream to a Node.js Readable at the return in
getResponse/getStream (response.body as unknown as Readable) which is unsafe and
will break consumers; replace that assertion by converting the Web stream to a
Node.js stream via Readable.fromWeb(response.body) when response.body is a
ReadableStream (use global.Readable or import from 'stream' depending on module
system) so the returned type matches Node's Readable. Also update the loose any
types: change body?: any to body?: Record<string, unknown>, and change
parameters named data: any to data: unknown in the functions referenced around
the diff, and remove the browser-only credentials: "include" option from the
fetch init so server-side fetch usage is correct. Ensure function/method names
mentioned (e.g., the method that returns response.body, any request/response
handlers around lines with body?: any and data: any) are updated accordingly and
preserve type-safe checks before calling Readable.fromWeb.

Comment on lines +41 to +51
constructor(options: XiaomiMimoWebClientOptions | string) {
if (typeof options === "string") {
try {
const parsed = JSON.parse(options) as XiaomiMimoWebClientOptions;
this.cookie = parsed.cookie;
} catch {
this.cookie = options;
}
} else {
this.cookie = options.cookie;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

构造参数缺少 cookie 必填校验,存在运行时崩溃风险

当前 JSON 字符串解析后直接读取 parsed.cookie,若字段缺失会在后续 this.cookie.split(...) 触发异常。

💡 建议修复
   constructor(options: XiaomiMimoWebClientOptions | string) {
     if (typeof options === "string") {
       try {
-        const parsed = JSON.parse(options) as XiaomiMimoWebClientOptions;
-        this.cookie = parsed.cookie;
+        const parsed = JSON.parse(options) as Partial<XiaomiMimoWebClientOptions>;
+        this.cookie = typeof parsed.cookie === "string" ? parsed.cookie : "";
       } catch {
         this.cookie = options;
       }
     } else {
       this.cookie = options.cookie;
     }
+    if (!this.cookie.trim()) {
+      throw new Error("XiaomiMimo cookie is required");
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/xiaomimo-web-client-browser.ts` around lines 41 - 51, The
constructor in XiaomiMimoWebClient currently parses string options and assigns
this.cookie without validating presence, which can cause a runtime crash when
later calling this.cookie.split(...); update the constructor to validate that a
cookie string exists after JSON.parse (and when options is an object) and throw
a clear error or handle a safe fallback if absent; specifically, in the
constructor method (constructor(options: XiaomiMimoWebClientOptions | string))
check parsed.cookie (and options.cookie) for a non-empty string and either set
this.cookie only when valid or throw a descriptive error like "cookie is
required" so downstream code using this.cookie.split(...) is safe.

Comment on lines +128 to +137
const modelInternal = MODEL_MAP[params.model] || params.model;
const convId = params.conversationId || "0";
const msgId = crypto.randomUUID().replace(/-/g, "");

// 构建完整消息 (系统提示 + 用户消息)
let fullMessage = params.message;
if (params.systemPrompt && params.systemPrompt.length > 0) {
const sysSnippet = params.systemPrompt.slice(0, 500); // 系统提示截断
fullMessage = `[系统提示: ${sysSnippet}]\n\n用户问题: ${params.message}`;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

systemPrompt 与会话续接逻辑未真正生效

已拼接 fullMessage,但实际传入 page.evaluate 的仍是 params.message;同时保存了 this.conversationId 却未作为默认 convId 使用,导致多轮上下文难以延续。

💡 建议修复
-    const convId = params.conversationId || "0";
+    const convId = params.conversationId ?? this.conversationId ?? "0";
@@
-      { message: params.message, modelInternal, convId, msgId },
+      { message: fullMessage, modelInternal, convId, msgId },
     );

Also applies to: 226-227, 233-235

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/xiaomimo-web-client-browser.ts` around lines 128 - 137, The
code builds fullMessage but still passes params.message into page.evaluate and
doesn't use this.conversationId as the default convId; update the logic so
convId defaults to this.conversationId when params.conversationId is absent and
ensure this.conversationId is updated when a new conversationId is produced, and
replace all usages where params.message is passed into page.evaluate (and the
similar occurrences around the other blocks at the indicated ranges) with the
constructed fullMessage so the systemPrompt and multi-turn context are actually
sent; refer to MODEL_MAP, params, convId, msgId, fullMessage, page.evaluate and
this.conversationId to locate and fix all instances.

Comment on lines +139 to +140
console.log(`[XiaomiMimo] Model: ${params.model} → ${modelInternal}`);
console.log(`[XiaomiMimo] ConvId: ${convId}, Msg: ${fullMessage.length} chars`);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

避免在常规日志中输出用户输入/模型响应片段

当前日志会打印请求体片段和响应正文片段,容易把敏感内容落盘。建议仅记录长度、状态码和追踪 ID。

💡 建议修复
-    console.log(`[XiaomiMimo] ConvId: ${convId}, Msg: ${fullMessage.length} chars`);
+    console.debug(`[XiaomiMimo] ConvId: ${convId}, MsgChars: ${fullMessage.length}`);
@@
-        console.log("[MiMo XHR] Body:", JSON.stringify(body).substring(0, 200));
+        console.debug("[MiMo XHR] BodySize:", JSON.stringify(body).length);
@@
-    console.log(`[XiaomiMimo] Response: ${result.data?.substring(0, 300)}`);
+    console.debug(`[XiaomiMimo] ResponseLen: ${result.data?.length || 0}`);

Also applies to: 169-170, 229-230

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/providers/xiaomimo-web-client-browser.ts` around lines 139 - 140, The
current console.log statements in xiaomimo-web-client-browser (references: the
logs that interpolate params.model and modelInternal, and the ones using convId
and fullMessage) output user input/response fragments; replace these to only log
non-sensitive metadata (e.g., model name only if non-sensitive or better:
modelInternal identifier, message length via fullMessage.length, HTTP status
codes, and a trace/convId) and remove any direct content or body snippets;
update the same pattern for the other occurrences around the blocks that
reference fullMessage and response body (mentions at the other logs around lines
169-170 and 229-230) so all logs record length/status/trace id instead of
payloads.

Updated file paths to be relative instead of absolute.
@aurelius1688
Copy link
Author

此PR为抛砖引玉.希望各位大佬友好讨论.
测试平台是Windows11 node v24.14.0
目前可以正常通过浏览器登录方式免费使用mimo模型,但是存在以下问题尚未解决:
1.提示词长度有限制,超过会提示
2.只有聊天的功能,没有执行能力
3.一些尚未发现的bugs.

@aurelius1688
Copy link
Author

此PR为抛砖引玉.希望各位大佬友好讨论. 测试平台是Windows11 node v24.14.0 目前可以正常通过浏览器登录方式免费使用mimo模型,但是存在以下问题尚未解决: 1.提示词长度有限制,超过会提示 2.只有聊天的功能,没有执行能力 3.一些尚未发现的bugs.

关于提示词限制的logs:
17:21:08 [XiaomiMimoWebStream] Truncating prompt from 123897 to 80000
17:21:08 [XiaomiMimoWebStream] Starting run for session: mimo-v2-pro
17:21:08 [XiaomiMimoWebStream] Conversation ID: new
17:21:08 [XiaomiMimoWebStream] Tools available: 70
17:21:08 [XiaomiMimoWebStream] Prompt length: 80000
17:21:09 [XiaomiMimo] Model: mimo-v2-pro -> mimo-v2-flash-studio
17:21:09 [XiaomiMimo] Conversation: 0
17:21:16 [XiaomiMimo] Result: ok=true, len=119
17:21:16 [XiaomiMimo] Response: id:48d25b5fd6d47e62682b68f3580a5685
event:error
data:{"type":"text","content":"抱歉,您发送的文本超长啦!建议您适当简化内容,或者分段发送。感谢您的理解"}

17:21:16 [XiaomiMimoWebStream] Stream completed. Parts: 1, Tools: 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant