重构仓库目录为统一的 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
run: python -m pip install -r requirements.txt ruff mypy
- 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
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

25
.gitignore vendored
View file

@ -42,21 +42,22 @@ data/**/*.log
data/**/*.err.log
platform/data/
scripts/.run/
runtime/operations/scripts/.run/
desktop/node_modules/
desktop/dist/
desktop/runtime-data/
# 本地密钥(随仓库目录迁移时记得复制此文件;勿提交)
src/_local/google_oauth_client.json
src/_local/mcp_local.env
_local/google_oauth_client.json
_local/mcp_local.env
# MCP admin export / 安装后自动备份(可重装 JSON,本机 path 与列表可能不同)
src/_local/mcp_registry_migrated.json
src/platform/data/*.sqlite
src/platform/data/*.sqlite-journal
src/platform/data/*.sqlite-shm
src/platform/data/*.sqlite-wal
src/platform/data/logs/
src/platform/data/locks/
src/platform/data/ops_runtime_state.json
_local/mcp_registry_migrated.json
platform/data/*.sqlite
platform/data/*.sqlite-journal
platform/data/*.sqlite-shm
platform/data/*.sqlite-wal
platform/data/logs/
platform/data/locks/
platform/data/ops_runtime_state.json
# 历史 Vite 前端已移除;若本地仍有残留目录可忽略或手动删除
web/
@ -70,5 +71,5 @@ oclaw/desktop/node_modules/
oclaw/desktop/dist/
oclaw/desktop/runtime-data/
oclaw/desktop/assets/oclaw.ico
vendor/openclaw-main.zip
vendor/openclaw/
vendor/oclaw-main.zip
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
- `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
- `domain/`: business rules and domain primitives
- `infrastructure/`: integrations and runtime adapters
- `shared/`: shared utilities/types
- `infrastructure/`: runtime-facing integrations/adapters
- `platform/`: shared platform capabilities (llm, persistence, config, files)
- `tools/`: tool registry, MCP adapters, public/system tools
- `skills/`: installable skills and runtime manifests
## Migration Rule
New business logic should be implemented in `oclaw/`.
`oclaw/` modules remain as compatibility bridges during migration.
## Naming Rule
- Use `oclaw` consistently in paths, symbols, and docs.
- 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/`.
Legacy `src/` modules may import from this package as a compatibility bridge.
All production code in this repository lives under this package root.
"""

View file

@ -1,9 +1,9 @@
# 推荐:复制为 src/_local/mcp_local.env(与 OAuth 等本地密钥同目录,见 .gitignore)。
# 兼容:仍可放在 data/mcp_local.env(与默认 SQLite 同目录);若两处都存在,同键以 src/_local 为准。
# 推荐:复制为 _local/mcp_local.env(与 OAuth 等本地密钥同目录,见 .gitignore)。
# 兼容:仍可放在 data/mcp_local.env(与默认 SQLite 同目录);若两处都存在,同键以 _local 为准。
# ${PROJECT_ROOT} 为仓库根目录。
# 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
#
# GitHub MCP (@modelcontextprotocol/server-github)
@ -29,17 +29,17 @@
#
# CONTEXT7_API_KEY=ctx7sk-b5806022-903e-490a-b593-67caa624f3bf
#
# OpenClaw runtime 默认不回退 legacy manager/runner;若紧急排障需临时回退,可显式打开:
# AIA_OPENCLAW_ALLOW_LEGACY_FALLBACK=1
# Oclaw runtime 默认不回退 legacy manager/runner;若紧急排障需临时回退,可显式打开:
# AIA_OCLAW_ALLOW_LEGACY_FALLBACK=1
#
# OpenClaw 仍生效的工具循环预算(可在 Admin -> Tool Policy 配置):
# Oclaw 仍生效的工具循环预算(可在 Admin -> Tool Policy 配置):
# AIA_TURN_MAX_TOOL_WORKERS=8
# AIA_TURN_MAX_TOOL_ROUNDS=8
# AIA_TURN_MAX_CONTEXT_MESSAGES=80
# 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)
# AIA_OPENCLAW_RETRY_CODES_STRICT_MODE=0
# AIA_OCLAW_RETRY_CODES_STRICT_MODE=0
#
# 内置工作区工具路径(read_file / run_command 等)默认限制在 AIA_WORKSPACE_ROOT(未设则为项目根)下。
# 全局扩展:多个绝对路径用 | 分隔;允许整盘访问(高风险):

View file

@ -24,7 +24,7 @@ npm run dev
The app will:
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.
Logs are written under:

View file

@ -122,7 +122,7 @@ async function startBackendProcess() {
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, {
cwd: APP_ROOT,
env,
@ -212,7 +212,7 @@ async function startChannelProcess() {
try {
const cleanupRes = await runPythonInline(
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 },
);
if (!cleanupRes.ok) {
@ -230,7 +230,7 @@ async function startChannelProcess() {
AIA_DATA_DIR: DATA_ROOT,
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;
channelProc = spawn(pythonBin, args, {
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 安装包
## 4) 打包产物位置

View file

@ -18,83 +18,83 @@
- `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`
- 默认:空
- 作用:**Legacy(已断开)**:旧 manager 决策模式(如 `rule`)
- 说明:oclaw runtime 默认不再走 `CompositeOpsAgent` 的 manager 决策;该变量仅保留以便后续接回 legacy
- 生效:`oclaw/agents/manager_agent.py`(仅 legacy 链路)
- 生效:`oclaw/runtime/agents/manager_agent.py`(仅 legacy 链路)
- `AIA_TURN_MAX_TOOL_WORKERS`
- 默认:`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`
- 默认:`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`
- 默认:`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 执行上限
- 生效:`oclaw/openclaw_runtime/gateway.py`, `oclaw/openclaw_runtime/worker.py`
- 生效:`oclaw/oclaw_runtime/gateway.py`, `oclaw/oclaw_runtime/worker.py`
- `AIA_PROMPT_FRONTMATTER_STRICT`
- 默认:`0`
- 作用:`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`
- 默认:`1`(开启;仅当技能运行时启用)
- 作用:是否在 system prompt 末尾附加 oclaw 风格的 `<available_skills>` 目录块(与原生 `tools` 并存)
- 说明:设为 `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`
- 默认:`18000`
- 作用:技能目录 XML 块最大字符数(超出则从列表尾部丢弃条目)
- 生效:`oclaw/openclaw_runtime/skills_prompt.py`
- 生效:`oclaw/oclaw_runtime/skills_prompt.py`
- `AIA_SKILL_DISABLED_NAMES`
- 默认:空数组(`[]`)
- 作用:按技能名禁用模型可见/可执行技能(JSON 数组字符串,例如 `["skill_a","skill_b"]`)
- 说明:禁用后同时影响 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`
- 默认:`1`
- 作用:是否允许自动安装 skill(admin auto-install / retry-install(auto))
- 说明:关闭后返回 `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`
- 作用:Agent Core run 外环的错误重试白名单(逗号分隔)
- 说明:仅当 attempt 返回 `status=retry` 且 `error_code` 命中该白名单时才进入下一次 attempt;未知 code 默认在 Admin 保存时会被过滤并告警
- 补充:`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`(启发式)或 `llm_json`(由当前 executor 的 `model.chat` 产出 `{mode,reason}` JSON;解析失败则回落 `rule`)
- 说明:亦可通过同名环境变量覆盖;提示词见 `oclaw/prompts_openclaw/router/decide_route.md`
- 生效:`oclaw/openclaw_runtime/router.py`, `oclaw/openclaw_runtime/gateway.py`
- 说明:亦可通过同名环境变量覆盖;提示词见 `oclaw/prompts_runtime/router/decide_route.md`
- 生效:`oclaw/oclaw_runtime/router.py`, `oclaw/oclaw_runtime/gateway.py`
- oclaw trace 字段与 `event_type` ↔ `oc_stage` 对照见 `oclaw/docs/openclaw-trace-taxonomy.md`
- Skill 安装错误码与重试建议、trace 排障路径见 `oclaw/docs/openclaw-skill-troubleshooting.md`
- Relay 文件指针(含 ACP 父子 run)错误码与排障见 `oclaw/docs/openclaw-skill-troubleshooting.md` 的“Relay 文件指针排障”
- oclaw trace 字段与 `event_type` ↔ `oc_stage` 对照见 `oclaw/docs/oclaw-trace-taxonomy.md`
- Skill 安装错误码与重试建议、trace 排障路径见 `oclaw/docs/oclaw-skill-troubleshooting.md`
- Relay 文件指针(含 ACP 父子 run)错误码与排障见 `oclaw/docs/oclaw-skill-troubleshooting.md` 的“Relay 文件指针排障”
- `AIA_OPENCLAW_RETRY_CODES_STRICT_MODE`
- `AIA_OCLAW_RETRY_CODES_STRICT_MODE`
- 默认:`0`
- 作用:控制 Admin 保存 `AIA_OPENCLAW_RETRYABLE_ERROR_CODES` 时的未知 code 行为
- 作用:控制 Admin 保存 `AIA_OCLAW_RETRYABLE_ERROR_CODES` 时的未知 code 行为
- 说明:`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`
- 默认:`first_round_only`
@ -111,11 +111,11 @@
- 作用:**Legacy(已断开)**:同签名工具调用预算
- 生效:仅 legacy 链路(保留占位,暂不影响 oclaw)
- `AIA_OPENCLAW_ALLOW_LEGACY_FALLBACK`
- `AIA_OCLAW_ALLOW_LEGACY_FALLBACK`
- 默认:`0`(关闭)
- 作用:oclaw 执行失败时,是否允许回退到 legacy `executor.run_turn(...)`
- 说明:默认 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 兼容)
@ -173,7 +173,7 @@
- 默认:`0`(不限制)
- 作用:工具结果写回 LLM 的消息长度上限
- 说明:`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}`
- `AIA_TOOL_LOG_MAX_CHARS`
@ -191,7 +191,7 @@
- `AIA_MCP_ENV_ALLOWLIST`
- 默认:内置 allowlist(Brave/Google/GitHub/Context7)
- 作用:MCP 子进程可透传环境变量白名单
- 生效:`oclaw/ops/mcp_env.py`
- 生效:`oclaw/runtime/operations/mcp_env.py`
- `AIA_MCP_FILESYSTEM_EXTRA_ROOTS`
- 默认:空
@ -270,7 +270,7 @@
- `AIA_IMAGE_MODEL`
- 默认:空(走 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`
- 默认:`https://api.openai.com/v1`
@ -329,7 +329,7 @@
- `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`
- 默认:空
@ -346,46 +346,46 @@
- `AIA_ASSISTANT_GATEWAY_HOST`
- 默认:`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`
- 默认:`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`
- 默认:空(使用内部默认目录)
- 作用:运行日志目录
- 生效:`oclaw/ops/runtime.py`
- 生效:`oclaw/runtime/operations/runtime.py`
- `AIA_SSE_QUEUE_MAXSIZE`
- 默认:`2000`
- 作用:SSE 事件队列上限
- 生效:`oclaw/admin/chat_api.py`
- 生效:`oclaw/interfaces/admin/chat_api.py`
## WeCom 长连接
- `AIA_WECOM_LONGCONN_WORKERS`
- 默认:`2`
- 作用:入站处理 worker 数
- 生效:`oclaw/channels/wecom/longconn_runner.py`
- 生效:`oclaw/interfaces/channels/wecom/longconn_runner.py`
- `AIA_WECOM_LONGCONN_INBOUND_QUEUE_MAXSIZE`
- 默认:`200`
- 作用:入站队列长度上限
- 生效:`oclaw/channels/wecom/longconn_runner.py`
- 生效:`oclaw/interfaces/channels/wecom/longconn_runner.py`
## 安全与密钥
- `AIA_ASSISTANT_PASSWORD`
- 默认:空(必须配置)
- 作用:管理台管理员密码(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`
- 默认:空
- 作用:密钥加密(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`)。
### 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_TOOL_CALL_ID_MAX_LEN`(默认 `40`)
- `AIA_PROMPT_TOOL_FALLBACK`(默认 `1`)
- `oclaw/platform/llm/OPENCLAW_MIT_LICENSE.txt`(oclaw 启发实现之 MIT 署名)
- `oclaw/platform/llm/OCLAW_MIT_LICENSE.txt`(oclaw 启发实现之 MIT 署名)
### Changed
- 变量前缀统一为 `AIA_*`,项目内不再使用 `OPS_*` / `AI_OPS_*`。
@ -105,15 +105,15 @@
## 2026-04-20 / Unreleased
### Added
- `AIA_OPENCLAW_ALLOW_LEGACY_FALLBACK`
- `AIA_OCLAW_ALLOW_LEGACY_FALLBACK`
- 默认值:`0`
- 用途: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
- `AIA_TURN_MAX_*`(tool workers/rounds/context)
- 变更前:由 legacy turn runner 读取(历史文件名可能为 `agent_core.py`)
- 变更后:由 oclaw runtime 读取并生效(`oclaw/openclaw_runtime/gateway.py`)
- 变更后:由 oclaw runtime 读取并生效(`oclaw/oclaw_runtime/gateway.py`)
- 是否需要重启:是(读取自 settings/db/env 的时机取决于运行方式)
### Deprecated
@ -135,7 +135,7 @@
### Changed
- 无新增环境变量;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 与新路由逻辑)
### Migration Checklist
@ -150,10 +150,10 @@
## 2026-04-20 / Unreleased (AgentCore Retry Matrix)
### 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`
- 用途:控制 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
- Agent Core 重试策略从“status=retry 即重试”升级为“retry + error_code 命中白名单才重试”。
@ -167,15 +167,15 @@
- [x] 已执行编译/测试回归
### Changed
- `AIA_OPENCLAW_RETRYABLE_ERROR_CODES` 已接入 Admin「Tool Policy」页读写链路。
- 影响模块:`oclaw/admin/routes.py`, `oclaw/admin/static/app.js`
- `AIA_OPENCLAW_RETRYABLE_ERROR_CODES` 保存时增加未知 code 过滤与告警返回(`unknown_retryable_error_codes`)。
- 影响模块:`oclaw/admin/routes.py`, `oclaw/admin/static/app.js`, `oclaw/openclaw_runtime/agent_core_run.py`
- `AIA_OPENCLAW_RETRYABLE_ERROR_CODES` 新增严格模式:可配置为未知 code 直接拒绝保存(400)。
- 影响模块:`oclaw/admin/routes.py`, `oclaw/admin/static/app.js`
- `AIA_OCLAW_RETRYABLE_ERROR_CODES` 已接入 Admin「Tool Policy」页读写链路。
- 影响模块:`oclaw/interfaces/admin/routes.py`, `oclaw/interfaces/admin/static/app.js`
- `AIA_OCLAW_RETRYABLE_ERROR_CODES` 保存时增加未知 code 过滤与告警返回(`unknown_retryable_error_codes`)。
- 影响模块:`oclaw/interfaces/admin/routes.py`, `oclaw/interfaces/admin/static/app.js`, `oclaw/oclaw_runtime/agent_core_run.py`
- `AIA_OCLAW_RETRYABLE_ERROR_CODES` 新增严格模式:可配置为未知 code 直接拒绝保存(400)。
- 影响模块:`oclaw/interfaces/admin/routes.py`, `oclaw/interfaces/admin/static/app.js`
### Added
- `AIA_OPENCLAW_RETRY_CODES_STRICT_MODE`
- `AIA_OCLAW_RETRY_CODES_STRICT_MODE`
- 默认值:`0`
- 用途:控制 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
- Name: `image.generate`
- Handler: `oclaw/gateway/server_methods/image.py`
- Handler: `oclaw/interfaces/gateway/server_methods/image.py`
## Input Params

View file

@ -10,7 +10,7 @@ Normalization is applied in these handlers:
- `chat.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

View file

@ -1,6 +1,6 @@
# 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`).
- `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)
- **`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
@ -73,7 +73,7 @@ All transports stream assistant output through the same internal callback:
For additional providers, follow this pattern:
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/`
4. Add/verify WS contract tests (delta + final + session.tool)

View file

@ -505,7 +505,7 @@ Keep responses deterministic and JSON-serializable.
- **作用**:按库名/版本拉取较新的官方文档片段,减少「API 记错版本」类幻觉。
- **安装**:`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,会自动追加)。
### 通识侧终端能力(`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.
## 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] `AIA_SKILLS_ROOT`
- [x] `oclaw/skills`
- [x] `oclaw/runtime/skills`
- [x] `skills/` fallback
## 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.
@ -17,7 +17,7 @@ This repository is migrating from legacy `oclaw/` runtime wiring to the new `ocl
## Runtime notes
- Gateway HTTP method adapter: `POST /gateway/method`
- 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`
- WS entrypoint moved to: `oclaw.interfaces.ws.entrypoint`
- 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.
## Prompt and skills policy
- Role context is loaded from `oclaw/agent/*`.
- Role context is loaded from `oclaw/runtime/assets/agent_workspaces/*`.
- Skills root priority:
1. `AIA_SKILLS_ROOT`
2. `oclaw/skills`
2. `oclaw/runtime/skills`
3. `skills/` (legacy fallback)

View file

@ -4,14 +4,14 @@
关联文档:
- trace 字段与阶段对照:`docs/openclaw-trace-taxonomy.md`
- skill 安装/执行排障:`docs/openclaw-skill-troubleshooting.md`
- trace 字段与阶段对照:`docs/oclaw-trace-taxonomy.md`
- skill 安装/执行排障:`docs/oclaw-skill-troubleshooting.md`
---
## 1. 统一入口(只保留最新)
所有运维命令统一通过 `scripts/`,不要再使用 `python -m oclaw.ops ...` 或历史 `.bat` 方式。
所有运维命令统一通过 `scripts/`,不要再使用 `python -m oclaw.runtime.operations ...` 或历史 `.bat` 方式。
补充:工具脚本也统一放在 `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)
@ -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/openclaw-weixin/state/openclaw-weixin/accounts.json`
- `data/channel_sidecar/oclaw-weixin/state/oclaw-weixin/accounts/*.json`
- `data/channel_sidecar/oclaw-weixin/state/oclaw-weixin/accounts.json`
### 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/openclaw-weixin/logs/weixin_sidecar.err.log`
- `data/channel_sidecar/oclaw-weixin/logs/weixin_sidecar.log`
- `data/channel_sidecar/oclaw-weixin/logs/weixin_sidecar.err.log`
### 11.4 当前行为说明
@ -440,7 +440,7 @@ python .\scripts\wiki_auto_smoke_test.py
该脚本会:
- 投递一条 `wiki_capture` 任务到 `openclaw_task`
- 投递一条 `wiki_capture` 任务到 `oclaw_task`
- 轮询任务状态直到 `done/failed/timeout`
- 输出当前写入产物状态(`merged-turns.md`、`topic-index.json`、`index.json`、`LINT_REPORT.md`)

View file

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

View file

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

View file

@ -7,15 +7,15 @@ Trace events share a common `payload` shape across components. Prefer joining on
| Key | Meaning |
| --- | --- |
| `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) |
| `lang` | Request language when known |
| `run_id` | Agent core run UUID (retry container) |
| `attempt_no` | 1-based attempt index inside `run_id` |
| `openclaw_task_id` | Async worker task id when present |
| `openclaw_worker_id` | Worker thread id when present |
| `oclaw_task_id` | Async worker task id when present |
| `oclaw_worker_id` | Worker thread id when present |
## Gateway (`pipeline=openclaw_gateway`)
## Gateway (`pipeline=oclaw_gateway`)
| `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_pointer_count`: pointer count inside envelope manifest
## Agent core (`pipeline=openclaw_agent_core`)
## Agent core (`pipeline=oclaw_agent_core`)
| `event_type` | `oc_stage` |
| --- | --- |
@ -46,7 +46,7 @@ Trace events share a common `payload` shape across components. Prefer joining on
| `run_compact` | `compact` |
| `run_retry` | `retry` |
## Direct loop (`pipeline=openclaw_direct_loop`)
## Direct loop (`pipeline=oclaw_direct_loop`)
| `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`.
## Skill executor (`pipeline=openclaw_skill_executor`)
## Skill executor (`pipeline=oclaw_skill_executor`)
| `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`.
## Attempt memory hook (`pipeline=openclaw_agent_core`)
## Attempt memory hook (`pipeline=oclaw_agent_core`)
| `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.responses import Response, StreamingResponse
from oclaw.ops.mcp_env import apply_gateway_mcp_env_to_os
from oclaw.agents.factory import build_gateway_executor
from oclaw.chat.agent import GenerationInterrupted
from oclaw.runtime.operations.mcp_env import apply_gateway_mcp_env_to_os
from oclaw.runtime.agents.factory import build_gateway_executor
from oclaw.runtime.chat.agent import GenerationInterrupted
from oclaw.platform.config.paths import db_path
from oclaw.platform.files.attachment_assets import AttachmentAssetStore
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.persistence.sqlite_store import SqliteStore
from oclaw.openclaw_runtime.gateway import OpenClawGateway
from oclaw.openclaw_runtime.types import StandardMessage, normalize_interaction_mode, normalize_requested_specialist
from oclaw.runtime.gateway import OclawGateway
from oclaw.runtime.types import StandardMessage, normalize_interaction_mode, normalize_requested_specialist
def _oclaw_config_path() -> Path:
@ -706,7 +706,7 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
if not sess:
raise HTTPException(status_code=404, detail="session_not_found")
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]] = []
for t in rows:
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)
_require_administrator_chat_viewer(ctx)
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)
dynamic_used = 0
fallback_generalist = 0
@ -1288,7 +1288,7 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
policy_session_id=str(session_id),
)
try:
gw = OpenClawGateway(store=store)
gw = OclawGateway(store=store)
msg = StandardMessage(
session_id=str(session_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"
_emit(kind, {"event": ev_name, "payload": pl})
gw = OpenClawGateway(store=store)
gw = OclawGateway(store=store)
msg = StandardMessage(
session_id=str(session_id),
tenant_id=tenant_id,

View file

@ -3,8 +3,8 @@ from __future__ import annotations
from typing import Any
from oclaw.tools.base import ToolRegistry, ToolSpec
from oclaw.tools.tool_validation import validate_tool_arguments
from oclaw.runtime.tools.base import ToolRegistry, ToolSpec
from oclaw.runtime.tools.tool_validation import validate_tool_arguments
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.responses import Response
from oclaw.agents.factory import DEFAULT_OLLAMA_BASE_URL, DEFAULT_OLLAMA_MODEL
from oclaw.agents.specialists import (
from oclaw.runtime.agents.factory import DEFAULT_OLLAMA_BASE_URL, DEFAULT_OLLAMA_MODEL
from oclaw.runtime.agents.specialists import (
AGENT_PROFILE_BINDINGS_KEY,
AGENT_ROLE_IDS,
dump_agent_profile_bindings,
parse_agent_profile_bindings,
)
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 (
LLM_BUILTIN_OLLAMA_PROFILE_ID,
SqliteStore,

View file

@ -12,38 +12,38 @@ from fastapi import APIRouter, Body, Header, Query
from fastapi import HTTPException
from fastapi.responses import HTMLResponse
from oclaw.ops.mcp_env import apply_gateway_mcp_env_to_os
from oclaw.ops.providers.registry import build_channel_registry
from oclaw.ops.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.orchestration.vector_store import read_vector_memory_runtime
from oclaw.runtime.operations.mcp_env import apply_gateway_mcp_env_to_os
from oclaw.runtime.operations.providers.registry import build_channel_registry
from oclaw.runtime.operations.runtime import cleanup_orphan_service_processes, detect_orphan_service_processes, status_services
from oclaw.runtime.operations.stack import cmd_stack_down, cmd_stack_status, cmd_stack_up
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.passwords import load_expected_password
from oclaw.platform.persistence.sqlite_store import SqliteStore
from oclaw.agents.specialists import SPECIALISTS
from oclaw.tools.mcp.installer import (
from oclaw.runtime.agents.specialists import SPECIALISTS
from oclaw.runtime.tools.mcp.installer import (
_safe_server_id,
detect_local_dependencies,
install_mcp_server,
preflight_mcp_server,
uninstall_mcp_server,
)
from oclaw.tools.mcp.market import search_mcp_market, trending_mcp_market
from oclaw.tools.mcp.manifest import McpServerManifest
from oclaw.ops.mcp_registry_export import (
from oclaw.runtime.tools.mcp.market import search_mcp_market, trending_mcp_market
from oclaw.runtime.tools.mcp.manifest import McpServerManifest
from oclaw.runtime.operations.mcp_registry_export import (
build_mcp_install_export_document,
mcp_migrated_json_path,
persist_mcp_migrated_file,
)
from oclaw.tools.mcp.filesystem_argv import build_mcp_process_command
from oclaw.tools.mcp.registry import McpRegistry
from oclaw.tools.mcp.runtime import McpProcessRuntime
from oclaw.admin.mcp_e2e_probe import build_mcp_e2e_probe_plans
from oclaw.tools.catalog import default_registry
from oclaw.chat.tool_runtime import ToolExecutionContext, ToolExecutor
from oclaw.runtime.tools.mcp.filesystem_argv import build_mcp_process_command
from oclaw.runtime.tools.mcp.registry import McpRegistry
from oclaw.runtime.tools.mcp.runtime import McpProcessRuntime
from oclaw.interfaces.admin.mcp_e2e_probe import build_mcp_e2e_probe_plans
from oclaw.runtime.tools.catalog import default_registry
from oclaw.runtime.chat.tool_runtime import ToolExecutionContext, ToolExecutor
from oclaw.platform.llm.chat_models import LLMToolCall
from oclaw.openclaw_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_attempt import ALL_ATTEMPT_ERROR_CODES
from oclaw.runtime.agent_core_run import DEFAULT_RETRYABLE_ERROR_CODES, resolve_retryable_error_codes
_WECOM_CLEAR_KEYS = [
"wecom_mode",
@ -251,8 +251,8 @@ def build_admin_router() -> APIRouter:
ctx = _resolve_auth(store, authorization)
_require_permission(ctx, "admin:tenant:write")
from oclaw.tools.expert_registry import clear_expert_tool_cache
from oclaw.tools.public_registry import clear_public_tool_cache
from oclaw.runtime.tools.expert_registry import clear_expert_tool_cache
from oclaw.runtime.tools.public_registry import clear_public_tool_cache
clear_public_tool_cache()
clear_expert_tool_cache()
@ -309,7 +309,7 @@ def build_admin_router() -> APIRouter:
store = SqliteStore(db_path())
ctx = _resolve_auth(store, authorization)
_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()
available_roles = _ordered_roles()
@ -349,7 +349,7 @@ def build_admin_router() -> APIRouter:
_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.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()
items: list[dict[str, Any]] = []
@ -412,7 +412,7 @@ def build_admin_router() -> APIRouter:
store = SqliteStore(db_path())
ctx = _resolve_auth(store, authorization)
_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()
available_roles = _ordered_roles()
@ -1312,8 +1312,8 @@ def build_admin_router() -> APIRouter:
return {"ok": True, "trace": rows}
@router.get("/admin/api/oclaw/tasks")
@router.get("/admin/api/openclaw/tasks")
def api_openclaw_tasks(
@router.get("/admin/api/oclaw/tasks")
def api_oclaw_tasks(
task_id: str | None = Query(default=None),
session_id: 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
st = str(status or "").strip() or None
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__}
rows = store.openclaw_task_list(
rows = store.oclaw_task_list(
status=st,
session_id=sid,
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}
@router.get("/admin/api/oclaw/runs")
@router.get("/admin/api/openclaw/runs")
def api_openclaw_runs(
@router.get("/admin/api/oclaw/runs")
def api_oclaw_runs(
run_id: str | None = Query(default=None),
session_id: 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")
tenant_id = str(ctx.get("tenant_id") or "")
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:
return {"ok": True, "run": None}
out = dict(row.__dict__)
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}
rows = store.openclaw_run_list(
rows = store.oclaw_run_list(
tenant_id=tenant_id,
session_id=str(session_id 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
item = dict(r.__dict__)
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)
configured_retryable = sorted(resolve_retryable_error_codes(store=store))
return {
@ -1384,7 +1384,7 @@ def build_admin_router() -> APIRouter:
"runs": out_rows,
"counts": by_status,
"retry_policy": {
"setting_key": "AIA_OPENCLAW_RETRYABLE_ERROR_CODES",
"setting_key": "AIA_OCLAW_RETRYABLE_ERROR_CODES",
"effective_retryable_error_codes": configured_retryable,
"default_retryable_error_codes": list(DEFAULT_RETRYABLE_ERROR_CODES),
},
@ -1440,7 +1440,7 @@ def build_admin_router() -> APIRouter:
store = SqliteStore(db_path())
ctx = _resolve_auth(store, authorization)
_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
retry_mode = "first_round_only"
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_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
# OpenClaw takeover: legacy runner switches are disconnected (kept in DB for later).
turn_runner_impl = "openclaw"
# OpenClaw takeover: legacy manager decision mode is disconnected (kept in DB for later).
# Oclaw takeover: legacy runner switches are disconnected (kept in DB for later).
turn_runner_impl = "oclaw"
# Oclaw takeover: legacy manager decision mode is disconnected (kept in DB for later).
manager_decision_mode = ""
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
@ -1475,10 +1475,10 @@ def build_admin_router() -> APIRouter:
tool_llm_message_max_chars = 0
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()
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:
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")
wc_workers_raw = str(store.get_setting("AIA_WECOM_LONGCONN_WORKERS") or "").strip()
if not wc_workers_raw:
@ -1508,8 +1508,8 @@ def build_admin_router() -> APIRouter:
"tool_llm_message_max_chars": tool_llm_message_max_chars,
"mcp_filesystem_extra_roots": mcp_fs_raw,
"mcp_env_allowlist": mcp_env_allow_raw,
"openclaw_retryable_error_codes": retry_codes_raw,
"openclaw_retry_codes_strict_mode": retry_codes_strict_mode,
"oclaw_retryable_error_codes": retry_codes_raw,
"oclaw_retry_codes_strict_mode": retry_codes_strict_mode,
"wecom_longconn_workers": wecom_longconn_workers,
"wecom_longconn_inbound_queue_maxsize": wecom_longconn_inbound_queue_maxsize,
}
@ -1523,7 +1523,7 @@ def build_admin_router() -> APIRouter:
store = SqliteStore(db_path())
ctx = _resolve_auth(store, authorization)
_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
retry_mode = "first_round_only"
sm = True
@ -1531,7 +1531,7 @@ def build_admin_router() -> APIRouter:
tmw = payload.get("turn_max_tool_workers", 8)
tmr = payload.get("turn_max_tool_rounds", 8)
tmc = payload.get("turn_max_context_messages", 80)
tri = "openclaw"
tri = "oclaw"
try:
tmw_n = max(1, min(int(tmw), 32))
except Exception:
@ -1562,8 +1562,8 @@ def build_admin_router() -> APIRouter:
tmsg = payload.get("tool_llm_message_max_chars", 0)
mcp_fs_roots = str(payload.get("mcp_filesystem_extra_roots") 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_strict_mode = bool(payload.get("openclaw_retry_codes_strict_mode", False))
retry_codes = str(payload.get("oclaw_retryable_error_codes") or "").strip()
retry_codes_strict_mode = bool(payload.get("oclaw_retry_codes_strict_mode", False))
unknown_retry_codes: list[str] = []
if retry_codes:
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_MCP_FILESYSTEM_EXTRA_ROOTS", mcp_fs_roots)
store.set_setting("AIA_MCP_ENV_ALLOWLIST", mcp_env_allow)
store.set_setting("AIA_OPENCLAW_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_RETRYABLE_ERROR_CODES", retry_codes)
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_INBOUND_QUEUE_MAXSIZE", str(wc_in_q_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"],
action="tool_policy_update",
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",
detail={
"disable_tool_confirm": disable_confirm,
@ -1663,8 +1663,8 @@ def build_admin_router() -> APIRouter:
"tool_llm_message_max_chars": tmsg_n,
"mcp_filesystem_extra_roots": mcp_fs_roots,
"mcp_env_allowlist": mcp_env_allow,
"openclaw_retryable_error_codes": retry_codes,
"openclaw_retry_codes_strict_mode": retry_codes_strict_mode,
"oclaw_retryable_error_codes": retry_codes,
"oclaw_retry_codes_strict_mode": retry_codes_strict_mode,
"unknown_retryable_error_codes": unknown_retry_codes,
"wecom_longconn_workers": wc_workers_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,
"mcp_filesystem_extra_roots": mcp_fs_roots,
"mcp_env_allowlist": mcp_env_allow,
"openclaw_retryable_error_codes": retry_codes,
"openclaw_retry_codes_strict_mode": retry_codes_strict_mode,
"oclaw_retryable_error_codes": retry_codes,
"oclaw_retry_codes_strict_mode": retry_codes_strict_mode,
"unknown_retryable_error_codes": unknown_retry_codes,
"wecom_longconn_workers": wc_workers_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)
user_id = str(payload.get("user_id") or "").strip() or None
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()
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]
return {"ok": True, "items": rows}
from oclaw.admin.chat_api import include_chat_routes
from oclaw.admin.models_api import include_model_mgmt_routes
from oclaw.admin.skills_api import include_skill_routes
from oclaw.interfaces.admin.chat_api import include_chat_routes
from oclaw.interfaces.admin.models_api import include_model_mgmt_routes
from oclaw.interfaces.admin.skills_api import include_skill_routes
include_chat_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 oclaw.agents.factory import build_gateway_executor
from oclaw.openclaw_runtime.skill_installer import (
from oclaw.runtime.agents.factory import build_gateway_executor
from oclaw.runtime.skill_installer import (
auto_install_skill_from_payload,
create_skill_from_template,
install_skill_from_local_dir,
@ -15,7 +15,7 @@ from oclaw.openclaw_runtime.skill_installer import (
list_skills_with_status,
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_KEY,
load_skill_role_binding_dict,
@ -23,12 +23,12 @@ from oclaw.openclaw_runtime.skill_role_binding import (
ordered_binding_roles,
skill_role_binding_enabled,
)
from oclaw.openclaw_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_prompt import collect_skill_catalog_entries
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.persistence.sqlite_store import SqliteStore
from oclaw.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 get_skill_detail as clawhub_get_skill_detail
from oclaw.runtime.tools.skills.clawhub_client import search_skills as clawhub_search_skills
def include_skill_routes(
@ -393,7 +393,7 @@ def include_skill_routes(
name = str(payload.get("name") or "").strip()
desc = str(payload.get("description") 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 {}
overwrite = bool(payload.get("overwrite"))
out = create_skill_from_template(
@ -401,7 +401,7 @@ def include_skill_routes(
name=name,
description=desc,
body_markdown=body,
metadata_openclaw=md,
metadata_oclaw=md,
overwrite=overwrite,
)
_audit(
@ -527,8 +527,8 @@ def include_skill_routes(
"name": str(payload.get("name") or "").strip() or target,
"description": str(payload.get("description") or "retry auto install"),
"body_markdown": str(payload.get("body_markdown") or ""),
"metadata_openclaw": dict(payload.get("metadata_openclaw") or {})
if isinstance(payload.get("metadata_openclaw"), dict)
"metadata_oclaw": dict(payload.get("metadata_oclaw") or {})
if isinstance(payload.get("metadata_oclaw"), dict)
else {},
},
)

View file

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

View file

@ -1037,7 +1037,7 @@ function parseReasoningSegments(raw) {
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
// handles truncated streams (unfinished tags) safely.
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");
}
// OpenClaw-style streaming stitcher: reduce boundary artifacts without destroying layout.
// Oclaw-style streaming stitcher: reduce boundary artifacts without destroying layout.
function createStreamStitcher() {
let prevTail = "";
return {
@ -2607,7 +2607,7 @@ async function renderChatUi() {
if (String(p.status || "") === "started") {
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.
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 typing import Any
from oclaw.application.gateway import process_inbound_payload_usecase
from oclaw.channels.wecom.normalize import normalize_wecom_event, normalize_wecom_event_batch
from oclaw.runtime.application.gateway import process_inbound_payload_usecase
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.integrations.wecom_client import WeComClient
from oclaw.platform.persistence.sqlite_store import SqliteStore

View file

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

View file

@ -1,6 +1,6 @@
# 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 oclaw.openclaw_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.tools.skills.clawhub_client import search_skills as clawhub_search_skills
from oclaw.runtime.skill_installer import install_skill_from_registry_archive
from oclaw.runtime.tools.skills.clawhub_client import get_skill_detail as clawhub_get_skill_detail
from oclaw.runtime.tools.skills.clawhub_client import search_skills as clawhub_search_skills
def build_common_gateway_context(*, store: Any) -> dict[str, Any]:

View file

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

View file

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

View file

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

View file

@ -2,7 +2,7 @@ from __future__ import annotations
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 .validation import error_shape
@ -92,7 +92,7 @@ def _agent_identity_get_handler(opts: dict[str, Any]) -> None:
respond,
{
"agentId": resolved_agent_id,
"displayName": "OpenClaw Assistant",
"displayName": "Oclaw Assistant",
"avatarUrl": None,
},
)

View file

@ -20,7 +20,7 @@ class _ConfigSnapshot:
def _read_config_file_snapshot() -> _ConfigSnapshot:
"""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.
"""
return _ConfigSnapshot(exists=False, valid=True, config={})
@ -152,7 +152,7 @@ def _config_open_file_handler(opts: dict[str, Any]) -> Any:
return None
if not assert_valid_params(params, _validate_config_get_params, "config.openFile", respond):
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)
return None

View file

@ -30,11 +30,11 @@ def _norm_str(v: Any) -> str | None:
def _state(context: Any) -> dict[str, Any]:
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")
if isinstance(st, dict):
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
return created

View file

@ -4,6 +4,7 @@ import importlib.util
from pathlib import Path
from typing import Any, Callable
from oclaw.platform.config.runtime_paths import runtime_extensions_root
from .shared_types import GatewayRequestHandlers
from .validation import error_shape
@ -35,10 +36,10 @@ def _load_generate_image_fn() -> Callable[..., Any]:
global _generate_image_fn
if _generate_image_fn is not None:
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():
# 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))
if spec is None or spec.loader is None:
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")
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}"
environment = _norm_str(params.get("environment"))

View file

@ -2,7 +2,7 @@ from __future__ import annotations
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 .telegram_send_normalize import normalize_transport_target_for_channel

View file

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

View file

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

View file

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

View file

@ -3,8 +3,8 @@ from __future__ import annotations
from dataclasses import dataclass
from typing import Any, Callable
from oclaw.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.agent_scope import resolve_agent_workspace_dir, resolve_default_agent_id
from oclaw.runtime.agents.subagent_registry import init_subagent_registry
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.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.ws import ws_gateway_loop
from oclaw.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.gateway.server_startup_plugins import prepare_gateway_plugin_bootstrap
from oclaw.openclaw_runtime.hooks_runtime import (
from oclaw.interfaces.admin.routes import admin_static_dir, build_admin_router
from oclaw.runtime.agents.agent_scope import list_agent_ids, resolve_agent_workspace_dir, resolve_default_agent_id
from oclaw.interfaces.gateway.server_startup_plugins import prepare_gateway_plugin_bootstrap
from oclaw.runtime.hooks_runtime import (
initialize_hooks_runtime,
resolve_runtime_config,
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.persistence.sqlite_store import SqliteStore
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
except Exception:
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]]:

View file

@ -15,7 +15,7 @@ def _require_ilink_auth(
authorization_type: str | None,
authorization: str | None,
) -> None:
# Minimal contract required by openclaw-weixin:
# Minimal contract required by oclaw-weixin:
# - AuthorizationType: ilink_bot_token
# - Authorization: Bearer <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