fix: improve cross-device evidence, request diagnostics and prompt efficiency
This commit is contained in:
1 parent
621f30e437
commit
a66803651a
60 files changed
+3097
-160
No files matched your search
@@ -178,7 +178,11 @@ def test_server_substitutions_do_not_use_shell_or_expand_unknown_values(tmp_path
|
||||
async def test_skill_load_and_reference_cannot_read_outside_package(store):
|
||||
enable(store, manifest())
|
||||
runtime = PluginRuntime(store=store)
|
||||
assert {t.name for t in runtime.declarations()} == {"plugin_load", "plugin_read_file"}
|
||||
assert {t.name for t in runtime.declarations()} == {
|
||||
"plugin_load",
|
||||
"plugin_read_file",
|
||||
"plugin_read_result",
|
||||
}
|
||||
result = await runtime.call("plugin_load", {"plugin_id": "test-plugin"})
|
||||
assert result.status == "success" and "先观察" in result.text()
|
||||
assert (
|
||||
@@ -659,7 +663,7 @@ server.run()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("target", ["computer", "mixed"])
|
||||
@pytest.mark.parametrize("target", ["computer", "mixed", "android"])
|
||||
async def test_flash_plugin_images_never_replace_the_mixed_phone_observation(monkeypatch, target):
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock, AsyncMock
|
||||
@@ -689,6 +693,16 @@ async def test_flash_plugin_images_never_replace_the_mixed_phone_observation(mon
|
||||
screenshot_bytes=b"desktop-after",
|
||||
ui_elements_text="desktop-tree",
|
||||
text_summary="Desktop observation",
|
||||
raw_result=[
|
||||
{"type": "text", "text": "Desktop observation"},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": "data:image/jpeg;base64,"
|
||||
+ base64.b64encode(b"desktop-after").decode()
|
||||
},
|
||||
},
|
||||
],
|
||||
metadata={"plugin_id": "test-plugin"},
|
||||
)
|
||||
),
|
||||
@@ -696,12 +710,13 @@ async def test_flash_plugin_images_never_replace_the_mixed_phone_observation(mon
|
||||
runner._build_action_record = Mock(return_value={"action": name})
|
||||
runner._record_action_step = Mock(return_value="step")
|
||||
state = SimpleNamespace(latest_screenshot="old-phone-path")
|
||||
messages = []
|
||||
result = await runner._execute_and_record_action(
|
||||
name,
|
||||
{},
|
||||
"tc",
|
||||
state,
|
||||
[],
|
||||
messages,
|
||||
"",
|
||||
{},
|
||||
b"phone-before",
|
||||
@@ -714,10 +729,17 @@ async def test_flash_plugin_images_never_replace_the_mixed_phone_observation(mon
|
||||
"",
|
||||
b"desktop-after",
|
||||
)
|
||||
if target == "mixed":
|
||||
assert result[:2] == (b"phone-after", "phone-tree-after")
|
||||
assert state.latest_screenshot == "phone-path"
|
||||
capture.assert_awaited_once()
|
||||
assert messages[0].tool_call_id == "tc"
|
||||
assert "Desktop observation" in str(messages[0].content)
|
||||
assert base64.b64encode(b"desktop-after").decode() in str(messages)
|
||||
if target != "computer":
|
||||
assert result[0] is None
|
||||
assert "安卓旧截图、元素编号和坐标已失效" in result[1]
|
||||
assert state.latest_screenshot is None
|
||||
assert state.indexed_elements == []
|
||||
assert state.indexed_points == []
|
||||
assert runner._android_observation_stale
|
||||
capture.assert_not_awaited()
|
||||
else:
|
||||
assert result[:2] == (b"desktop-after", "desktop-tree")
|
||||
capture.assert_not_awaited()
|
||||
@@ -1012,3 +1034,57 @@ async def test_plugin_image_text_stays_with_its_own_observation(store, tmp_path,
|
||||
assert engine.storage.get_image(names[1]).ui_tree == "changed"
|
||||
finally:
|
||||
await runtime.aclose()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_long_plugin_result_roundtrips_through_task_scoped_reader(store, tmp_path):
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
from mcp.types import Tool, ToolAnnotations
|
||||
from artemis.config.constants import PLUGIN_PROMPT_TEXT_CHARS
|
||||
|
||||
plugin = manifest()
|
||||
enable(store, plugin)
|
||||
engine = MagicMock(base_dir=tmp_path / "task-a")
|
||||
ctx = SimpleNamespace(data_engine=engine)
|
||||
runtime = PluginRuntime(store=store, ctx=ctx)
|
||||
tool = Tool(
|
||||
name="observe",
|
||||
inputSchema={"type": "object"},
|
||||
annotations=ToolAnnotations(readOnlyHint=True),
|
||||
)
|
||||
original = "private-value\n" + "node 中文\n" * 9000 + "END"
|
||||
runtime.bindings["plug_test_observe"] = (plugin.id, tool)
|
||||
session = SimpleNamespace(
|
||||
call=AsyncMock(
|
||||
return_value=CallToolResult(content=[TextContent(type="text", text=original)])
|
||||
)
|
||||
)
|
||||
runtime.sessions[plugin.id] = session
|
||||
try:
|
||||
outcome = await runtime.call("plug_test_observe", {})
|
||||
assert outcome.status == "success"
|
||||
assert outcome.text_ref == outcome.call_id
|
||||
assert runtime.is_read_only("plug_test_observe")
|
||||
shown = runtime.content_blocks(outcome)[0]["text"]
|
||||
assert len(shown) <= PLUGIN_PROMPT_TEXT_CHARS
|
||||
assert outcome.text_ref in shown
|
||||
text = outcome.text()
|
||||
pages = []
|
||||
for offset in range(0, len(text), PLUGIN_PROMPT_TEXT_CHARS):
|
||||
page = await runtime.call(
|
||||
"plugin_read_result", {"call_id": outcome.text_ref, "offset": offset}
|
||||
)
|
||||
assert page.status == "success"
|
||||
delivered = runtime.content_blocks(page)[0]["text"]
|
||||
pages.append(delivered.split("\n", 1)[1])
|
||||
assert "".join(pages) == text
|
||||
assert "private-value" not in text and "已隐藏密钥" in text
|
||||
assert text.endswith("END")
|
||||
engine.base_dir = tmp_path / "task-b"
|
||||
inaccessible = await runtime.call("plugin_read_result", {"call_id": outcome.text_ref})
|
||||
assert inaccessible.status == "error"
|
||||
session.call.assert_awaited_once()
|
||||
finally:
|
||||
runtime.sessions.clear()
|
||||
await runtime.aclose()
|
||||
Reference in new issue
Block a user