diff --git a/docs/plans/core-decomposition-plan.md b/docs/plans/core-decomposition-plan.md index 64dfab7be..0c78d8eb9 100644 --- a/docs/plans/core-decomposition-plan.md +++ b/docs/plans/core-decomposition-plan.md @@ -1087,6 +1087,11 @@ pub fn create_tool_registry() -> ToolRegistry { - `Tool` trait、`ToolUseContext` 和具体工具实现仍在 core;它们直接连接 workspace service、snapshot wrapper、computer-use host、cancellation token 与 Deep Review checkpoint hook。`ToolContextFacts` / `PortableToolContextProvider` 只能作为只读事实投影,继续迁移前必须先确认 service port 方案,并补工具清单等价性测试。 - 最新主干新增的 Deep Review shared-context / evidence-ledger checkpoint hook 仍保留在 core 的 `ToolUseContext` 中;在设计独立 tool context / event port 前,不应把 `ToolUseContext` 或 concrete tool implementation 继续外移。 - 最新主干新增 on-demand tool spec discovery:`ToolExposure`、`GetToolSpec` 名称、collapsed prompt stub、manifest ordering 与 GetToolSpec presentation/schema 的纯契约已可由 `bitfun-agent-tools` 承载;`manifest_resolver`、collapsed-tool catalog、context-aware `description_with_context` / `input_schema_for_model_with_context`、`GetToolSpecTool` 执行以及 `ToolUseContext.unlocked_collapsed_tools` 仍会影响模型可见工具集合。该变化不推翻 PR4 的低风险结论,但把后续 tool/provider 迁移提升为高风险项,不能在 product-domain runtime 收尾中顺带执行。 +- H1 start(2026-05-19):`StaticToolProviderGroup` 通用容器已迁入 + `bitfun-agent-tools`,core 的 `static_providers.rs` 只负责实例化 concrete tools 并按既有 + provider group 顺序装配。该切片不移动 concrete tool implementation、`ToolUseContext`、 + runtime manifest assembly 或 `GetToolSpec` 执行;provider id、工具顺序与 manifest 快照由 + `bitfun-agent-tools` contract test、core registry snapshot 和 boundary check 共同保护。 **验证:** diff --git a/scripts/check-core-boundaries.mjs b/scripts/check-core-boundaries.mjs index c2969477e..8ef7c20c2 100644 --- a/scripts/check-core-boundaries.mjs +++ b/scripts/check-core-boundaries.mjs @@ -1165,6 +1165,10 @@ const requiredContentRules = [ regex: /\bpub fn sort_tool_manifest_definitions\b/, message: 'missing prompt-visible manifest ordering helper', }, + { + regex: /\bpub struct StaticToolProviderGroup\b/, + message: 'missing generic static provider group container', + }, ], }, { @@ -1227,8 +1231,8 @@ const requiredContentRules = [ message: 'missing builtin static tool provider owner', }, { - regex: /\bStaticToolProvider\b/, - message: 'missing static provider contract use', + regex: /\bStaticToolProviderGroup\b/, + message: 'missing generic static provider group contract use', }, { regex: /core\.basic/, @@ -3077,7 +3081,7 @@ function runManifestParserSelfTest() { path: 'src/crates/core/src/agentic/tools/static_providers.rs', contracts: [ 'builtin_static_tool_providers', - 'StaticToolProvider', + 'StaticToolProviderGroup', 'core.basic', 'core.agent', 'core.session', @@ -3092,6 +3096,7 @@ function runManifestParserSelfTest() { 'PortableToolContextProvider', 'ToolWorkspaceKind', 'StaticToolProvider', + 'StaticToolProviderGroup', 'install_static_provider', ], }, diff --git a/src/crates/agent-tools/AGENTS.md b/src/crates/agent-tools/AGENTS.md index e96f3bab5..2afc685ce 100644 --- a/src/crates/agent-tools/AGENTS.md +++ b/src/crates/agent-tools/AGENTS.md @@ -13,6 +13,9 @@ the product tool runtime. path-resolution DTOs, generic/static/dynamic provider contracts, pure manifest/exposure helpers, GetToolSpec presentation/schema helpers, and `ToolContextFacts` / `PortableToolContextProvider`. +- This crate may own generic provider containers such as + `StaticToolProviderGroup`, but concrete tool construction and product runtime + registration stay outside this crate until H1 explicitly moves an owner. - Do not move `ToolUseContext`, concrete tools, workspace services, cancellation tokens, snapshot decoration, collapsed unlock state, runtime manifest assembly, or `GetToolSpec` execution here without H1 approval and equivalence diff --git a/src/crates/agent-tools/src/framework.rs b/src/crates/agent-tools/src/framework.rs index c46bc0728..f6acb4dcb 100644 --- a/src/crates/agent-tools/src/framework.rs +++ b/src/crates/agent-tools/src/framework.rs @@ -349,6 +349,27 @@ pub trait StaticToolProvider: Send + Sync { fn tools(&self) -> Vec>; } +pub struct StaticToolProviderGroup { + provider_id: &'static str, + tools: Vec>, +} + +impl StaticToolProviderGroup { + pub fn new(provider_id: &'static str, tools: Vec>) -> Self { + Self { provider_id, tools } + } +} + +impl StaticToolProvider for StaticToolProviderGroup { + fn provider_id(&self) -> &'static str { + self.provider_id + } + + fn tools(&self) -> Vec> { + self.tools.clone() + } +} + pub struct ToolRegistry { tools: IndexMap>, dynamic_tools: IndexMap, diff --git a/src/crates/agent-tools/src/lib.rs b/src/crates/agent-tools/src/lib.rs index 909f38d53..9562614f1 100644 --- a/src/crates/agent-tools/src/lib.rs +++ b/src/crates/agent-tools/src/lib.rs @@ -11,15 +11,15 @@ pub use bitfun_runtime_ports::{ DynamicToolDescriptor, DynamicToolProvider, PortError, PortErrorKind, PortResult, ToolDecorator, }; pub use framework::{ - build_collapsed_tool_stub_definition, build_get_tool_spec_assistant_detail, - build_get_tool_spec_collapsed_tool_entry, build_get_tool_spec_description, - build_get_tool_spec_duplicate_load_hint, get_tool_spec_input_schema, - resolve_tool_manifest_policy, sort_tool_manifest_definitions, tool_manifest_sort_rank, - validate_get_tool_spec_input, DynamicMcpToolInfo, DynamicToolInfo, PortableToolContextProvider, - StaticToolProvider, ToolContextFacts, ToolExposure, ToolManifestDefinition, - ToolManifestPolicyResolution, ToolManifestPolicyTool, ToolPathBackend, ToolPathOperation, - ToolPathPolicy, ToolPathResolution, ToolRef, ToolRegistry, ToolRegistryItem, ToolRenderOptions, - ToolRestrictionError, ToolResult, ToolRuntimeRestrictions, ToolWorkspaceKind, ValidationResult, - GET_TOOL_SPEC_TOOL_NAME, + DynamicMcpToolInfo, DynamicToolInfo, GET_TOOL_SPEC_TOOL_NAME, PortableToolContextProvider, + StaticToolProvider, StaticToolProviderGroup, ToolContextFacts, ToolExposure, + ToolManifestDefinition, ToolManifestPolicyResolution, ToolManifestPolicyTool, ToolPathBackend, + ToolPathOperation, ToolPathPolicy, ToolPathResolution, ToolRef, ToolRegistry, ToolRegistryItem, + ToolRenderOptions, ToolRestrictionError, ToolResult, ToolRuntimeRestrictions, + ToolWorkspaceKind, ValidationResult, build_collapsed_tool_stub_definition, + build_get_tool_spec_assistant_detail, build_get_tool_spec_collapsed_tool_entry, + build_get_tool_spec_description, build_get_tool_spec_duplicate_load_hint, + get_tool_spec_input_schema, resolve_tool_manifest_policy, sort_tool_manifest_definitions, + tool_manifest_sort_rank, validate_get_tool_spec_input, }; pub use input_validator::InputValidator; diff --git a/src/crates/agent-tools/tests/tool_contracts.rs b/src/crates/agent-tools/tests/tool_contracts.rs index 959e32eec..9daad164c 100644 --- a/src/crates/agent-tools/tests/tool_contracts.rs +++ b/src/crates/agent-tools/tests/tool_contracts.rs @@ -1,16 +1,16 @@ use bitfun_agent_tools::{ - build_collapsed_tool_stub_definition, build_get_tool_spec_assistant_detail, - build_get_tool_spec_collapsed_tool_entry, build_get_tool_spec_description, - build_get_tool_spec_duplicate_load_hint, get_tool_spec_input_schema, - resolve_tool_manifest_policy, sort_tool_manifest_definitions, validate_get_tool_spec_input, - DynamicMcpToolInfo, DynamicToolInfo, InputValidator, ToolContextFacts, ToolExposure, - ToolImageAttachment, ToolManifestDefinition, ToolManifestPolicyTool, ToolPathBackend, - ToolPathResolution, ToolRenderOptions, ToolResult, ToolRuntimeRestrictions, ToolWorkspaceKind, - ValidationResult, GET_TOOL_SPEC_TOOL_NAME, + DynamicMcpToolInfo, DynamicToolInfo, GET_TOOL_SPEC_TOOL_NAME, InputValidator, ToolContextFacts, + ToolExposure, ToolImageAttachment, ToolManifestDefinition, ToolManifestPolicyTool, + ToolPathBackend, ToolPathResolution, ToolRenderOptions, ToolResult, ToolRuntimeRestrictions, + ToolWorkspaceKind, ValidationResult, build_collapsed_tool_stub_definition, + build_get_tool_spec_assistant_detail, build_get_tool_spec_collapsed_tool_entry, + build_get_tool_spec_description, build_get_tool_spec_duplicate_load_hint, + get_tool_spec_input_schema, resolve_tool_manifest_policy, sort_tool_manifest_definitions, + validate_get_tool_spec_input, }; use bitfun_agent_tools::{ DynamicToolDescriptor, DynamicToolProvider, PortResult, PortableToolContextProvider, - StaticToolProvider, ToolDecorator, ToolRegistry, ToolRegistryItem, + StaticToolProvider, StaticToolProviderGroup, ToolDecorator, ToolRegistry, ToolRegistryItem, }; use serde_json::json; use std::path::PathBuf; @@ -428,9 +428,10 @@ fn collapsed_tool_stub_definition_preserves_prompt_visible_guardrail() { assert_eq!(stub.name, "WebFetch"); assert!(stub.description.contains("Fetch a URL")); - assert!(stub - .description - .contains("First call `GetToolSpec` with {\"tool_name\":\"WebFetch\"}")); + assert!( + stub.description + .contains("First call `GetToolSpec` with {\"tool_name\":\"WebFetch\"}") + ); assert_eq!( stub.parameters, json!({ @@ -475,10 +476,12 @@ fn get_tool_spec_contract_preserves_input_schema_and_validation() { assert_eq!(schema["additionalProperties"], false); assert_eq!(schema["required"], json!(["tool_name"])); assert_eq!(schema["properties"]["tool_name"]["type"], "string"); - assert!(schema["properties"]["tool_name"]["description"] - .as_str() - .unwrap_or_default() - .contains("canonical casing")); + assert!( + schema["properties"]["tool_name"]["description"] + .as_str() + .unwrap_or_default() + .contains("canonical casing") + ); let missing = validate_get_tool_spec_input(&json!({})); assert!(!missing.result); @@ -599,6 +602,27 @@ impl StaticToolProvider for RegistryMarkerProvider { } } +#[test] +fn static_tool_provider_group_preserves_provider_id_and_tool_order() { + let provider = StaticToolProviderGroup::new( + "core-basic", + vec![ + registry_marker_tool("Read", None), + registry_marker_tool("Write", None), + ], + ); + + assert_eq!(provider.provider_id(), "core-basic"); + assert_eq!( + provider + .tools() + .iter() + .map(|tool| tool.name()) + .collect::>(), + vec!["Read", "Write"] + ); +} + struct RegistryMarkerDecorator; impl ToolDecorator> for RegistryMarkerDecorator { diff --git a/src/crates/core/src/agentic/tools/static_providers.rs b/src/crates/core/src/agentic/tools/static_providers.rs index 2b9d2f26b..0222f3544 100644 --- a/src/crates/core/src/agentic/tools/static_providers.rs +++ b/src/crates/core/src/agentic/tools/static_providers.rs @@ -2,29 +2,14 @@ use crate::agentic::tools::framework::Tool; use crate::agentic::tools::implementations::*; -use bitfun_agent_tools::{StaticToolProvider, ToolRef}; +use bitfun_agent_tools::StaticToolProviderGroup; use std::sync::Arc; -pub(crate) struct CoreStaticToolProvider { - provider_id: &'static str, - tools: Vec>, -} - -impl StaticToolProvider for CoreStaticToolProvider { - fn provider_id(&self) -> &'static str { - self.provider_id - } - - fn tools(&self) -> Vec> { - self.tools.clone() - } -} - -pub(crate) fn builtin_static_tool_providers() -> Vec { +pub(crate) fn builtin_static_tool_providers() -> Vec> { vec![ - CoreStaticToolProvider { - provider_id: "core.basic", - tools: vec![ + StaticToolProviderGroup::new( + "core.basic", + vec![ Arc::new(LSTool::new()), Arc::new(FileReadTool::new()), Arc::new(GlobTool::new()), @@ -34,10 +19,10 @@ pub(crate) fn builtin_static_tool_providers() -> Vec { Arc::new(DeleteFileTool::new()), Arc::new(BashTool::new()), ], - }, - CoreStaticToolProvider { - provider_id: "core.agent", - tools: vec![ + ), + StaticToolProviderGroup::new( + "core.agent", + vec![ Arc::new(TaskTool::new()), Arc::new(SkillTool::new()), Arc::new(AskUserQuestionTool::new()), @@ -48,20 +33,20 @@ pub(crate) fn builtin_static_tool_providers() -> Vec { Arc::new(GetFileDiffTool::new()), Arc::new(LogTool::new()), ], - }, - CoreStaticToolProvider { - provider_id: "core.session", - tools: vec![ + ), + StaticToolProviderGroup::new( + "core.session", + vec![ Arc::new(TerminalControlTool::new()), Arc::new(SessionControlTool::new()), Arc::new(SessionMessageTool::new()), Arc::new(SessionHistoryTool::new()), Arc::new(CronTool::new()), ], - }, - CoreStaticToolProvider { - provider_id: "core.integration", - tools: vec![ + ), + StaticToolProviderGroup::new( + "core.integration", + vec![ Arc::new(WebSearchTool::new()), Arc::new(WebFetchTool::new()), Arc::new(ListMCPResourcesTool::new()), @@ -75,6 +60,6 @@ pub(crate) fn builtin_static_tool_providers() -> Vec { Arc::new(ComputerUseTool::new()), Arc::new(PlaybookTool::new()), ], - }, + ), ] }