diff --git a/docs/design/Interfaces.md b/docs/design/Interfaces.md index 636e8cb0..2175823c 100644 --- a/docs/design/Interfaces.md +++ b/docs/design/Interfaces.md @@ -1,410 +1,602 @@ -# DARE Framework 接口设计(Draft,package = dare_framework) +# DARE Framework 接口设计(Synced) -> 状态:草案(用于评审) +> 状态:已与当前代码同步(2026-02-25) > -> 本文给出当前目标接口面:domain / types / stable interfaces(Kernel contracts)/ pluggable components / managers。 -> -> 证据与可追溯:见 `docs/design/DARE_evidence.yaml`。 +> 本文是跨模块接口总表,来源于 `dare_framework/*/{kernel,interfaces,types}.py`。 +> 详细流程设计请看 `docs/design/modules/*/README.md`。 --- -## 0. 分域目录结构约定 +## 0. 分域目录约定 -每个 domain SHOULD 遵循: +每个 domain 推荐结构: -``` +```text dare_framework// types.py - kernel.py # Kernel contracts(稳定) - interfaces.py # 可选(可插拔/组合接口位) + kernel.py + interfaces.py # 可选:可插拔接口或组合接口 __init__.py - _internal/ # 可选(默认实现;不稳定;不作为公共 API) + _internal/ # 默认实现(非稳定) ``` -推荐依赖规则: -- `types.py` MUST NOT 依赖 `interfaces.py` 或 `_internal/` -- `kernel.py` SHOULD 只依赖 `types.py` -- `interfaces.py` MAY 依赖其他域的 `kernel.py`(表达组合) -- `_internal/` 默认实现对外通过 domain factory 或 `__init__.py` facade 暴露,其他域不直接引用实现模块 +约束: +- `types.py` 不依赖 `_internal/`。 +- `kernel.py` 定义稳定契约(Kernel contracts)。 +- `interfaces.py` 放策略位、组合接口、manager 接口。 +- `_internal/` 实现不作为稳定 API 承诺。 --- -## 1. agent +## 1. 跨模块核心字段契约 + +### 1.1 上下文契约(context/types.py) + +- `Message` + - `role: str` + - `content: str` + - `name: str | None` + - `metadata: dict[str, Any]` +- `Budget` + - limits: `max_tokens/max_cost/max_time_seconds/max_tool_calls` + - usage: `used_tokens/used_cost/used_time_seconds/used_tool_calls` +- `AssembledContext` + - `messages: list[Message]` + - `sys_prompt: Prompt | None` + - `tools: list[CapabilityDescriptor]` + - `metadata: dict[str, Any]` + +### 1.2 计划与运行结果契约(plan/types.py) + +- `Task`: `description/task_id/milestones/metadata/previous_session_summary` +- `Milestone`: `milestone_id/description/user_input/success_criteria` +- `ProposedPlan` vs `ValidatedPlan` +- `Envelope`: `allowed_capability_ids/budget/done_predicate/risk_level` +- `RunResult`: `success/output/output_text/errors/metadata/session_id/session_summary` + +### 1.3 能力与调用结果契约(tool/types.py) + +- `CapabilityDescriptor` + - `id/type/name/description/input_schema/output_schema/metadata` +- `CapabilityMetadata` + - `risk_level/requires_approval/timeout_seconds/is_work_unit/capability_kind` +- `RunContext` + - `deps/metadata/run_id/task_id/milestone_id/config` +- `ToolResult` + - `success/output/error/evidence` + +### 1.4 传输契约(transport/types.py) + +- `TransportEnvelope` + - `id/reply_to/kind/payload/meta/stream_id/seq` +- `EnvelopeKind` + - `MESSAGE/ACTION/CONTROL` -### 1.1 `agent/kernel.py` +--- -```python -from __future__ import annotations +## 2. agent -from typing import Any, Protocol +### 2.1 Kernel(agent/kernel.py) -from dare_framework.plan.types import Task, RunResult +```python +class IAgent(ABC): + async def __call__( + self, + message: str | Task, + deps: Any | None = None, + *, + transport: AgentChannel | None = None, + ) -> RunResult: ... + + async def start(self) -> None: ... + async def stop(self) -> None: ... + def interrupt(self) -> None: ... + def pause(self) -> dict[str, Any]: ... + def retry(self) -> dict[str, Any]: ... + def reverse(self) -> dict[str, Any]: ... + def get_status(self) -> AgentStatus: ... +``` +### 2.2 Pluggable(agent/interfaces.py) -class IAgent(Protocol): - """框架对外最小运行面。""" +```python +class IAgentOrchestration(ABC): + async def execute( + self, + task: str | Task, + *, + transport: AgentChannel | None = None, + ) -> RunResult: ... +``` - async def run(self, task: str | Task, deps: Any | None = None) -> RunResult: - """执行任务并返回 RunResult。 +### 2.3 关键说明 - 约束: - - deps MUST NOT 写入 Task(保持 Task 可序列化与审计友好)。 - """ +- 统一入口是 `__call__`,而非历史文档中的 `run(...)`。 +- `Task` 与 `str` 并存:支持 simple/react/five-layer 统一调用面。 - ... -``` +--- -### 1.2 可选:编排策略位 +## 3. context -如果希望“一个 Agent facade + 可插拔编排策略”,可以增加: +### 3.1 Kernel(context/kernel.py) ```python -from __future__ import annotations +class IRetrievalContext(ABC): + def get(self, query: str = "", **kwargs: Any) -> list[Message]: ... -from typing import Any, Protocol +class IContext(ABC): + @property + def id(self) -> str: ... + @property + def budget(self) -> Budget: ... + @property + def short_term_memory(self) -> IRetrievalContext: ... + @property + def long_term_memory(self) -> IRetrievalContext: ... + @property + def knowledge(self) -> IRetrievalContext: ... + @property + def config(self) -> Config: ... + @property + def sys_prompt(self) -> Prompt: ... + @property + def sys_skill(self) -> Skill | None: ... -from dare_framework.plan.types import Task, RunResult + def stm_add(self, message: Message) -> None: ... + def stm_get(self) -> list[Message]: ... + def stm_clear(self) -> list[Message]: ... + def budget_use(self, resource: str, amount: float) -> None: ... + def budget_check(self) -> None: ... + def budget_remaining(self, resource: str) -> float: ... -class IAgentOrchestration(Protocol): - """一种编排实现(五层循环只是其中之一)。""" + @property + def tool_gateway(self) -> IToolGateway | None: ... + def set_tool_gateway(self, tool_gateway: IToolGateway | None) -> None: ... - async def run_task(self, task: Task, deps: Any | None = None) -> RunResult: - ... + def list_tools(self) -> list[CapabilityDescriptor]: ... + def assemble(self) -> AssembledContext: ... + def compress(self, **options: Any) -> None: ... ``` --- -## 2. context(上下文工程) - -> 本节以 `dare_framework` 的 context-centric 设计为准:Context 是核心实体,messages 在每次模型调用前 request-time 组装。 - -### 2.1 `context/types.py`(核心类型) +## 4. tool -建议最小集合: -- `Message`:统一消息格式(role/content/name/metadata) -- `Budget`:资源预算(max_* + used_*) -- `AssembledContext`:单次模型调用的 request-time 上下文(messages + tools + metadata) - -### 2.2 `context/kernel.py`(核心稳定契约) +### 4.1 Kernel(tool/kernel.py) ```python -from __future__ import annotations - -from typing import Any, Protocol - - -class IRetrievalContext(Protocol): - """统一检索接口(STM/LTM/Knowledge 等实现该接口)。""" - - def get(self, query: str = "", **kwargs: Any) -> list["Message"]: - ... - - -class IContext(Protocol): - """Context-centric 核心实体。 +class IToolProvider(ABC): + def list_tools(self) -> list[ITool]: ... - 语义: - - messages 不作为长期字段存储,而是每次调用前 assemble() 临时组装。 - - budget 与 external retrieval refs 挂在 Context 上,便于审计与复验。 - """ - - # Fields - id: str - budget: "Budget" - config: dict[str, Any] | None - - short_term_memory: IRetrievalContext - long_term_memory: IRetrievalContext | None - knowledge: IRetrievalContext | None +class ITool(IComponent, ABC): + @property + def name(self) -> str: ... + @property + def description(self) -> str: ... + @property + def input_schema(self) -> dict[str, Any]: ... + @property + def output_schema(self) -> dict[str, Any] | None: ... + @property + def tool_type(self) -> ToolType: ... + @property + def risk_level(self) -> RiskLevelName: ... + @property + def requires_approval(self) -> bool: ... + @property + def timeout_seconds(self) -> int: ... + @property + def is_work_unit(self) -> bool: ... + @property + def capability_kind(self) -> CapabilityKind: ... - # Short-term memory methods - def stm_add(self, message: "Message") -> None: ... - def stm_get(self) -> list["Message"]: ... - def stm_clear(self) -> list["Message"]: ... + async def execute(self, *, run_context: RunContext[Any], **params: Any) -> ToolResult[Any]: ... - # Budget methods - def budget_use(self, resource: str, amount: float) -> None: ... - def budget_check(self) -> None: ... - def budget_remaining(self, resource: str) -> float: ... +class IToolGateway(ABC): + def list_capabilities(self) -> list[CapabilityDescriptor]: ... + async def invoke( + self, + capability_id: str, + *, + envelope: Envelope, + context: Context | None = None, + **params: Any, + ) -> ToolResult: ... - # Tool listing (for ModelInput.tools) - def listing_tools(self) -> list[dict[str, Any]]: ... +class IToolManager(ABC): + def load_tools(self, *, config: Config | None = None) -> list[ITool]: ... + def register_tool(self, tool: ITool, *, namespace: str | None = None, version: str | None = None) -> CapabilityDescriptor: ... + def get_tool(self, capability_id: str) -> ITool: ... + def unregister_tool(self, capability_id: str) -> bool: ... + def change_capability_status(self, capability_id: str, enabled: bool) -> None: ... + def register_provider(self, provider: IToolProvider) -> None: ... + def unregister_provider(self, provider: IToolProvider) -> bool: ... + async def refresh(self) -> list[CapabilityDescriptor]: ... + def list_capabilities(self, *, include_disabled: bool = False) -> list[CapabilityDescriptor]: ... + def get_capability(self, capability_id: str, *, include_disabled: bool = False) -> CapabilityDescriptor | None: ... +``` - # Assembly (core) - def assemble(self, **options: Any) -> "AssembledContext": ... +### 4.2 Pluggable(tool/interfaces.py) +```python +class IExecutionControl(ABC): + def poll(self) -> ExecutionSignal: ... + def poll_or_raise(self) -> None: ... + async def pause(self, reason: str) -> str: ... + async def resume(self, checkpoint_id: str) -> None: ... + async def checkpoint(self, label: str, payload: dict[str, Any]) -> str: ... + async def wait_for_human(self, checkpoint_id: str, reason: str) -> None: ... ``` -补充语义(关键约束): -- tool defs 的来源必须可追溯到 ToolManager 的可信 registry(同源可信),并与 `IToolGateway` 的可调用能力一致。 -- (可选兼容)如果某模型需要“文本化的 tool catalog”,由 adapter/策略层渲染,不作为 Context 的必选语义。 - --- -## 3. tool(能力模型 + 系统调用边界) +## 5. plan -### 3.1 Canonical capability +### 5.1 Kernel(plan/kernel.py) -`CapabilityDescriptor` 描述任意可调用能力: -- TOOL / AGENT / UI +- 当前 `plan/kernel.py` 为轻量占位;稳定策略接口在 `plan/interfaces.py`。 -### 3.2 `tool/kernel.py`(稳定边界) +### 5.2 Pluggable(plan/interfaces.py) ```python -from __future__ import annotations +class IPlanner(IComponent, ABC): + async def plan(self, ctx: IContext) -> ProposedPlan: ... + async def decompose(self, task: Task, ctx: IContext) -> DecompositionResult: ... -from typing import Any, Literal, Protocol, Sequence +class IValidator(IComponent, ABC): + async def validate_plan(self, plan: ProposedPlan, ctx: IContext) -> ValidatedPlan: ... + async def verify_milestone(self, result: RunResult, ctx: IContext, *, plan: ValidatedPlan | None = None) -> VerifyResult: ... -from dare_framework.config.types import Config -from dare_framework.plan.types import Envelope -from dare_framework.infra.component import ComponentType, IComponent -from dare_framework.tool.types import ( - CapabilityDescriptor, - CapabilityKind, - ProviderStatus, - RiskLevelName, - RunContext, - ToolDefinition, - ToolResult, - ToolType, -) +class IRemediator(IComponent, ABC): + async def remediate(self, verify_result: VerifyResult, ctx: IContext) -> str: ... +class IPlanAttemptSandbox(ABC): + def create_snapshot(self, ctx: IContext) -> str: ... + def rollback(self, ctx: IContext, snapshot_id: str) -> None: ... + def commit(self, snapshot_id: str) -> None: ... -class IToolProvider(Protocol): - """提供工具实例,供 ToolManager 注册。""" - - def list_tools(self) -> list["ITool"]: ... +class IStepExecutor(ABC): + async def execute_step(self, step: ValidatedStep, ctx: IContext, previous_results: list[StepResult]) -> StepResult: ... +class IEvidenceCollector(ABC): + def collect(self, source: str, data: dict, evidence_type: str) -> Evidence: ... +``` -class ITool(IComponent, Protocol): - @property - def name(self) -> str: ... +--- - @property - def component_type(self) -> Literal[ComponentType.TOOL]: ... +## 6. model - @property - def description(self) -> str: ... +### 6.1 Kernel(model/kernel.py) +```python +class IModelAdapter(IComponent, ABC): @property - def input_schema(self) -> dict[str, Any]: ... - + def name(self) -> str: ... @property - def output_schema(self) -> dict[str, Any]: ... + def model(self) -> str: ... + async def generate( + self, + model_input: ModelInput, + *, + options: GenerateOptions | None = None, + ) -> ModelResponse: ... +``` - @property - def tool_type(self) -> ToolType: ... +### 6.2 Pluggable(model/interfaces.py) - @property - def risk_level(self) -> RiskLevelName: ... +```python +class IModelAdapterManager(ABC): + def load_model_adapter(self, *, config: Config | None = None) -> IModelAdapter | None: ... - @property - def requires_approval(self) -> bool: ... +class IPromptLoader(ABC): + def load(self) -> list[Prompt]: ... - @property - def timeout_seconds(self) -> int: ... +class IPromptStore(ABC): + def get(self, prompt_id: str, *, model: str | None = None, version: str | None = None) -> Prompt: ... +``` - @property - def is_work_unit(self) -> bool: ... +--- - @property - def capability_kind(self) -> CapabilityKind: ... +## 7. security - async def execute(self, input: dict[str, Any], context: RunContext[Any]) -> ToolResult: ... +### 7.1 Kernel(security/kernel.py) +```python +class ISecurityBoundary(Protocol): + async def verify_trust(self, *, input: dict[str, Any], context: dict[str, Any]) -> TrustedInput: ... + async def check_policy(self, *, action: str, resource: str, context: dict[str, Any]) -> PolicyDecision: ... + async def execute_safe(self, *, action: str, fn: Callable[[], Any], sandbox: SandboxSpec) -> Any: ... +``` -class IToolGateway(Protocol): - """系统调用边界:所有外部副作用必须经由 invoke。""" +### 7.2 类型(security/types.py) - async def list_capabilities(self) -> Sequence[CapabilityDescriptor]: ... +- `RiskLevel`: `READ_ONLY/IDEMPOTENT_WRITE/COMPENSATABLE/NON_IDEMPOTENT_EFFECT` +- `PolicyDecision`: `ALLOW/DENY/APPROVE_REQUIRED` +- `TrustedInput`: `params/risk_level/metadata` +- `SandboxSpec`: `mode/details` - async def invoke(self, capability_id: str, params: dict[str, Any], *, envelope: Envelope) -> ToolResult: ... +--- - def register_provider(self, provider: object) -> None: ... +## 8. event +### 8.1 Kernel(event/kernel.py) -class IToolManager(IToolGateway, Protocol): - """可信工具注册表与管理接口。""" +```python +class IEventLog(Protocol): + async def append(self, event_type: str, payload: dict[str, Any]) -> str: ... + async def query(self, *, filter: dict[str, Any] | None = None, limit: int = 100) -> Sequence[Event]: ... + async def replay(self, *, from_event_id: str) -> RuntimeSnapshot: ... + async def verify_chain(self) -> bool: ... +``` - def load_tools(self, *, config: Config | None = None) -> list[ITool]: ... +### 8.2 类型(event/types.py) - def register_tool(self, tool: ITool, *, namespace: str | None = None, version: str | None = None) -> CapabilityDescriptor: ... +- `Event`: `event_type/payload/event_id/timestamp/prev_hash/event_hash` +- `RuntimeSnapshot`: `from_event_id/events` - def unregister_tool(self, capability_id: str) -> bool: ... +--- - def update_tool(self, tool: ITool, *, capability_id: str, enabled: bool | None = None) -> CapabilityDescriptor: ... +## 9. hook - def set_capability_enabled(self, capability_id: str, enabled: bool) -> None: ... +### 9.1 Kernel(hook/kernel.py) - def register_provider(self, provider: IToolProvider) -> None: ... +```python +class IHook(IComponent, Protocol): + async def invoke(self, phase: HookPhase, *args: Any, **kwargs: Any) -> HookResult | dict[str, Any] | None: ... - def unregister_provider(self, provider: IToolProvider) -> bool: ... +class IExtensionPoint(Protocol): + def register_hook(self, phase: HookPhase, hook: HookFn) -> None: ... + async def emit(self, phase: HookPhase, payload: dict[str, Any]) -> HookResult: ... +``` - async def refresh(self) -> list[CapabilityDescriptor]: ... +### 9.2 Pluggable(hook/interfaces.py) - def list_capabilities(self, *, include_disabled: bool = False) -> list[CapabilityDescriptor]: ... +```python +class IHookManager(Protocol): + def load_hooks(self, *, config: Config | None = None) -> list[IHook]: ... +``` - def list_tool_defs(self) -> list[ToolDefinition]: ... +### 9.3 类型(hook/types.py) - def get_capability(self, capability_id: str, *, include_disabled: bool = False) -> CapabilityDescriptor | None: ... +- `HookPhase`: 生命周期 phase 枚举(`BEFORE_*` / `AFTER_*`) +- `HookDecision`: `ALLOW/BLOCK/ASK` +- `HookEnvelope`: `hook_version/phase/invocation_id/context_id/timestamp_ms/payload` +- `HookResult`: `decision/patch/message` - async def health_check(self) -> dict[str, ProviderStatus]: ... +--- - async def invoke(self, capability_id: str, params: dict[str, Any], *, envelope: Envelope) -> ToolResult: ... +## 10. config +### 10.1 Kernel(config/kernel.py) +```python +class IConfigProvider(Protocol): + def current(self) -> Config: ... + def reload(self) -> Config: ... ``` -### 3.3 `tool/interfaces.py`(control plane) +### 10.2 类型(config/types.py) -```python -from __future__ import annotations +核心: +- `Config` +- `LLMConfig` +- `ProxyConfig` +- `ComponentConfig` +- `HooksConfig` +- `ObservabilityConfig` +- `RedactionConfig` -from typing import Any, Protocol - -from dare_framework.tool.types import ExecutionSignal +关键操作: +- `component_settings(...)` +- `is_component_enabled(...)` +- `component_config(...)` +- `filter_enabled(...)` +--- -class IExecutionControl(Protocol): - def poll(self) -> ExecutionSignal: ... +## 11. memory / knowledge - def poll_or_raise(self) -> None: ... +### 11.1 memory(memory/kernel.py) - async def pause(self, reason: str) -> str: ... +```python +class IShortTermMemory(IComponent, IRetrievalContext, ABC): + def add(self, message: Message) -> None: ... + def clear(self) -> None: ... + def compress(self, max_messages: int | None = None, **kwargs) -> int: ... - async def resume(self, checkpoint_id: str) -> None: ... +class ILongTermMemory(IComponent, IRetrievalContext, ABC): + async def persist(self, messages: list[Message]) -> None: ... +``` - async def checkpoint(self, label: str, payload: dict[str, Any]) -> str: ... +### 11.2 knowledge(knowledge/kernel.py + interfaces.py) - async def wait_for_human(self, checkpoint_id: str, reason: str) -> None: ... +```python +class IKnowledge(IRetrievalContext, ABC): + def get(self, query: str, **kwargs: Any) -> list[Message]: ... + def add(self, content: str, **kwargs: Any) -> None: ... +class IKnowledgeTool(IKnowledge, ITool, ABC): + ... +``` -@runtime_checkable -class IProtocolAdapter(Protocol): - @property - def protocol_name(self) -> str: ... +### 11.3 配置类型 - async def connect(self, endpoint: str, config: dict[str, Any]) -> None: ... +- `LongTermMemoryConfig` +- `KnowledgeConfig` - async def disconnect(self) -> None: ... +--- - async def discover(self) -> Sequence[CapabilityDescriptor]: ... +## 12. skill - async def invoke(self, capability_id: str, params: dict[str, Any], *, timeout: float | None = None) -> Any: ... +### 12.1 Kernel(skill/kernel.py) +```python +class ISkill(IComponent, ABC): + @property + def name(self) -> str: ... + @property + def description(self) -> str: ... +class ISkillTool(ITool, ABC): + ... ``` -### 3.4 可信 metadata 约定(建议) +### 12.2 Pluggable(skill/interfaces.py) -`CapabilityDescriptor.metadata` 推荐保留: -- `risk_level`: string enum -- `requires_approval`: bool -- `timeout_seconds`: int +```python +class ISkillLoader(ABC): + def load(self) -> list[Skill]: ... + +class ISkillStore(ABC): + def list_skills(self) -> list[Skill]: ... + def get_skill(self, skill_id: str) -> Skill | None: ... + def select_for_task(self, query: str, limit: int = 5) -> list[Skill]: ... +``` -补充约定: -- `capability_id` 为 UUID,LLM 侧 `function.name` 与该 id 保持一致,以确保调用路由唯一。 -- `is_work_unit`: bool -- `capability_kind`: `tool` / `skill` / `plan_tool` / `agent` / `ui` +### 12.3 类型(skill/types.py) -安全规则: -- 上述字段必须来自可信 registry(gateway/providers),不能来自模型/规划器输出。 +- `Skill` + - `id/name/description/content/skill_dir/scripts` + - `to_context_section()` + - `get_script_path(script_name)` --- -## 4. plan(任务、计划、结果) +## 13. mcp -### 4.1 Proposed vs Validated +### 13.1 Kernel(mcp/kernel.py) -- Proposed plan/steps:不可信(来自 planner) -- Validated plan/steps:可信(来自 validator + registry 派生) +```python +class IMCPClient(Protocol): + @property + def name(self) -> str: ... + @property + def transport(self) -> str: ... -并且必须满足:Plan Attempt Isolation(失败计划不得污染外层状态)。 + async def connect(self) -> None: ... + async def disconnect(self) -> None: ... + async def list_tools(self) -> list[ITool]: ... + async def call_tool(self, tool_name: str, arguments: dict[str, Any], context: RunContext[Any]) -> ToolResult: ... +``` -### 4.2 策略接口(`plan/interfaces.py`) +### 13.2 类型(mcp/types.py) -- `IPlanner.plan(ctx) -> ProposedPlan` -- `IValidator.validate_plan(plan, ctx) -> ValidatedPlan` -- `IValidator.verify_milestone(result, ctx) -> VerifyResult` -- `IRemediator.remediate(verify_result, ctx) -> str` +- `TransportType`: `STDIO/HTTP/GRPC` +- `MCPServerConfig` + - `name/transport/command/env/url/headers/endpoint/tls/timeout_seconds/enabled/cwd` +- `MCPConfigFile`: `source_path/servers` --- -## 5. model(LLM 调用适配) - -### 5.1 统一输入面 +## 14. embedding -标准化模型输入为: -- `ModelInput(messages + trusted tool defs + metadata)` +### 14.1 Pluggable(embedding/interfaces.py) -规则: -- tool defs 必须可追溯到 ToolManager 的可信 registry,并与 ToolGateway 可调用能力一致。 -- (可选)对不支持结构化 tools 的模型:可由 adapter/策略层渲染 tool catalog system message(审计友好)。 +```python +class IEmbeddingAdapter(Protocol): + async def embed(self, text: str, *, options: EmbeddingOptions | None = None) -> EmbeddingResult: ... + async def embed_batch(self, texts: list[str], *, options: EmbeddingOptions | None = None) -> list[EmbeddingResult]: ... +``` -### 5.2 Adapter 接口(`model/kernel.py`) +### 14.2 类型(embedding/types.py) -- `IModelAdapter.generate(model_input: ModelInput, options=None) -> ModelResponse` +- `EmbeddingOptions`: `model/metadata` +- `EmbeddingResult`: `vector/metadata` --- -## 6. security(Trust + Policy + Sandbox) +## 15. observability -`security/kernel.py`: -- `verify_trust`:派生可信输入(含风险字段) -- `check_policy`:ALLOW/DENY/APPROVE_REQUIRED -- `execute_safe`:沙箱执行包装 +### 15.1 Kernel(observability/kernel.py) ---- +```python +class ITelemetryProvider(Protocol): + @property + def name(self) -> str: ... + @contextmanager + def start_span(self, name: str, *, kind: str = "internal", attributes: dict[str, Any] | None = None) -> Any: ... + def record_metric(self, name: str, value: float, *, attributes: dict[str, Any] | None = None) -> None: ... + def record_event(self, name: str, attributes: dict[str, Any] | None = None) -> None: ... + def shutdown(self) -> None: ... + +class ISpan(Protocol): + def set_attribute(self, key: str, value: Any) -> None: ... + def add_event(self, name: str, attributes: dict[str, Any] | None = None) -> None: ... + def set_status(self, status: str, description: str | None = None) -> None: ... + def end(self) -> None: ... +``` -## 7. event(审计与重放) +### 15.2 类型(observability/types.py) -`event/kernel.py`: -- append-only WORM -- query + replay -- 可选 hash-chain verify +- `TelemetryConfig` +- `RunMetrics` +- `SpanKind`, `SpanStatus`, `GenAIOperation` +- `TokenUsage`, `SpanContext` --- -## 8. hook(生命周期扩展点) +## 16. transport -`hook/kernel.py`: -- `IExtensionPoint.register_hook(...)` -- `IExtensionPoint.emit(...)` +### 16.1 Kernel(transport/kernel.py) -默认语义建议:best-effort(hook 失败不应默认导致运行崩溃)。 +```python +class ClientChannel(Protocol): + def attach_agent_envelope_sender(self, sender: Sender) -> None: ... + def agent_envelope_receiver(self) -> Receiver: ... ---- +class AgentChannel(Protocol): + async def start(self) -> None: ... + async def stop(self) -> None: ... + async def poll(self) -> TransportEnvelope | list[TransportEnvelope]: ... + async def send(self, msg: TransportEnvelope) -> None: ... -## 9. config(配置与 managers) + def add_action_handler_dispatcher(self, dispatcher: ActionHandlerDispatcher) -> None: ... + def add_agent_control_handler(self, handler: AgentControlHandler) -> None: ... -- `IConfigProvider`:提供 effective config + reload(位于 `config/kernel.py`) -- managers(Layer 3)负责确定性装配: - - discovery(entrypoints) - - selection(single-select vs multi-load) - - filtering(enable/disable/allowlists) - - ordering(稳定 `order`) - - instantiation + def get_action_handler_dispatcher(self) -> ActionHandlerDispatcher | None: ... + def get_agent_control_handler(self) -> AgentControlHandler | None: ... -Kernel 不依赖 entrypoints discovery。 + @staticmethod + def build(client_channel: ClientChannel, *, max_inbox: int = 100, max_outbox: int = 100, action_timeout_seconds: float = 30.0) -> AgentChannel: ... +``` ---- +### 16.2 interaction 子域(transport/interaction/*) -## 10. memory / knowledge(统一检索面 + 组合接口位) +- `ActionHandlerDispatcher` + - ACTION envelope 校验、路由、统一 result/error 结构化返回。 +- `AgentControlHandler` + - `interrupt/pause/retry/reverse` 到 agent lifecycle 的映射。 +- payload builders + - success/error/approval_pending/approval_resolved。 -- `memory` 与 `knowledge` 应实现 `IRetrievalContext`。 -- 当某 domain 既要 retrieval 又要 callable capability 时,使用 `interfaces.py` 做组合接口。 +--- -例: -- `IKnowledgeTool = IKnowledge + ITool` +## 17. 跨模块调用主链(摘要) + +```mermaid +flowchart TD + A["Agent __call__/execute"] --> B["Context.assemble"] + B --> C["ModelAdapter.generate"] + C --> D{"tool_calls?"} + D -- no --> E["RunResult"] + D -- yes --> F["ToolGateway.invoke"] + F --> G["ToolResult + Evidence"] + G --> B + + A --> H["Hook emit"] + H --> I["ObservabilityHook / Telemetry"] + A --> J["EventLog append"] + A --> K["Transport send/poll (optional)"] +``` --- -## 11. Plan Tool(控制类工具) +## 18. 已同步差异说明(相对旧草案) -规则: -- Execute 遇到 Plan Tool 必须中止执行并返回外层(Milestone/Plan)触发 re-plan。 +- `agent` 统一入口改为 `IAgent.__call__`(不再以 `run(...)` 作为最小契约)。 +- `context` 工具接口为 `list_tools()`(非 `listing_tools()`)。 +- `tool` 的 `IToolGateway.list_capabilities()` 为同步方法,`invoke(...)` 为异步。 +- `plan/kernel.py` 当前为空壳,策略接口位于 `plan/interfaces.py`。 +- 新增 `transport`、`observability`、`mcp`、`embedding`、`skill` 的完整契约节。 -推荐: -- 通过可信 registry metadata 标记 `capability_kind=plan_tool`。 -- 兼容:允许 `plan:` 前缀约定。 diff --git a/docs/design/modules/README.md b/docs/design/modules/README.md index a9c33079..c1c9b790 100644 --- a/docs/design/modules/README.md +++ b/docs/design/modules/README.md @@ -1,9 +1,9 @@ # Modules Design Index -> Status: updated (2026-01-31). +> Status: updated (2026-02-25). > > This directory holds per-module design documents aligned with `dare_framework/`. -> TODO markers indicate gaps or ambiguity that need module owners to confirm. +> Each module README now contains explicit: **Public Contract / Core Fields / Runtime Flow**. ## Modules - agent: `docs/design/modules/agent/README.md` @@ -25,7 +25,10 @@ - skill: `docs/design/modules/skill/README.md` (assessment: `docs/design/modules/skill/Assessment.md`) - mcp: `docs/design/modules/mcp/README.md` (assessment: `docs/design/modules/mcp/Assessment.md`) - embedding: `docs/design/modules/embedding/README.md` -- transport (design-only): `docs/design/modules/transport/transport_mvp.md` (see also `docs/design/modules/transport/Transport_Domain_Design.md`) +- transport: `docs/design/modules/transport/README.md` + - supplemental: `docs/design/modules/transport/transport_mvp.md` + - supplemental: `docs/design/modules/transport/Transport_Domain_Design.md` + - supplemental: `docs/design/modules/transport/InteractionStreaming.md` ## Related Docs - interface map: `docs/design/Interfaces.md` diff --git a/docs/design/modules/agent/README.md b/docs/design/modules/agent/README.md index 5ed8fdd7..acd138e8 100644 --- a/docs/design/modules/agent/README.md +++ b/docs/design/modules/agent/README.md @@ -27,3 +27,35 @@ - `examples/06-dare-coding-agent-mcp/README.md` 说明:DareAgent 当前语义为 five-layer only,不承担 simple/react 自动降级。 + +## 4. 对外接口(Public Contract) + +- 统一入口:`IAgent.__call__(task, transport=None)` +- 编排入口:`IAgentOrchestration.execute(task, transport)` +- 结果契约:统一输出 `RunResult`(含 `output_text`) + +详细签名与约束见: +- `SimpleChatAgent_Detailed.md`(最小调用链) +- `ReactAgent_Detailed.md`(ReAct 工具循环) +- `DareAgent_Detailed.md`(five-layer 编排) + +## 5. 核心字段(Core Fields) + +- 统一任务输入:`Task`(`description/task_id/milestones/metadata`) +- 统一运行输出:`RunResult`(`success/output/output_text/errors/metadata`) +- Five-layer 状态(DareAgent): + - `SessionState`: `task_id/run_id/current_milestone_idx/milestone_states` + - `MilestoneState`: `attempts/attempted_plans/reflections/evidence_collected` + +## 6. 关键流程(Runtime Flow) + +```mermaid +flowchart TB + A["task input"] --> B{"agent kind"} + B -- SimpleChat --> C["single model call"] + B -- React --> D["model <-> tool loop"] + B -- Dare --> E["session -> milestone -> plan -> execute -> tool -> verify"] + C --> F["RunResult"] + D --> F + E --> F +``` diff --git a/docs/design/modules/config/README.md b/docs/design/modules/config/README.md index 19f60ed8..4b1dc32c 100644 --- a/docs/design/modules/config/README.md +++ b/docs/design/modules/config/README.md @@ -1,50 +1,97 @@ # Module: config -> Status: aligned to `dare_framework/config` (2026-01-31). +> Status: detailed design aligned to `dare_framework/config` (2026-02-25). ## 1. 定位与职责 -- 提供全局配置模型与加载策略。 -- 支持多层配置合并(user + workspace)。 -- 为 Manager/Builder 提供组件启用/禁用与参数解析。 - -## 2. 关键概念与数据结构 - -- `Config`:统一配置入口(llm/tools/components/workspace_dir/user_dir/skill_mode/skill_paths/initial_skill_path)。 -- `LLMConfig` / `ProxyConfig`:模型连接与代理配置。 -- `ComponentConfig`:组件级 enable/disable 配置。 - -## 3. 关键接口与实现 - -- Kernel:`IConfigProvider`(`dare_framework/config/kernel.py`) -- 默认实现:`FileConfigProvider`(`dare_framework/config/file_config_provider.py`) - -## 4. 配置层级与合并规则 - -- 默认配置文件:`.dare/config.json` -- 合并顺序:**user 层 → workspace 层**(workspace 覆盖 user) -- 自动写入空配置文件(当文件不存在时)。 - -## 5. 与其他模块的交互 - -- **Model**:`Config.llm` 决定默认 adapter/endpoint/api_key。 -- **Tool**:`Config.tools` 提供 tool-specific config;`components` 控制启用/禁用。 -- **Builder/Manager**:按组件类型过滤/选择组件。 -- **Skill**:`skill_mode` 控制 skill 模式;`skill_paths` 提供技能目录集合;`initial_skill_path` 用于 agent 模式挂载单一 skill。 - -## 6. 约束与限制 - -- 仅支持 JSON 配置文件。 -- `allow_tools` / `allow_mcps` 未在 ToolManager 中强制执行(TODO)。 - -## 7. TODO / 未决问题 - -- TODO: 增加环境变量或多格式配置支持(YAML/TOML)。 -- TODO: enforce allowlists(allow_tools/allow_mcps)。 -- TODO: 配置热更新与订阅机制。 - -## 8. Design Clarifications (2026-02-03) - -- Doc gap: component-level config schema is not defined; `component_config()` returns `Any`. -- Impl gap: tighten config typing (at least `dict[str, Any]`) for component configs. -- Surface: `FileConfigProvider` is exposed as a default implementation in the config facade. +- 提供全局配置读取、分层合并与类型化访问。 +- 为 Builder / Manager 提供统一的组件启停、实例参数与目录路径。 +- 承担 observability / hooks / model / tool / mcp / skill 的统一入口配置。 + +## 2. 依赖与边界 + +- 核心依赖:`dare_framework/config/types.py`(配置模型)、`dare_framework/config/kernel.py`(稳定接口)。 +- 默认实现:`FileConfigProvider`(JSON 文件,workspace 覆盖 user)。 +- 边界约束: + - config 只负责“配置值解析与快照”,不负责运行时热更新通知。 + - `allow_tools` / `allow_mcps` 当前只落在配置模型,尚未在 Tool/MCP 执行链强制。 + +## 3. 对外接口(Public Contract) + +- `IConfigProvider.current() -> Config` + - 返回当前配置快照。 +- `IConfigProvider.reload() -> Config` + - 重新加载并返回新快照。 +- `build_config_provider(workspace_dir, user_dir) -> IConfigProvider` + - 创建默认 `FileConfigProvider`。 +- `Config` 实例方法(跨模块常用) + - `component_settings(component_type) -> ComponentConfig` + - `is_component_enabled(component) -> bool` + - `component_config(component) -> Any | None` + - `filter_enabled(components) -> list[IComponent]` + +## 4. 关键字段(Core Fields) + +### 4.1 顶层 `Config` + +- `llm: LLMConfig` +- `mcp: dict[str, dict[str, Any]]` +- `mcp_paths: list[str]` +- `skill_paths: list[str]` +- `tools: dict[str, dict[str, Any]]` +- `allow_tools: list[str]` +- `allow_mcps: list[str]` +- `components: dict[str, ComponentConfig]` +- `hooks: HooksConfig` +- `knowledge: dict[str, Any]` +- `long_term_memory: dict[str, Any]` +- `workspace_dir: str` +- `user_dir: str` +- `prompt_store_path_pattern: str` +- `default_prompt_id: str | None` +- `observability: ObservabilityConfig` + +### 4.2 子结构 + +- `LLMConfig` + - `adapter`, `endpoint`, `api_key`, `model`, `proxy`, `extra` +- `ProxyConfig` + - `http`, `https`, `no_proxy`, `use_system_proxy`, `disabled` +- `ComponentConfig` + - `disabled`, `entries` +- `HooksConfig` + - `version`, `defaults`, `entries`, `priority_for(...)` +- `ObservabilityConfig` + - `enabled`, `traces_enabled`, `metrics_enabled`, `exporter`, `sampling_ratio`, `redaction`, ... + +## 5. 关键流程(Runtime Flow) + +```mermaid +flowchart TD + A["FileConfigProvider.reload"] --> B["Load user .dare/config.json"] + B --> C["Load workspace .dare/config.json"] + C --> D["Deep merge user -> workspace"] + D --> E["Config.from_dict"] + E --> F["Typed Config snapshot"] + F --> G["Builder / Manager consume"] +``` + +## 6. 与其他模块的交互 + +- **Model**:读取 `Config.llm` 初始化 adapter 与 endpoint。 +- **Tool**:读取 `tools/components/allow_tools` 决定工具装配与筛选。 +- **MCP**:读取 `mcp` / `mcp_paths` 构建 client。 +- **Skill**:读取 `skill_paths` 驱动 skill 加载。 +- **Hook/Observability**:读取 `hooks` 与 `observability`。 + +## 7. 约束与限制 + +- 当前只支持 JSON 配置文件。 +- `reload()` 是显式触发,不带订阅/广播语义。 +- 组件配置值仍有 `Any`,需要逐步收敛类型。 + +## 8. TODO / 未决问题 + +- TODO: 支持 YAML/TOML 或环境变量分层。 +- TODO: 打通 `allow_tools` / `allow_mcps` 的强制执行。 +- TODO: 增加配置热更新与变更事件语义。 diff --git a/docs/design/modules/context/README.md b/docs/design/modules/context/README.md index 8a4a2b20..32943a58 100644 --- a/docs/design/modules/context/README.md +++ b/docs/design/modules/context/README.md @@ -279,3 +279,34 @@ flowchart TD - TODO: 给 LTM/Knowledge 定义统一去重 key 与冲突消解规则。 - TODO: 明确知识写入权限、审计与成本计量策略。 - TODO: 增加“召回质量 + 压缩损失”评估指标并接入观测。 + +## 14. 对外接口汇总(Public Contract Snapshot) + +- `IRetrievalContext.get(query="", **kwargs) -> list[Message]` +- `IContext` + - `stm_add(message)`, `stm_get()`, `stm_clear()` + - `budget_use(resource, amount)`, `budget_check()`, `budget_remaining(resource)` + - `list_tools() -> list[CapabilityDescriptor]` + - `assemble() -> AssembledContext` + - `compress(**options) -> None` + - `set_tool_gateway(tool_gateway)` + +## 15. 核心字段汇总(Core Fields Snapshot) + +- `Message`: `role`, `content`, `name`, `metadata` +- `Budget`: `max_tokens/max_cost/max_time_seconds/max_tool_calls` + `used_*` +- `AssembledContext`: `messages`, `sys_prompt`, `tools`, `metadata` +- 推荐 metadata 最小审计字段: + - `context_id` + - `retrieval.query/ltm_count/knowledge_count` + - `compression.trigger/strategies_applied/before_token_estimate/after_token_estimate` + +## 16. 关键流程汇总(Flow Snapshot) + +```mermaid +flowchart TD + A["Agent before model call"] --> B["Context budget_check"] + B --> C["Context compress (optional)"] + C --> D["Context assemble"] + D --> E["AssembledContext -> ModelInput"] +``` diff --git a/docs/design/modules/embedding/README.md b/docs/design/modules/embedding/README.md index 70871218..74d69952 100644 --- a/docs/design/modules/embedding/README.md +++ b/docs/design/modules/embedding/README.md @@ -1,43 +1,63 @@ # Module: embedding -> Status: aligned to `dare_framework/embedding` (2026-01-31). TODO indicates gaps vs desired architecture. +> Status: detailed design aligned to `dare_framework/embedding` (2026-02-25). ## 1. 定位与职责 -- 提供文本向量化能力接口(embedding adapter)。 -- 供知识检索 / RAG / 语义匹配等模块使用。 +- 提供统一向量化接口,支撑 knowledge / memory 的向量检索路径。 +- 隔离第三方 embedding SDK,向上层暴露稳定 `IEmbeddingAdapter` 协议。 -## 2. 关键概念与数据结构 +## 2. 依赖与边界 -- `EmbeddingResult`:向量 + metadata。 -- `EmbeddingOptions`:embedding 参数(model/metadata)。 -- `IEmbeddingAdapter`:embedding 适配器接口。 +- 核心协议:`dare_framework/embedding/interfaces.py` +- 数据类型:`dare_framework/embedding/types.py` +- 默认实现:`OpenAIEmbeddingAdapter`(`langchain-openai`) +- 边界约束: + - embedding 只负责“文本->向量”,不负责检索排序与召回融合。 + - 适配器层不管理知识库存储生命周期。 -## 3. 当前实现 +## 3. 对外接口(Public Contract) -- `OpenAIEmbeddingAdapter`(LangChain OpenAIEmbeddings)。 +- `IEmbeddingAdapter.embed(text, options=None) -> EmbeddingResult` +- `IEmbeddingAdapter.embed_batch(texts, options=None) -> list[EmbeddingResult]` -## 4. 与其他模块的交互 +默认实现补充: +- `OpenAIEmbeddingAdapter(model, api_key, endpoint, http_client_options)` +- 支持 OpenAI 兼容 endpoint。 -- **Knowledge**:知识检索可调用 embedding 生成向量(当前未接入)。 -- **Config**:embedding 尚未纳入 Config 管理(TODO)。 +## 4. 关键字段(Core Fields) -## 5. 约束与限制 +- `EmbeddingOptions` + - `model: str | None` + - `metadata: dict[str, Any]` +- `EmbeddingResult` + - `vector: list[float]` + - `metadata: dict[str, Any]`(可含 model/usage) -- 依赖 `langchain-openai`,未提供 fallback。 -- 无 Manager / Factory 统一选择逻辑(TODO)。 +## 5. 关键流程(Runtime Flow) -## 6. 扩展点 +```mermaid +flowchart TD + A["Knowledge / Memory request embedding"] --> B["IEmbeddingAdapter.embed(_batch)"] + B --> C["Adapter ensure client"] + C --> D["OpenAI-compatible embedding API"] + D --> E["EmbeddingResult(vector, metadata)"] + E --> F["Vector store consume"] +``` -- 实现新的 embedding adapter(本地模型/第三方 API)。 -- 增加 Manager/Factory 统一管理。 +## 6. 与其他模块的交互 -## 7. TODO / 未决问题 +- **Knowledge**:vector knowledge 写入/检索依赖 embedding。 +- **Memory**:vector LTM 构建依赖 embedding。 +- **Config**:目前 embedding 独立于 config domain,后续需统一。 -- TODO: 接入 Knowledge/RAG pipeline。 -- TODO: 统一配置与 adapter 选择策略。 +## 7. 约束与限制 -## 8. Design Clarifications (2026-02-03) +- 依赖可选第三方包 `langchain-openai`。 +- 当前未定义 adapter manager / provider 统一选择逻辑。 -- Doc/Impl gap: embedding domain lacks a `kernel.py` despite kernel conventions elsewhere. -- Type cleanup: reduce `Any` usage in adapter client construction. +## 8. TODO / 未决问题 + +- TODO: 增加 embedding domain 的 kernel 层统一入口(与其他域一致)。 +- TODO: 收敛 adapter client 构造中的 `Any`。 +- TODO: 增加本地 embedding 模型支持与 fallback 策略。 diff --git a/docs/design/modules/event/README.md b/docs/design/modules/event/README.md index 0f3ebaef..84724e11 100644 --- a/docs/design/modules/event/README.md +++ b/docs/design/modules/event/README.md @@ -1,41 +1,64 @@ # Module: event -> Status: interface-only (2026-01-31). TODO indicates missing implementation and integration. +> Status: interface-first detailed design aligned to `dare_framework/event` (2026-02-25). ## 1. 定位与职责 -- 提供 WORM 事件日志接口,支持审计、查询与重放。 -- 作为“事实来源”,支持任务复验与外部审计系统。 +- 提供 WORM(append-only)事件日志契约,支撑审计、追溯与重放。 +- 作为运行时事实来源,服务于 session 复验与外部合规系统。 -## 2. 关键概念与数据结构 +## 2. 依赖与边界 -- `Event`:事件记录(event_type/payload/timestamp/hash)。 -- `RuntimeSnapshot`:基于 event log 的重放快照。 +- 核心协议:`dare_framework/event/kernel.py` (`IEventLog`) +- 核心类型:`dare_framework/event/types.py` (`Event`, `RuntimeSnapshot`) +- 边界约束: + - event domain 只定义事件存储契约,不绑定具体存储后端。 + - 与 legacy `dare_framework/events/*` 事件总线语义需区分(总线 != WORM 日志)。 -## 3. 关键接口 +## 3. 对外接口(Public Contract) -- `IEventLog.append(...)`:追加事件。 -- `IEventLog.query(...)`:查询事件。 -- `IEventLog.replay(...)`:按 event_id 重放。 -- `IEventLog.verify_chain()`:哈希链校验。 +- `IEventLog.append(event_type, payload) -> str` +- `IEventLog.query(filter=None, limit=100) -> Sequence[Event]` +- `IEventLog.replay(from_event_id) -> RuntimeSnapshot` +- `IEventLog.verify_chain() -> bool` -## 4. 与其他模块的交互 +## 4. 关键字段(Core Fields) -- **Agent**:DareAgent 可选记录 session/plan/tool/model 事件。 -- **HITL**:未来可记录 pause/wait/resume 事件链。 +- `Event` + - `event_type: str` + - `payload: dict[str, Any]` + - `event_id: str` + - `timestamp: datetime` + - `prev_hash: str | None` + - `event_hash: str | None` +- `RuntimeSnapshot` + - `from_event_id: str` + - `events: Sequence[Event]` -## 5. 现状与限制 +## 5. 关键流程(Runtime Flow) -- 当前仅有接口与类型,缺少默认实现。 -- 另有 `dare_framework/events/*` 旧 event bus 实现(legacy),未与新架构对齐。 +```mermaid +flowchart TD + A["Agent emits runtime fact"] --> B["IEventLog.append"] + B --> C["Persist Event + hash link"] + C --> D["IEventLog.query / replay"] + D --> E["Audit / recovery / analytics"] + C --> F["IEventLog.verify_chain"] +``` -## 6. TODO / 未决问题 +## 6. 与其他模块的交互 -- TODO: 提供默认 EventLog 实现(持久化 + hash-chain)。 -- TODO: 统一 legacy event bus 与 WORM event log 的关系。 -- TODO: 定义稳定事件 taxonomy 与 payload schema。 +- **Agent**:记录 `session.*`、`milestone.*`、`tool.*`、`model.*` 事件。 +- **Observability**:`TraceAwareEventLog` 在 append 前注入 trace metadata。 +- **Hook**:Hook payload 可镜像进入 event log,形成审计闭环。 -## 7. Design Clarifications (2026-02-03) +## 7. 约束与限制 -- Doc/Impl gap: `dare_framework/events/*` (legacy) coexists with `event` domain; needs migration policy. -- Doc gap: event taxonomy/schema must be defined for cross-module payloads. +- 当前仓库缺少默认持久化实现(接口优先)。 +- 事件 taxonomy 与 payload schema 仍需统一规范。 + +## 8. TODO / 未决问题 + +- TODO: 提供默认实现(例如 sqlite + hash-chain)。 +- TODO: 定义 legacy events -> event domain 的迁移策略。 +- TODO: 固化跨模块事件命名与字段协议。 diff --git a/docs/design/modules/hook/README.md b/docs/design/modules/hook/README.md index d0d12220..300acf78 100644 --- a/docs/design/modules/hook/README.md +++ b/docs/design/modules/hook/README.md @@ -237,3 +237,32 @@ shadow rollout: - 形成分层 hook lane(control/observe)与正式策略包发布机制 - 为 patch 引入更细粒度字段级策略与审计标签 + +## 14. 对外接口汇总(Public Contract Snapshot) + +- `IHook.invoke(phase, *args, **kwargs) -> HookResult | dict | None` +- `IExtensionPoint.register_hook(phase, hook)` +- `IExtensionPoint.emit(phase, payload) -> HookResult` +- `IHookManager.load_hooks(config=None) -> list[IHook]` + +## 15. 核心字段汇总(Core Fields Snapshot) + +- `HookPhase`: `BEFORE_*` / `AFTER_*` 生命周期枚举 +- `HookDecision`: `ALLOW`, `BLOCK`, `ASK` +- `HookEnvelope` + - `hook_version`, `phase`, `invocation_id`, `context_id`, `timestamp_ms`, `payload` +- `HookResult` + - `decision`, `patch`, `message` + +## 16. 关键流程汇总(Flow Snapshot) + +```mermaid +flowchart TD + A["Agent emits phase payload"] --> B["HookExtensionPoint.emit"] + B --> C["hook selector + runner"] + C --> D["decision arbiter"] + D --> E{"decision"} + E -- ALLOW --> F["continue runtime"] + E -- BLOCK --> G["abort current path"] + E -- ASK --> H["approval bridge / deny fallback"] +``` diff --git a/docs/design/modules/mcp/README.md b/docs/design/modules/mcp/README.md index 55276fe4..8bdf4adc 100644 --- a/docs/design/modules/mcp/README.md +++ b/docs/design/modules/mcp/README.md @@ -1,42 +1,69 @@ # Module: mcp -> Status: draft (2026-02-03). Aligned to `dare_framework/mcp`. +> Status: detailed design aligned to `dare_framework/mcp` (2026-02-25). ## 1. 定位与职责 -- 负责 MCP (Model Context Protocol) 客户端接入。 -- 将 MCP server 的工具封装为 `IToolProvider` 以接入 ToolManager。 -- 提供配置加载(`.dare/mcp/*.json`)与 client 工厂。 +- 负责 MCP server 配置加载、client 构建与连接生命周期。 +- 把远端 MCP tools 转换为本地 `IToolProvider`,纳入统一 ToolManager 调度。 -## 2. 关键概念与数据结构 +## 2. 依赖与边界 -- `MCPServerConfig` / `MCPConfigFile`:MCP 配置类型。 -- `IMCPClient`:MCP 客户端稳定接口(kernel)。 -- `MCPToolProvider`:将 MCP tools 暴露为 ITool。 +- 核心协议:`IMCPClient` (`dare_framework/mcp/kernel.py`) +- 核心配置:`MCPServerConfig`, `MCPConfigFile`, `TransportType` (`dare_framework/mcp/types.py`) +- 默认组件: + - `MCPConfigLoader`(目录扫描 + JSON/YAML/Markdown 解析) + - `MCPClientFactory`(按 transport 构建 client) + - `MCPToolProvider`(`McpToolManager`) +- 边界约束: + - MCP 仅负责“远端能力接入”,不负责工具安全策略最终判定。 -## 3. 当前实现 +## 3. 对外接口(Public Contract) -- `MCPClient`:基于 transport 的 JSON-RPC 客户端。 -- `MCPConfigLoader` / `load_mcp_configs`:读取 MCP 配置文件。 -- `MCPClientFactory` / `create_mcp_clients`:按配置创建客户端。 -- `MCPToolProvider`:将 MCP tools 缓存并转换为 ITool。 +- `IMCPClient.connect() / disconnect()` +- `IMCPClient.list_tools() -> list[ITool]` +- `IMCPClient.call_tool(tool_name, arguments, context) -> ToolResult` +- `load_mcp_configs(paths, workspace_dir, user_dir) -> list[MCPServerConfig]` +- `create_mcp_clients(configs, connect=False, skip_errors=True) -> list[IMCPClient]` +- `MCPToolProvider.list_tools(mcp_name=None) -> list[ITool]` -## 4. 与其他模块的交互 +## 4. 关键字段(Core Fields) -- **Tool**:`MCPToolProvider` 实现 `IToolProvider`,注册到 ToolManager。 -- **Agent/Builder**:当 `config.mcp_paths` 设置时,builder 自动加载 MCP tools。 +- `MCPServerConfig` + - `name`, `transport`, `command`, `env` + - `url`, `headers` + - `endpoint`, `tls` + - `timeout_seconds`, `enabled`, `cwd` +- `MCPConfigFile` + - `source_path` + - `servers` -## 5. 约束与限制 +## 5. 关键流程(Runtime Flow) -- 目前仅支持 stdio/http/grpc transport 组合的基础配置。 -- MCP tools 的风险级别/审批信息依赖 server 侧提供。 +```mermaid +flowchart TD + A["Scan .dare/mcp/*.json|yaml|md"] --> B["MCPConfigLoader.load"] + B --> C["MCPServerConfig[]"] + C --> D["MCPClientFactory.create"] + D --> E["IMCPClient.connect + list_tools"] + E --> F["MCPToolProvider cache tools"] + F --> G["ToolManager.refresh registers capabilities"] + G --> H["Agent tool loop invoke"] +``` -## 6. Public Surface +## 6. 与其他模块的交互 -- `dare_framework.mcp`:仅导出 `IMCPClient` + config types。 -- `dare_framework.mcp.defaults`:默认实现(client/loader/factory/tool_provider)。 +- **Tool**:作为 `IToolProvider` 被 ToolManager 接管。 +- **Config**:读取 `config.mcp` / `config.mcp_paths`。 +- **Agent/Builder**:在构建时注入 MCP provider 到 tool gateway。 -## 7. TODO / 未决问题 +## 7. 约束与限制 -- TODO: 增强 MCP tool 的 policy gate(allowlist/approval)。 -- TODO: 明确 transport 安全边界与 sandbox 策略。 +- grpc transport 在 factory 中仍标记为未实现。 +- MCP tool 风险等级/审批字段依赖 server 提供,可信化仍需 policy 层二次校验。 + +## 8. TODO / 未决问题 + +- TODO: 接入 `ISecurityBoundary` 做 MCP 工具策略门控。 +- TODO: 明确 transport 安全隔离与 sandbox 策略。 +- TODO: 增加断线重连与健康检查策略。 diff --git a/docs/design/modules/memory_knowledge/README.md b/docs/design/modules/memory_knowledge/README.md index d9be483d..32ba94b4 100644 --- a/docs/design/modules/memory_knowledge/README.md +++ b/docs/design/modules/memory_knowledge/README.md @@ -1,50 +1,80 @@ # Module: memory / knowledge -> Status: aligned to `dare_framework/memory` + `dare_framework/knowledge` (2026-01-31). TODO indicates gaps vs desired architecture. +> Status: detailed design aligned to `dare_framework/memory` + `dare_framework/knowledge` (2026-02-25). ## 1. 定位与职责 -- 提供统一检索接口 `IRetrievalContext` 的具体实现(STM/LTM/Knowledge)。 -- 作为 Context 的检索来源(短期/长期/知识库)。 - -## 2. 关键概念与数据结构 - -- `IRetrievalContext`:统一检索接口(Context kernel)。 -- `IShortTermMemory`:短期记忆接口(可写)。 -- `ILongTermMemory`:长期记忆接口(持久化)。 -- `IKnowledge`:知识检索接口(RAG/GraphRAG 等)。 -- `IKnowledgeTool`:Knowledge 作为 Tool 暴露的组合接口。 - -## 3. 当前实现 - -- `InMemorySTM`:默认短期记忆实现(内存列表)。 -- LongTermMemory / Knowledge 提供默认实现(rawdata / vector,内部实现),通常通过 factory 创建: - - `create_long_term_memory(...)` - - `create_knowledge(...)` - -## 4. 与其他模块的交互 - -- **Context**:持有 STM/LTM/Knowledge 引用;`assemble()` 默认只取 STM。 -- **Tool**:Knowledge 可作为 Tool 暴露(`IKnowledgeTool`)。 -- **Model**:检索结果通过 Context 组装进入 ModelInput.messages。 - -## 5. 约束与限制 - -- 检索融合策略未标准化(默认 assemble 不合入 LTM/Knowledge)。 -- 默认实现依赖 embedding adapter(vector 类型时)。 - -## 6. 扩展点 - -- 自定义 STM/LTM/Knowledge 实现,注入 Context。 -- 自定义 `Context.assemble()` 以合并检索结果。 - -## 7. TODO / 未决问题 - -- TODO: 提供默认 LTM/Knowledge 实现(或接入外部向量库)。 -- TODO: 统一检索融合策略(排序、去重、预算控制)。 -- TODO: 知识作为 Tool 的统一策略(权限、计费、审计)。 - -## 8. Design Clarifications (2026-02-03) - -- Doc gap: design doc is combined, but code is split into separate `memory/` and `knowledge/` domains. -- Impl gap: factories depend on embedding adapter; dependency should be documented and typed. +- 提供 `Context` 的三类检索来源:STM / LTM / Knowledge。 +- 统一 retrieval contract(`IRetrievalContext.get`),并支持知识写入与知识工具化。 + +## 2. 依赖与边界 + +- memory kernel:`IShortTermMemory`, `ILongTermMemory` +- knowledge kernel:`IKnowledge` +- composed interface:`IKnowledgeTool` +- factory: + - `create_long_term_memory(config, embedding_adapter)` + - `create_knowledge(config, embedding_adapter)` +- 边界约束: + - memory/knowledge 负责“存取与检索”,不负责最终上下文融合排序。 + +## 3. 对外接口(Public Contract) + +- `IShortTermMemory` + - `add(message)` + - `get(query="", **kwargs) -> list[Message]` + - `clear()` + - `compress(max_messages=None, **kwargs) -> int` +- `ILongTermMemory` + - `get(query="", **kwargs) -> list[Message]` + - `persist(messages) -> None` +- `IKnowledge` + - `get(query, **kwargs) -> list[Message]` + - `add(content, **kwargs) -> None` +- 工具化接口 + - `KnowledgeGetTool.execute(query, top_k=5)` + - `KnowledgeAddTool.execute(content, metadata=None)` + +## 4. 关键字段(Core Fields) + +- `LongTermMemoryConfig` + - `type: "vector" | "rawdata"` + - `storage: "in_memory" | "sqlite" | "chromadb"` + - `options: dict[str, Any]` +- `KnowledgeConfig` + - `type: "vector" | "rawdata"` + - `storage: "in_memory" | "sqlite" | "chromadb"` + - `options: dict[str, Any]` + +## 5. 关键流程(Runtime Flow) + +```mermaid +flowchart TD + A["Context assemble"] --> B["STM.get"] + A --> C["LTM.get(query, top_k)"] + A --> D["Knowledge.get(query, top_k)"] + B --> E["Context merge + rank"] + C --> E + D --> E + + F["Tool: knowledge_add"] --> G["IKnowledge.add"] + H["Tool: knowledge_get"] --> I["IKnowledge.get"] + I --> E +``` + +## 6. 与其他模块的交互 + +- **Context**:持有 STM/LTM/Knowledge 引用并在 `assemble()` 调用。 +- **Embedding**:vector 类型后端依赖 embedding adapter。 +- **Tool**:Knowledge 可暴露为工具能力。 + +## 7. 约束与限制 + +- 默认 `Context.assemble()` 仍以 STM 为主,LTM/Knowledge 融合策略待统一。 +- vector 路径对 embedding 适配器有强依赖。 + +## 8. TODO / 未决问题 + +- TODO: 统一 retrieval 参数协议(`top_k/min_similarity/filters`)。 +- TODO: 明确 LTM/Knowledge 冲突消解和去重规则。 +- TODO: 完善知识写入权限、审计与成本计量。 diff --git a/docs/design/modules/model/README.md b/docs/design/modules/model/README.md index 85e21adb..6ac936fa 100644 --- a/docs/design/modules/model/README.md +++ b/docs/design/modules/model/README.md @@ -1,60 +1,70 @@ # Module: model -> Status: aligned to `dare_framework/model` (2026-01-31). TODO indicates gaps vs desired architecture. +> Status: detailed design aligned to `dare_framework/model` (2026-02-25). ## 1. 定位与职责 -- 统一模型调用入口(`IModelAdapter.generate(...)`)。 -- 定义运行时模型输入 `ModelInput(messages + tools + metadata)`。 -- 提供 Prompt 管理与解析(见 `Model_Prompt_Management.md`)。 - -## 2. 关键概念与数据结构 - -- `ModelInput`:运行时模型请求结构(messages/tools/metadata)。 -- `ModelResponse`:模型输出,包含 content 与 tool_calls。 -- `GenerateOptions`:模型生成参数(temperature/max_tokens/etc)。 -- `Prompt`:Prompt 定义(prompt_id/role/content/supported_models/order)。 - -## 3. 关键接口与实现 - -- Kernel:`IModelAdapter`(`dare_framework/model/kernel.py`) -- Manager:`IModelAdapterManager`, `IPromptLoader`, `IPromptStore`(`dare_framework/model/interfaces.py`) -- 默认管理器:`DefaultModelAdapterManager`(OpenAI/OpenRouter) -- Prompt Store:`LayeredPromptStore` + loaders - -## 4. 内置适配器(当前实现) - -- `OpenAIModelAdapter`(LangChain,支持工具调用) -- `OpenRouterModelAdapter`(OpenAI SDK 兼容接口) - -> 现状说明:流式输出与多模型路由未实现(TODO)。 - -## 5. 与其他模块的交互 - -- **Context**:Context.assemble() 提供 messages/tools;Agent 负责构造 ModelInput。 -- **Tool**:ModelResponse.tool_calls 触发 Tool Loop。 -- **Config**:`Config.llm` 决定默认 adapter 与连接参数。 - -## 6. 约束与限制(当前实现) - -- Prompt Store 默认按 workspace → user → built-in 的层级解析。 -- Prompt 不支持热更新;需重新构造 PromptStore(TODO: reload)。 -- Tool defs 需满足 OpenAI function-call 格式;adapter 做轻量兼容转换。 - -## 7. 扩展点 - -- 新增 ModelAdapter:实现 `IModelAdapter` 并注入 Manager。 -- 新增 PromptLoader:加载远端或自定义 manifest。 -- Prompt 版本策略:通过 `Prompt.version` + Store 选择逻辑扩展。 +- 提供统一模型调用抽象:`IModelAdapter.generate`。 +- 定义模型输入/输出结构:`ModelInput`、`ModelResponse`。 +- 提供 prompt 装载与分层解析能力(store + loader)。 + +## 2. 依赖与边界 + +- kernel:`IModelAdapter` +- manager/store 接口:`IModelAdapterManager`, `IPromptLoader`, `IPromptStore` +- 类型:`Prompt`, `ModelInput`, `ModelResponse`, `GenerateOptions` +- 边界约束: + - model domain 负责“调用与格式适配”,不负责执行循环与工具决策。 + +## 3. 对外接口(Public Contract) + +- `IModelAdapter.generate(model_input, options=None) -> ModelResponse` +- `IModelAdapterManager.load_model_adapter(config=None) -> IModelAdapter | None` +- `IPromptLoader.load() -> list[Prompt]` +- `IPromptStore.get(prompt_id, model=None, version=None) -> Prompt` + +## 4. 关键字段(Core Fields) + +- `Prompt` + - `prompt_id`, `role`, `content`, `supported_models`, `order`, `version`, `metadata` +- `ModelInput` + - `messages: list[Message]` + - `tools: list[CapabilityDescriptor]` + - `metadata: dict[str, Any]` +- `ModelResponse` + - `content: str` + - `tool_calls: list[dict[str, Any]]` + - `usage: dict[str, Any] | None` + - `metadata: dict[str, Any]` +- `GenerateOptions` + - `temperature`, `max_tokens`, `top_p`, `stop`, `metadata` + +## 5. 关键流程(Runtime Flow) + +```mermaid +flowchart TD + A["Agent execute loop"] --> B["Context.assemble -> ModelInput"] + B --> C["IModelAdapter.generate"] + C --> D["ModelResponse(content, tool_calls, usage)"] + D --> E{"tool_calls empty?"} + E -- yes --> F["Write assistant message"] + E -- no --> G["Tool loop invoke"] +``` + +## 6. 与其他模块的交互 + +- **Context**:提供 messages/tools。 +- **Tool**:通过 `tool_calls` 触发 `IToolGateway.invoke`。 +- **Config**:`Config.llm` 决定 adapter 类型与连接参数。 +- **Observability**:从 `usage` 提取 token 指标。 + +## 7. 约束与限制 + +- 当前流式输出和增量 tool-call 仍是待补齐项。 +- tool defs 仍以 OpenAI function-call schema 为主。 ## 8. TODO / 未决问题 -- TODO: 流式输出与增量 tool calls 支持。 -- TODO: 多模型策略(fallback/router/ensemble)。 -- TODO: Prompt 多阶段(plan/execute/verify)与上下文预算联动。 - -## 9. Design Clarifications (2026-02-03) - -- Impl gap: adapter client construction uses `Any`; define minimal client protocol or alias. -- Doc gap: tool definition schema normalization should be explicitly documented. -- Surface: default adapters/loaders live in the model package and are part of the facade. +- TODO: 增加 streaming 与多模型路由策略。 +- TODO: 明确跨 adapter 的 tool schema 归一化规范。 +- TODO: 收敛 adapter client typing,减少 `Any`。 diff --git a/docs/design/modules/observability/README.md b/docs/design/modules/observability/README.md index e2eccc95..d31ce614 100644 --- a/docs/design/modules/observability/README.md +++ b/docs/design/modules/observability/README.md @@ -1,98 +1,84 @@ # Module: observability -> Status: v2 implementation (2026-02-01). +> Status: detailed design aligned to `dare_framework/observability` (2026-02-25). ## 1. 定位与职责 -- 提供基于 OpenTelemetry 的 traces / metrics / logs 观测能力(可选依赖)。 -- 通过 Hook 与 EventLog 扩展点,做到最小侵入的采集与关联。 -- 覆盖上下文长度、tokens 消耗、工具执行、调用链等核心指标。 - -## 2. 关键概念与数据结构 - -- `ITelemetryProvider`: 统一观测接口(start_span / record_metric / record_event)。 -- `ISpan`: 最小 span 接口(set_attribute / add_event / set_status / end)。 -- `TelemetryConfig`: OTel 相关配置(service / exporter / sampling / privacy)。 -- `RunMetrics`: 单次运行聚合指标(tokens/context/tool/loops/budget)。 -- `ObservabilityHook`: Hook 驱动的观测采集实现。 -- `MetricsCollector`: RunMetrics 聚合器。 -- `TraceAwareEventLog`: EventLog 注入 trace 上下文的桥接实现。 - -## 3. 关键接口与实现 - -- Kernel: `ITelemetryProvider`, `ISpan` (`dare_framework/observability/kernel.py`) -- Types: `TelemetryConfig`, `RunMetrics`, `SpanKind`, `SpanStatus` (`dare_framework/observability/types.py`) -- OpenTelemetry 实现: - - `OTelTelemetryProvider` / `NoOpTelemetryProvider` (`dare_framework/observability/_internal/otel_provider.py`) - - `ObservabilityHook` (`dare_framework/observability/_internal/tracing_hook.py`) - - `MetricsCollector` (`dare_framework/observability/_internal/metrics_collector.py`) - - `TraceAwareEventLog` (`dare_framework/observability/_internal/event_trace_bridge.py`) - -## 4. 与其他模块的交互 - -- **Agent** - - `DareAgent` 接收 `telemetry` 参数,默认使用 `NoOpTelemetryProvider`。 - - `DareAgent` 在初始化时包装 `event_log` 为 trace-aware。 - - 当 `telemetry` 为 `OTelTelemetryProvider` 时自动挂载 `ObservabilityHook`。 -- **Hook** - - `HookExtensionPoint` 分发 HookPhase payload。 - - `ObservabilityHook` 从 payload 提取关键字段,创建 spans/metrics。 -- **EventLog** - - `TraceAwareEventLog` 自动注入 `_trace` 字段并与 span 关联。 - -## 5. Hook payload 关键字段(v2) - -最小要求字段(其余可扩展): -- BEFORE_RUN: `task_id`, `session_id`, `agent_name`, `execution_mode` -- AFTER_RUN: `success`, `token_usage`, `errors` -- BEFORE_TOOL: `tool_name`, `tool_call_id`, `capability_id`, `attempt`, `risk_level`, `requires_approval` -- AFTER_TOOL: `tool_call_id`, `tool_name`, `success`, `error`, `approved`, `evidence_collected` - -建议字段: -- AFTER_CONTEXT_ASSEMBLE: `context_length`, `context_messages_count`, `context_tools_count` -- AFTER_MODEL: `model_usage`(含 prompt/completion tokens) - -## 6. Span 层级(v2) - -``` -dare.session -└── dare.milestone - ├── dare.plan - ├── dare.execute - │ ├── llm.chat - │ └── dare.tool - └── dare.verify +- 提供 traces / metrics / events 的统一观测能力,默认对主流程最小侵入。 +- 基于 HookPhase payload 采集 Agent 全链路运行信号。 +- 输出可用于排障、容量分析和审计关联的结构化指标。 + +## 2. 依赖与边界 + +- kernel:`ITelemetryProvider`, `ISpan` +- types:`TelemetryConfig`, `RunMetrics`, `SpanKind`, `SpanStatus` +- 默认实现: + - `OTelTelemetryProvider` / `NoOpTelemetryProvider` + - `ObservabilityHook` + - `MetricsCollector` + - `TraceAwareEventLog` +- 边界约束: + - observability 只做采集与导出,不改变业务决策。 + +## 3. 对外接口(Public Contract) + +- `ITelemetryProvider.start_span(name, kind="internal", attributes=None)` +- `ITelemetryProvider.record_metric(name, value, attributes=None)` +- `ITelemetryProvider.record_event(name, attributes=None)` +- `ITelemetryProvider.shutdown()` +- `ISpan.set_attribute(...) / add_event(...) / set_status(...) / end()` + +## 4. 关键字段(Core Fields) + +### 4.1 `TelemetryConfig` + +- `service_name`, `service_version`, `deployment_environment` +- `enabled`, `exporter_type`, `otlp_endpoint`, `otlp_headers` +- `sample_rate`, `capture_content`, `resource_attributes` + +### 4.2 `RunMetrics` + +- Token:`total_input_tokens`, `total_output_tokens`, `cached_tokens` +- Context:`max_context_length`, `max_messages_count`, `max_tools_count` +- Tool:`tool_calls_total`, `tool_calls_success`, `tool_calls_failed`, `tool_by_name` +- Loop:`model_invocations`, `execute_iterations`, `milestone_attempts`, `plan_attempts` +- Timing:`total_duration`, `model_duration`, `tool_duration` +- Budget/Error:`budget_*`, `errors_total`, `errors_by_type` + +## 5. 关键流程(Runtime Flow) + +```mermaid +flowchart TD + A["Agent emits HookPhase payload"] --> B["ObservabilityHook.invoke"] + B --> C["Start/End spans by phase"] + B --> D["MetricsCollector aggregate"] + C --> E["ITelemetryProvider.export trace"] + D --> F["record_metric export"] + E --> G["Trace-aware event log correlation"] ``` -## 7. Metrics(v2) +## 6. Hook payload 契约(最小字段) -- `gen_ai.client.token.usage`(Histogram) -- `gen_ai.client.operation.duration`(Histogram) -- `dare.context.length`(Histogram) -- `dare.tool.invocations`(Counter) -- `dare.loop.iterations`(Counter) +- `BEFORE_RUN`: `task_id`, `session_id`, `agent_name`, `execution_mode` +- `AFTER_RUN`: `success`, `token_usage`, `errors` +- `BEFORE_TOOL`: `tool_name`, `tool_call_id`, `capability_id`, `attempt`, `risk_level`, `requires_approval` +- `AFTER_TOOL`: `tool_call_id`, `tool_name`, `success`, `error`, `approved`, `evidence_collected` +- `AFTER_CONTEXT_ASSEMBLE`: `context_length`, `context_messages_count`, `context_tools_count` +- `AFTER_MODEL`: `model_usage` -## 8. 配置 - -`TelemetryConfig` 通过代码初始化: - -```python -telemetry = OTelTelemetryProvider( - TelemetryConfig( - service_name="dare-framework", - exporter_type="console", - sample_rate=1.0, - ) -) -``` +## 7. 与其他模块的交互 -YAML 示例见 `docs/design/modules/observability/Observability_Design_v2.md`。 +- **Agent**:在 builder/runtime 装配 telemetry 与 observability hook。 +- **Hook**:通过 phase 事件分发触发 span/metric。 +- **Event**:通过 trace bridge 写入 trace 上下文。 -## 9. 现状与限制 +## 8. 约束与限制 -- OpenTelemetry SDK 为可选依赖;缺失时自动退化为 no-op。 -- 当前 Hook payload 仍以 Agent 层为主,工具内部细粒度 span 可后续补充。 +- OpenTelemetry 依赖缺失时自动降级为 no-op。 +- payload schema 目前主要靠约定,缺少统一强校验层。 -## 10. Design Clarifications (2026-02-03) +## 9. TODO / 未决问题 -- Doc gap: minimal hook payload schema must be treated as a contract across modules. +- TODO: 固化 Hook payload schema(跨模块 contract)。 +- TODO: 增加工具内部细粒度 span 与开销归因。 +- TODO: 完善敏感字段脱敏与内容采集策略。 diff --git a/docs/design/modules/plan/README.md b/docs/design/modules/plan/README.md index def20379..d2c37bd6 100644 --- a/docs/design/modules/plan/README.md +++ b/docs/design/modules/plan/README.md @@ -1,63 +1,72 @@ # Module: plan -> Status: aligned to `dare_framework/plan` (2026-01-31). TODO indicates gaps vs desired architecture. +> Status: detailed design aligned to `dare_framework/plan` (2026-02-25). ## 1. 定位与职责 -- 任务/计划/结果模型定义(Task / Milestone / Plan / RunResult)。 -- Planner 生成 `ProposedPlan`,Validator 生成 `ValidatedPlan`,Remediator 生成反思。 -- 定义 Tool Loop 的 `Envelope` 与 `DonePredicate`。 - -## 2. 关键概念与数据结构 - -- `Task`:用户任务输入,支持可选 milestones。 -- `Milestone`:最小验证单元。 -- `ProposedPlan` / `ValidatedPlan`:计划的非可信/可信两阶段表示。 -- `ProposedStep` / `ValidatedStep`:计划步骤结构。 -- `Envelope` / `DonePredicate`:工具调用边界与完成条件。 -- `VerifyResult`:里程碑验证结果。 - -## 3. 关键接口与实现 - -- Planner:`IPlanner.plan(ctx) -> ProposedPlan` -- Validator:`IValidator.validate_plan(...) -> ValidatedPlan` / `verify_milestone(...) -> VerifyResult` -- Remediator:`IRemediator.remediate(...) -> str` -- 管理器接口:`IPlannerManager`, `IValidatorManager`, `IRemediatorManager` - -默认实现: -- `DefaultPlanner`:基于 LLM 的 evidence-driven 计划(`dare_framework/plan/_internal/default_planner.py`) -- `RegistryPlanValidator`:从 ToolRegistry 推导可信元数据(`dare_framework/plan/_internal/registry_validator.py`) -- `DefaultRemediator`:基于 LLM 的反思文本(`dare_framework/plan/_internal/default_remediator.py`) -- `CompositeValidator`:多 validator 组合(`dare_framework/plan/_internal/composite_validator.py`) - -## 4. 与 Agent 的交互(当前实现) - -- DareAgent 在 Milestone Loop 中调用 planner + validator。 -- 验证失败会记录 attempt;可选 remediator 输出反思。 -- 验证成功后进入 Execute Loop。 - -> 现状差距:ValidatedPlan.steps 未驱动执行;Execute Loop 由模型自主决定工具调用(TODO)。 - -## 5. 约束与限制(当前实现) - -- **计划隔离不足**:失败计划不会回滚 STM 或上下文状态(TODO)。 -- **风险/审批未闭环**:Validator 可派生 `risk_level`,但未接入 policy gate(TODO)。 -- **证据闭环未统一**:Planner 侧 evidence 与 ToolResult evidence 体系尚未完全对齐(TODO)。 - -## 6. 扩展点 - -- 自定义 Planner/Validator/Remediator。 -- 使用 `RegistryPlanValidator` 组合自定义 Validator,实现可信元数据派生。 -- 在 Execute Loop 中引入“计划驱动执行”策略(TODO)。 - -## 7. TODO / 未决问题 - -- TODO: 将 ValidatedPlan.steps 绑定工具执行(计划驱动)。 -- TODO: 计划 attempt 隔离(Context snapshot / rollback)。 -- TODO: 统一证据模型(planner evidence ↔ tool evidence)。 -- TODO: 明确 plan tool 的元数据与 policy gate 语义。 - -## 8. Design Clarifications (2026-02-03) - -- Doc/Impl gap: `plan/kernel.py` is empty; decide kernel surface or document interfaces-only. -- Type cleanup: internal validators/planners should avoid `Any` for core plan types. +- 定义任务分解、计划验证、里程碑验证与执行边界的数据契约。 +- 把 planner 输出与 trusted validated plan 分离,降低模型不可信输入风险。 + +## 2. 依赖与边界 + +- 接口:`IPlanner`, `IValidator`, `IRemediator`, `IStepExecutor`, `IPlanAttemptSandbox` +- 类型:`Task`, `Milestone`, `ProposedPlan`, `ValidatedPlan`, `RunResult`, `Envelope`, ... +- 边界约束: + - plan domain 定义“计划/验证/补救”的协议,不直接执行工具副作用。 + - 工具调用实际由 tool gateway 完成。 + +## 3. 对外接口(Public Contract) + +- `IPlanner.plan(ctx) -> ProposedPlan` +- `IPlanner.decompose(task, ctx) -> DecompositionResult` +- `IValidator.validate_plan(plan, ctx) -> ValidatedPlan` +- `IValidator.verify_milestone(result, ctx, plan=None) -> VerifyResult` +- `IRemediator.remediate(verify_result, ctx) -> str` +- `IStepExecutor.execute_step(step, ctx, previous_results) -> StepResult` +- `IPlanAttemptSandbox.create_snapshot/rollback/commit` + +## 4. 关键字段(Core Fields) + +- `Task` + - `description`, `task_id`, `milestones`, `metadata`, `previous_session_summary` +- `Milestone` + - `milestone_id`, `description`, `user_input`, `success_criteria` +- `ProposedPlan` + - `plan_description`, `steps`, `attempt`, `metadata` +- `ValidatedPlan` + - `plan_description`, `steps`, `success`, `errors`, `metadata` +- `Envelope` + - `allowed_capability_ids`, `budget`, `done_predicate`, `risk_level` +- `RunResult` + - `success`, `output`, `output_text`, `errors`, `metadata`, `session_summary` + +## 5. 关键流程(Runtime Flow) + +```mermaid +flowchart TD + A["Task input"] --> B["Planner.decompose (optional)"] + B --> C["Planner.plan -> ProposedPlan"] + C --> D["Validator.validate_plan -> ValidatedPlan"] + D --> E["Execute loop (model/tool)"] + E --> F["Validator.verify_milestone"] + F -->|pass| G["next milestone / finish"] + F -->|fail| H["Remediator.remediate"] + H --> C +``` + +## 6. 与其他模块的交互 + +- **Agent**:五层循环中的 plan / verify 阶段直接消费 plan domain。 +- **Tool**:`Envelope` 驱动 tool loop 边界。 +- **Security**:`risk_level` 与 policy gate 语义对齐。 + +## 7. 约束与限制 + +- 当前实现中 `ValidatedPlan.steps` 尚未完整驱动 step-driven 执行。 +- `plan/kernel.py` 为空壳,稳定 surface 主要位于 interfaces/types。 + +## 8. TODO / 未决问题 + +- TODO: 打通 step-driven 执行引擎。 +- TODO: 建立 plan attempt snapshot/rollback 的默认实现。 +- TODO: 统一 evidence 模型(planner/tool/verify)。 diff --git a/docs/design/modules/security/README.md b/docs/design/modules/security/README.md index d13e5ac7..3fa2a099 100644 --- a/docs/design/modules/security/README.md +++ b/docs/design/modules/security/README.md @@ -1,42 +1,71 @@ # Module: security -> Status: interface-only (2026-01-31). TODO indicates missing implementation and integration. +> Status: interface-first detailed design aligned to `dare_framework/security` (2026-02-25). ## 1. 定位与职责 -- 提供 Trust / Policy / Sandbox 的统一边界与接口规范。 -- 作为模型不可信输入的“可信化”入口,保证风险字段来自 registry。 +- 提供 trust / policy / sandbox 的统一安全边界。 +- 确保安全关键字段从 trusted registry 推导,而非直接信任模型输出。 -## 2. 关键概念与数据结构 +## 2. 依赖与边界 -- `RiskLevel`:能力风险等级(read_only / idempotent_write / compensatable / non_idempotent_effect)。 -- `PolicyDecision`:ALLOW / DENY / APPROVE_REQUIRED。 -- `TrustedInput`:从不可信输入派生的可信参数集合。 -- `SandboxSpec`:沙箱执行参数(占位)。 +- kernel:`ISecurityBoundary` +- types:`RiskLevel`, `PolicyDecision`, `TrustedInput`, `SandboxSpec` +- 边界约束: + - security domain 定义协议,不绑定具体策略引擎或沙箱实现。 + - agent/tool 需要显式接入,才会形成执行期安全闭环。 -## 3. 关键接口 +## 3. 对外接口(Public Contract) -- `ISecurityBoundary.verify_trust(...)`:从 registry 推导可信输入。 -- `ISecurityBoundary.check_policy(...)`:策略评估。 -- `ISecurityBoundary.execute_safe(...)`:沙箱执行包装。 +- `ISecurityBoundary.verify_trust(input, context) -> TrustedInput` +- `ISecurityBoundary.check_policy(action, resource, context) -> PolicyDecision` +- `ISecurityBoundary.execute_safe(action, fn, sandbox) -> Any` -## 4. 与其他模块的交互 +## 4. 关键字段(Core Fields) -- **Plan**:Validator 可调用 registry 派生风险元数据。 -- **Tool**:Tool invocation 应受 policy gate 约束(TODO)。 -- **Agent**:执行计划前与工具调用前应调用 policy gate(TODO)。 +- `RiskLevel` + - `READ_ONLY` + - `IDEMPOTENT_WRITE` + - `COMPENSATABLE` + - `NON_IDEMPOTENT_EFFECT` +- `PolicyDecision` + - `ALLOW` + - `DENY` + - `APPROVE_REQUIRED` +- `TrustedInput` + - `params: dict[str, Any]` + - `risk_level: RiskLevel` + - `metadata: dict[str, Any]` +- `SandboxSpec` + - `mode: str` + - `details: dict[str, Any]` -## 5. 现状与限制 +## 5. 关键流程(Runtime Flow) -- 当前仅有接口与类型定义,无默认实现。 -- DareAgent 未接入 SecurityBoundary(TODO)。 +```mermaid +flowchart TD + A["Untrusted request (model/tool params)"] --> B["verify_trust"] + B --> C["TrustedInput + risk_level"] + C --> D["check_policy(action, resource)"] + D --> E{"PolicyDecision"} + E -- ALLOW --> F["execute_safe"] + E -- APPROVE_REQUIRED --> G["HITL approval bridge"] + E -- DENY --> H["reject + audit event"] +``` -## 6. TODO / 未决问题 +## 6. 与其他模块的交互 -- TODO: 提供默认 Policy/Sandbox 实现。 -- TODO: 在 Agent 的 Plan→Execute 与 Tool invoke 前接入 policy gate。 -- TODO: 与 HITL (`IExecutionControl`) 形成审批闭环。 +- **Plan**:验证阶段需要风险等级与可信参数。 +- **Tool**:tool invoke 前应经过 policy gate。 +- **Agent**:plan->execute / tool loop 入口应调用 security boundary。 -## 7. Design Clarifications (2026-02-03) +## 7. 约束与限制 -- Doc/Impl gap: security is interface-only; define minimal default stub or explicit no-op policy. +- 当前仓库仍以接口为主,缺少默认 policy/sandbox 实现。 +- 与 HITL 的审批闭环尚未完成。 + +## 8. TODO / 未决问题 + +- TODO: 提供默认 no-op / stub 与 production policy 的标准实现。 +- TODO: 在 DareAgent ToolLoop 中接入强制 policy gate。 +- TODO: 明确审批超时、拒绝与回滚语义。 diff --git a/docs/design/modules/skill/README.md b/docs/design/modules/skill/README.md index d235df1a..d4fdb951 100644 --- a/docs/design/modules/skill/README.md +++ b/docs/design/modules/skill/README.md @@ -1,94 +1,72 @@ # Module: skill -> Status: aligned to `dare_framework/skill` (2026-01-31). TODO indicates gaps vs desired architecture. +> Status: detailed design aligned to `dare_framework/skill` (2026-02-25). ## 1. 定位与职责 -- 提供“Agent Skills”格式(SKILL.md)的解析、存储与选择能力。 -- 支持通过 `search_skill` 工具检索技能并返回 prompt。 - -## 2. 关键概念与数据结构 - -- `Skill`:技能定义(id/name/description/content)。 -- `ISkill`:技能接口(非执行,kernel)。 -- `ISkillTool`:技能工具标记接口(工具层适配)。 -- `ISkillLoader`:技能加载接口(文件系统)。 -- `ISkillStore`:技能存储与检索。 -- `ISkillSelector`:任务相关性选择器。 - -## 2.1 Skill 模板(SKILL.md + scripts) - -**SKILL.md 结构**: -- YAML Frontmatter(键值对) -- Markdown 正文(技能说明、步骤、约束) - -**典型目录结构**: - -```text -my_skill/ -├── SKILL.md -└── scripts/ - ├── run_tool.py - └── check.sh -``` - -**SKILL.md 示例**: - -```markdown ---- -id: code-review -name: Code Review -description: Review code for defects and risks ---- -# Usage -1. Read relevant files -2. Identify defects and risks -3. Provide actionable feedback +- 定义 skill(`SKILL.md`)的加载、存储、检索与 prompt 注入策略。 +- 通过技能检索工具把“可执行工作流约束”注入模型上下文。 + +## 2. 依赖与边界 + +- kernel:`ISkill`, `ISkillTool` +- interfaces:`ISkillLoader`, `ISkillStore` +- types:`Skill` +- 默认实现: + - `FileSystemSkillLoader` + - `SkillStore` + - `SearchSkillTool` + - `prompt_enricher`(技能注入) +- 边界约束: + - skill domain 不直接执行脚本,只暴露脚本路径给上层工具链。 + +## 3. 对外接口(Public Contract) + +- `ISkillLoader.load() -> list[Skill]` +- `ISkillStore.list_skills() -> list[Skill]` +- `ISkillStore.get_skill(skill_id) -> Skill | None` +- `ISkillStore.select_for_task(query, limit=5) -> list[Skill]` +- `SearchSkillTool.execute(skill, args="") -> ToolResult` +- prompt enrich API: + - `enrich_prompt_with_skill(base_prompt, skill)` + - `enrich_prompt_with_skills(base_prompt, skill_paths)` + - `enrich_prompt_with_skill_summaries(base_prompt, skills)` + +## 4. 关键字段(Core Fields) + +- `Skill` + - `id`, `name`, `description`, `content` + - `skill_dir: Path | None` + - `scripts: dict[str, Path]` +- `SearchSkillTool` 输出关键字段 + - `skill_id`, `name`, `description`, `content` + - `skill_path`, `scripts`, `prompt`, `args` + +## 5. 关键流程(Runtime Flow) + +```mermaid +flowchart TD + A["Scan skill_paths"] --> B["FileSystemSkillLoader.load"] + B --> C["SkillStore index"] + C --> D["Model requests skill tool"] + D --> E["SearchSkillTool.resolve + return prompt"] + E --> F["Context assemble enrich sys_prompt"] + F --> G["Next LLM call uses enriched prompt"] ``` -## 3. 当前实现 - -- `FileSystemSkillLoader`:从目录扫描 `SKILL.md` + `scripts/`(default)。 -- `SkillStore`:内存存储与检索(default)。 -- `KeywordSkillSelector`:基于关键词匹配的选择策略(default)。 -- `SkillSearchTool`:统一工具 `search_skill`,返回技能 prompt(default)。 - -## 4. 与其他模块的交互 - -- **Tool**:`SkillSearchTool` 实现 `ISkillTool`,可注册到 ToolManager。其输出会在执行循环内写入 Context,作为后续 assemble 的 skill prompt。 -- **Model/Context**:技能内容可注入 system prompt(需上层实现,当前未内置)。 - -## 4.1 Skill 模式 - -- **模式 1:persistent_skill_mode**:单一 agent 挂载 `initial_skill_path`(多 skill 编排策略待定)。 -- **模式 2:auto_skill_mode**:单一 agent 注册 `search_skill` 工具(来自 `skill_paths`),工具返回 skill prompt,并在后续 assemble 时注入上下文。 - -## 5. 约束与限制 - -- 技能加载仅支持文件系统;无远端技能源。 -- Skill 内容注入 Context 尚无默认路径(TODO)。 -- 不内置脚本执行(依赖外部工具/流程)。 - -## 6. 扩展点 - -- 新 Skill Loader(例如远端仓库)。 -- 自定义 Skill Selector(更高级的语义匹配)。 -- Skill 内容注入策略(结合 Prompt 管理)。 - -## 7. TODO / 未决问题 +## 6. 与其他模块的交互 -- TODO: 标准化“技能注入上下文”的默认路径与安全边界。 -- TODO: skill 检索权限与审计机制。 +- **Tool**:`SearchSkillTool` 作为 capability 注册到 tool registry。 +- **Context/Model**:skill prompt 在 assemble 时注入系统提示。 +- **Config**:`skill_paths` 与 `skill_mode` 控制加载模式。 -## 7.1 Config 支持 +## 7. 约束与限制 -- `skill_mode`: `"persistent_skill_mode"` | `"auto_skill_mode"` -- `initial_skill_path`: 单个技能路径(用于 persistent 模式) -- `skill_paths`: 技能根目录列表(用于 auto 模式) +- 当前只支持文件系统 skill source。 +- 自动注入路径与审批边界仍需进一步标准化。 -## 8. Design Clarifications (2026-02-03) +## 8. TODO / 未决问题 -- Kernel: `ISkill`/`ISkillTool` live in `dare_framework.skill.kernel`. -- Defaults: `FileSystemSkillLoader`/`SkillStore`/`KeywordSkillSelector`/`SkillSearchTool` - live in `dare_framework.skill.defaults`. -- Doc gap: skill injection path into context/prompt is not specified. +- TODO: 收敛 skill 注入策略(何时注入、注入范围、冲突优先级)。 +- TODO: 增加 skill 检索权限控制与审计。 +- TODO: 支持远程 skill 仓库与签名校验。 diff --git a/docs/design/modules/tool/README.md b/docs/design/modules/tool/README.md index e91a5398..f5c7003f 100644 --- a/docs/design/modules/tool/README.md +++ b/docs/design/modules/tool/README.md @@ -121,3 +121,34 @@ Tool 定义对外输出为 OpenAI function-call 兼容结构,由 `ToolManager. - Impl gap: `IToolGateway.invoke()` returns `Any` in kernel; should return `ToolResult`. - Type cleanup: replace string annotations for `ITool`/`IToolProvider` in kernel with direct types. + +## 11. 对外接口汇总(Public Contract Snapshot) + +- `ITool.execute(run_context, **params) -> ToolResult` +- `IToolGateway.invoke(capability_id, envelope, context=None, **params) -> ToolResult` +- `IToolGateway.list_capabilities() -> list[CapabilityDescriptor]` +- `IToolManager` + - `load_tools`, `register_tool`, `get_tool`, `unregister_tool` + - `register_provider`, `refresh`, `list_capabilities`, `get_capability` + +## 12. 核心字段汇总(Core Fields Snapshot) + +- `CapabilityDescriptor` + - `id`, `type`, `name`, `description`, `input_schema`, `output_schema`, `metadata` +- `CapabilityMetadata` + - `risk_level`, `requires_approval`, `timeout_seconds`, `is_work_unit`, `capability_kind` +- `RunContext` + - `deps`, `metadata`, `run_id`, `task_id`, `milestone_id`, `config` +- `ToolResult` + - `success`, `output`, `error`, `evidence` + +## 13. 关键流程汇总(Flow Snapshot) + +```mermaid +flowchart TD + A["ModelResponse.tool_calls"] --> B["ToolLoopRequest(capability_id, params, envelope)"] + B --> C["IToolGateway.invoke"] + C --> D["Tool implementation execute"] + D --> E["ToolResult(success/output/error/evidence)"] + E --> F["Context + Event + Hook update"] +``` diff --git a/docs/design/modules/transport/README.md b/docs/design/modules/transport/README.md new file mode 100644 index 00000000..73a3cf2a --- /dev/null +++ b/docs/design/modules/transport/README.md @@ -0,0 +1,82 @@ +# Module: transport + +> Status: detailed design aligned to `dare_framework/transport` (2026-02-25). + +## 1. 定位与职责 + +- 提供 Agent 与外部客户端(CLI/Web/API)之间的统一信封通信层。 +- 通过 `TransportEnvelope` + `AgentChannel` 屏蔽具体连接协议差异。 +- 管理 action/control/message 三类交互路径与错误回执。 + +## 2. 依赖与边界 + +- kernel:`AgentChannel`, `ClientChannel` +- types:`EnvelopeKind`, `TransportEnvelope` +- 默认实现:`DefaultAgentChannel` +- interaction 子域:`ActionHandlerDispatcher`, `AgentControlHandler`, payload builders +- 边界约束: + - transport 负责消息路由与回压,不负责任务业务语义。 + - action/control 的业务执行由 dispatcher/agent handler 提供。 + +## 3. 对外接口(Public Contract) + +- `AgentChannel` + - `start()`, `stop()` + - `poll() -> TransportEnvelope | list[TransportEnvelope]` + - `send(msg: TransportEnvelope)` + - `add_action_handler_dispatcher(...)` + - `add_agent_control_handler(...)` + - `build(client_channel, max_inbox=100, max_outbox=100, action_timeout_seconds=30.0)` +- `ClientChannel` + - `attach_agent_envelope_sender(sender)` + - `agent_envelope_receiver() -> Receiver` + +## 4. 关键字段(Core Fields) + +- `EnvelopeKind` + - `MESSAGE`, `ACTION`, `CONTROL` +- `TransportEnvelope` + - `id`, `reply_to`, `kind`, `payload`, `meta`, `stream_id`, `seq` + +统一返回 payload(interaction/payloads): +- success: `{type:"result", kind, target, ok:true, resp}` +- error: `{type:"error", kind, target, ok:false, code, reason, resp}` + +## 5. 关键流程(Runtime Flow) + +```mermaid +flowchart TD + A["Client sends TransportEnvelope"] --> B["DefaultAgentChannel._enqueue_inbox"] + B --> C{"kind"} + C -- MESSAGE --> D["put inbox -> Agent poll"] + C -- ACTION --> E["ActionHandlerDispatcher.handle_action"] + C -- CONTROL --> F["AgentControlHandler.invoke"] + E --> G["build success/error payload"] + F --> G + D --> H["Agent business loop"] + H --> I["channel.send -> outbox"] + I --> J["pump_outbox_to_receiver"] +``` + +## 6. 与其他模块的交互 + +- **Agent**:通过 `poll/send` 进入 transport loop 或 direct-call 通道。 +- **Hook/Observability**:可通过 transport 发送事件 envelope 到外部 UI。 +- **Tool/HITL**:审批状态可经 transport payload 回传客户端。 + +## 7. 约束与限制 + +- 默认 channel 为阻塞回压模型,未提供优先级队列。 +- 未提供持久化队列与断线恢复机制。 + +## 8. TODO / 未决问题 + +- TODO: 支持 reconnect/resume 与 envelope replay。 +- TODO: 定义 streaming chunk 的标准 envelope 协议。 +- TODO: 增加 action/control schema 校验与版本化。 + +## 9. 相关文档 + +- `docs/design/modules/transport/transport_mvp.md` +- `docs/design/modules/transport/Transport_Domain_Design.md` +- `docs/design/modules/transport/InteractionStreaming.md`