use crate::llm::compactors::SharedObservations;
use rig::{
message::ToolResultContent,
tool::{Tool, ToolContext},
};
use serde::{Deserialize, Serialize};
use serde_json::json;
#[derive(Debug, 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>;
#[tracing::instrument(skip(self, _context))]
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::ObservationNotFound {
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 integer ID `N` from a masked tool result placeholder (e.g., `[Observation:N - masked]`). \
For example, if you see '[Observation:3 - masked]', pass 3 as this parameter. \
**Only** use this tool to recover outputs that are explicitly masked in the *current* conversation history. \
Do not guess IDs or attempt to retrieve observations that are not currently visible as placeholders.";
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)
}
}