重构仓库目录为统一的 runtime 分层并清理历史 openclaw 残留。

本次迁移将网关/通道/工具/技能/脚本与协议资源集中到新结构,统一路径常量与脚本转发机制,减少顶层噪音并保证运行与测试行为一致。

Made-with: Cursor
This commit is contained in:
oliver 2026-04-25 01:24:23 +08:00
parent ba3836f00f
commit 4a23b715a2
498 changed files with 2760 additions and 2200 deletions

View file

@ -15,7 +15,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: python -m pip install -r requirements.txt ruff mypy run: python -m pip install -r requirements.txt ruff mypy
- name: Lint changed architecture modules - name: Lint changed architecture modules
run: ruff check oclaw/interfaces oclaw/extensions oclaw/tests/test_oclaw_gateway_optimizations.py run: ruff check oclaw/interfaces oclaw/runtime/extensions oclaw/tests/test_oclaw_gateway_optimizations.py
- name: Type check critical gateway modules - name: Type check critical gateway modules
run: mypy --ignore-missing-imports oclaw/interfaces/gateway/context_builder.py oclaw/interfaces/ws/server_methods_bridge.py oclaw/interfaces/ws/turn_runner.py run: mypy --ignore-missing-imports oclaw/interfaces/gateway/context_builder.py oclaw/interfaces/ws/server_methods_bridge.py oclaw/interfaces/ws/turn_runner.py
- name: Run tests - name: Run tests

25
.gitignore vendored
View file

