localharness 0.55.0

Agents that own themselves: one Rust crate that's both an agent SDK (streaming, tools, hooks, policies, triggers, MCP) and a wallet-owning, self-sovereign agent that runs in the browser.
Documentation
//! `finish` — special tool the model calls to terminate the turn.
//!
//! When `response_schema` is configured, the model is asked to call
//! `finish` with the structured payload as the `output` arg; the loop
//! pulls that out and stashes it as `structured_output` on the
//! conversation state.
//!
//! The loop recognises `finish` by name (see [`FINISH_TOOL_NAME`]) and
//! exits the outer dispatch loop after handling it — `execute` here is
//! just a no-op that echoes the args so the function response is well
//! formed for the model's history.

use std::sync::Arc;

use async_trait::async_trait;
use serde_json::{json, Value};

use crate::error::Result;
use crate::tools::{Tool, ToolContext};

pub const FINISH_TOOL_NAME: &str = "finish";

pub struct Finish;

#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl Tool for Finish {
    fn name(&self) -> &str {
        FINISH_TOOL_NAME
    }

    fn description(&self) -> &str {
        "Signal that the turn is complete. This is the ABSOLUTE END of the turn — \
         calling it stops the loop immediately; do NOT add a separate closing reply, \
         and do NOT call it just to say a final sentence. Only pass `summary` (one or \
         two sentences) when the turn would otherwise end SILENTLY — i.e. you ran \
         tools but said nothing this turn; it is shown as the closing reply ONLY in \
         that case and is ignored if you already replied in text. Pass `output` when \
         the agent is configured with a response schema; it will be returned to the \
         caller as the structured output of this turn."
    }

    fn input_schema(&self) -> Value {
        json!({
            "type": "object",
            "properties": {
                "summary": { "type": "string", "description": "Optional short closing message, shown ONLY when the turn would otherwise end silently after tool calls (ignored if you already replied in text this turn)." },
                "output": { "description": "Optional structured output. Must conform to the agent's response_schema when one is set." }
            }
        })
    }

    async fn execute(&self, args: Value, _ctx: Option<Arc<ToolContext>>) -> Result<Value> {
        // The runtime intercepts this call to extract `output` before we run.
        // Returning the args back lets the model see a well-formed response
        // even if the runtime didn't intercept (defensive).
        Ok(json!({ "ok": true, "args": args }))
    }
}