use async_trait::async_trait;
use supercode_harness::tools::{Tool, ToolContext};
use supercode_harness::{Agent, ChatMessage, ChatRequest, Config, Provider, Result, Usage};
struct WordCount;
#[async_trait]
impl Tool for WordCount {
fn name(&self) -> &str {
"word_count"
}
fn description(&self) -> &str {
"Count the words in the given text."
}
fn parameters(&self) -> serde_json::Value {
serde_json::json!({
"type": "object",
"properties": { "text": { "type": "string" } },
"required": ["text"]
})
}
async fn execute(&self, args: serde_json::Value, _ctx: &ToolContext) -> Result<String> {
let text = args["text"].as_str().unwrap_or("");
Ok(text.split_whitespace().count().to_string())
}
}
struct Scripted;
#[async_trait]
impl Provider for Scripted {
async fn complete(
&self,
req: &ChatRequest,
_on_delta: &(dyn for<'a> Fn(&'a str) + Send + Sync),
) -> Result<(ChatMessage, Usage)> {
let last_is_tool = matches!(
req.messages.last().map(|m| m.role),
Some(supercode_harness::Role::Tool)
);
if last_is_tool {
let n = req
.messages
.last()
.and_then(|m| m.content.clone())
.unwrap_or_default();
Ok((
ChatMessage::assistant(format!("That text has {n} words.")),
Usage::default(),
))
} else {
let mut msg = ChatMessage::assistant("");
msg.tool_calls = Some(vec![supercode_harness::ToolCall {
id: "call_1".into(),
kind: "function".into(),
function: supercode_harness::FunctionCall {
name: "word_count".into(),
arguments: r#"{"text":"the quick brown fox jumps"}"#.into(),
},
}]);
Ok((msg, Usage::default()))
}
}
}
#[tokio::main]
async fn main() -> Result<()> {
let mut agent = Agent::with_provider(Config::builder().build(), Box::new(Scripted));
agent.register_tool(WordCount);
let reply = agent.send("How many words in that sentence?").await?;
println!("{reply}");
assert!(
reply.contains('5'),
"the agent should have used word_count → 5"
);
println!("\n✓ the agent invoked the custom `word_count` tool");
Ok(())
}