"""content_publish tool — publish a file for inline viewing in the chat client.
Copies the file into the content store (navi/content/<uuid>/) and returns a URL
served via /content/<uuid>/filename. The client renders it as an interactive card.
"""
from pathlib import Path
from navi.content_store import publish
from .base import Tool, ToolResult, current_session_id
class ContentPublishTool(Tool):
name = "content_publish"
description = (
"Publish a file for inline viewing in the chat client. "
"Use this when you generate or produce content the user will want to see interactively "
"(3D models, HTML pages, SVG graphics, etc.). "
"The file will be copied to a public URL and displayed as an embeddable card. "
"IMPORTANT — path must be an ABSOLUTE path (e.g. /home/user/model.stl)."
)
parameters = {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Absolute path to the file to publish",
},
"filename": {
"type": "string",
"description": (
"Published filename shown to the user. "
"Defaults to the original filename."
),
},
"title": {
"type": "string",
"description": "Human-readable title for the content card",
},
"content_type": {
"type": "string",
"enum": ["stl", "html", "svg", "pdf", "image", "video", "unknown"],
"description": "Content type for viewer selection. Auto-detected from extension if omitted.",
},
},
"required": ["path"],
}
async def execute(self, params: dict) -> ToolResult:
session_id = current_session_id.get()
if not session_id:
return ToolResult(success=False, output="No active session context.", error="no_session")
src = Path(params["path"]).expanduser().resolve()
if not src.exists():
return ToolResult(success=False, output=f"File not found: {src}", error="not_found")
if not src.is_file():
return ToolResult(success=False, output=f"Path is not a file: {src}", error="not_a_file")
try:
info = await publish(
session_id=session_id,
src_path=src,
filename=params.get("filename"),
title=params.get("title"),
content_type=params.get("content_type"),
)
except Exception as e:
return ToolResult(success=False, output=f"Publish failed: {e}", error="publish_failed")
return ToolResult(
success=True,
output=(
f"Published: {info['title']} ({info['content_type']})\n"
f"URL: {info['url']}\n"
f"ID: {info['id']}"
),
metadata=info,
)