|
16 | 16 | from typing import TYPE_CHECKING, Any |
17 | 17 |
|
18 | 18 | from . import config |
| 19 | +from .attachments import image_placeholder |
19 | 20 | from .client import Client, LLMClient |
20 | 21 | from .diffrender import sanitize_for_display |
21 | 22 | from .mcp.config import MCPConfig |
22 | 23 | from .mcp.manager import MCPManager |
23 | | -from .models import AgentMode |
| 24 | +from .models import AgentMode, ImagePart |
24 | 25 | from .persistence import SessionPersistence, escape_role_headers |
25 | 26 | from .planmode import PlanMode |
26 | 27 | from .prompts import RESERVED_AGENT_NAME, _tool_excluded, discover_agents, index_skills |
@@ -650,6 +651,18 @@ def _conversation_text(self, messages: list) -> str: |
650 | 651 | # escaped: a body line that looks like a `**role**: ` block |
651 | 652 | # header would otherwise split the message on restore |
652 | 653 | body = escape_role_headers(m.text()) |
| 654 | + # Mark messages that contained image attachments: the image |
| 655 | + # data itself cannot be persisted in the markdown format, so |
| 656 | + # a placeholder notes what was attached. The original file |
| 657 | + # path (when the image came from a path) is recorded so a |
| 658 | + # restored session can re-attach it. On restore, the |
| 659 | + # placeholder text survives so the user/agent knows an image |
| 660 | + # was present but is no longer available. |
| 661 | + if isinstance(m.content, list): |
| 662 | + image_count = sum(1 for p in m.content if isinstance(p, ImagePart)) |
| 663 | + if image_count: |
| 664 | + paths = [p.path for p in m.content if isinstance(p, ImagePart) and p.path] |
| 665 | + body = f"{image_placeholder(image_count, paths)}\n{body}" |
653 | 666 | if m.role == "assistant" and m.tool_calls: |
654 | 667 | calls = ", ".join(tc.name for tc in m.tool_calls) |
655 | 668 | body = (body + f"\n[tool calls: {calls}]").strip() |
|
0 commit comments