163 lines
5.8 KiB
Python
163 lines
5.8 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from utils.context_manager import ContextManager
|
|
from utils.tool_result_formatter import (
|
|
extract_mcp_content_for_context,
|
|
format_tool_result_for_context,
|
|
)
|
|
|
|
|
|
class MediaStoreAndMCPContentTest(unittest.TestCase):
|
|
def setUp(self):
|
|
self.temp_dir = tempfile.TemporaryDirectory()
|
|
root = Path(self.temp_dir.name)
|
|
self.project_dir = root / "project"
|
|
self.project_dir.mkdir(parents=True, exist_ok=True)
|
|
self.data_dir = root / "data"
|
|
self.data_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
def tearDown(self):
|
|
self.temp_dir.cleanup()
|
|
|
|
def test_media_store_survives_source_file_deletion(self):
|
|
image_path = self.project_dir / "demo.png"
|
|
image_path.write_bytes(b"\x89PNG\r\n\x1a\nfake-image-data")
|
|
|
|
ctx = ContextManager(project_path=str(self.project_dir), data_dir=str(self.data_dir))
|
|
conv_id = ctx.start_new_conversation(project_path=str(self.project_dir), thinking_mode=False)
|
|
ctx.add_conversation("user", "看图", images=["demo.png"])
|
|
message = ctx.conversation_history[-1]
|
|
|
|
refs = message.get("media_refs") or []
|
|
self.assertTrue(refs, message)
|
|
self.assertEqual(refs[0].get("kind"), "image")
|
|
|
|
image_path.unlink()
|
|
payload = ctx._build_content_with_images(
|
|
message.get("content") or "",
|
|
message.get("images") or [],
|
|
message.get("videos") or [],
|
|
media_refs=refs,
|
|
)
|
|
|
|
self.assertIsInstance(payload, list, payload)
|
|
image_parts = [item for item in payload if isinstance(item, dict) and item.get("type") == "image_url"]
|
|
self.assertTrue(image_parts, payload)
|
|
self.assertTrue(str(image_parts[0].get("image_url", {}).get("url", "")).startswith("data:image/"))
|
|
|
|
index_file = self.data_dir / "conversations" / "media_store" / "index.json"
|
|
self.assertTrue(index_file.exists())
|
|
index_data = json.loads(index_file.read_text(encoding="utf-8"))
|
|
self.assertIn(conv_id, index_data.get("message_map", {}))
|
|
self.assertIn(message.get("message_id"), (index_data.get("message_map", {}).get(conv_id) or {}))
|
|
|
|
def test_add_tool_message_with_inline_mcp_media_refs(self):
|
|
ctx = ContextManager(project_path=str(self.project_dir), data_dir=str(self.data_dir))
|
|
ctx.start_new_conversation(project_path=str(self.project_dir), thinking_mode=False)
|
|
|
|
saved = ctx.add_conversation(
|
|
"tool",
|
|
"截图已记录",
|
|
tool_call_id="call_1",
|
|
name="mcp__browsermcp__browser_screenshot",
|
|
media_refs=[
|
|
{
|
|
"kind": "image",
|
|
"mime_type": "image/png",
|
|
"data_base64": "aGVsbG8=",
|
|
"source": "mcp_content",
|
|
}
|
|
],
|
|
)
|
|
|
|
refs = (saved or {}).get("media_refs") or []
|
|
self.assertTrue(refs, saved)
|
|
self.assertTrue(str(refs[0].get("media_id") or "").startswith("sha256:"))
|
|
|
|
payload = ctx._build_content_with_images(
|
|
saved.get("content") or "",
|
|
[],
|
|
[],
|
|
media_refs=refs,
|
|
)
|
|
self.assertIsInstance(payload, list, payload)
|
|
image_parts = [item for item in payload if isinstance(item, dict) and item.get("type") == "image_url"]
|
|
self.assertTrue(image_parts, payload)
|
|
self.assertTrue(str(image_parts[0].get("image_url", {}).get("url", "")).startswith("data:image/png;base64,"))
|
|
|
|
def test_mcp_formatter_keeps_non_text_information(self):
|
|
result_data = {
|
|
"success": True,
|
|
"server_id": "browsermcp",
|
|
"tool_alias": "mcp__browsermcp__browser_screenshot",
|
|
"tool_name": "browser_screenshot",
|
|
"message": "MCP 工具调用完成",
|
|
"content": [
|
|
{
|
|
"type": "image",
|
|
"mimeType": "image/png",
|
|
"data": "aGVsbG8=",
|
|
}
|
|
],
|
|
"raw_result": {
|
|
"content": [
|
|
{
|
|
"type": "image",
|
|
"mimeType": "image/png",
|
|
"data": "aGVsbG8=",
|
|
}
|
|
]
|
|
},
|
|
}
|
|
|
|
text = format_tool_result_for_context("mcp__browsermcp__browser_screenshot", result_data, "")
|
|
self.assertIn("MCP image #1", text)
|
|
parsed = extract_mcp_content_for_context(result_data)
|
|
self.assertTrue(parsed.get("media_items"))
|
|
sanitized = parsed.get("sanitized_payload") or {}
|
|
content = (sanitized.get("content") or [{}])[0]
|
|
self.assertNotIn("data", content)
|
|
self.assertTrue(content.get("data_omitted"))
|
|
|
|
def test_mcp_formatter_returns_empty_when_content_is_empty(self):
|
|
result_data = {
|
|
"success": True,
|
|
"server_id": "browsermcp",
|
|
"tool_alias": "mcp__browsermcp__browser_get_console_logs",
|
|
"tool_name": "browser_get_console_logs",
|
|
"message": "MCP 工具调用完成",
|
|
"content": [
|
|
{
|
|
"type": "text",
|
|
"text": "",
|
|
}
|
|
],
|
|
"raw_result": {
|
|
"content": [
|
|
{
|
|
"type": "text",
|
|
"text": "",
|
|
}
|
|
]
|
|
},
|
|
}
|
|
|
|
parsed = extract_mcp_content_for_context(result_data)
|
|
self.assertEqual(parsed.get("text"), "")
|
|
|
|
text = format_tool_result_for_context(
|
|
"mcp__browsermcp__browser_get_console_logs",
|
|
result_data,
|
|
raw_text='{"success": true}',
|
|
)
|
|
self.assertEqual(text, "")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|