重构仓库目录为统一的 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

80
runtime/tools/base.py Normal file
View file

@ -0,0 +1,80 @@
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Callable
ToolHandler = Callable[[dict[str, Any]], Any]
@dataclass(frozen=True)
class ToolRateLimit:
"""Best-effort per-tool rate limiting metadata (enforced by runtime when implemented)."""
# tokens per window (simple leaky bucket style); None means unlimited.
limit: int | None = None
window_s: int = 60
@dataclass(frozen=True)
class ToolSpec:
name: str
description: str
parameters: dict[str, Any]
handler: ToolHandler
tags: frozenset[str] = field(default_factory=frozenset)
# Contract metadata (non-OpenAI; used by orchestrator/runtime)
version: str = "v1"
risk_level: str = "low" # low|high (extendable)
timeout_s: float | None = None
rate_limit: ToolRateLimit | None = None
required_permissions: frozenset[str] = field(default_factory=frozenset)
execution_mode: str = "in_process" # in_process|subprocess (best-effort)
#: If true, may run in parallel with other consecutive read-only tools (cc-mini-style batching).
read_only: bool = False
def is_read_only(self) -> bool:
"""Compatibility helper mirroring cc-mini Tool.is_read_only()."""
return bool(self.read_only)
def as_openai_tool(self) -> dict[str, Any]:
return {
"type": "function",
"function": {
"name": self.name,
"description": self.description,
"parameters": self.parameters,
},
}
class ToolRegistry:
def __init__(self, tools: list[ToolSpec] | None = None):
self._tools: dict[str, ToolSpec] = {}
self._openai_tools_cache: list[dict[str, Any]] | None = None
if tools:
for t in tools:
self.register(t)
def register(self, tool: ToolSpec) -> None:
self._tools[tool.name] = tool
self._openai_tools_cache = None
def get(self, name: str) -> ToolSpec | None:
return self._tools.get(name)
def list(self) -> list[ToolSpec]:
return list(self._tools.values())
def as_openai_tools(self) -> list[dict[str, Any]]:
if self._openai_tools_cache is None:
self._openai_tools_cache = [t.as_openai_tool() for t in self.list()]
return list(self._openai_tools_cache)
__all__ = [
"ToolHandler",
"ToolRateLimit",
"ToolSpec",
"ToolRegistry",
]