Fix image search: embed markdown instead of describing URLs
- tools.py: search_images result now includes 'embed' (ready-to-use markdown image syntax) and 'citation' fields instead of raw 'local_url'; adds 'instructions' field so the model knows to render them verbatim - llm.py: system prompt now explicitly tells the model to embed images using the 'embed' field rather than describing or listing URLs - markdown.ts: explicitly allow src/alt in PURIFY_OPTS_FULL so img tags are never stripped by DOMPurify Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,7 @@ const headingRenderer = {
|
|||||||
marked.use({ renderer: headingRenderer });
|
marked.use({ renderer: headingRenderer });
|
||||||
|
|
||||||
const PURIFY_OPTS_FULL = {
|
const PURIFY_OPTS_FULL = {
|
||||||
ADD_ATTR: ["data-tag", "data-title"],
|
ADD_ATTR: ["data-tag", "data-title", "src", "alt"],
|
||||||
FORCE_BODY: true,
|
FORCE_BODY: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -398,6 +398,11 @@ async def build_context(
|
|||||||
tool_lines.append("Use search_todos to find a specific CalDAV todo by keyword when list_todos would return too many results.")
|
tool_lines.append("Use search_todos to find a specific CalDAV todo by keyword when list_todos would return too many results.")
|
||||||
tool_lines.append("For relative dates like 'Friday' or 'next week', resolve them to YYYY-MM-DD format.")
|
tool_lines.append("For relative dates like 'Friday' or 'next week', resolve them to YYYY-MM-DD format.")
|
||||||
tool_lines.append("When creating notes, use the `tags` parameter — do not embed #tag text in the note body.")
|
tool_lines.append("When creating notes, use the `tags` parameter — do not embed #tag text in the note body.")
|
||||||
|
tool_lines.append(
|
||||||
|
"When search_images returns results, embed each image directly in your response by writing "
|
||||||
|
"the 'embed' field verbatim (e.g. ), then the 'citation' field on the "
|
||||||
|
"next line. Never describe images as text or list their URLs — always render them as markdown images."
|
||||||
|
)
|
||||||
tool_lines.append(
|
tool_lines.append(
|
||||||
"Use update_note to edit/expand an existing note OR to update a task's status/priority/due_date. "
|
"Use update_note to edit/expand an existing note OR to update a task's status/priority/due_date. "
|
||||||
"Use create_note ONLY for genuinely new notes with a different title. "
|
"Use create_note ONLY for genuinely new notes with a different title. "
|
||||||
|
|||||||
@@ -1264,18 +1264,28 @@ async def execute_tool(user_id: int, tool_name: str, arguments: dict) -> dict:
|
|||||||
source_domain=r.get("source_domain"),
|
source_domain=r.get("source_domain"),
|
||||||
)
|
)
|
||||||
if record:
|
if record:
|
||||||
|
title = record.title or query
|
||||||
|
page_url = r.get("page_url", "")
|
||||||
|
source_domain = r.get("source_domain", "")
|
||||||
images.append({
|
images.append({
|
||||||
"local_url": f"/api/images/{record.id}",
|
"embed": f"",
|
||||||
"page_url": r.get("page_url", ""),
|
"citation": f"*Source: [{source_domain or 'image'}]({page_url})*",
|
||||||
"source_domain": r.get("source_domain", ""),
|
"page_url": page_url,
|
||||||
"title": record.title or query,
|
"title": title,
|
||||||
})
|
})
|
||||||
if not images:
|
if not images:
|
||||||
return {"success": False, "error": f"Could not retrieve images for '{query}'"}
|
return {"success": False, "error": f"Could not retrieve images for '{query}'"}
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"type": "image_search",
|
"type": "image_search",
|
||||||
"data": {"query": query, "images": images},
|
"data": {
|
||||||
|
"query": query,
|
||||||
|
"images": images,
|
||||||
|
"instructions": (
|
||||||
|
"Embed each image in your response by writing the 'embed' field verbatim, "
|
||||||
|
"then the 'citation' field on the next line. Do not paraphrase or list URLs."
|
||||||
|
),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user