重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。

同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。

Made-with: Cursor
This commit is contained in:
oliver 2026-04-26 08:34:33 +08:00
parent 4a23b715a2
commit dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions

View file

@ -1,14 +1,54 @@
from __future__ import annotations
import threading
from typing import Any
from oclaw.runtime.memory_stage import render_memory_context_block
from oclaw.runtime.project_context_prompt import build_project_context_block
from oclaw.runtime.skills_prompt import build_skills_catalog_block
from oclaw.runtime.types import OclawMemoryContext
from oclaw.runtime.workspaces.experts import expert_workspace_signature_token
from oclaw.prompts.loader import render_runtime_prompt
from oclaw.runtime.tools.base import ToolRegistry
_EXECUTOR_STATIC_PROMPT_CACHE_LOCK = threading.Lock()
_EXECUTOR_STATIC_PROMPT_CACHE: dict[tuple[Any, ...], str] = {}
def _executor_prompt_settings_signature(store: Any) -> tuple[str, ...]:
keys = (
"AIA_SKILL_RUNTIME_ENABLED",
"AIA_SKILLS_PROMPT_IN_SYSTEM",
"AIA_SKILL_DISABLED_NAMES",
"AIA_SKILL_ROLE_BINDING_ENABLED",
"AIA_SKILL_ROLE_BINDING_MANAGER_INHERIT",
"AIA_PROJECT_CONTEXT_MAX_FILE_CHARS",
"AIA_PROJECT_CONTEXT_MAX_TOTAL_CHARS",
)
parts: list[str] = []
for key in keys:
try:
val = str(store.get_setting(key) or "")
except Exception:
val = ""
parts.append(f"{key}={val}")
return tuple(parts)
def _unified_skill_policy_guidance() -> str:
# Global policy for all agents (including dynamic/ephemeral) — appended to base_system in build_executor_system_prompt.
return (
"- 如果用户问你有哪些技能(skill/技能),请直接根据已注入的技能目录及其 description 回答。\n"
"- 不要为了“列出技能”而去读取 SKILL.md。只有在你确实需要某个技能的详细使用说明时,才读取对应 SKILL.md。\n"
"- 当你需要技能细节时,请按目录中给出的 path 读取对应的 SKILL.md。"
"- 技能包由说明文档和可选文件组成。运行时不会自动执行技能 `scripts/` 目录下的文件;\n"
"- internal hooks 是独立系统,也不会自动执行这些脚本。\n"
"- 当用户明确要求运行技能脚本时,请使用项目允许的 terminal/bash/exec(或同类)工具执行;\n"
"- 如果脚本依赖相对路径(例如 `.learnings/`),请将工作目录设置为用户工作区。\n"
"- 在没有显式工具调用成功结果前,不要假设脚本已经执行。\n"
"- 在 Windows 上,`.sh` 可能需要 Git Bash、WSL 或等效环境。\n"
)
def build_executor_system_prompt(
*,
@ -26,17 +66,53 @@ def build_executor_system_prompt(
`lang` is reserved for future localized system fragments; current templates are bilingual/static.
"""
_ = lang # reserved for i18n extensions
final_system = get_executor_prompt_static(
store=store,
tools=tools,
base_url=base_url,
base_system=base_system,
workspace_dir=workspace_dir,
skill_binding_role=skill_binding_role,
)
mem_block = render_memory_context_block(memory_context or OclawMemoryContext())
if not mem_block:
return final_system
return render_runtime_prompt(
"runtime/system_with_memory.md",
variables={"system_prompt": final_system, "memory_context": mem_block},
strict=True,
)
def get_executor_prompt_static(
*,
store: Any,
tools: ToolRegistry | None,
base_url: str,
base_system: str,
workspace_dir: str | None = None,
skill_binding_role: str | None = None,
) -> str:
cache_key = (
str(base_url or "").strip(),
str(base_system or "").strip(),
str(workspace_dir or "").strip(),
str(skill_binding_role or "").strip().lower(),
expert_workspace_signature_token(),
_executor_prompt_settings_signature(store),
bool(tools is not None),
)
with _EXECUTOR_STATIC_PROMPT_CACHE_LOCK:
cached = _EXECUTOR_STATIC_PROMPT_CACHE.get(cache_key)
if isinstance(cached, str):
return cached
final_system = str(base_system or "").strip()
guide = _unified_skill_policy_guidance().strip()
if guide and guide not in final_system:
final_system = f"{final_system}\n\n{guide}".strip()
project_block = build_project_context_block(store=store, workspace_dir=workspace_dir)
if project_block:
final_system = f"{final_system}\n\n{project_block}".strip()
mem_block = render_memory_context_block(memory_context or OclawMemoryContext())
if mem_block:
final_system = render_runtime_prompt(
"runtime/system_with_memory.md",
variables={"system_prompt": final_system, "memory_context": mem_block},
strict=True,
)
if tools is not None:
cat = build_skills_catalog_block(
store=store,
@ -50,11 +126,42 @@ def build_executor_system_prompt(
variables={"system_body": final_system, "skills_catalog": cat},
strict=True,
)
with _EXECUTOR_STATIC_PROMPT_CACHE_LOCK:
_EXECUTOR_STATIC_PROMPT_CACHE[cache_key] = final_system
if len(_EXECUTOR_STATIC_PROMPT_CACHE) > 256:
_EXECUTOR_STATIC_PROMPT_CACHE.clear()
return final_system
def warm_executor_prompt_cache(
*,
store: Any,
tools: ToolRegistry | None,
base_url: str,
role_base_systems: dict[str, str],
workspace_dir: str | None = None,
) -> dict[str, int]:
warmed = 0
for role, base_system in (role_base_systems or {}).items():
_ = get_executor_prompt_static(
store=store,
tools=tools,
base_url=base_url,
base_system=str(base_system or ""),
workspace_dir=workspace_dir,
skill_binding_role=str(role or "").strip().lower() or None,
)
warmed += 1
return {"roles_warmed": int(warmed)}
def build_oclaw_executor_system_prompt(**kwargs: Any) -> str:
return build_executor_system_prompt(**kwargs)
__all__ = ["build_executor_system_prompt", "build_oclaw_executor_system_prompt"]
__all__ = [
"build_executor_system_prompt",
"build_oclaw_executor_system_prompt",
"get_executor_prompt_static",
"warm_executor_prompt_cache",
]