@ -42,21 +42,22 @@ data/**/*.log
data/**/*.err.log data/**/*.err.log
platform/data/ platform/data/
scripts/.run/ scripts/.run/
runtime/operations/scripts/.run/
desktop/node_modules/ desktop/node_modules/
desktop/dist/ desktop/dist/
desktop/runtime-data/ desktop/runtime-data/
# 本地密钥(随仓库目录迁移时记得复制此文件;勿提交) # 本地密钥(随仓库目录迁移时记得复制此文件;勿提交)
src/_local/google_oauth_client.json _local/google_oauth_client.json
src/_local/mcp_local.env _local/mcp_local.env
# MCP admin export / 安装后自动备份(可重装 JSON,本机 path 与列表可能不同) # MCP admin export / 安装后自动备份(可重装 JSON,本机 path 与列表可能不同)
src/_local/mcp_registry_migrated.json _local/mcp_registry_migrated.json
src/platform/data/*.sqlite platform/data/*.sqlite
src/platform/data/*.sqlite-journal platform/data/*.sqlite-journal
src/platform/data/*.sqlite-shm platform/data/*.sqlite-shm
src/platform/data/*.sqlite-wal platform/data/*.sqlite-wal
src/platform/data/logs/ platform/data/logs/
src/platform/data/locks/ platform/data/locks/
src/platform/data/ops_runtime_state.json platform/data/ops_runtime_state.json
# 历史 Vite 前端已移除;若本地仍有残留目录可忽略或手动删除 # 历史 Vite 前端已移除;若本地仍有残留目录可忽略或手动删除
web/ web/
@ -70,5 +71,5 @@ oclaw/desktop/node_modules/
oclaw/desktop/dist/ oclaw/desktop/dist/
oclaw/desktop/runtime-data/ oclaw/desktop/runtime-data/
oclaw/desktop/assets/oclaw.ico oclaw/desktop/assets/oclaw.ico
vendor/openclaw-main.zip vendor/oclaw-main.zip
vendor/openclaw/ vendor/oclaw/

View file

@ -1,15 +1,18 @@
# OpenClaw Architecture Root # Oclaw Architecture Root
This directory is the new architecture root for ongoing refactors. This repository is fully consolidated under `oclaw/`.
## Layers ## Layers
- `interfaces/`: transport adapters (HTTP/WS/gateway handlers) - `runtime/`: core execution loop, routing, skill runtime, hook runtime
- `interfaces/`: transport adapters (HTTP/WS)
- `gateway/`: method handlers and protocol bridging
- `application/`: use-cases and orchestration services - `application/`: use-cases and orchestration services
- `domain/`: business rules and domain primitives - `infrastructure/`: runtime-facing integrations/adapters
- `infrastructure/`: integrations and runtime adapters - `platform/`: shared platform capabilities (llm, persistence, config, files)
- `shared/`: shared utilities/types - `tools/`: tool registry, MCP adapters, public/system tools
- `skills/`: installable skills and runtime manifests
## Migration Rule ## Naming Rule
New business logic should be implemented in `oclaw/`. - Use `oclaw` consistently in paths, symbols, and docs.
`oclaw/` modules remain as compatibility bridges during migration. - Avoid introducing legacy aliases or old naming variants.

View file

@ -1,6 +1,5 @@
"""OpenClaw v2 package root. """Oclaw v2 package root.
All new architecture-first code should live under `oclaw/`. All production code in this repository lives under this package root.
Legacy `src/` modules may import from this package as a compatibility bridge.
""" """

View file

@ -1,9 +1,9 @@
# 推荐:复制为 src/_local/mcp_local.env(与 OAuth 等本地密钥同目录,见 .gitignore)。 # 推荐:复制为 _local/mcp_local.env(与 OAuth 等本地密钥同目录,见 .gitignore)。
# 兼容:仍可放在 data/mcp_local.env(与默认 SQLite 同目录);若两处都存在,同键以 src/_local 为准。 # 兼容:仍可放在 data/mcp_local.env(与默认 SQLite 同目录);若两处都存在,同键以 _local 为准。
# ${PROJECT_ROOT} 为仓库根目录。 # ${PROJECT_ROOT} 为仓库根目录。
# BRAVE_API_KEY=your_brave_search_api_key # BRAVE_API_KEY=your_brave_search_api_key
# GOOGLE_OAUTH_CREDENTIALS=${PROJECT_ROOT}/src/_local/google_oauth_client.json # GOOGLE_OAUTH_CREDENTIALS=${PROJECT_ROOT}/_local/google_oauth_client.json
# 或本机固定路径: GOOGLE_OAUTH_CREDENTIALS=%USERPROFILE%/.ops-assistant/google_oauth_client.json # 或本机固定路径: GOOGLE_OAUTH_CREDENTIALS=%USERPROFILE%/.ops-assistant/google_oauth_client.json
# #
# GitHub MCP (@modelcontextprotocol/server-github) # GitHub MCP (@modelcontextprotocol/server-github)
@ -29,17 +29,17 @@
# #
# CONTEXT7_API_KEY=ctx7sk-b5806022-903e-490a-b593-67caa624f3bf # CONTEXT7_API_KEY=ctx7sk-b5806022-903e-490a-b593-67caa624f3bf
# #
# OpenClaw runtime 默认不回退 legacy manager/runner;若紧急排障需临时回退,可显式打开: # Oclaw runtime 默认不回退 legacy manager/runner;若紧急排障需临时回退,可显式打开:
# AIA_OPENCLAW_ALLOW_LEGACY_FALLBACK=1 # AIA_OCLAW_ALLOW_LEGACY_FALLBACK=1
# #
# OpenClaw 仍生效的工具循环预算(可在 Admin -> Tool Policy 配置): # Oclaw 仍生效的工具循环预算(可在 Admin -> Tool Policy 配置):
# AIA_TURN_MAX_TOOL_WORKERS=8 # AIA_TURN_MAX_TOOL_WORKERS=8
# AIA_TURN_MAX_TOOL_ROUNDS=8 # AIA_TURN_MAX_TOOL_ROUNDS=8
# AIA_TURN_MAX_CONTEXT_MESSAGES=80 # AIA_TURN_MAX_CONTEXT_MESSAGES=80
# Agent Core run 外环的可重试错误白名单(逗号分隔): # Agent Core run 外环的可重试错误白名单(逗号分隔):
# AIA_OPENCLAW_RETRYABLE_ERROR_CODES=provider_timeout,provider_rate_limited,provider_temporary_error,provider_unavailable,context_overflow,tool_execution_failed # AIA_OCLAW_RETRYABLE_ERROR_CODES=provider_timeout,provider_rate_limited,provider_temporary_error,provider_unavailable,context_overflow,tool_execution_failed
# Admin 保存 retry code 的未知值行为:0=过滤并告警,1=拒绝保存(400) # Admin 保存 retry code 的未知值行为:0=过滤并告警,1=拒绝保存(400)
# AIA_OPENCLAW_RETRY_CODES_STRICT_MODE=0 # AIA_OCLAW_RETRY_CODES_STRICT_MODE=0
# #
# 内置工作区工具路径(read_file / run_command 等)默认限制在 AIA_WORKSPACE_ROOT(未设则为项目根)下。 # 内置工作区工具路径(read_file / run_command 等)默认限制在 AIA_WORKSPACE_ROOT(未设则为项目根)下。
# 全局扩展:多个绝对路径用 | 分隔;允许整盘访问(高风险): # 全局扩展:多个绝对路径用 | 分隔;允许整盘访问(高风险):

View file

@ -24,7 +24,7 @@ npm run dev
The app will: The app will:
1. Pick an available local port (default prefers `8787`). 1. Pick an available local port (default prefers `8787`).
2. Start backend using `python -m oclaw.ops gateway start --host 127.0.0.1 --port <port>`. 2. Start backend using `python -m oclaw.runtime.operations gateway start --host 127.0.0.1 --port <port>`.
3. Open `http://127.0.0.1:<port>/chat` in the desktop window. 3. Open `http://127.0.0.1:<port>/chat` in the desktop window.
Logs are written under: Logs are written under:

View file

@ -122,7 +122,7 @@ async function startBackendProcess() {
AIA_DESKTOP_MODE: "1", AIA_DESKTOP_MODE: "1",
}; };
const args = ["-m", "oclaw.ops", "gateway", "start", "--host", host, "--port", String(port)]; const args = ["-m", "oclaw.runtime.operations", "gateway", "start", "--host", host, "--port", String(port)];
backendProc = spawn(pythonBin, args, { backendProc = spawn(pythonBin, args, {
cwd: APP_ROOT, cwd: APP_ROOT,
env, env,
@ -212,7 +212,7 @@ async function startChannelProcess() {
try { try {
const cleanupRes = await runPythonInline( const cleanupRes = await runPythonInline(
pythonBin, pythonBin,
"from oclaw.ops.runtime import cleanup_orphan_service_processes; k=cleanup_orphan_service_processes('channel:wecom'); print('killed=' + ','.join(str(x) for x in k))", "from oclaw.runtime.operations.runtime import cleanup_orphan_service_processes; k=cleanup_orphan_service_processes('channel:wecom'); print('killed=' + ','.join(str(x) for x in k))",
{ AIA_DATA_DIR: DATA_ROOT }, { AIA_DATA_DIR: DATA_ROOT },
); );
if (!cleanupRes.ok) { if (!cleanupRes.ok) {
@ -230,7 +230,7 @@ async function startChannelProcess() {
AIA_DATA_DIR: DATA_ROOT, AIA_DATA_DIR: DATA_ROOT,
AIA_DESKTOP_MODE: "1", AIA_DESKTOP_MODE: "1",
}; };
const args = ["-m", "oclaw.ops", "channel", "wecom", "start", "--mode", "ws", "--interval", "3.0", "--deliver-outbound"]; const args = ["-m", "oclaw.runtime.operations", "channel", "wecom", "start", "--mode", "ws", "--interval", "3.0", "--deliver-outbound"];
channelStopping = false; channelStopping = false;
channelProc = spawn(pythonBin, args, { channelProc = spawn(pythonBin, args, {
cwd: APP_ROOT, cwd: APP_ROOT,

View file

@ -0,0 +1,32 @@
# 架构总览(当前真相)
本文件用于描述当前仓库分层与目录职责,避免迁移后“认知滞后”。
## 顶层目录职责
- `runtime/`:运行时主域(agent、gateway 执行流、skills/hooks/extensions、operations)。
- `interfaces/`:对外接口层(HTTP、WS、Admin、Gateway method bridge)。
- `platform/`:通用平台能力(配置、存储、LLM transport、文件层)。
- `prompts/`:统一提示词体系(含 runtime 相关提示模板)。
- `tests/`:测试代码(按你的要求保持顶层)。
- `docs/`:设计文档、运维说明、迁移记录。
## runtime 内部建议边界
- `runtime/core/`:可复用执行内核(如 agent 执行管线聚合入口)。
- `runtime/app/`:应用侧入口组织(面向外部流程的 runtime 编排)。
- `runtime/agents|chat|orchestration|workers`:领域能力模块。
- `runtime/skills|hooks|extensions`:可扩展能力载体。
- `runtime/operations/scripts`:运维脚本与生成器。
## 路径规范
- 运行时资源路径统一通过 `platform/config/runtime_paths.py` 获取。
- 禁止新增硬编码目录字符串(如直接拼 `oclaw/runtime/...`)。
## 依赖方向(原则)
- `interfaces -> runtime -> platform`(尽量单向)。
- `runtime` 不反向依赖 `interfaces`(必要时通过协议/回调解耦)。
- `docs/tests` 可依赖任意层,但不应反向影响运行时代码设计。

View file

@ -29,7 +29,7 @@ npm run pack:win
这个命令会自动做两件事: 这个命令会自动做两件事:
1. 执行 `prepare:icon`,从 `oclaw/admin/static/oliver.svg` 生成 `desktop/assets/oclaw.ico` 1. 执行 `prepare:icon`,从 `oclaw/interfaces/admin/static/oliver.svg` 生成 `desktop/assets/oclaw.ico`
2. 调用 `electron-builder` 生成 NSIS 安装包 2. 调用 `electron-builder` 生成 NSIS 安装包
## 4) 打包产物位置 ## 4) 打包产物位置

View file

@ -18,83 +18,83 @@
- `AIA_ASSISTANT_MODE` - `AIA_ASSISTANT_MODE`
- 默认:空(代码内决定默认模式) - 默认:空(代码内决定默认模式)
- 作用:助手模式选择 - 作用:助手模式选择
- 生效:`oclaw/platform/llm/chat_models.py`, `oclaw/agents/factory.py` - 生效:`oclaw/platform/llm/chat_models.py`, `oclaw/runtime/agents/factory.py`
- `AIA_MANAGER_DECISION_MODE` - `AIA_MANAGER_DECISION_MODE`
- 默认:空 - 默认:空
- 作用:**Legacy(已断开)**:旧 manager 决策模式(如 `rule`) - 作用:**Legacy(已断开)**:旧 manager 决策模式(如 `rule`)
- 说明:oclaw runtime 默认不再走 `CompositeOpsAgent` 的 manager 决策;该变量仅保留以便后续接回 legacy - 说明:oclaw runtime 默认不再走 `CompositeOpsAgent` 的 manager 决策;该变量仅保留以便后续接回 legacy
- 生效:`oclaw/agents/manager_agent.py`(仅 legacy 链路) - 生效:`oclaw/runtime/agents/manager_agent.py`(仅 legacy 链路)
- `AIA_TURN_MAX_TOOL_WORKERS` - `AIA_TURN_MAX_TOOL_WORKERS`
- 默认:`8` - 默认:`8`
- 作用:单轮工具并发上限 - 作用:单轮工具并发上限
- 生效:`oclaw/openclaw_runtime/gateway.py`, `oclaw/openclaw_runtime/direct_loop.py` - 生效:`oclaw/oclaw_runtime/gateway.py`, `oclaw/oclaw_runtime/direct_loop.py`
- `AIA_TURN_MAX_TOOL_ROUNDS` - `AIA_TURN_MAX_TOOL_ROUNDS`
- 默认:`8` - 默认:`8`
- 作用:工具循环轮次上限 - 作用:工具循环轮次上限
- 生效:`oclaw/openclaw_runtime/gateway.py`, `oclaw/openclaw_runtime/direct_loop.py` - 生效:`oclaw/oclaw_runtime/gateway.py`, `oclaw/oclaw_runtime/direct_loop.py`
- `AIA_TURN_MAX_CONTEXT_MESSAGES` - `AIA_TURN_MAX_CONTEXT_MESSAGES`
- 默认:`80` - 默认:`80`
- 作用:上下文消息上限 - 作用:上下文消息上限
- 生效:`oclaw/openclaw_runtime/gateway.py`, `oclaw/openclaw_runtime/direct_loop.py` - 生效:`oclaw/oclaw_runtime/gateway.py`, `oclaw/oclaw_runtime/direct_loop.py`
- oclaw async queue/worker(`router -> openclaw_task -> worker`) - oclaw async queue/worker(`router -> oclaw_task -> worker`)
- 当前版本无独立环境变量;复用以上 `AIA_TURN_MAX_*` 配置控制 direct loop 执行上限 - 当前版本无独立环境变量;复用以上 `AIA_TURN_MAX_*` 配置控制 direct loop 执行上限
- 生效:`oclaw/openclaw_runtime/gateway.py`, `oclaw/openclaw_runtime/worker.py` - 生效:`oclaw/oclaw_runtime/gateway.py`, `oclaw/oclaw_runtime/worker.py`
- `AIA_PROMPT_FRONTMATTER_STRICT` - `AIA_PROMPT_FRONTMATTER_STRICT`
- 默认:`0` - 默认:`0`
- 作用:`1` 时 `SKILL.md` / `oclaw/prompts/*.md` 的 frontmatter 必须为可解析 YAML;解析失败直接报错(不回落旧版行解析) - 作用:`1` 时 `SKILL.md` / `oclaw/prompts/*.md` 的 frontmatter 必须为可解析 YAML;解析失败直接报错(不回落旧版行解析)
- 生效:`oclaw/prompts/frontmatter.py`, `oclaw/prompts/loader.py`, `oclaw/openclaw_runtime/skills.py` - 生效:`oclaw/prompts/frontmatter.py`, `oclaw/prompts/loader.py`, `oclaw/oclaw_runtime/skills.py`
- `AIA_SKILLS_PROMPT_IN_SYSTEM` - `AIA_SKILLS_PROMPT_IN_SYSTEM`
- 默认:`1`(开启;仅当技能运行时启用) - 默认:`1`(开启;仅当技能运行时启用)
- 作用:是否在 system prompt 末尾附加 oclaw 风格的 `<available_skills>` 目录块(与原生 `tools` 并存) - 作用:是否在 system prompt 末尾附加 oclaw 风格的 `<available_skills>` 目录块(与原生 `tools` 并存)
- 说明:设为 `0` 可关闭以降低 token;Admin `AIA_SKILL_RUNTIME_ENABLED` 关闭时本块不生成 - 说明:设为 `0` 可关闭以降低 token;Admin `AIA_SKILL_RUNTIME_ENABLED` 关闭时本块不生成
- 生效:`oclaw/openclaw_runtime/skills_prompt.py`, `oclaw/openclaw_runtime/direct_loop.py` - 生效:`oclaw/oclaw_runtime/skills_prompt.py`, `oclaw/oclaw_runtime/direct_loop.py`
- `AIA_SKILLS_PROMPT_MAX_CHARS` - `AIA_SKILLS_PROMPT_MAX_CHARS`
- 默认:`18000` - 默认:`18000`
- 作用:技能目录 XML 块最大字符数(超出则从列表尾部丢弃条目) - 作用:技能目录 XML 块最大字符数(超出则从列表尾部丢弃条目)
- 生效:`oclaw/openclaw_runtime/skills_prompt.py` - 生效:`oclaw/oclaw_runtime/skills_prompt.py`
- `AIA_SKILL_DISABLED_NAMES` - `AIA_SKILL_DISABLED_NAMES`
- 默认:空数组(`[]`) - 默认:空数组(`[]`)
- 作用:按技能名禁用模型可见/可执行技能(JSON 数组字符串,例如 `["skill_a","skill_b"]`) - 作用:按技能名禁用模型可见/可执行技能(JSON 数组字符串,例如 `["skill_a","skill_b"]`)
- 说明:禁用后同时影响 manifest/prompt 渲染与 direct loop 工具暴露 - 说明:禁用后同时影响 manifest/prompt 渲染与 direct loop 工具暴露
- 生效:`oclaw/openclaw_runtime/skills.py`, `oclaw/openclaw_runtime/skills_prompt.py`, `oclaw/openclaw_runtime/skill_installer.py` - 生效:`oclaw/oclaw_runtime/skills.py`, `oclaw/oclaw_runtime/skills_prompt.py`, `oclaw/oclaw_runtime/skill_installer.py`
- `AIA_SKILL_AUTO_INSTALL_ENABLED` - `AIA_SKILL_AUTO_INSTALL_ENABLED`
- 默认:`1` - 默认:`1`
- 作用:是否允许自动安装 skill(admin auto-install / retry-install(auto)) - 作用:是否允许自动安装 skill(admin auto-install / retry-install(auto))
- 说明:关闭后返回 `auto_install_disabled`,并标记为不可重试 - 说明:关闭后返回 `auto_install_disabled`,并标记为不可重试
- 生效:`oclaw/openclaw_runtime/skill_installer.py`, `oclaw/admin/skills_api.py` - 生效:`oclaw/oclaw_runtime/skill_installer.py`, `oclaw/interfaces/admin/skills_api.py`
- `AIA_OPENCLAW_RETRYABLE_ERROR_CODES` - `AIA_OCLAW_RETRYABLE_ERROR_CODES`
- 默认:`provider_timeout,provider_rate_limited,provider_temporary_error,provider_unavailable,context_overflow,tool_execution_failed` - 默认:`provider_timeout,provider_rate_limited,provider_temporary_error,provider_unavailable,context_overflow,tool_execution_failed`
- 作用:Agent Core run 外环的错误重试白名单(逗号分隔) - 作用:Agent Core run 外环的错误重试白名单(逗号分隔)
- 说明:仅当 attempt 返回 `status=retry` 且 `error_code` 命中该白名单时才进入下一次 attempt;未知 code 默认在 Admin 保存时会被过滤并告警 - 说明:仅当 attempt 返回 `status=retry` 且 `error_code` 命中该白名单时才进入下一次 attempt;未知 code 默认在 Admin 保存时会被过滤并告警
- 补充:`relay_envelope_invalid`、`relay_envelope_unsupported_version` 属于输入契约错误,运行时固定按 non-retryable 处理(即使被误加入白名单也不会进入重试链) - 补充:`relay_envelope_invalid`、`relay_envelope_unsupported_version` 属于输入契约错误,运行时固定按 non-retryable 处理(即使被误加入白名单也不会进入重试链)
- 生效:`oclaw/openclaw_runtime/agent_core_run.py` - 生效:`oclaw/oclaw_runtime/agent_core_run.py`
- `AIA_OPENCLAW_ROUTER_MODE` - `AIA_OCLAW_ROUTER_MODE`
- 默认:`rule` - 默认:`rule`
- 取值:`rule`(启发式)或 `llm_json`(由当前 executor 的 `model.chat` 产出 `{mode,reason}` JSON;解析失败则回落 `rule`) - 取值:`rule`(启发式)或 `llm_json`(由当前 executor 的 `model.chat` 产出 `{mode,reason}` JSON;解析失败则回落 `rule`)
- 说明:亦可通过同名环境变量覆盖;提示词见 `oclaw/prompts_openclaw/router/decide_route.md` - 说明:亦可通过同名环境变量覆盖;提示词见 `oclaw/prompts_runtime/router/decide_route.md`
- 生效:`oclaw/openclaw_runtime/router.py`, `oclaw/openclaw_runtime/gateway.py` - 生效:`oclaw/oclaw_runtime/router.py`, `oclaw/oclaw_runtime/gateway.py`
- oclaw trace 字段与 `event_type` ↔ `oc_stage` 对照见 `oclaw/docs/openclaw-trace-taxonomy.md` - oclaw trace 字段与 `event_type` ↔ `oc_stage` 对照见 `oclaw/docs/oclaw-trace-taxonomy.md`
- Skill 安装错误码与重试建议、trace 排障路径见 `oclaw/docs/openclaw-skill-troubleshooting.md` - Skill 安装错误码与重试建议、trace 排障路径见 `oclaw/docs/oclaw-skill-troubleshooting.md`
- Relay 文件指针(含 ACP 父子 run)错误码与排障见 `oclaw/docs/openclaw-skill-troubleshooting.md` 的“Relay 文件指针排障” - Relay 文件指针(含 ACP 父子 run)错误码与排障见 `oclaw/docs/oclaw-skill-troubleshooting.md` 的“Relay 文件指针排障”
- `AIA_OPENCLAW_RETRY_CODES_STRICT_MODE` - `AIA_OCLAW_RETRY_CODES_STRICT_MODE`
- 默认:`0` - 默认:`0`
- 作用:控制 Admin 保存 `AIA_OPENCLAW_RETRYABLE_ERROR_CODES` 时的未知 code 行为 - 作用:控制 Admin 保存 `AIA_OCLAW_RETRYABLE_ERROR_CODES` 时的未知 code 行为
- 说明:`0`=过滤并告警;`1`=直接拒绝保存(HTTP 400) - 说明:`0`=过滤并告警;`1`=直接拒绝保存(HTTP 400)
- 生效:`oclaw/admin/routes.py`, `oclaw/admin/static/app.js` - 生效:`oclaw/interfaces/admin/routes.py`, `oclaw/interfaces/admin/static/app.js`
- `AIA_TOOL_ENFORCED_RETRY_MODE` - `AIA_TOOL_ENFORCED_RETRY_MODE`
- 默认:`first_round_only` - 默认:`first_round_only`
@ -111,11 +111,11 @@
- 作用:**Legacy(已断开)**:同签名工具调用预算 - 作用:**Legacy(已断开)**:同签名工具调用预算
- 生效:仅 legacy 链路(保留占位,暂不影响 oclaw) - 生效:仅 legacy 链路(保留占位,暂不影响 oclaw)
- `AIA_OPENCLAW_ALLOW_LEGACY_FALLBACK` - `AIA_OCLAW_ALLOW_LEGACY_FALLBACK`
- 默认:`0`(关闭) - 默认:`0`(关闭)
- 作用:oclaw 执行失败时,是否允许回退到 legacy `executor.run_turn(...)` - 作用:oclaw 执行失败时,是否允许回退到 legacy `executor.run_turn(...)`
- 说明:默认 fail-closed(不回退),避免无意中触发旧 manager/runner - 说明:默认 fail-closed(不回退),避免无意中触发旧 manager/runner
- 生效:`oclaw/openclaw_runtime/gateway.py`, `oclaw/agents/specialist_agent.py` - 生效:`oclaw/oclaw_runtime/gateway.py`, `oclaw/runtime/agents/specialist_agent.py`
## LLM 传输与 replay(OpenAI 兼容) ## LLM 传输与 replay(OpenAI 兼容)
@ -173,7 +173,7 @@
- 默认:`0`(不限制) - 默认:`0`(不限制)
- 作用:工具结果写回 LLM 的消息长度上限 - 作用:工具结果写回 LLM 的消息长度上限
- 说明:`0` 表示不做限制(不推荐,可能触发部分网关的单条消息上限 400) - 说明:`0` 表示不做限制(不推荐,可能触发部分网关的单条消息上限 400)
- 生效:`oclaw/chat/tool_runtime.py` - 生效:`oclaw/runtime/chat/tool_runtime.py`
- 观测:管理端聊天流 `tool_use_result` 事件会携带 `llm_wire.{truncated_for_llm,max_chars,result_bytes,result_for_llm_bytes,truncate_ms}` - 观测:管理端聊天流 `tool_use_result` 事件会携带 `llm_wire.{truncated_for_llm,max_chars,result_bytes,result_for_llm_bytes,truncate_ms}`
- `AIA_TOOL_LOG_MAX_CHARS` - `AIA_TOOL_LOG_MAX_CHARS`
@ -191,7 +191,7 @@
- `AIA_MCP_ENV_ALLOWLIST` - `AIA_MCP_ENV_ALLOWLIST`
- 默认:内置 allowlist(Brave/Google/GitHub/Context7) - 默认:内置 allowlist(Brave/Google/GitHub/Context7)
- 作用:MCP 子进程可透传环境变量白名单 - 作用:MCP 子进程可透传环境变量白名单
- 生效:`oclaw/ops/mcp_env.py` - 生效:`oclaw/runtime/operations/mcp_env.py`
- `AIA_MCP_FILESYSTEM_EXTRA_ROOTS` - `AIA_MCP_FILESYSTEM_EXTRA_ROOTS`
- 默认:空 - 默认:空
@ -270,7 +270,7 @@
- `AIA_IMAGE_MODEL` - `AIA_IMAGE_MODEL`
- 默认:空(走 profile/模型默认) - 默认:空(走 profile/模型默认)
- 作用:图像模型 - 作用:图像模型
- 生效:`oclaw/platform/llm/image_message_client.py`, `oclaw/agents/specialist_agent.py` - 生效:`oclaw/platform/llm/image_message_client.py`, `oclaw/runtime/agents/specialist_agent.py`
- `AIA_IMAGE_BASE_URL` - `AIA_IMAGE_BASE_URL`
- 默认:`https://api.openai.com/v1` - 默认:`https://api.openai.com/v1`
@ -329,7 +329,7 @@
- `AIA_WORKSPACE_ROOT` - `AIA_WORKSPACE_ROOT`
- 默认:项目根 - 默认:项目根
- 作用:工作区主根路径 - 作用:工作区主根路径
- 生效:`oclaw/tools/experts/workspace/workspace_base.py`, `oclaw/indexing/workspace_indexer.py` - 生效:`oclaw/tools/experts/workspace/workspace_base.py`, `oclaw/tools/workspace_indexer.py`
- `AIA_WORKSPACE_EXTRA_ROOTS` - `AIA_WORKSPACE_EXTRA_ROOTS`
- 默认:空 - 默认:空
@ -346,46 +346,46 @@
- `AIA_ASSISTANT_GATEWAY_HOST` - `AIA_ASSISTANT_GATEWAY_HOST`
- 默认:`0.0.0.0` - 默认:`0.0.0.0`
- 作用:网关监听地址 - 作用:网关监听地址
- 生效:`oclaw/app_server/fastapi_main.py`, `oclaw/ops/main.py` - 生效:`oclaw/app_server/fastapi_main.py`, `oclaw/runtime/operations/main.py`
- `AIA_ASSISTANT_GATEWAY_PORT` - `AIA_ASSISTANT_GATEWAY_PORT`
- 默认:`8787` - 默认:`8787`
- 作用:网关监听端口 - 作用:网关监听端口
- 生效:`oclaw/app_server/fastapi_main.py`, `oclaw/ops/main.py` - 生效:`oclaw/app_server/fastapi_main.py`, `oclaw/runtime/operations/main.py`
- `AIA_RUNTIME_LOG_DIR` - `AIA_RUNTIME_LOG_DIR`
- 默认:空(使用内部默认目录) - 默认:空(使用内部默认目录)
- 作用:运行日志目录 - 作用:运行日志目录
- 生效:`oclaw/ops/runtime.py` - 生效:`oclaw/runtime/operations/runtime.py`
- `AIA_SSE_QUEUE_MAXSIZE` - `AIA_SSE_QUEUE_MAXSIZE`
- 默认:`2000` - 默认:`2000`
- 作用:SSE 事件队列上限 - 作用:SSE 事件队列上限
- 生效:`oclaw/admin/chat_api.py` - 生效:`oclaw/interfaces/admin/chat_api.py`
## WeCom 长连接 ## WeCom 长连接
- `AIA_WECOM_LONGCONN_WORKERS` - `AIA_WECOM_LONGCONN_WORKERS`
- 默认:`2` - 默认:`2`
- 作用:入站处理 worker 数 - 作用:入站处理 worker 数
- 生效:`oclaw/channels/wecom/longconn_runner.py` - 生效:`oclaw/interfaces/channels/wecom/longconn_runner.py`
- `AIA_WECOM_LONGCONN_INBOUND_QUEUE_MAXSIZE` - `AIA_WECOM_LONGCONN_INBOUND_QUEUE_MAXSIZE`
- 默认:`200` - 默认:`200`
- 作用:入站队列长度上限 - 作用:入站队列长度上限
- 生效:`oclaw/channels/wecom/longconn_runner.py` - 生效:`oclaw/interfaces/channels/wecom/longconn_runner.py`
## 安全与密钥 ## 安全与密钥
- `AIA_ASSISTANT_PASSWORD` - `AIA_ASSISTANT_PASSWORD`
- 默认:空(必须配置) - 默认:空(必须配置)
- 作用:管理台管理员密码(bootstrap/login) - 作用:管理台管理员密码(bootstrap/login)
- 生效:`oclaw/platform/config/passwords.py`, `oclaw/admin/routes.py` - 生效:`oclaw/platform/config/passwords.py`, `oclaw/interfaces/admin/routes.py`
- `AIA_ASSISTANT_MASTER_KEY` - `AIA_ASSISTANT_MASTER_KEY`
- 默认:空 - 默认:空
- 作用:密钥加密(Fernet)主密钥 - 作用:密钥加密(Fernet)主密钥
- 生效:`oclaw/platform/persistence/sqlite_store.py`, `oclaw/admin/routes.py` - 生效:`oclaw/platform/persistence/sqlite_store.py`, `oclaw/interfaces/admin/routes.py`
## 存储与迁移 ## 存储与迁移

View file

@ -66,7 +66,7 @@
- 依赖:`PyYAML`(`requirements.txt`)。 - 依赖:`PyYAML`(`requirements.txt`)。
### Changed ### Changed
- `oclaw/prompts/loader.py` 与 `oclaw/openclaw_runtime/skills.py` 统一使用 YAML 解析 frontmatter(失败时默认回落旧行解析,除非开启 STRICT)。 - `oclaw/prompts/loader.py` 与 `oclaw/oclaw_runtime/skills.py` 统一使用 YAML 解析 frontmatter(失败时默认回落旧行解析,除非开启 STRICT)。
--- ---
@ -80,7 +80,7 @@
- `AIA_REPLAY_REPAIR_TOOL_PAIRING`(默认 `1`) - `AIA_REPLAY_REPAIR_TOOL_PAIRING`(默认 `1`)
- `AIA_TOOL_CALL_ID_MAX_LEN`(默认 `40`) - `AIA_TOOL_CALL_ID_MAX_LEN`(默认 `40`)
- `AIA_PROMPT_TOOL_FALLBACK`(默认 `1`) - `AIA_PROMPT_TOOL_FALLBACK`(默认 `1`)
- `oclaw/platform/llm/OPENCLAW_MIT_LICENSE.txt`(oclaw 启发实现之 MIT 署名) - `oclaw/platform/llm/OCLAW_MIT_LICENSE.txt`(oclaw 启发实现之 MIT 署名)
### Changed ### Changed
- 变量前缀统一为 `AIA_*`,项目内不再使用 `OPS_*` / `AI_OPS_*`。 - 变量前缀统一为 `AIA_*`,项目内不再使用 `OPS_*` / `AI_OPS_*`。
@ -105,15 +105,15 @@
## 2026-04-20 / Unreleased ## 2026-04-20 / Unreleased
### Added ### Added
- `AIA_OPENCLAW_ALLOW_LEGACY_FALLBACK` - `AIA_OCLAW_ALLOW_LEGACY_FALLBACK`
- 默认值:`0` - 默认值:`0`
- 用途:oclaw runtime 失败时是否允许回退到 legacy `run_turn` - 用途:oclaw runtime 失败时是否允许回退到 legacy `run_turn`
- 影响模块:`oclaw/openclaw_runtime/gateway.py`, `oclaw/agents/specialist_agent.py` - 影响模块:`oclaw/oclaw_runtime/gateway.py`, `oclaw/runtime/agents/specialist_agent.py`
### Changed ### Changed
- `AIA_TURN_MAX_*`(tool workers/rounds/context) - `AIA_TURN_MAX_*`(tool workers/rounds/context)
- 变更前:由 legacy turn runner 读取(历史文件名可能为 `agent_core.py`) - 变更前:由 legacy turn runner 读取(历史文件名可能为 `agent_core.py`)
- 变更后:由 oclaw runtime 读取并生效(`oclaw/openclaw_runtime/gateway.py`) - 变更后:由 oclaw runtime 读取并生效(`oclaw/oclaw_runtime/gateway.py`)
- 是否需要重启:是(读取自 settings/db/env 的时机取决于运行方式) - 是否需要重启:是(读取自 settings/db/env 的时机取决于运行方式)
### Deprecated ### Deprecated
@ -135,7 +135,7 @@
### Changed ### Changed
- 无新增环境变量;oclaw runtime 在现有变量下补齐了 memory stage、router sync/async 分流、sqlite task queue、worker 执行链路。 - 无新增环境变量;oclaw runtime 在现有变量下补齐了 memory stage、router sync/async 分流、sqlite task queue、worker 执行链路。
- 影响模块:`oclaw/openclaw_runtime/gateway.py`, `oclaw/openclaw_runtime/direct_loop.py`, `oclaw/openclaw_runtime/router.py`, `oclaw/openclaw_runtime/worker.py`, `oclaw/platform/persistence/sqlite_store.py` - 影响模块:`oclaw/oclaw_runtime/gateway.py`, `oclaw/oclaw_runtime/direct_loop.py`, `oclaw/oclaw_runtime/router.py`, `oclaw/oclaw_runtime/worker.py`, `oclaw/platform/persistence/sqlite_store.py`
- 是否需要重启:是(升级代码后建议重启进程以启动 worker 与新路由逻辑) - 是否需要重启:是(升级代码后建议重启进程以启动 worker 与新路由逻辑)
### Migration Checklist ### Migration Checklist
@ -150,10 +150,10 @@
## 2026-04-20 / Unreleased (AgentCore Retry Matrix) ## 2026-04-20 / Unreleased (AgentCore Retry Matrix)
### Added ### Added
- `AIA_OPENCLAW_RETRYABLE_ERROR_CODES` - `AIA_OCLAW_RETRYABLE_ERROR_CODES`
- 默认值:`provider_timeout,provider_rate_limited,provider_temporary_error,provider_unavailable,context_overflow,tool_execution_failed` - 默认值:`provider_timeout,provider_rate_limited,provider_temporary_error,provider_unavailable,context_overflow,tool_execution_failed`
- 用途:控制 Agent Core run 外环可重试错误白名单 - 用途:控制 Agent Core run 外环可重试错误白名单
- 影响模块:`oclaw/openclaw_runtime/agent_core_run.py`, `oclaw/admin/routes.py`, `oclaw/admin/static/app.js` - 影响模块:`oclaw/oclaw_runtime/agent_core_run.py`, `oclaw/interfaces/admin/routes.py`, `oclaw/interfaces/admin/static/app.js`
### Changed ### Changed
- Agent Core 重试策略从“status=retry 即重试”升级为“retry + error_code 命中白名单才重试”。 - Agent Core 重试策略从“status=retry 即重试”升级为“retry + error_code 命中白名单才重试”。
@ -167,15 +167,15 @@
- [x] 已执行编译/测试回归 - [x] 已执行编译/测试回归
### Changed ### Changed
- `AIA_OPENCLAW_RETRYABLE_ERROR_CODES` 已接入 Admin「Tool Policy」页读写链路。 - `AIA_OCLAW_RETRYABLE_ERROR_CODES` 已接入 Admin「Tool Policy」页读写链路。
- 影响模块:`oclaw/admin/routes.py`, `oclaw/admin/static/app.js` - 影响模块:`oclaw/interfaces/admin/routes.py`, `oclaw/interfaces/admin/static/app.js`
- `AIA_OPENCLAW_RETRYABLE_ERROR_CODES` 保存时增加未知 code 过滤与告警返回(`unknown_retryable_error_codes`)。 - `AIA_OCLAW_RETRYABLE_ERROR_CODES` 保存时增加未知 code 过滤与告警返回(`unknown_retryable_error_codes`)。
- 影响模块:`oclaw/admin/routes.py`, `oclaw/admin/static/app.js`, `oclaw/openclaw_runtime/agent_core_run.py` - 影响模块:`oclaw/interfaces/admin/routes.py`, `oclaw/interfaces/admin/static/app.js`, `oclaw/oclaw_runtime/agent_core_run.py`
- `AIA_OPENCLAW_RETRYABLE_ERROR_CODES` 新增严格模式:可配置为未知 code 直接拒绝保存(400)。 - `AIA_OCLAW_RETRYABLE_ERROR_CODES` 新增严格模式:可配置为未知 code 直接拒绝保存(400)。
- 影响模块:`oclaw/admin/routes.py`, `oclaw/admin/static/app.js` - 影响模块:`oclaw/interfaces/admin/routes.py`, `oclaw/interfaces/admin/static/app.js`
### Added ### Added
- `AIA_OPENCLAW_RETRY_CODES_STRICT_MODE` - `AIA_OCLAW_RETRY_CODES_STRICT_MODE`
- 默认值:`0` - 默认值:`0`
- 用途:控制 Admin 保存 retry code 时对未知值的处理(过滤告警 / 拒绝) - 用途:控制 Admin 保存 retry code 时对未知值的处理(过滤告警 / 拒绝)
- 影响模块:`oclaw/admin/routes.py`, `oclaw/admin/static/app.js` - 影响模块:`oclaw/interfaces/admin/routes.py`, `oclaw/interfaces/admin/static/app.js`

View file

@ -5,7 +5,7 @@ This document describes the Python gateway method `image.generate`.
## Method ## Method
- Name: `image.generate` - Name: `image.generate`
- Handler: `oclaw/gateway/server_methods/image.py` - Handler: `oclaw/interfaces/gateway/server_methods/image.py`
## Input Params ## Input Params

View file

@ -10,7 +10,7 @@ Normalization is applied in these handlers:
- `chat.send` - `chat.send`
- `sessions.send` - `sessions.send`
The shared implementation lives in `oclaw/gateway/server_methods/telegram_send_normalize.py`. The shared implementation lives in `oclaw/interfaces/gateway/server_methods/telegram_send_normalize.py`.
## Input fields ## Input fields

View file

@ -1,6 +1,6 @@
# LLM provider/transport capability matrix (oclaw) # LLM provider/transport capability matrix (oclaw)
This project follows an **OpenClaw-style explicit provider/transport selection**: This project follows an **Oclaw-style explicit provider/transport selection**:
- You select the transport via **LLM profile `mode`** (not by inferring from `base_url`). - You select the transport via **LLM profile `mode`** (not by inferring from `base_url`).
- `base_url` can be the same unified gateway URL for all providers; the `mode` determines the wire protocol. - `base_url` can be the same unified gateway URL for all providers; the `mode` determines the wire protocol.
@ -12,7 +12,7 @@ This project follows an **OpenClaw-style explicit provider/transport selection**
- **`base_url`**: gateway host URL (may be shared across providers) - **`base_url`**: gateway host URL (may be shared across providers)
- **`api_key`** (profile secret): primary credential source (reused across modes) - **`api_key`** (profile secret): primary credential source (reused across modes)
Transport selection happens in `oclaw/agents/factory.py`. Transport selection happens in `oclaw/runtime/agents/factory.py`.
## Modes and transports ## Modes and transports
@ -73,7 +73,7 @@ All transports stream assistant output through the same internal callback:
For additional providers, follow this pattern: For additional providers, follow this pattern:
1. Add a new transport class under `oclaw/platform/llm/transports/` 1. Add a new transport class under `oclaw/platform/llm/transports/`
2. Extend `mode` selection in `oclaw/agents/factory.py` 2. Extend `mode` selection in `oclaw/runtime/agents/factory.py`
3. Add an **offline stream parser test** under `tests/` 3. Add an **offline stream parser test** under `tests/`
4. Add/verify WS contract tests (delta + final + session.tool) 4. Add/verify WS contract tests (delta + final + session.tool)

View file

@ -505,7 +505,7 @@ Keep responses deterministic and JSON-serializable.
- **作用**:按库名/版本拉取较新的官方文档片段,减少「API 记错版本」类幻觉。 - **作用**:按库名/版本拉取较新的官方文档片段,减少「API 记错版本」类幻觉。
- **安装**:`python scripts/install_mcp_context7.py`,或管理台 `POST /admin/api/mcp/install` 使用 [`examples/mcp_install_context7.json`](../examples/mcp_install_context7.json) 中的 `payload`。 - **安装**:`python scripts/install_mcp_context7.py`,或管理台 `POST /admin/api/mcp/install` 使用 [`examples/mcp_install_context7.json`](../examples/mcp_install_context7.json) 中的 `payload`。
- **密钥**:在 **`oclaw/_local/mcp_local.env`**(推荐)或 `data/mcp_local.env`(兼容)设置 `CONTEXT7_API_KEY`(见 [context7.com/dashboard](https://context7.com/dashboard))。两处都存在时**同键以 `oclaw/_local/mcp_local.env` 为准**(覆盖 `data` 中的同键)。未自定义 `OPS_MCP_ENV_ALLOWLIST` 时,网关默认 allowlist 已包含 `CONTEXT7_API_KEY`(见 `oclaw/ops/mcp_env.py`);若你自定义了 allowlist,请手动追加该键。 - **密钥**:在 **`oclaw/_local/mcp_local.env`**(推荐)或 `data/mcp_local.env`(兼容)设置 `CONTEXT7_API_KEY`(见 [context7.com/dashboard](https://context7.com/dashboard))。两处都存在时**同键以 `oclaw/_local/mcp_local.env` 为准**(覆盖 `data` 中的同键)。未自定义 `OPS_MCP_ENV_ALLOWLIST` 时,网关默认 allowlist 已包含 `CONTEXT7_API_KEY`(见 `oclaw/runtime/operations/mcp_env.py`);若你自定义了 allowlist,请手动追加该键。
- **装完后**:`Health` → `Sync Tools` → 将 `mcp-context7` 加入通识 specialist 的 MCP 绑定(若脚本已成功 Sync,会自动追加)。 - **装完后**:`Health` → `Sync Tools` → 将 `mcp-context7` 加入通识 specialist 的 MCP 绑定(若脚本已成功 Sync,会自动追加)。
### 通识侧终端能力(`run_command`) ### 通识侧终端能力(`run_command`)

View file

@ -17,10 +17,10 @@ Use this checklist to verify readiness and post-delete safety for `oclaw/app_ser
- [x] Plugin bootstrap still loads expected extension set. - [x] Plugin bootstrap still loads expected extension set.
## Prompt/skill checks ## Prompt/skill checks
- [x] Runtime role context still loads from `oclaw/agent/*`. - [x] Runtime role context still loads from `oclaw/runtime/assets/agent_workspaces/*`.
- [x] Skill root priority still effective: - [x] Skill root priority still effective:
- [x] `AIA_SKILLS_ROOT` - [x] `AIA_SKILLS_ROOT`
- [x] `oclaw/skills` - [x] `oclaw/runtime/skills`
- [x] `skills/` fallback - [x] `skills/` fallback
## Extension policy checks ## Extension policy checks

View file

@ -1,4 +1,4 @@
# OpenClaw Migration Guide # Oclaw Migration Guide
This repository is migrating from legacy `oclaw/` runtime wiring to the new `oclaw/` architecture root. This repository is migrating from legacy `oclaw/` runtime wiring to the new `oclaw/` architecture root.
@ -17,7 +17,7 @@ This repository is migrating from legacy `oclaw/` runtime wiring to the new `ocl
## Runtime notes ## Runtime notes
- Gateway HTTP method adapter: `POST /gateway/method` - Gateway HTTP method adapter: `POST /gateway/method`
- WS dispatch first resolves method handlers from shared dispatcher. - WS dispatch first resolves method handlers from shared dispatcher.
- Inbound payload use-case entrypoint: `oclaw.application.gateway.process_inbound_payload_usecase` - Inbound payload use-case entrypoint: `oclaw.runtime.application.gateway.process_inbound_payload_usecase`
- HTTP app entrypoint moved to: `oclaw.interfaces.http.fastapi_app` - HTTP app entrypoint moved to: `oclaw.interfaces.http.fastapi_app`
- WS entrypoint moved to: `oclaw.interfaces.ws.entrypoint` - WS entrypoint moved to: `oclaw.interfaces.ws.entrypoint`
- WS runtime bridge path: `oclaw.interfaces.ws.runtime` - WS runtime bridge path: `oclaw.interfaces.ws.runtime`
@ -62,9 +62,9 @@ This repository is migrating from legacy `oclaw/` runtime wiring to the new `ocl
- Legacy root `extensions/` has been merged into `oclaw/extensions/` and removed. - Legacy root `extensions/` has been merged into `oclaw/extensions/` and removed.
## Prompt and skills policy ## Prompt and skills policy
- Role context is loaded from `oclaw/agent/*`. - Role context is loaded from `oclaw/runtime/assets/agent_workspaces/*`.
- Skills root priority: - Skills root priority:
1. `AIA_SKILLS_ROOT` 1. `AIA_SKILLS_ROOT`
2. `oclaw/skills` 2. `oclaw/runtime/skills`
3. `skills/` (legacy fallback) 3. `skills/` (legacy fallback)

View file

@ -4,14 +4,14 @@
关联文档: 关联文档:
- trace 字段与阶段对照:`docs/openclaw-trace-taxonomy.md` - trace 字段与阶段对照:`docs/oclaw-trace-taxonomy.md`
- skill 安装/执行排障:`docs/openclaw-skill-troubleshooting.md` - skill 安装/执行排障:`docs/oclaw-skill-troubleshooting.md`
--- ---
## 1. 统一入口(只保留最新) ## 1. 统一入口(只保留最新)
所有运维命令统一通过 `scripts/`,不要再使用 `python -m oclaw.ops ...` 或历史 `.bat` 方式。 所有运维命令统一通过 `scripts/`,不要再使用 `python -m oclaw.runtime.operations ...` 或历史 `.bat` 方式。
补充:工具脚本也统一放在 `scripts/`(例如 `seed_mcp_registry.py`、`ws_probe.py`)。 补充:工具脚本也统一放在 `scripts/`(例如 `seed_mcp_registry.py`、`ws_probe.py`)。
@ -272,7 +272,7 @@ powershell -ExecutionPolicy Bypass -File .\scripts\weixin_install.ps1
安装目录: 安装目录:
- `data/channel_sidecar/openclaw-weixin/` - `data/channel_sidecar/oclaw-weixin/`
### 11.2 扫码登录(获取 bot token) ### 11.2 扫码登录(获取 bot token)
@ -282,8 +282,8 @@ powershell -ExecutionPolicy Bypass -File .\scripts\weixin_login.ps1
登录态写入: 登录态写入:
- `data/channel_sidecar/openclaw-weixin/state/openclaw-weixin/accounts/*.json` - `data/channel_sidecar/oclaw-weixin/state/oclaw-weixin/accounts/*.json`
- `data/channel_sidecar/openclaw-weixin/state/openclaw-weixin/accounts.json` - `data/channel_sidecar/oclaw-weixin/state/oclaw-weixin/accounts.json`
### 11.3 启动微信 sidecar ### 11.3 启动微信 sidecar
@ -305,8 +305,8 @@ powershell -ExecutionPolicy Bypass -File .\scripts\weixin_stop.ps1
日志文件: 日志文件:
- `data/channel_sidecar/openclaw-weixin/logs/weixin_sidecar.log` - `data/channel_sidecar/oclaw-weixin/logs/weixin_sidecar.log`
- `data/channel_sidecar/openclaw-weixin/logs/weixin_sidecar.err.log` - `data/channel_sidecar/oclaw-weixin/logs/weixin_sidecar.err.log`
### 11.4 当前行为说明 ### 11.4 当前行为说明
@ -440,7 +440,7 @@ python .\scripts\wiki_auto_smoke_test.py
该脚本会: 该脚本会:
- 投递一条 `wiki_capture` 任务到 `openclaw_task` - 投递一条 `wiki_capture` 任务到 `oclaw_task`
- 轮询任务状态直到 `done/failed/timeout` - 轮询任务状态直到 `done/failed/timeout`
- 输出当前写入产物状态(`merged-turns.md`、`topic-index.json`、`index.json`、`LINT_REPORT.md`) - 输出当前写入产物状态(`merged-turns.md`、`topic-index.json`、`index.json`、`LINT_REPORT.md`)

View file

@ -11,5 +11,5 @@
如需查看完整细粒度字段定义,请在仓库中搜索: 如需查看完整细粒度字段定义,请在仓库中搜索:
- `pipeline` - `pipeline`
- `openclaw_task_id` - `oclaw_task_id`
- `openclaw_worker_id` - `oclaw_worker_id`

View file

@ -27,19 +27,19 @@
推荐按下列顺序查询同一个 `trace_id`: 推荐按下列顺序查询同一个 `trace_id`:
1. `openclaw_gateway` 1. `oclaw_gateway`
- `skill_manifest` - `skill_manifest`
- `router_decision` - `router_decision`
2. `openclaw_agent_core` 2. `oclaw_agent_core`
- `run_started` - `run_started`
- `attempt_started` - `attempt_started`
3. `openclaw_direct_loop` 3. `oclaw_direct_loop`
- `tool_wire_filter` - `tool_wire_filter`
- `tool_result_context_guard` - `tool_result_context_guard`
4. `openclaw_skill_executor` 4. `oclaw_skill_executor`
- `skill_selected` - `skill_selected`
- `skill_executed` - `skill_executed`
5. `openclaw_agent_core` 5. `oclaw_agent_core`
- `after_turn_memory` - `after_turn_memory`
- `attempt_finished` - `attempt_finished`
- `run_finished` - `run_finished`
@ -52,7 +52,7 @@
- `AIA_SKILLS_PROMPT_IN_SYSTEM` 是否开启 - `AIA_SKILLS_PROMPT_IN_SYSTEM` 是否开启
- `AIA_SKILL_DISABLED_NAMES` 是否误禁用了目标 skill - `AIA_SKILL_DISABLED_NAMES` 是否误禁用了目标 skill
- `AIA_SKILL_AUTO_INSTALL_ENABLED` 是否关闭 - `AIA_SKILL_AUTO_INSTALL_ENABLED` 是否关闭
- 目标 skill 的 `SKILL.md` 是否包含合法 frontmatter(尤其 `metadata.openclaw.install`) - 目标 skill 的 `SKILL.md` 是否包含合法 frontmatter(尤其 `metadata.oclaw.install`)
## 5) 典型故障定位 ## 5) 典型故障定位

View file

@ -7,15 +7,15 @@ Trace events share a common `payload` shape across components. Prefer joining on
| Key | Meaning | | Key | Meaning |
| --- | --- | | --- | --- |
| `trace_id` | Correlates all events for one gateway turn | | `trace_id` | Correlates all events for one gateway turn |
| `pipeline` | Which subsystem emitted the event (`openclaw_gateway`, `openclaw_agent_core`, `openclaw_direct_loop`, `openclaw_skill_executor`) | | `pipeline` | Which subsystem emitted the event (`oclaw_gateway`, `oclaw_agent_core`, `oclaw_direct_loop`, `oclaw_skill_executor`) |
| `oc_stage` | Normalized lifecycle stage (see tables below) | | `oc_stage` | Normalized lifecycle stage (see tables below) |
| `lang` | Request language when known | | `lang` | Request language when known |
| `run_id` | Agent core run UUID (retry container) | | `run_id` | Agent core run UUID (retry container) |
| `attempt_no` | 1-based attempt index inside `run_id` | | `attempt_no` | 1-based attempt index inside `run_id` |
| `openclaw_task_id` | Async worker task id when present | | `oclaw_task_id` | Async worker task id when present |
| `openclaw_worker_id` | Worker thread id when present | | `oclaw_worker_id` | Worker thread id when present |
## Gateway (`pipeline=openclaw_gateway`) ## Gateway (`pipeline=oclaw_gateway`)
| `event_type` | `oc_stage` | | `event_type` | `oc_stage` |
| --- | --- | | --- | --- |
@ -35,7 +35,7 @@ Trace events share a common `payload` shape across components. Prefer joining on
- `relay_envelope_present`: whether `metadata.relay_share_envelope` exists - `relay_envelope_present`: whether `metadata.relay_share_envelope` exists
- `relay_envelope_pointer_count`: pointer count inside envelope manifest - `relay_envelope_pointer_count`: pointer count inside envelope manifest
## Agent core (`pipeline=openclaw_agent_core`) ## Agent core (`pipeline=oclaw_agent_core`)
| `event_type` | `oc_stage` | | `event_type` | `oc_stage` |
| --- | --- | | --- | --- |
@ -46,7 +46,7 @@ Trace events share a common `payload` shape across components. Prefer joining on
| `run_compact` | `compact` | | `run_compact` | `compact` |
| `run_retry` | `retry` | | `run_retry` | `retry` |
## Direct loop (`pipeline=openclaw_direct_loop`) ## Direct loop (`pipeline=oclaw_direct_loop`)
| `event_type` | `oc_stage` | | `event_type` | `oc_stage` |
| --- | --- | | --- | --- |
@ -55,7 +55,7 @@ Trace events share a common `payload` shape across components. Prefer joining on
Both include `trace_id` and, when provided by the parent attempt, `run_id` and `attempt_no`. Both include `trace_id` and, when provided by the parent attempt, `run_id` and `attempt_no`.
## Skill executor (`pipeline=openclaw_skill_executor`) ## Skill executor (`pipeline=oclaw_skill_executor`)
| `event_type` | `oc_stage` | | `event_type` | `oc_stage` |
| --- | --- | | --- | --- |
@ -64,7 +64,7 @@ Both include `trace_id` and, when provided by the parent attempt, `run_id` and `
The payload includes `run_id` and `attempt_no` when available, so skill execution can be joined back to `run_started/attempt_started`. The payload includes `run_id` and `attempt_no` when available, so skill execution can be joined back to `run_started/attempt_started`.
## Attempt memory hook (`pipeline=openclaw_agent_core`) ## Attempt memory hook (`pipeline=oclaw_agent_core`)
| `event_type` | `oc_stage` | | `event_type` | `oc_stage` |
| --- | --- | | --- | --- |

View file

@ -1,13 +0,0 @@
"""Python gateway runtime rewrite entrypoint.
This package is the Python rewrite surface for gateway modules.
"""
from .server_plugins import load_gateway_plugins
from .server_startup_plugins import prepare_gateway_plugin_bootstrap
__all__ = [
"load_gateway_plugins",
"prepare_gateway_plugin_bootstrap",
]

View file

@ -1,2 +0,0 @@
"""Infrastructure integrations (LLM, persistence, plugins, etc.)."""

View file

@ -1,6 +0,0 @@
"""Agent-context loaders from `oclaw/agent/*`."""
from .loader import build_role_system_context
__all__ = ["build_role_system_context"]

View file

@ -14,9 +14,9 @@ from pathlib import Path
from fastapi import APIRouter, Body, File, Header, HTTPException, Query, UploadFile from fastapi import APIRouter, Body, File, Header, HTTPException, Query, UploadFile
from fastapi.responses import Response, StreamingResponse from fastapi.responses import Response, StreamingResponse
from oclaw.ops.mcp_env import apply_gateway_mcp_env_to_os from oclaw.runtime.operations.mcp_env import apply_gateway_mcp_env_to_os
from oclaw.agents.factory import build_gateway_executor from oclaw.runtime.agents.factory import build_gateway_executor
from oclaw.chat.agent import GenerationInterrupted from oclaw.runtime.chat.agent import GenerationInterrupted
from oclaw.platform.config.paths import db_path from oclaw.platform.config.paths import db_path
from oclaw.platform.files.attachment_assets import AttachmentAssetStore from oclaw.platform.files.attachment_assets import AttachmentAssetStore
from oclaw.platform.files.file_attachments import ( from oclaw.platform.files.file_attachments import (
@ -29,8 +29,8 @@ from oclaw.platform.files.file_attachments import (
) )
from oclaw.platform.files.session_export import export_session_json, export_session_markdown from oclaw.platform.files.session_export import export_session_json, export_session_markdown
from oclaw.platform.persistence.sqlite_store import SqliteStore from oclaw.platform.persistence.sqlite_store import SqliteStore
from oclaw.openclaw_runtime.gateway import OpenClawGateway from oclaw.runtime.gateway import OclawGateway
from oclaw.openclaw_runtime.types import StandardMessage, normalize_interaction_mode, normalize_requested_specialist from oclaw.runtime.types import StandardMessage, normalize_interaction_mode, normalize_requested_specialist
def _oclaw_config_path() -> Path: def _oclaw_config_path() -> Path:
@ -706,7 +706,7 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
if not sess: if not sess:
raise HTTPException(status_code=404, detail="session_not_found") raise HTTPException(status_code=404, detail="session_not_found")
after_iso = str(after or "").strip() after_iso = str(after or "").strip()
rows = store.openclaw_task_list(tenant_id=tenant_id, session_id=str(session_id), limit=max(50, int(limit) * 5)) rows = store.oclaw_task_list(tenant_id=tenant_id, session_id=str(session_id), limit=max(50, int(limit) * 5))
events: list[dict[str, Any]] = [] events: list[dict[str, Any]] = []
for t in rows: for t in rows:
if str(t.task_type or "") != "wiki_capture": if str(t.task_type or "") != "wiki_capture":
@ -894,7 +894,7 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
labels = _dispatch_reason_labels_with_overrides(store) labels = _dispatch_reason_labels_with_overrides(store)
_require_administrator_chat_viewer(ctx) _require_administrator_chat_viewer(ctx)
tenant_id = str(ctx.get("tenant_id") or "") tenant_id = str(ctx.get("tenant_id") or "")
rows = store.openclaw_task_list(tenant_id=tenant_id, limit=limit) rows = store.oclaw_task_list(tenant_id=tenant_id, limit=limit)
total = len(rows) total = len(rows)
dynamic_used = 0 dynamic_used = 0
fallback_generalist = 0 fallback_generalist = 0
@ -1288,7 +1288,7 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
policy_session_id=str(session_id), policy_session_id=str(session_id),
) )
try: try:
gw = OpenClawGateway(store=store) gw = OclawGateway(store=store)
msg = StandardMessage( msg = StandardMessage(
session_id=str(session_id), session_id=str(session_id),
tenant_id=tenant_id, tenant_id=tenant_id,
@ -1431,7 +1431,7 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
kind = "skill_ui" if ev_name.startswith("skill_") else "tool_ui" kind = "skill_ui" if ev_name.startswith("skill_") else "tool_ui"
_emit(kind, {"event": ev_name, "payload": pl}) _emit(kind, {"event": ev_name, "payload": pl})
gw = OpenClawGateway(store=store) gw = OclawGateway(store=store)
msg = StandardMessage( msg = StandardMessage(
session_id=str(session_id), session_id=str(session_id),
tenant_id=tenant_id, tenant_id=tenant_id,

View file

@ -3,8 +3,8 @@ from __future__ import annotations
from typing import Any from typing import Any
from oclaw.tools.base import ToolRegistry, ToolSpec from oclaw.runtime.tools.base import ToolRegistry, ToolSpec
from oclaw.tools.tool_validation import validate_tool_arguments from oclaw.runtime.tools.tool_validation import validate_tool_arguments
def parse_mcp_bound_tool_name(full_name: str) -> tuple[str, str] | None: def parse_mcp_bound_tool_name(full_name: str) -> tuple[str, str] | None:

View file

@ -12,15 +12,15 @@ from typing import Any
from fastapi import APIRouter, Body, Header, HTTPException, Query from fastapi import APIRouter, Body, Header, HTTPException, Query
from fastapi.responses import Response from fastapi.responses import Response
from oclaw.agents.factory import DEFAULT_OLLAMA_BASE_URL, DEFAULT_OLLAMA_MODEL from oclaw.runtime.agents.factory import DEFAULT_OLLAMA_BASE_URL, DEFAULT_OLLAMA_MODEL
from oclaw.agents.specialists import ( from oclaw.runtime.agents.specialists import (
AGENT_PROFILE_BINDINGS_KEY, AGENT_PROFILE_BINDINGS_KEY,
AGENT_ROLE_IDS, AGENT_ROLE_IDS,
dump_agent_profile_bindings, dump_agent_profile_bindings,
parse_agent_profile_bindings, parse_agent_profile_bindings,
) )
from oclaw.platform.config.paths import db_path from oclaw.platform.config.paths import db_path
from oclaw.orchestration.evaluation import eval_summary from oclaw.runtime.orchestration.evaluation import eval_summary
from oclaw.platform.persistence.sqlite_store import ( from oclaw.platform.persistence.sqlite_store import (
LLM_BUILTIN_OLLAMA_PROFILE_ID, LLM_BUILTIN_OLLAMA_PROFILE_ID,
SqliteStore, SqliteStore,

View file

@ -12,38 +12,38 @@ from fastapi import APIRouter, Body, Header, Query
from fastapi import HTTPException from fastapi import HTTPException
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from oclaw.ops.mcp_env import apply_gateway_mcp_env_to_os from oclaw.runtime.operations.mcp_env import apply_gateway_mcp_env_to_os
from oclaw.ops.providers.registry import build_channel_registry from oclaw.runtime.operations.providers.registry import build_channel_registry
from oclaw.ops.runtime import cleanup_orphan_service_processes, detect_orphan_service_processes, status_services from oclaw.runtime.operations.runtime import cleanup_orphan_service_processes, detect_orphan_service_processes, status_services
from oclaw.ops.stack import cmd_stack_down, cmd_stack_status, cmd_stack_up from oclaw.runtime.operations.stack import cmd_stack_down, cmd_stack_status, cmd_stack_up
from oclaw.orchestration.vector_store import read_vector_memory_runtime from oclaw.runtime.orchestration.vector_store import read_vector_memory_runtime
from oclaw.platform.config.paths import PROJECT_ROOT, db_path from oclaw.platform.config.paths import PROJECT_ROOT, db_path
from oclaw.platform.config.passwords import load_expected_password from oclaw.platform.config.passwords import load_expected_password
from oclaw.platform.persistence.sqlite_store import SqliteStore from oclaw.platform.persistence.sqlite_store import SqliteStore
from oclaw.agents.specialists import SPECIALISTS from oclaw.runtime.agents.specialists import SPECIALISTS
from oclaw.tools.mcp.installer import ( from oclaw.runtime.tools.mcp.installer import (
_safe_server_id, _safe_server_id,
detect_local_dependencies, detect_local_dependencies,
install_mcp_server, install_mcp_server,
preflight_mcp_server, preflight_mcp_server,
uninstall_mcp_server, uninstall_mcp_server,
) )
from oclaw.tools.mcp.market import search_mcp_market, trending_mcp_market from oclaw.runtime.tools.mcp.market import search_mcp_market, trending_mcp_market
from oclaw.tools.mcp.manifest import McpServerManifest from oclaw.runtime.tools.mcp.manifest import McpServerManifest
from oclaw.ops.mcp_registry_export import ( from oclaw.runtime.operations.mcp_registry_export import (
build_mcp_install_export_document, build_mcp_install_export_document,
mcp_migrated_json_path, mcp_migrated_json_path,
persist_mcp_migrated_file, persist_mcp_migrated_file,
) )
from oclaw.tools.mcp.filesystem_argv import build_mcp_process_command from oclaw.runtime.tools.mcp.filesystem_argv import build_mcp_process_command
from oclaw.tools.mcp.registry import McpRegistry from oclaw.runtime.tools.mcp.registry import McpRegistry
from oclaw.tools.mcp.runtime import McpProcessRuntime from oclaw.runtime.tools.mcp.runtime import McpProcessRuntime
from oclaw.admin.mcp_e2e_probe import build_mcp_e2e_probe_plans from oclaw.interfaces.admin.mcp_e2e_probe import build_mcp_e2e_probe_plans
from oclaw.tools.catalog import default_registry from oclaw.runtime.tools.catalog import default_registry
from oclaw.chat.tool_runtime import ToolExecutionContext, ToolExecutor from oclaw.runtime.chat.tool_runtime import ToolExecutionContext, ToolExecutor
from oclaw.platform.llm.chat_models import LLMToolCall from oclaw.platform.llm.chat_models import LLMToolCall
from oclaw.openclaw_runtime.agent_core_attempt import ALL_ATTEMPT_ERROR_CODES from oclaw.runtime.agent_core_attempt import ALL_ATTEMPT_ERROR_CODES
from oclaw.openclaw_runtime.agent_core_run import DEFAULT_RETRYABLE_ERROR_CODES, resolve_retryable_error_codes from oclaw.runtime.agent_core_run import DEFAULT_RETRYABLE_ERROR_CODES, resolve_retryable_error_codes
_WECOM_CLEAR_KEYS = [ _WECOM_CLEAR_KEYS = [
"wecom_mode", "wecom_mode",
@ -251,8 +251,8 @@ def build_admin_router() -> APIRouter:
ctx = _resolve_auth(store, authorization) ctx = _resolve_auth(store, authorization)
_require_permission(ctx, "admin:tenant:write") _require_permission(ctx, "admin:tenant:write")
from oclaw.tools.expert_registry import clear_expert_tool_cache from oclaw.runtime.tools.expert_registry import clear_expert_tool_cache
from oclaw.tools.public_registry import clear_public_tool_cache from oclaw.runtime.tools.public_registry import clear_public_tool_cache
clear_public_tool_cache() clear_public_tool_cache()
clear_expert_tool_cache() clear_expert_tool_cache()
@ -309,7 +309,7 @@ def build_admin_router() -> APIRouter:
store = SqliteStore(db_path()) store = SqliteStore(db_path())
ctx = _resolve_auth(store, authorization) ctx = _resolve_auth(store, authorization)
_require_permission(ctx, "admin:tenant:write") _require_permission(ctx, "admin:tenant:write")
from oclaw.tools.exposure_plan import build_internal_tool_specs from oclaw.runtime.tools.exposure_plan import build_internal_tool_specs
r = str(role or "").strip().lower() r = str(role or "").strip().lower()
available_roles = _ordered_roles() available_roles = _ordered_roles()
@ -349,7 +349,7 @@ def build_admin_router() -> APIRouter:
_require_permission(ctx, "admin:tenant:write") _require_permission(ctx, "admin:tenant:write")
from oclaw.platform.llm.tool_wire_policy import load_role_mode_for_role, load_tool_policies_dict_for_role from oclaw.platform.llm.tool_wire_policy import load_role_mode_for_role, load_tool_policies_dict_for_role
from oclaw.tools.exposure_plan import build_internal_tool_specs, build_llm_tools_plan from oclaw.runtime.tools.exposure_plan import build_internal_tool_specs, build_llm_tools_plan
roles = _ordered_roles() roles = _ordered_roles()
items: list[dict[str, Any]] = [] items: list[dict[str, Any]] = []
@ -412,7 +412,7 @@ def build_admin_router() -> APIRouter:
store = SqliteStore(db_path()) store = SqliteStore(db_path())
ctx = _resolve_auth(store, authorization) ctx = _resolve_auth(store, authorization)
_require_permission(ctx, "admin:tenant:write") _require_permission(ctx, "admin:tenant:write")
from oclaw.tools.exposure_plan import build_llm_tools_plan from oclaw.runtime.tools.exposure_plan import build_llm_tools_plan
r = str(role or "").strip().lower() r = str(role or "").strip().lower()
available_roles = _ordered_roles() available_roles = _ordered_roles()
@ -1312,8 +1312,8 @@ def build_admin_router() -> APIRouter:
return {"ok": True, "trace": rows} return {"ok": True, "trace": rows}
@router.get("/admin/api/oclaw/tasks") @router.get("/admin/api/oclaw/tasks")
@router.get("/admin/api/openclaw/tasks") @router.get("/admin/api/oclaw/tasks")
def api_openclaw_tasks( def api_oclaw_tasks(
task_id: str | None = Query(default=None), task_id: str | None = Query(default=None),
session_id: str | None = Query(default=None), session_id: str | None = Query(default=None),
status: str | None = Query(default=None), status: str | None = Query(default=None),
@ -1327,9 +1327,9 @@ def build_admin_router() -> APIRouter:
sid = str(session_id or "").strip() or None sid = str(session_id or "").strip() or None
st = str(status or "").strip() or None st = str(status or "").strip() or None
if task_id: if task_id:
task = store.openclaw_task_get(task_id=str(task_id), tenant_id=tenant_id) task = store.oclaw_task_get(task_id=str(task_id), tenant_id=tenant_id)
return {"ok": True, "task": None if not task else task.__dict__} return {"ok": True, "task": None if not task else task.__dict__}
rows = store.openclaw_task_list( rows = store.oclaw_task_list(
status=st, status=st,
session_id=sid, session_id=sid,
tenant_id=tenant_id, tenant_id=tenant_id,
@ -1342,8 +1342,8 @@ def build_admin_router() -> APIRouter:
return {"ok": True, "tasks": [r.__dict__ for r in rows], "counts": by_status} return {"ok": True, "tasks": [r.__dict__ for r in rows], "counts": by_status}
@router.get("/admin/api/oclaw/runs") @router.get("/admin/api/oclaw/runs")
@router.get("/admin/api/openclaw/runs") @router.get("/admin/api/oclaw/runs")
def api_openclaw_runs( def api_oclaw_runs(
run_id: str | None = Query(default=None), run_id: str | None = Query(default=None),
session_id: str | None = Query(default=None), session_id: str | None = Query(default=None),
status: str | None = Query(default=None), status: str | None = Query(default=None),
@ -1356,14 +1356,14 @@ def build_admin_router() -> APIRouter:
_require_permission(ctx, "admin:read") _require_permission(ctx, "admin:read")
tenant_id = str(ctx.get("tenant_id") or "") tenant_id = str(ctx.get("tenant_id") or "")
if run_id: if run_id:
row = store.openclaw_run_get(run_id=str(run_id), tenant_id=tenant_id) row = store.oclaw_run_get(run_id=str(run_id), tenant_id=tenant_id)
if not row: if not row:
return {"ok": True, "run": None} return {"ok": True, "run": None}
out = dict(row.__dict__) out = dict(row.__dict__)
if int(include_attempts or 0): if int(include_attempts or 0):
out["attempts"] = store.openclaw_attempt_list(run_id=row.run_id, limit=50) out["attempts"] = store.oclaw_attempt_list(run_id=row.run_id, limit=50)
return {"ok": True, "run": out} return {"ok": True, "run": out}
rows = store.openclaw_run_list( rows = store.oclaw_run_list(
tenant_id=tenant_id, tenant_id=tenant_id,
session_id=str(session_id or "").strip() or None, session_id=str(session_id or "").strip() or None,
status=str(status or "").strip() or None, status=str(status or "").strip() or None,
@ -1376,7 +1376,7 @@ def build_admin_router() -> APIRouter:
by_status[s] = int(by_status.get(s, 0)) + 1 by_status[s] = int(by_status.get(s, 0)) + 1
item = dict(r.__dict__) item = dict(r.__dict__)
if int(include_attempts or 0): if int(include_attempts or 0):
item["attempts"] = store.openclaw_attempt_list(run_id=r.run_id, limit=20) item["attempts"] = store.oclaw_attempt_list(run_id=r.run_id, limit=20)
out_rows.append(item) out_rows.append(item)
configured_retryable = sorted(resolve_retryable_error_codes(store=store)) configured_retryable = sorted(resolve_retryable_error_codes(store=store))
return { return {
@ -1384,7 +1384,7 @@ def build_admin_router() -> APIRouter:
"runs": out_rows, "runs": out_rows,
"counts": by_status, "counts": by_status,
"retry_policy": { "retry_policy": {
"setting_key": "AIA_OPENCLAW_RETRYABLE_ERROR_CODES", "setting_key": "AIA_OCLAW_RETRYABLE_ERROR_CODES",
"effective_retryable_error_codes": configured_retryable, "effective_retryable_error_codes": configured_retryable,
"default_retryable_error_codes": list(DEFAULT_RETRYABLE_ERROR_CODES), "default_retryable_error_codes": list(DEFAULT_RETRYABLE_ERROR_CODES),
}, },
@ -1440,7 +1440,7 @@ def build_admin_router() -> APIRouter:
store = SqliteStore(db_path()) store = SqliteStore(db_path())
ctx = _resolve_auth(store, authorization) ctx = _resolve_auth(store, authorization)
_require_permission(ctx, "admin:tenant:write") _require_permission(ctx, "admin:tenant:write")
# OpenClaw takeover: legacy tool-policy switches are disconnected (kept in DB for later). # Oclaw takeover: legacy tool-policy switches are disconnected (kept in DB for later).
disabled = False disabled = False
retry_mode = "first_round_only" retry_mode = "first_round_only"
loop_state_machine = True loop_state_machine = True
@ -1451,9 +1451,9 @@ def build_admin_router() -> APIRouter:
turn_max_tool_workers = max(1, min(int(tmw_raw), 32)) if tmw_raw.isdigit() else 8 turn_max_tool_workers = max(1, min(int(tmw_raw), 32)) if tmw_raw.isdigit() else 8
turn_max_tool_rounds = max(1, min(int(tmr_raw), 30)) if tmr_raw.isdigit() else 8 turn_max_tool_rounds = max(1, min(int(tmr_raw), 30)) if tmr_raw.isdigit() else 8
turn_max_context_messages = max(10, min(int(tmc_raw), 400)) if tmc_raw.isdigit() else 80 turn_max_context_messages = max(10, min(int(tmc_raw), 400)) if tmc_raw.isdigit() else 80
# OpenClaw takeover: legacy runner switches are disconnected (kept in DB for later). # Oclaw takeover: legacy runner switches are disconnected (kept in DB for later).
turn_runner_impl = "openclaw" turn_runner_impl = "oclaw"
# OpenClaw takeover: legacy manager decision mode is disconnected (kept in DB for later). # Oclaw takeover: legacy manager decision mode is disconnected (kept in DB for later).
manager_decision_mode = "" manager_decision_mode = ""
sse_raw = str(store.get_setting("AIA_SSE_QUEUE_MAXSIZE") or "").strip() sse_raw = str(store.get_setting("AIA_SSE_QUEUE_MAXSIZE") or "").strip()
sse_queue_maxsize = max(200, min(int(sse_raw), 50_000)) if sse_raw.isdigit() else 2000 sse_queue_maxsize = max(200, min(int(sse_raw), 50_000)) if sse_raw.isdigit() else 2000
@ -1475,10 +1475,10 @@ def build_admin_router() -> APIRouter:
tool_llm_message_max_chars = 0 tool_llm_message_max_chars = 0
mcp_fs_raw = str(store.get_setting("AIA_MCP_FILESYSTEM_EXTRA_ROOTS") or "").strip() mcp_fs_raw = str(store.get_setting("AIA_MCP_FILESYSTEM_EXTRA_ROOTS") or "").strip()
mcp_env_allow_raw = str(store.get_setting("AIA_MCP_ENV_ALLOWLIST") or "").strip() mcp_env_allow_raw = str(store.get_setting("AIA_MCP_ENV_ALLOWLIST") or "").strip()
retry_codes_raw = str(store.get_setting("AIA_OPENCLAW_RETRYABLE_ERROR_CODES") or "").strip() retry_codes_raw = str(store.get_setting("AIA_OCLAW_RETRYABLE_ERROR_CODES") or "").strip()
if not retry_codes_raw: if not retry_codes_raw:
retry_codes_raw = ",".join(DEFAULT_RETRYABLE_ERROR_CODES) retry_codes_raw = ",".join(DEFAULT_RETRYABLE_ERROR_CODES)
retry_strict_raw = str(store.get_setting("AIA_OPENCLAW_RETRY_CODES_STRICT_MODE") or "").strip().lower() retry_strict_raw = str(store.get_setting("AIA_OCLAW_RETRY_CODES_STRICT_MODE") or "").strip().lower()
retry_codes_strict_mode = retry_strict_raw in ("1", "true", "yes", "on") retry_codes_strict_mode = retry_strict_raw in ("1", "true", "yes", "on")
wc_workers_raw = str(store.get_setting("AIA_WECOM_LONGCONN_WORKERS") or "").strip() wc_workers_raw = str(store.get_setting("AIA_WECOM_LONGCONN_WORKERS") or "").strip()
if not wc_workers_raw: if not wc_workers_raw:
@ -1508,8 +1508,8 @@ def build_admin_router() -> APIRouter:
"tool_llm_message_max_chars": tool_llm_message_max_chars, "tool_llm_message_max_chars": tool_llm_message_max_chars,
"mcp_filesystem_extra_roots": mcp_fs_raw, "mcp_filesystem_extra_roots": mcp_fs_raw,
"mcp_env_allowlist": mcp_env_allow_raw, "mcp_env_allowlist": mcp_env_allow_raw,
"openclaw_retryable_error_codes": retry_codes_raw, "oclaw_retryable_error_codes": retry_codes_raw,
"openclaw_retry_codes_strict_mode": retry_codes_strict_mode, "oclaw_retry_codes_strict_mode": retry_codes_strict_mode,
"wecom_longconn_workers": wecom_longconn_workers, "wecom_longconn_workers": wecom_longconn_workers,
"wecom_longconn_inbound_queue_maxsize": wecom_longconn_inbound_queue_maxsize, "wecom_longconn_inbound_queue_maxsize": wecom_longconn_inbound_queue_maxsize,
} }
@ -1523,7 +1523,7 @@ def build_admin_router() -> APIRouter:
store = SqliteStore(db_path()) store = SqliteStore(db_path())
ctx = _resolve_auth(store, authorization) ctx = _resolve_auth(store, authorization)
_require_permission(ctx, "admin:tenant:write") _require_permission(ctx, "admin:tenant:write")
# OpenClaw takeover: legacy tool-policy switches are disconnected (kept in DB for later). # Oclaw takeover: legacy tool-policy switches are disconnected (kept in DB for later).
disable_confirm = False disable_confirm = False
retry_mode = "first_round_only" retry_mode = "first_round_only"
sm = True sm = True
@ -1531,7 +1531,7 @@ def build_admin_router() -> APIRouter:
tmw = payload.get("turn_max_tool_workers", 8) tmw = payload.get("turn_max_tool_workers", 8)
tmr = payload.get("turn_max_tool_rounds", 8) tmr = payload.get("turn_max_tool_rounds", 8)
tmc = payload.get("turn_max_context_messages", 80) tmc = payload.get("turn_max_context_messages", 80)
tri = "openclaw" tri = "oclaw"
try: try:
tmw_n = max(1, min(int(tmw), 32)) tmw_n = max(1, min(int(tmw), 32))
except Exception: except Exception:
@ -1562,8 +1562,8 @@ def build_admin_router() -> APIRouter:
tmsg = payload.get("tool_llm_message_max_chars", 0) tmsg = payload.get("tool_llm_message_max_chars", 0)
mcp_fs_roots = str(payload.get("mcp_filesystem_extra_roots") or "").strip() mcp_fs_roots = str(payload.get("mcp_filesystem_extra_roots") or "").strip()
mcp_env_allow = str(payload.get("mcp_env_allowlist") or "").strip() mcp_env_allow = str(payload.get("mcp_env_allowlist") or "").strip()
retry_codes = str(payload.get("openclaw_retryable_error_codes") or "").strip() retry_codes = str(payload.get("oclaw_retryable_error_codes") or "").strip()
retry_codes_strict_mode = bool(payload.get("openclaw_retry_codes_strict_mode", False)) retry_codes_strict_mode = bool(payload.get("oclaw_retry_codes_strict_mode", False))
unknown_retry_codes: list[str] = [] unknown_retry_codes: list[str] = []
if retry_codes: if retry_codes:
vals = [x.strip().lower() for x in retry_codes.split(",") if x and x.strip()] vals = [x.strip().lower() for x in retry_codes.split(",") if x and x.strip()]
@ -1631,8 +1631,8 @@ def build_admin_router() -> APIRouter:
store.set_setting("AIA_TOOL_LLM_MESSAGE_MAX_CHARS", str(tmsg_n)) store.set_setting("AIA_TOOL_LLM_MESSAGE_MAX_CHARS", str(tmsg_n))
store.set_setting("AIA_MCP_FILESYSTEM_EXTRA_ROOTS", mcp_fs_roots) store.set_setting("AIA_MCP_FILESYSTEM_EXTRA_ROOTS", mcp_fs_roots)
store.set_setting("AIA_MCP_ENV_ALLOWLIST", mcp_env_allow) store.set_setting("AIA_MCP_ENV_ALLOWLIST", mcp_env_allow)
store.set_setting("AIA_OPENCLAW_RETRYABLE_ERROR_CODES", retry_codes) store.set_setting("AIA_OCLAW_RETRYABLE_ERROR_CODES", retry_codes)
store.set_setting("AIA_OPENCLAW_RETRY_CODES_STRICT_MODE", "1" if retry_codes_strict_mode else "0") store.set_setting("AIA_OCLAW_RETRY_CODES_STRICT_MODE", "1" if retry_codes_strict_mode else "0")
store.set_setting("AIA_WECOM_LONGCONN_WORKERS", str(wc_workers_n)) store.set_setting("AIA_WECOM_LONGCONN_WORKERS", str(wc_workers_n))
store.set_setting("AIA_WECOM_LONGCONN_INBOUND_QUEUE_MAXSIZE", str(wc_in_q_n)) store.set_setting("AIA_WECOM_LONGCONN_INBOUND_QUEUE_MAXSIZE", str(wc_in_q_n))
store.set_setting("WECOM_LONGCONN_WORKERS", str(wc_workers_n)) store.set_setting("WECOM_LONGCONN_WORKERS", str(wc_workers_n))
@ -1642,7 +1642,7 @@ def build_admin_router() -> APIRouter:
actor_user_id=ctx["user_id"], actor_user_id=ctx["user_id"],
action="tool_policy_update", action="tool_policy_update",
target_type="tool_policy", target_type="tool_policy",
target_id="AIA_TURN_MAX_TOOL_WORKERS,AIA_TURN_MAX_TOOL_ROUNDS,AIA_TURN_MAX_CONTEXT_MESSAGES,AIA_SSE_QUEUE_MAXSIZE,AIA_TOOL_LOG_MAX_CHARS,AIA_ENABLE_MCP_TOOLS,AIA_ENABLE_PLUGIN_TOOLS,AIA_SKILL_RUNTIME_ENABLED,AIA_SKILL_AUTO_INSTALL_ENABLED,AIA_TOOL_LLM_MESSAGE_MAX_CHARS,AIA_MCP_FILESYSTEM_EXTRA_ROOTS,AIA_MCP_ENV_ALLOWLIST,AIA_OPENCLAW_RETRYABLE_ERROR_CODES,AIA_OPENCLAW_RETRY_CODES_STRICT_MODE,AIA_WECOM_LONGCONN_WORKERS,AIA_WECOM_LONGCONN_INBOUND_QUEUE_MAXSIZE", target_id="AIA_TURN_MAX_TOOL_WORKERS,AIA_TURN_MAX_TOOL_ROUNDS,AIA_TURN_MAX_CONTEXT_MESSAGES,AIA_SSE_QUEUE_MAXSIZE,AIA_TOOL_LOG_MAX_CHARS,AIA_ENABLE_MCP_TOOLS,AIA_ENABLE_PLUGIN_TOOLS,AIA_SKILL_RUNTIME_ENABLED,AIA_SKILL_AUTO_INSTALL_ENABLED,AIA_TOOL_LLM_MESSAGE_MAX_CHARS,AIA_MCP_FILESYSTEM_EXTRA_ROOTS,AIA_MCP_ENV_ALLOWLIST,AIA_OCLAW_RETRYABLE_ERROR_CODES,AIA_OCLAW_RETRY_CODES_STRICT_MODE,AIA_WECOM_LONGCONN_WORKERS,AIA_WECOM_LONGCONN_INBOUND_QUEUE_MAXSIZE",
status="ok", status="ok",
detail={ detail={
"disable_tool_confirm": disable_confirm, "disable_tool_confirm": disable_confirm,
@ -1663,8 +1663,8 @@ def build_admin_router() -> APIRouter:
"tool_llm_message_max_chars": tmsg_n, "tool_llm_message_max_chars": tmsg_n,
"mcp_filesystem_extra_roots": mcp_fs_roots, "mcp_filesystem_extra_roots": mcp_fs_roots,
"mcp_env_allowlist": mcp_env_allow, "mcp_env_allowlist": mcp_env_allow,
"openclaw_retryable_error_codes": retry_codes, "oclaw_retryable_error_codes": retry_codes,
"openclaw_retry_codes_strict_mode": retry_codes_strict_mode, "oclaw_retry_codes_strict_mode": retry_codes_strict_mode,
"unknown_retryable_error_codes": unknown_retry_codes, "unknown_retryable_error_codes": unknown_retry_codes,
"wecom_longconn_workers": wc_workers_n, "wecom_longconn_workers": wc_workers_n,
"wecom_longconn_inbound_queue_maxsize": wc_in_q_n, "wecom_longconn_inbound_queue_maxsize": wc_in_q_n,
@ -1690,8 +1690,8 @@ def build_admin_router() -> APIRouter:
"tool_llm_message_max_chars": tmsg_n, "tool_llm_message_max_chars": tmsg_n,
"mcp_filesystem_extra_roots": mcp_fs_roots, "mcp_filesystem_extra_roots": mcp_fs_roots,
"mcp_env_allowlist": mcp_env_allow, "mcp_env_allowlist": mcp_env_allow,
"openclaw_retryable_error_codes": retry_codes, "oclaw_retryable_error_codes": retry_codes,
"openclaw_retry_codes_strict_mode": retry_codes_strict_mode, "oclaw_retry_codes_strict_mode": retry_codes_strict_mode,
"unknown_retryable_error_codes": unknown_retry_codes, "unknown_retryable_error_codes": unknown_retry_codes,
"wecom_longconn_workers": wc_workers_n, "wecom_longconn_workers": wc_workers_n,
"wecom_longconn_inbound_queue_maxsize": wc_in_q_n, "wecom_longconn_inbound_queue_maxsize": wc_in_q_n,
@ -2804,7 +2804,7 @@ def build_admin_router() -> APIRouter:
_require_tenant_scope(ctx, tenant_id) _require_tenant_scope(ctx, tenant_id)
user_id = str(payload.get("user_id") or "").strip() or None user_id = str(payload.get("user_id") or "").strip() or None
from oclaw.platform.embeddings.embedding_client import build_default_embedding_client from oclaw.platform.embeddings.embedding_client import build_default_embedding_client
from oclaw.orchestration.vector_store import build_vector_store, MemoryVectorItem from oclaw.runtime.orchestration.vector_store import build_vector_store, MemoryVectorItem
client = build_default_embedding_client() client = build_default_embedding_client()
vector = build_vector_store(store) vector = build_vector_store(store)
@ -3054,9 +3054,9 @@ def build_admin_router() -> APIRouter:
rows = [r for r in rows if str(r.get("status") or "") == st] rows = [r for r in rows if str(r.get("status") or "") == st]
return {"ok": True, "items": rows} return {"ok": True, "items": rows}
from oclaw.admin.chat_api import include_chat_routes from oclaw.interfaces.admin.chat_api import include_chat_routes
from oclaw.admin.models_api import include_model_mgmt_routes from oclaw.interfaces.admin.models_api import include_model_mgmt_routes
from oclaw.admin.skills_api import include_skill_routes from oclaw.interfaces.admin.skills_api import include_skill_routes
include_chat_routes(router, resolve_auth=_resolve_auth) include_chat_routes(router, resolve_auth=_resolve_auth)
include_model_mgmt_routes(router, resolve_auth=_resolve_auth) include_model_mgmt_routes(router, resolve_auth=_resolve_auth)

View file

@ -6,8 +6,8 @@ from typing import Any
from fastapi import APIRouter, Body, Header, HTTPException from fastapi import APIRouter, Body, Header, HTTPException
from oclaw.agents.factory import build_gateway_executor from oclaw.runtime.agents.factory import build_gateway_executor
from oclaw.openclaw_runtime.skill_installer import ( from oclaw.runtime.skill_installer import (
auto_install_skill_from_payload, auto_install_skill_from_payload,
create_skill_from_template, create_skill_from_template,
install_skill_from_local_dir, install_skill_from_local_dir,
@ -15,7 +15,7 @@ from oclaw.openclaw_runtime.skill_installer import (
list_skills_with_status, list_skills_with_status,
set_skill_enabled, set_skill_enabled,
) )
from oclaw.openclaw_runtime.skill_role_binding import ( from oclaw.runtime.skill_role_binding import (
SKILL_ROLE_BINDING_ENABLED_SETTING, SKILL_ROLE_BINDING_ENABLED_SETTING,
SKILL_ROLE_BINDING_KEY, SKILL_ROLE_BINDING_KEY,
load_skill_role_binding_dict, load_skill_role_binding_dict,
@ -23,12 +23,12 @@ from oclaw.openclaw_runtime.skill_role_binding import (
ordered_binding_roles, ordered_binding_roles,
skill_role_binding_enabled, skill_role_binding_enabled,
) )
from oclaw.openclaw_runtime.skills_prompt import collect_skill_catalog_entries from oclaw.runtime.skills_prompt import collect_skill_catalog_entries
from oclaw.openclaw_runtime.skills import _allowed_tool_names_after_wire_policy, discover_workspace_skill_manifests from oclaw.runtime.skills import _allowed_tool_names_after_wire_policy, discover_workspace_skill_manifests
from oclaw.platform.config.paths import db_path from oclaw.platform.config.paths import db_path
from oclaw.platform.persistence.sqlite_store import SqliteStore from oclaw.platform.persistence.sqlite_store import SqliteStore
from oclaw.tools.skills.clawhub_client import get_skill_detail as clawhub_get_skill_detail from oclaw.runtime.tools.skills.clawhub_client import get_skill_detail as clawhub_get_skill_detail
from oclaw.tools.skills.clawhub_client import search_skills as clawhub_search_skills from oclaw.runtime.tools.skills.clawhub_client import search_skills as clawhub_search_skills
def include_skill_routes( def include_skill_routes(
@ -393,7 +393,7 @@ def include_skill_routes(
name = str(payload.get("name") or "").strip() name = str(payload.get("name") or "").strip()
desc = str(payload.get("description") or "").strip() desc = str(payload.get("description") or "").strip()
body = str(payload.get("body_markdown") or "").strip() body = str(payload.get("body_markdown") or "").strip()
md = payload.get("metadata_openclaw") md = payload.get("metadata_oclaw")
md = dict(md) if isinstance(md, dict) else {} md = dict(md) if isinstance(md, dict) else {}
overwrite = bool(payload.get("overwrite")) overwrite = bool(payload.get("overwrite"))
out = create_skill_from_template( out = create_skill_from_template(
@ -401,7 +401,7 @@ def include_skill_routes(
name=name, name=name,
description=desc, description=desc,
body_markdown=body, body_markdown=body,
metadata_openclaw=md, metadata_oclaw=md,
overwrite=overwrite, overwrite=overwrite,
) )
_audit( _audit(
@ -527,8 +527,8 @@ def include_skill_routes(
"name": str(payload.get("name") or "").strip() or target, "name": str(payload.get("name") or "").strip() or target,
"description": str(payload.get("description") or "retry auto install"), "description": str(payload.get("description") or "retry auto install"),
"body_markdown": str(payload.get("body_markdown") or ""), "body_markdown": str(payload.get("body_markdown") or ""),
"metadata_openclaw": dict(payload.get("metadata_openclaw") or {}) "metadata_oclaw": dict(payload.get("metadata_oclaw") or {})
if isinstance(payload.get("metadata_openclaw"), dict) if isinstance(payload.get("metadata_oclaw"), dict)
else {}, else {},
}, },
) )

View file

@ -3580,7 +3580,7 @@ async function renderPlugins() {
turn_max_tool_workers: 8, turn_max_tool_workers: 8,
turn_max_tool_rounds: 8, turn_max_tool_rounds: 8,
turn_max_context_messages: 80, turn_max_context_messages: 80,
turn_runner_impl: "openclaw", turn_runner_impl: "oclaw",
manager_decision_mode: "", manager_decision_mode: "",
sse_queue_maxsize: 2000, sse_queue_maxsize: 2000,
tool_log_max_chars: 200000, tool_log_max_chars: 200000,
@ -3589,8 +3589,8 @@ async function renderPlugins() {
tool_llm_message_max_chars: 0, tool_llm_message_max_chars: 0,
mcp_filesystem_extra_roots: "", mcp_filesystem_extra_roots: "",
mcp_env_allowlist: "", mcp_env_allowlist: "",
openclaw_retryable_error_codes: "", oclaw_retryable_error_codes: "",
openclaw_retry_codes_strict_mode: false, oclaw_retry_codes_strict_mode: false,
wecom_longconn_workers: 2, wecom_longconn_workers: 2,
wecom_longconn_inbound_queue_maxsize: 200, wecom_longconn_inbound_queue_maxsize: 200,
}; };
@ -3818,13 +3818,13 @@ async function renderPlugins() {
value: String(toolPolicy.mcp_env_allowlist || ""), value: String(toolPolicy.mcp_env_allowlist || ""),
placeholder: "BRAVE_API_KEY,GOOGLE_OAUTH_CREDENTIALS,...", placeholder: "BRAVE_API_KEY,GOOGLE_OAUTH_CREDENTIALS,...",
}); });
const openclawRetryableErrorCodesInput = el("input", { const oclawRetryableErrorCodesInput = el("input", {
class: "input", class: "input",
value: String(toolPolicy.openclaw_retryable_error_codes || ""), value: String(toolPolicy.oclaw_retryable_error_codes || ""),
placeholder: "provider_timeout,provider_rate_limited,...", placeholder: "provider_timeout,provider_rate_limited,...",
}); });
const openclawRetryCodesStrictModeCb = el("input", { type: "checkbox" }); const oclawRetryCodesStrictModeCb = el("input", { type: "checkbox" });
openclawRetryCodesStrictModeCb.checked = !!toolPolicy.openclaw_retry_codes_strict_mode; oclawRetryCodesStrictModeCb.checked = !!toolPolicy.oclaw_retry_codes_strict_mode;
const wecomLongconnWorkersInput = el("input", { const wecomLongconnWorkersInput = el("input", {
class: "input", class: "input",
type: "number", type: "number",
@ -3857,8 +3857,8 @@ async function renderPlugins() {
tool_llm_message_max_chars: Number(toolLlmMessageMaxCharsInput.value || 0), tool_llm_message_max_chars: Number(toolLlmMessageMaxCharsInput.value || 0),
mcp_filesystem_extra_roots: String(mcpFilesystemExtraRootsInput.value || ""), mcp_filesystem_extra_roots: String(mcpFilesystemExtraRootsInput.value || ""),
mcp_env_allowlist: String(mcpEnvAllowlistInput.value || ""), mcp_env_allowlist: String(mcpEnvAllowlistInput.value || ""),
openclaw_retryable_error_codes: String(openclawRetryableErrorCodesInput.value || ""), oclaw_retryable_error_codes: String(oclawRetryableErrorCodesInput.value || ""),
openclaw_retry_codes_strict_mode: !!openclawRetryCodesStrictModeCb.checked, oclaw_retry_codes_strict_mode: !!oclawRetryCodesStrictModeCb.checked,
wecom_longconn_workers: Number(wecomLongconnWorkersInput.value || 2), wecom_longconn_workers: Number(wecomLongconnWorkersInput.value || 2),
wecom_longconn_inbound_queue_maxsize: Number(wecomLongconnInboundQueueInput.value || 200), wecom_longconn_inbound_queue_maxsize: Number(wecomLongconnInboundQueueInput.value || 200),
}); });
@ -4948,9 +4948,9 @@ async function renderPlugins() {
]), ]),
el("div", { class: "row" }, [ el("div", { class: "row" }, [
el("label", { text: "oclaw retryable error codes (comma separated)" }), el("label", { text: "oclaw retryable error codes (comma separated)" }),
openclawRetryableErrorCodesInput, oclawRetryableErrorCodesInput,
]), ]),
el("label", { class: "kv" }, [openclawRetryCodesStrictModeCb, document.createTextNode(" Strict mode: reject unknown retry codes")]), el("label", { class: "kv" }, [oclawRetryCodesStrictModeCb, document.createTextNode(" Strict mode: reject unknown retry codes")]),
el("div", { class: "row" }, [ el("div", { class: "row" }, [
el("label", { text: "WeCom longconn workers (1-8)" }), el("label", { text: "WeCom longconn workers (1-8)" }),
wecomLongconnWorkersInput, wecomLongconnWorkersInput,

View file

@ -1037,7 +1037,7 @@ function parseReasoningSegments(raw) {
return parts.length ? parts : [{ type: "text", text: "" }]; return parts.length ? parts : [{ type: "text", text: "" }];
} }
// OpenClaw-style: strip <think>/<thinking>/<final> blocks from visible text, // Oclaw-style: strip <think>/<thinking>/<final> blocks from visible text,
// while keeping code fences intact. This avoids "reasoning leaking" into正文 and // while keeping code fences intact. This avoids "reasoning leaking" into正文 and
// handles truncated streams (unfinished tags) safely. // handles truncated streams (unfinished tags) safely.
const _OC_QUICK_TAG_RE = /<\s*\/?\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking|final)\b/i; const _OC_QUICK_TAG_RE = /<\s*\/?\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking|final)\b/i;
@ -1172,7 +1172,7 @@ function normalizeStreamBodyForUi(raw) {
.replace(/\n{3,}/g, "\n\n"); .replace(/\n{3,}/g, "\n\n");
} }
// OpenClaw-style streaming stitcher: reduce boundary artifacts without destroying layout. // Oclaw-style streaming stitcher: reduce boundary artifacts without destroying layout.
function createStreamStitcher() { function createStreamStitcher() {
let prevTail = ""; let prevTail = "";
return { return {
@ -2607,7 +2607,7 @@ async function renderChatUi() {
if (String(p.status || "") === "started") { if (String(p.status || "") === "started") {
continue; continue;
} }
// OpenClaw-style: response ack does not terminate the stream. // Oclaw-style: response ack does not terminate the stream.
// Wait strictly for chat final/aborted/error or session.message assistant. // Wait strictly for chat final/aborted/error or session.message assistant.
continue; continue;
} }

View file

Before

Width:  |  Height:  |  Size: 307 KiB

After

Width:  |  Height:  |  Size: 307 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Before After
Before After

View file

@ -11,8 +11,8 @@ from collections import deque
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
from oclaw.application.gateway import process_inbound_payload_usecase from oclaw.runtime.application.gateway import process_inbound_payload_usecase
from oclaw.channels.wecom.normalize import normalize_wecom_event, normalize_wecom_event_batch from oclaw.interfaces.channels.wecom.normalize import normalize_wecom_event, normalize_wecom_event_batch
from oclaw.platform.config.paths import db_path from oclaw.platform.config.paths import db_path
from oclaw.platform.integrations.wecom_client import WeComClient from oclaw.platform.integrations.wecom_client import WeComClient
from oclaw.platform.persistence.sqlite_store import SqliteStore from oclaw.platform.persistence.sqlite_store import SqliteStore

View file

@ -2,7 +2,7 @@ from __future__ import annotations
from typing import Any from typing import Any
from oclaw.channels.base import ChannelAdapter, InboundMessage, OutboundMessage from oclaw.interfaces.channels.base import ChannelAdapter, InboundMessage, OutboundMessage
class WeComAdapter(ChannelAdapter): class WeComAdapter(ChannelAdapter):

View file

@ -1,6 +1,6 @@
# gateway # gateway
`gateway` 是对 `vendor/openclaw/oclaw/gateway` 的 Python 重写目录。 `gateway` 是对 `vendor/oclaw/oclaw/gateway` 的 Python 重写目录。
## 当前状态 ## 当前状态
- 已重写核心挂载链路: - 已重写核心挂载链路:

View file

@ -2,9 +2,9 @@ from __future__ import annotations
from typing import Any from typing import Any
from oclaw.openclaw_runtime.skill_installer import install_skill_from_registry_archive from oclaw.runtime.skill_installer import install_skill_from_registry_archive
from oclaw.tools.skills.clawhub_client import get_skill_detail as clawhub_get_skill_detail from oclaw.runtime.tools.skills.clawhub_client import get_skill_detail as clawhub_get_skill_detail
from oclaw.tools.skills.clawhub_client import search_skills as clawhub_search_skills from oclaw.runtime.tools.skills.clawhub_client import search_skills as clawhub_search_skills
def build_common_gateway_context(*, store: Any) -> dict[str, Any]: def build_common_gateway_context(*, store: Any) -> dict[str, Any]:

View file

@ -1,12 +1,12 @@
from __future__ import annotations from __future__ import annotations
from oclaw.gateway.server_methods.agent import agent_handlers from oclaw.interfaces.gateway.server_methods.agent import agent_handlers
from oclaw.gateway.server_methods.chat import chat_handlers from oclaw.interfaces.gateway.server_methods.chat import chat_handlers
from oclaw.gateway.server_methods.commands import commands_handlers from oclaw.interfaces.gateway.server_methods.commands import commands_handlers
from oclaw.gateway.server_methods.connect import connect_handlers from oclaw.interfaces.gateway.server_methods.connect import connect_handlers
from oclaw.gateway.server_methods.sessions import sessions_handlers from oclaw.interfaces.gateway.server_methods.sessions import sessions_handlers
from oclaw.gateway.server_methods.skills import skills_handlers from oclaw.interfaces.gateway.server_methods.skills import skills_handlers
from oclaw.gateway.server_methods.shared_types import GatewayRequestHandlers from oclaw.interfaces.gateway.server_methods.shared_types import GatewayRequestHandlers
def build_gateway_method_handlers() -> GatewayRequestHandlers: def build_gateway_method_handlers() -> GatewayRequestHandlers:

View file

@ -8,7 +8,8 @@ from types import ModuleType
from typing import Any, Iterable from typing import Any, Iterable
from types import SimpleNamespace from types import SimpleNamespace
from oclaw.extensions.plugin_api import PluginEntry from oclaw.platform.config.runtime_paths import runtime_extensions_root
from oclaw.runtime.extensions.plugin_api import PluginEntry
def _sanitize_module_name(value: str) -> str: def _sanitize_module_name(value: str) -> str:
@ -158,7 +159,7 @@ def discover_python_extension_entries(
ext_id = ext_dir.name ext_id = ext_dir.name
if wanted and ext_id not in wanted: if wanted and ext_id not in wanted:
continue continue
module_name = f"openclaw_pyext_{_sanitize_module_name(ext_id)}" module_name = f"oclaw_pyext_{_sanitize_module_name(ext_id)}"
module = _load_package_from_dir(package_name=module_name, package_dir=ext_dir) module = _load_package_from_dir(package_name=module_name, package_dir=ext_dir)
entry = getattr(module, "plugin_entry", None) entry = getattr(module, "plugin_entry", None)
if isinstance(entry, PluginEntry): if isinstance(entry, PluginEntry):
@ -193,9 +194,9 @@ def build_python_extensions_registry(
api = RuntimePluginApi(plugin_config={}, config=app_config, logger=logger) api = RuntimePluginApi(plugin_config={}, config=app_config, logger=logger)
# Support both workspace roots: # Support both workspace roots:
# - repo root (contains `oclaw/extensions`) # - repo root (contains `oclaw/runtime/extensions`)
# - `oclaw` package root (contains `extensions`) # - `oclaw` package root (contains `runtime/extensions`)
extension_roots = [ws_dir / "oclaw" / "extensions", ws_dir / "extensions"] extension_roots = [runtime_extensions_root(), ws_dir / "oclaw" / "runtime" / "extensions", ws_dir / "runtime" / "extensions"]
diagnostics: list[dict[str, Any]] = [] diagnostics: list[dict[str, Any]] = []
loaded_by_id: dict[str, LoadedExtension] = {} loaded_by_id: dict[str, LoadedExtension] = {}
for root in extension_roots: for root in extension_roots:

View file

@ -1,6 +1,6 @@
# server_methods # server_methods
这是 `vendor/openclaw/oclaw/gateway/server-methods` 的 Python 重写目录。 这是 `vendor/oclaw/oclaw/gateway/server-methods` 的 Python 重写目录。
## 当前已迁移 ## 当前已迁移
- `connect.ts` -> `connect.py` - `connect.ts` -> `connect.py`

View file

@ -2,7 +2,7 @@ from __future__ import annotations
from typing import Any from typing import Any
from oclaw.agents.agent_scope import resolve_agent_id_from_session_key, resolve_session_agent_id from oclaw.runtime.agents.agent_scope import resolve_agent_id_from_session_key, resolve_session_agent_id
from .shared_types import GatewayRequestHandlers from .shared_types import GatewayRequestHandlers
from .validation import error_shape from .validation import error_shape
@ -92,7 +92,7 @@ def _agent_identity_get_handler(opts: dict[str, Any]) -> None:
respond, respond,
{ {
"agentId": resolved_agent_id, "agentId": resolved_agent_id,
"displayName": "OpenClaw Assistant", "displayName": "Oclaw Assistant",
"avatarUrl": None, "avatarUrl": None,
}, },
) )

View file

@ -20,7 +20,7 @@ class _ConfigSnapshot:
def _read_config_file_snapshot() -> _ConfigSnapshot: def _read_config_file_snapshot() -> _ConfigSnapshot:
"""Staging adapter. """Staging adapter.
The upstream TS version reads JSON5 from OpenClaw config root. The upstream TS version reads JSON5 from Oclaw config root.
Here we keep a minimal in-memory placeholder until full config I/O is ported. Here we keep a minimal in-memory placeholder until full config I/O is ported.
""" """
return _ConfigSnapshot(exists=False, valid=True, config={}) return _ConfigSnapshot(exists=False, valid=True, config={})
@ -152,7 +152,7 @@ def _config_open_file_handler(opts: dict[str, Any]) -> Any:
return None return None
if not assert_valid_params(params, _validate_config_get_params, "config.openFile", respond): if not assert_valid_params(params, _validate_config_get_params, "config.openFile", respond):
return None return None
config_path = os.getenv("OPENCLAW_CONFIG_PATH") or "oclaw/oclaw.json" config_path = os.getenv("OCLAW_CONFIG_PATH") or "oclaw/oclaw.json"
respond(True, {"ok": True, "path": config_path}, None, None) respond(True, {"ok": True, "path": config_path}, None, None)
return None return None

View file

@ -30,11 +30,11 @@ def _norm_str(v: Any) -> str | None:
def _state(context: Any) -> dict[str, Any]: def _state(context: Any) -> dict[str, Any]:
if not isinstance(context, dict): if not isinstance(context, dict):
return {"path": ".openclaw/exec-approvals.json", "exists": False, "hash": None, "file": {}} return {"path": ".oclaw/exec-approvals.json", "exists": False, "hash": None, "file": {}}
st = context.get("_exec_approvals_state") st = context.get("_exec_approvals_state")
if isinstance(st, dict): if isinstance(st, dict):
return st return st
created = {"path": ".openclaw/exec-approvals.json", "exists": False, "hash": None, "file": {}} created = {"path": ".oclaw/exec-approvals.json", "exists": False, "hash": None, "file": {}}
context["_exec_approvals_state"] = created context["_exec_approvals_state"] = created
return created return created

View file

@ -4,6 +4,7 @@ import importlib.util
from pathlib import Path from pathlib import Path
from typing import Any, Callable from typing import Any, Callable
from oclaw.platform.config.runtime_paths import runtime_extensions_root
from .shared_types import GatewayRequestHandlers from .shared_types import GatewayRequestHandlers
from .validation import error_shape from .validation import error_shape
@ -35,10 +36,10 @@ def _load_generate_image_fn() -> Callable[..., Any]:
global _generate_image_fn global _generate_image_fn
if _generate_image_fn is not None: if _generate_image_fn is not None:
return _generate_image_fn return _generate_image_fn
file_path = (Path(__file__).resolve().parents[2] / "extensions" / "image-generation-core" / "api.py").resolve() file_path = (runtime_extensions_root() / "image-generation-core" / "api.py").resolve()
if not file_path.exists(): if not file_path.exists():
# Backward compatibility for legacy layout. # Backward compatibility for legacy layout.
file_path = Path("extensions/image-generation-core/api.py").resolve() file_path = Path("runtime/extensions/image-generation-core/api.py").resolve()
spec = importlib.util.spec_from_file_location("gateway_image_generation_core_api", str(file_path)) spec = importlib.util.spec_from_file_location("gateway_image_generation_core_api", str(file_path))
if spec is None or spec.loader is None: if spec is None or spec.loader is None:
raise RuntimeError("failed to load image-generation-core api module") raise RuntimeError("failed to load image-generation-core api module")

View file

@ -41,7 +41,7 @@ def _push_test_handler(opts: dict[str, Any]) -> None:
_bad(respond, "nodeId required") _bad(respond, "nodeId required")
return return
title = _norm_str(params.get("title")) or "OpenClaw" title = _norm_str(params.get("title")) or "Oclaw"
body = _norm_str(params.get("body")) or f"Push test for node {node_id}" body = _norm_str(params.get("body")) or f"Push test for node {node_id}"
environment = _norm_str(params.get("environment")) environment = _norm_str(params.get("environment"))

View file

@ -2,7 +2,7 @@ from __future__ import annotations
from typing import Any from typing import Any
from oclaw.agents.agent_scope import resolve_default_agent_id from oclaw.runtime.agents.agent_scope import resolve_default_agent_id
from .shared_types import GatewayRequestHandlers from .shared_types import GatewayRequestHandlers
from .telegram_send_normalize import normalize_transport_target_for_channel from .telegram_send_normalize import normalize_transport_target_for_channel

View file

@ -3,14 +3,14 @@ from __future__ import annotations
import json import json
from typing import Any from typing import Any
from oclaw.openclaw_runtime.skill_installer import ( from oclaw.runtime.skill_installer import (
create_skill_from_template, create_skill_from_template,
install_skill_from_local_dir, install_skill_from_local_dir,
install_skill_from_registry_archive, install_skill_from_registry_archive,
list_skills_with_status, list_skills_with_status,
set_skill_enabled, set_skill_enabled,
) )
from oclaw.openclaw_runtime.skills import discover_workspace_skill_manifests, load_skill_manifest from oclaw.runtime.skills import discover_workspace_skill_manifests, load_skill_manifest
from .shared_types import GatewayRequestHandlers from .shared_types import GatewayRequestHandlers
from .validation import error_shape from .validation import error_shape
@ -58,7 +58,7 @@ def _skills_bins_handler(opts: dict[str, Any]) -> None:
respond = opts.get("respond") respond = opts.get("respond")
bins: set[str] = set() bins: set[str] = set()
for m in discover_workspace_skill_manifests(): for m in discover_workspace_skill_manifests():
oc = dict(m.metadata_openclaw or {}) oc = dict(m.metadata_oclaw or {})
req = oc.get("requires") req = oc.get("requires")
if isinstance(req, dict): if isinstance(req, dict):
for k in ("bins", "anyBins"): for k in ("bins", "anyBins"):
@ -143,7 +143,7 @@ def _skills_detail_handler(opts: dict[str, Any]) -> None:
"description": manifest.description, "description": manifest.description,
"skillDir": manifest.skill_dir, "skillDir": manifest.skill_dir,
"skillFile": manifest.skill_file, "skillFile": manifest.skill_file,
"metadata": {"openclaw": dict(manifest.metadata_openclaw)}, "metadata": {"oclaw": dict(manifest.metadata_oclaw)},
"body": manifest.body, "body": manifest.body,
}, },
) )
@ -191,14 +191,14 @@ def _skills_install_handler(opts: dict[str, Any]) -> None:
return return
description = _normalize_optional_str(params.get("description")) or f"{name} skill" description = _normalize_optional_str(params.get("description")) or f"{name} skill"
body = _normalize_optional_str(params.get("body")) or "" body = _normalize_optional_str(params.get("body")) or ""
md = params.get("metadata_openclaw") md = params.get("metadata_oclaw")
md = dict(md) if isinstance(md, dict) else {} md = dict(md) if isinstance(md, dict) else {}
res = create_skill_from_template( res = create_skill_from_template(
store=store, store=store,
name=name, name=name,
description=description, description=description,
body_markdown=body, body_markdown=body,
metadata_openclaw=md, metadata_oclaw=md,
overwrite=overwrite, overwrite=overwrite,
) )
_ok(respond, {"ok": res.ok, "result": res.__dict__}) _ok(respond, {"ok": res.ok, "result": res.__dict__})

View file

@ -2,7 +2,7 @@ from __future__ import annotations
from typing import Any from typing import Any
from oclaw.extensions.telegram import ( from oclaw.runtime.extensions.telegram import (
normalize_telegram_messaging_target, normalize_telegram_messaging_target,
parse_telegram_reply_to_message_id, parse_telegram_reply_to_message_id,
parse_telegram_target, parse_telegram_target,

View file

@ -4,6 +4,7 @@ from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Any, Callable from typing import Any, Callable
from oclaw.platform.config.runtime_paths import runtime_extensions_root
from .python_extensions_loader import build_python_extensions_registry from .python_extensions_loader import build_python_extensions_registry
GatewayHandler = Callable[..., Any] GatewayHandler = Callable[..., Any]
@ -44,8 +45,9 @@ def _resolve_gateway_startup_plugin_ids(
return out return out
# Auto-discover local plugins when explicit list is absent. # Auto-discover local plugins when explicit list is absent.
roots = [ roots = [
ws_root / "oclaw" / "extensions", runtime_extensions_root(),
ws_root / "extensions", ws_root / "oclaw" / "runtime" / "extensions",
ws_root / "runtime" / "extensions",
] ]
seen: set[str] = set() seen: set[str] = set()
for root in roots: for root in roots:
@ -66,14 +68,14 @@ def _resolve_gateway_startup_plugin_ids(
return out return out
def _load_openclaw_plugins( def _load_oclaw_plugins(
*, *,
config: dict[str, Any], config: dict[str, Any],
workspace_dir: str, workspace_dir: str,
only_plugin_ids: list[str], only_plugin_ids: list[str],
core_gateway_handlers: dict[str, GatewayHandler] | None = None, core_gateway_handlers: dict[str, GatewayHandler] | None = None,
) -> dict[str, Any]: ) -> dict[str, Any]:
"""Minimal Python replacement for loadOpenClawPlugins. """Minimal Python replacement for loadOclawPlugins.
This function intentionally returns a stable registry shape that matches This function intentionally returns a stable registry shape that matches
the gateway startup contract used by this project. the gateway startup contract used by this project.
@ -113,7 +115,7 @@ def load_gateway_plugins(
plugin_registry = {"plugins": [], "gateway_handlers": {}, "http_routes": [], "diagnostics": []} plugin_registry = {"plugins": [], "gateway_handlers": {}, "http_routes": [], "diagnostics": []}
return GatewayPluginLoadResult(plugin_registry=plugin_registry, gateway_methods=list(base_methods)) return GatewayPluginLoadResult(plugin_registry=plugin_registry, gateway_methods=list(base_methods))
plugin_registry = _load_openclaw_plugins( plugin_registry = _load_oclaw_plugins(
config=resolved_cfg, config=resolved_cfg,
workspace_dir=workspace_dir, workspace_dir=workspace_dir,
only_plugin_ids=chosen_plugin_ids, only_plugin_ids=chosen_plugin_ids,

View file

@ -3,8 +3,8 @@ from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any, Callable from typing import Any, Callable
from oclaw.agents.agent_scope import resolve_agent_workspace_dir, resolve_default_agent_id from oclaw.runtime.agents.agent_scope import resolve_agent_workspace_dir, resolve_default_agent_id
from oclaw.agents.subagent_registry import init_subagent_registry from oclaw.runtime.agents.subagent_registry import init_subagent_registry
from .server_plugins import GatewayPluginLoadResult, load_gateway_plugins from .server_plugins import GatewayPluginLoadResult, load_gateway_plugins

View file

@ -10,18 +10,18 @@ from fastapi import Request
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from oclaw.application.gateway import process_inbound_payload_usecase from oclaw.runtime.application.gateway import process_inbound_payload_usecase
from oclaw.interfaces.gateway.http_adapter import dispatch_gateway_http_method from oclaw.interfaces.gateway.http_adapter import dispatch_gateway_http_method
from oclaw.interfaces.ws import ws_gateway_loop from oclaw.interfaces.ws import ws_gateway_loop
from oclaw.admin.routes import admin_static_dir, build_admin_router from oclaw.interfaces.admin.routes import admin_static_dir, build_admin_router
from oclaw.agents.agent_scope import list_agent_ids, resolve_agent_workspace_dir, resolve_default_agent_id from oclaw.runtime.agents.agent_scope import list_agent_ids, resolve_agent_workspace_dir, resolve_default_agent_id
from oclaw.gateway.server_startup_plugins import prepare_gateway_plugin_bootstrap from oclaw.interfaces.gateway.server_startup_plugins import prepare_gateway_plugin_bootstrap
from oclaw.openclaw_runtime.hooks_runtime import ( from oclaw.runtime.hooks_runtime import (
initialize_hooks_runtime, initialize_hooks_runtime,
resolve_runtime_config, resolve_runtime_config,
trigger_hook_event, trigger_hook_event,
) )
from oclaw.openclaw_runtime.skills import skill_runtime_diagnostics from oclaw.runtime.skills import skill_runtime_diagnostics
from oclaw.platform.config.paths import PROJECT_ROOT, db_path from oclaw.platform.config.paths import PROJECT_ROOT, db_path
from oclaw.platform.persistence.sqlite_store import SqliteStore from oclaw.platform.persistence.sqlite_store import SqliteStore
from oclaw.interfaces.http.weixin_ilink_api import router as weixin_ilink_router from oclaw.interfaces.http.weixin_ilink_api import router as weixin_ilink_router
@ -36,7 +36,7 @@ def _resolve_startup_workspace_dir(cfg: dict[str, Any]) -> str:
return ws_text return ws_text
except Exception: except Exception:
pass pass
return str((PROJECT_ROOT / "oclaw" / "workspace-main").resolve()) return str((PROJECT_ROOT / "oclaw" / "runtime" / "assets" / "agent_workspaces" / "workspace-main").resolve())
def _resolve_startup_workspace_dirs(cfg: dict[str, Any]) -> list[tuple[str, str]]: def _resolve_startup_workspace_dirs(cfg: dict[str, Any]) -> list[tuple[str, str]]:

View file

@ -15,7 +15,7 @@ def _require_ilink_auth(
authorization_type: str | None, authorization_type: str | None,
authorization: str | None, authorization: str | None,
) -> None: ) -> None:
# Minimal contract required by openclaw-weixin: # Minimal contract required by oclaw-weixin:
# - AuthorizationType: ilink_bot_token # - AuthorizationType: ilink_bot_token
# - Authorization: Bearer <token> # - Authorization: Bearer <token>
if (authorization_type or "").strip() != "ilink_bot_token": if (authorization_type or "").strip() != "ilink_bot_token":

Some files were not shown because too many files have changed in this diff Show more