monothink 0.4.7

A totally non-agentic coding assistant
/*
* This file is part of monothink.
*
* monothink is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* monothink is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Wavething.
* If not, see <https://www.gnu.org/licenses/>.

*/

use crate::llm::compactors::SharedObservations;
use rig::{
    message::ToolResultContent,
    tool::{Tool, ToolContext},
};
use serde::{Deserialize, Serialize};
use serde_json::json;

#[derive(Deserialize, Serialize)]
pub struct RetrieveObservationArgs {
    id: u64,
}

#[derive(Debug)]
pub struct RetrieveObservation {
    pub observations: SharedObservations,
}

impl RetrieveObservation {
    pub fn new(observations: SharedObservations) -> Self {
        Self { observations }
    }
}

impl Tool for RetrieveObservation {
    const NAME: &'static str = "retrieve_observation";

    type Error = super::ToolError;
    type Args = RetrieveObservationArgs;
    type Output = Vec<ToolResultContent>;

    async fn call(
        &self,
        _context: &mut ToolContext,
        args: Self::Args,
    ) -> Result<Self::Output, Self::Error> {
        self.observations
            .lock()
            .await
            .get(&args.id)
            .ok_or_else(|| super::ToolError::ResourceNotFound {
                resource_type: super::ResourceType::Observation,
                identifier: args.id.to_string(),
            })
            .cloned()
    }

    fn description(&self) -> String {
        "Retrieve the full content of a masked tool result from conversation history. \
     When conversation history is compacted to save context space, older tool results \
     are replaced with placeholders like '[Observation:3 - masked]'. \
     Use this tool when you need to see the full content of a masked result. \
     The number inside the brackets (e.g., 3 in '[Observation:3 - masked]') is the \
     id you should pass to this tool. Each tool result in the history is assigned a \
     unique observation number starting from 1."
            .to_string()
    }

    fn parameters(&self) -> serde_json::Value {
        let id_description = "The numeric identifier of the observation to retrieve. \
        When a tool result is masked in the conversation history, it appears as \
        '[Observation:N - masked]' where N is this identifier. For example, \
        if you see '[Observation:3 - masked]', pass 3 as this parameter. \
        Observation IDs start at 1 and increment sequentially.";

        json!({
            "type": "object",
            "properties": {
                "id": {
                    "type": "integer",
                    "description": id_description
                 },
            },
            "required": ["id"]
        })
    }

    fn map_error(&self, error: Self::Error) -> rig::tool::ToolExecutionError {
        rig::tool::ToolExecutionError::from_error(error)
    }
}