use std::sync::Arc;
use async_trait::async_trait;
use serde_json::{json, Value};
use crate::error::Result;
use crate::tools::{Tool, ToolContext};
pub struct RenderHtml;
crate::tool_params! {
struct Args: lenient {
source: req_str = "the HTML document to render",
}
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl Tool for RenderHtml {
fn name(&self) -> &str {
"render_html"
}
fn description(&self) -> &str {
"Render an HTML document onto the visual display (a 512x512 pixel \
framebuffer the user sees). This is a snapshot text renderer, NOT \
a browser: it shows block-level text (h1-h6, p, ul/li, blockquote, \
br) laid out and word-wrapped in a bitmap font, monochrome. It does \
NOT run JavaScript, apply CSS, or load images — headings just get a \
bigger font. Pass the full HTML source as `source`. For an \
interactive or animated app, use `run_cartridge` instead. Tip: pair \
with create_file to save the same HTML as `index.html` if you want \
it to persist."
}
fn input_schema(&self) -> Value {
Args::schema()
}
async fn execute(&self, args: Value, _ctx: Option<Arc<ToolContext>>) -> Result<Value> {
let Args { source } = Args::lenient(&args);
if source.is_empty() {
return Ok(json!({ "error": "source is required" }));
}
#[cfg(all(target_arch = "wasm32", feature = "browser-app"))]
{
match crate::app::display::render_html(&source) {
Ok(()) => Ok(json!({ "status": "rendered on display" })),
Err(err) => Ok(json!({
"error": "render failed",
"detail": format!("{err:?}")
})),
}
}
#[cfg(not(all(target_arch = "wasm32", feature = "browser-app")))]
{
Ok(json!({
"rendered": false,
"note": "the visual display requires the browser app"
}))
}
}
}
#[cfg(test)]
mod schema_tests {
use super::Args;
use serde_json::json;
#[test]
fn schema_is_byte_identical_to_the_frozen_original() {
let frozen = json!({
"type": "object",
"properties": {
"source": {
"type": "string",
"description": "the HTML document to render"
}
},
"required": ["source"]
});
assert_eq!(Args::schema().to_string(), frozen.to_string());
}
}