diff --git a/docs/src/guides/custom-framework.md b/docs/src/guides/custom-framework.md index ad88cea..d864c4e 100644 --- a/docs/src/guides/custom-framework.md +++ b/docs/src/guides/custom-framework.md @@ -73,7 +73,9 @@ use reloaded_code_core::{ // Implement ToolContext for your tool impl ToolContext for MyReadTool { - const NAME: &'static str = tool_metadata::read::NAME; + fn name(&self) -> &'static str { + tool_metadata::read::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Read { diff --git a/src/reloaded-code-core/README.md b/src/reloaded-code-core/README.md index 54b33b6..f970512 100644 --- a/src/reloaded-code-core/README.md +++ b/src/reloaded-code-core/README.md @@ -162,7 +162,9 @@ impl ReadTool { } impl ToolContext for ReadTool { - const NAME: &'static str = tool_metadata::read::NAME; + fn name(&self) -> &'static str { + tool_metadata::read::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Read { @@ -196,7 +198,9 @@ impl ReadTool { } impl ToolContext for ReadTool { - const NAME: &'static str = tool_metadata::read::NAME; + fn name(&self) -> &'static str { + tool_metadata::read::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Read { diff --git a/src/reloaded-code-core/examples/system_prompt/mock_tools.rs b/src/reloaded-code-core/examples/system_prompt/mock_tools.rs index 3e5f7cd..83ef1db 100644 --- a/src/reloaded-code-core/examples/system_prompt/mock_tools.rs +++ b/src/reloaded-code-core/examples/system_prompt/mock_tools.rs @@ -121,7 +121,9 @@ macro_rules! path_tool_with_line_numbers { impl ToolContext for $tool { - const NAME: &'static str = $name; + fn name(&self) -> &'static str { + $name + } fn context(&self) -> ToolPrompt { ToolPrompt::$variant { @@ -138,7 +140,9 @@ macro_rules! path_tool { struct $tool; impl ToolContext for $tool { - const NAME: &'static str = $name; + fn name(&self) -> &'static str { + $name + } fn context(&self) -> ToolPrompt { ToolPrompt::$variant { @@ -158,7 +162,9 @@ path_tool_with_line_numbers!(MockGrepTool, tool_metadata::grep::NAME, Grep); struct MockBashTool; impl ToolContext for MockBashTool { - const NAME: &'static str = tool_metadata::bash::NAME; + fn name(&self) -> &'static str { + tool_metadata::bash::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Bash { @@ -171,7 +177,9 @@ impl ToolContext for MockBashTool { struct MockWebFetchTool; impl ToolContext for MockWebFetchTool { - const NAME: &'static str = tool_metadata::webfetch::NAME; + fn name(&self) -> &'static str { + tool_metadata::webfetch::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::WebFetch @@ -181,7 +189,9 @@ impl ToolContext for MockWebFetchTool { struct MockTodoWriteTool; impl ToolContext for MockTodoWriteTool { - const NAME: &'static str = tool_metadata::todo_write::NAME; + fn name(&self) -> &'static str { + tool_metadata::todo_write::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::TodoWrite @@ -191,7 +201,9 @@ impl ToolContext for MockTodoWriteTool { struct MockTodoReadTool; impl ToolContext for MockTodoReadTool { - const NAME: &'static str = tool_metadata::todo_read::NAME; + fn name(&self) -> &'static str { + tool_metadata::todo_read::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::TodoRead @@ -201,7 +213,9 @@ impl ToolContext for MockTodoReadTool { struct MockTaskTool; impl ToolContext for MockTaskTool { - const NAME: &'static str = tool_metadata::task::NAME; + fn name(&self) -> &'static str { + tool_metadata::task::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Task diff --git a/src/reloaded-code-core/src/context/mod.rs b/src/reloaded-code-core/src/context/mod.rs index bd897b9..c33138a 100644 --- a/src/reloaded-code-core/src/context/mod.rs +++ b/src/reloaded-code-core/src/context/mod.rs @@ -18,7 +18,9 @@ //! struct NotesTool; //! //! impl ToolContext for ReadTool { -//! const NAME: &'static str = "read"; +//! fn name(&self) -> &'static str { +//! "read" +//! } //! //! fn context(&self) -> ToolPrompt { //! ToolPrompt::Read { @@ -29,7 +31,9 @@ //! } //! //! impl ToolContext for NotesTool { -//! const NAME: &'static str = "notes"; +//! fn name(&self) -> &'static str { +//! "notes" +//! } //! //! fn context(&self) -> ToolPrompt { //! ToolPrompt::Static("Use this tool for short project notes.") @@ -68,7 +72,9 @@ pub const GITHUB_CLI: &str = include_str!("github_cli.txt"); /// struct MyTool; /// /// impl ToolContext for MyTool { -/// const NAME: &'static str = "mytool"; +/// fn name(&self) -> &'static str { +/// "mytool" +/// } /// /// fn context(&self) -> ToolPrompt { /// ToolPrompt::Static("Instructions for using MyTool...") @@ -76,11 +82,12 @@ pub const GITHUB_CLI: &str = include_str!("github_cli.txt"); /// } /// ``` pub trait ToolContext { - /// Tool name used for section headers in generated system prompt. + /// Returns the tool name for section headers in generated system prompt. /// /// Should be lowercase (e.g., "read", "bash", "glob"). /// SystemPromptBuilder capitalizes this for display. - const NAME: &'static str; + #[must_use] + fn name(&self) -> &'static str; /// Returns the guidance for this tool. #[must_use] @@ -91,6 +98,24 @@ pub trait ToolContext { mod tests { use super::*; + #[test] + fn trait_is_object_safe() { + // Verify that Box can be constructed. + // This proves the trait is object-safe (no associated constants, + // no methods requiring Self: Sized). + struct DummyTool; + impl ToolContext for DummyTool { + fn name(&self) -> &'static str { + "dummy" + } + fn context(&self) -> ToolPrompt { + ToolPrompt::Static("Dummy context") + } + } + + let _: Box = Box::new(DummyTool); + } + #[test] fn context_strings_are_not_empty() { assert!( diff --git a/src/reloaded-code-core/src/system_prompt.rs b/src/reloaded-code-core/src/system_prompt.rs index b845fed..6532f01 100644 --- a/src/reloaded-code-core/src/system_prompt.rs +++ b/src/reloaded-code-core/src/system_prompt.rs @@ -27,7 +27,9 @@ struct ContextEntry { /// struct ReadTool; /// /// impl ToolContext for ReadTool { -/// const NAME: &'static str = "read"; +/// fn name(&self) -> &'static str { +/// "read" +/// } /// /// fn context(&self) -> ToolPrompt { /// ToolPrompt::Read { @@ -87,7 +89,9 @@ impl SystemPromptBuilder { /// struct MyTool; /// /// impl ToolContext for MyTool { - /// const NAME: &'static str = "read"; + /// fn name(&self) -> &'static str { + /// "read" + /// } /// /// fn context(&self) -> ToolPrompt { /// ToolPrompt::Read { @@ -113,7 +117,7 @@ impl SystemPromptBuilder { /// ``` pub fn track(&mut self, tool: T) -> T { self.entries.push(ContextEntry { - name: T::NAME, + name: tool.name(), prompt: tool.context(), }); tool @@ -388,7 +392,9 @@ mod tests { } impl ToolContext for MockTool { - const NAME: &'static str = "mock"; + fn name(&self) -> &'static str { + "mock" + } fn context(&self) -> ToolPrompt { ToolPrompt::Static("Mock tool context.") } @@ -397,7 +403,9 @@ mod tests { struct OtherTool; impl ToolContext for OtherTool { - const NAME: &'static str = "other"; + fn name(&self) -> &'static str { + "other" + } fn context(&self) -> ToolPrompt { ToolPrompt::Static("Other context.") } @@ -418,7 +426,9 @@ mod tests { impl ToolContext for $tool { - const NAME: &'static str = $name; + fn name(&self) -> &'static str { + $name + } fn context(&self) -> ToolPrompt { ToolPrompt::$variant { @@ -435,7 +445,9 @@ mod tests { struct $tool; impl ToolContext for $tool { - const NAME: &'static str = $name; + fn name(&self) -> &'static str { + $name + } fn context(&self) -> ToolPrompt { ToolPrompt::$variant { @@ -451,7 +463,9 @@ mod tests { struct $tool; impl ToolContext for $tool { - const NAME: &'static str = $name; + fn name(&self) -> &'static str { + $name + } fn context(&self) -> ToolPrompt { $prompt @@ -1200,7 +1214,9 @@ mod tests { struct SandboxedBashTool; impl ToolContext for SandboxedBashTool { - const NAME: &'static str = bash::NAME; + fn name(&self) -> &'static str { + bash::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Bash { network_disabled: true, @@ -1212,7 +1228,9 @@ mod tests { struct HostBashTool; impl ToolContext for HostBashTool { - const NAME: &'static str = bash::NAME; + fn name(&self) -> &'static str { + bash::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Bash { network_disabled: false, diff --git a/src/reloaded-code-provider-config/src/config.rs b/src/reloaded-code-provider-config/src/config.rs index b8b9a6e..79091dc 100644 --- a/src/reloaded-code-provider-config/src/config.rs +++ b/src/reloaded-code-provider-config/src/config.rs @@ -39,6 +39,7 @@ pub struct ProviderConfig { pub api_url: Option, /// API type string, mapped via [`crate::api_type::api_type_from_str`]. /// Defaults to `"openai-compatible"` when omitted. + #[allow(rustdoc::private_intra_doc_links)] pub api_type: Option, /// Environment variable names checked by `CredentialResolver`, in order. pub env: Option>, diff --git a/src/reloaded-code-serdesai/src/task/tool.rs b/src/reloaded-code-serdesai/src/task/tool.rs index 54e4b6c..17e7de6 100644 --- a/src/reloaded-code-serdesai/src/task/tool.rs +++ b/src/reloaded-code-serdesai/src/task/tool.rs @@ -83,7 +83,9 @@ impl ToolContext for TaskTool where C: CredentialLookup + Send + Sync + 'static, { - const NAME: &'static str = task_meta::NAME; + fn name(&self) -> &'static str { + task_meta::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Task @@ -117,6 +119,11 @@ mod tests { #[test] fn task_tool_name_matches_metadata() { - assert_eq!(TaskTool::::NAME, task_meta::NAME); + let targets = vec![ + summary("alpha", "Alpha agent"), + summary("beta", "Beta agent"), + ]; + let definition = task_tool_definition(&targets); + assert_eq!(definition.name(), task_meta::NAME); } } diff --git a/src/reloaded-code-serdesai/src/tools/bash.rs b/src/reloaded-code-serdesai/src/tools/bash.rs index 8a352cb..fc11cfc 100644 --- a/src/reloaded-code-serdesai/src/tools/bash.rs +++ b/src/reloaded-code-serdesai/src/tools/bash.rs @@ -259,7 +259,9 @@ fn bash_prompt_sandboxed(mode: &BashExecutionMode) -> bool { } impl ToolContext for BashTool { - const NAME: &'static str = bash_meta::NAME; + fn name(&self) -> &'static str { + bash_meta::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Bash { diff --git a/src/reloaded-code-serdesai/src/tools/edit.rs b/src/reloaded-code-serdesai/src/tools/edit.rs index f782b18..a7bf6a1 100644 --- a/src/reloaded-code-serdesai/src/tools/edit.rs +++ b/src/reloaded-code-serdesai/src/tools/edit.rs @@ -81,7 +81,9 @@ impl Tool for Ed } impl ToolContext for EditTool { - const NAME: &'static str = edit_meta::NAME; + fn name(&self) -> &'static str { + edit_meta::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Edit { diff --git a/src/reloaded-code-serdesai/src/tools/glob.rs b/src/reloaded-code-serdesai/src/tools/glob.rs index 623c58f..76f03c6 100644 --- a/src/reloaded-code-serdesai/src/tools/glob.rs +++ b/src/reloaded-code-serdesai/src/tools/glob.rs @@ -116,7 +116,9 @@ fn glob_output_to_return(output: GlobOutput) -> ToolReturn { } impl ToolContext for GlobTool { - const NAME: &'static str = glob_meta::NAME; + fn name(&self) -> &'static str { + glob_meta::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Glob { diff --git a/src/reloaded-code-serdesai/src/tools/grep.rs b/src/reloaded-code-serdesai/src/tools/grep.rs index 17f0354..c272009 100644 --- a/src/reloaded-code-serdesai/src/tools/grep.rs +++ b/src/reloaded-code-serdesai/src/tools/grep.rs @@ -118,7 +118,9 @@ fn grep_output_to_return(output: GrepOutput, formatting: GrepFormattingSettings) } impl ToolContext for GrepTool { - const NAME: &'static str = grep_meta::NAME; + fn name(&self) -> &'static str { + grep_meta::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Grep { diff --git a/src/reloaded-code-serdesai/src/tools/read.rs b/src/reloaded-code-serdesai/src/tools/read.rs index 4902b1a..3971822 100644 --- a/src/reloaded-code-serdesai/src/tools/read.rs +++ b/src/reloaded-code-serdesai/src/tools/read.rs @@ -99,7 +99,9 @@ impl Tool for Re } impl ToolContext for ReadTool { - const NAME: &'static str = read_meta::NAME; + fn name(&self) -> &'static str { + read_meta::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Read { diff --git a/src/reloaded-code-serdesai/src/tools/todo.rs b/src/reloaded-code-serdesai/src/tools/todo.rs index 2e189d1..fd0a783 100644 --- a/src/reloaded-code-serdesai/src/tools/todo.rs +++ b/src/reloaded-code-serdesai/src/tools/todo.rs @@ -55,7 +55,9 @@ impl Tool for TodoWriteTool { } impl ToolContext for TodoWriteTool { - const NAME: &'static str = todo_write_meta::NAME; + fn name(&self) -> &'static str { + todo_write_meta::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::TodoWrite @@ -94,7 +96,9 @@ impl Tool for TodoReadTool { } impl ToolContext for TodoReadTool { - const NAME: &'static str = todo_read_meta::NAME; + fn name(&self) -> &'static str { + todo_read_meta::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::TodoRead diff --git a/src/reloaded-code-serdesai/src/tools/webfetch.rs b/src/reloaded-code-serdesai/src/tools/webfetch.rs index feac580..48b18d8 100644 --- a/src/reloaded-code-serdesai/src/tools/webfetch.rs +++ b/src/reloaded-code-serdesai/src/tools/webfetch.rs @@ -80,7 +80,9 @@ impl Tool for WebFetchTool { } impl ToolContext for WebFetchTool { - const NAME: &'static str = webfetch_meta::NAME; + fn name(&self) -> &'static str { + webfetch_meta::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::WebFetch diff --git a/src/reloaded-code-serdesai/src/tools/write.rs b/src/reloaded-code-serdesai/src/tools/write.rs index 722af1e..de1682e 100644 --- a/src/reloaded-code-serdesai/src/tools/write.rs +++ b/src/reloaded-code-serdesai/src/tools/write.rs @@ -79,7 +79,9 @@ impl Tool for Wr } impl ToolContext for WriteTool { - const NAME: &'static str = write_meta::NAME; + fn name(&self) -> &'static str { + write_meta::NAME + } fn context(&self) -> ToolPrompt { ToolPrompt::Write {