Skip to content

适用于windows的修改 #157

@colorwlof

Description

@colorwlof

Pre-checks

What problem does this solve?

Clawith 自定义修改记录

记录 Clawith 升级时需要保留的修改,避免被覆盖。


1. httpx 禁用系统代理

文件: backend/app/services/llm_client.py

位置: 4 个客户端类的 _get_client() 方法

  • Line 215: OpenAICompatibleClient._get_client()
  • Line 546: GeminiClient._get_client()
  • Line 852: AnthropicClient._get_client()
  • Line 1343: OllamaClient._get_client()

问题: httpx 默认读取系统代理设置,导致请求被拦截,LLM 调用返回 502。

修改: 在创建 httpx.AsyncClient 时添加 trust_env=False

async def _get_client(self) -> httpx.AsyncClient:
    if self._client is None or self._client.is_closed:
        self._client = httpx.AsyncClient(timeout=self.timeout, follow_redirects=True, trust_env=False)
    return self._client

搜索 trust_env=False 确认所有 4 处都已修改


2. Windows subprocess 支持 (Python 3.12)

文件: backend/app/services/agent_tools.py

2.1 模块级事件循环策略

位置: 文件开头,from loguru import logger 之后

问题: Python 3.12 在 Windows 上默认 SelectorEventLoop 不支持 subprocess,导致 asyncio.create_subprocess_exec 抛出 NotImplementedError

修改:

from loguru import logger

import sys as _sys
if _sys.platform == "win32":
    import asyncio as _asyncio
    _asyncio.set_event_loop_policy(_asyncio.WindowsProactorEventLoopPolicy())

2.2 subprocess 编码修复

位置: _execute_code 函数内,await asyncio.wait_for(proc.communicate(), timeout=timeout) 之后

问题: Windows subprocess 默认输出用 GBK 编码,但代码用 UTF-8 解码导致乱码。

修改:

# 修改前
stdout_str = stdout.decode("utf-8", errors="replace")[:10000]
stderr_str = stderr.decode("utf-8", errors="replace")[:5000]

# 修改后
_enc = "gbk" if _sys.platform == "win32" else "utf-8"
stdout_str = stdout.decode(_enc, errors="replace")[:10000]
stderr_str = stderr.decode(_enc, errors="replace")[:5000]

2.3 bash/shell 命令 PATH 修复

位置: _execute_code 函数内,if language == "bash" 分支

问题: Windows 没有 bashpython3 命令。

修改:

# 修改前
elif language == "bash":
    ext = ".sh"
    cmd_prefix = ["bash"]
elif language == "python":
    ext = ".py"
    cmd_prefix = ["python3"]

# 修改后
elif language == "bash":
    ext = ".sh"
    import shutil as _shutil
    if _shutil.which("bash"):
        cmd_prefix = ["bash"]
    elif _shutil.which("cmd"):
        cmd_prefix = ["cmd", "/c"]
    else:
        cmd_prefix = ["powershell", "-Command"]
elif language == "python":
    ext = ".py"
    cmd_prefix = ["python"]

3. feishu tool_call 历史记录修复

文件: backend/app/api/feishu.py

位置: _call_agent_llm 函数内,历史记录构建部分(约 line 992)

问题: feishu 路由的消息在加载历史时跳过了 role='tool_call' 的消息,导致多轮工具调用对话中工具调用信息丢失,LLM 报错 "No tool output found for function call"。

修改: 将简单的列表推导式替换为循环,正确处理 tool_call 角色:

# 修改前
_history = [{"role": m.role, "content": m.content} for m in reversed(_hist_r.scalars().all())]

# 修改后
_hist_list = list(reversed(_hist_r.scalars().all()))
_history = []
for m in _hist_list:
    if m.role == "tool_call":
        import json as _j_tc
        try:
            tc_data = _j_tc.loads(m.content)
            tc_name = tc_data.get("name", "unknown")
            tc_args = tc_data.get("args", {})
            tc_result = tc_data.get("result", "")
            tc_id = f"call_{m.id}"
            _history.append({
                "role": "assistant",
                "content": None,
                "tool_calls": [{
                    "id": tc_id,
                    "type": "function",
                    "function": {"name": tc_name, "arguments": _j_tc.dumps(tc_args, ensure_ascii=False)},
                }],
            })
            _history.append({
                "role": "tool",
                "tool_call_id": tc_id,
                "content": str(tc_result)[:500],
            })
        except Exception:
            continue
    else:
        entry = {"role": m.role, "content": m.content}
        if hasattr(m, 'thinking') and m.thinking:
            entry["thinking"] = m.thinking
        _history.append(entry)

4. emoji 日志编码修复

文件: backend/app/main.py

位置: migrate_enterprise_info() 函数内的 print 语句

问题: Windows GBK 终端无法打印 emoji 字符,导致启动时异常退出。

修改: 将 emoji 替换为 ASCII 字符:

# 修改前
print(f"[startup] ✅ Migrated enterprise_info → enterprise_info_{_tenant.id}", flush=True)
print(f"[startup] ℹ️ enterprise_info_{_tenant.id} already exists, skipping migration", flush=True)

# 修改后
print(f"[startup] [OK] Migrated enterprise_info -> enterprise_info_{_tenant.id}", flush=True)
print(f"[startup] [i] enterprise_info_{_tenant.id} already exists, skipping migration", flush=True)

5. 启动脚本路径修复

文件: links.batclawith.bat

问题: Windows 上 venv Scripts 路径为 .venv\Scripts\ 而非 .venv/bin/

修改 (links.bat):

# 修改前
.venv/bin/uvicorn app.main:app --host 0.0.0.0 --port $BACKEND_PORT

# 修改后
.venv/Scripts/uvicorn app.main:app --host 0.0.0.0 --port $BACKEND_PORT

修改 (clawith.bat):

REM 修改前
uv run uvicorn app.main:app --reload --port 8008

REM 修改后
.venv\Scripts\uvicorn app.main:app --port 8008

注意:移除了 --reload 参数,因为 watchfiles 子进程可能与 Windows 事件循环冲突。


6. 禁用 Agent Seeder

文件: backend/app/main.py

位置: startup() 函数(约 line 181-184)

问题: 每次重启服务都会运行 seed_default_agents(),覆盖用户自定义的 Agent。

修改: 注释掉相关调用:

# await seed_default_agents()
# 如果以上命令报错,可能是重复的 agent name,执行以下命令解决:
# truncate_table("agents")

7. 其他(已在 v1.7.1 合并)

以下修复在 v1.7.1 中已合并,无需手动修改:

  • write_text() 添加 encoding="utf-8" 解决 Windows GBK 编码问题
  • Skill 创建时初始化 files = [] 避免异步懒加载错误

Proposed solution

No response

Willing to contribute?

  • I'd be interested in working on this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions