Files
2026-07-13 13:12:33 +08:00

2966 lines
102 KiB
Python

from __future__ import annotations
import hashlib
import json
from collections.abc import AsyncIterator
from types import SimpleNamespace
from typing import Any
import pytest
from opensquilla.engine import Agent, AgentConfig, ToolResult, ToolResultEvent
from opensquilla.engine.history import limit_turns
from opensquilla.engine.session_sanitize import (
project_historical_tool_payloads,
sanitize_session_messages,
)
from opensquilla.engine.types import ThinkingLevel
from opensquilla.memory.session_flush import _usage_from_complete_response
from opensquilla.provider import (
ChatConfig,
ContentBlockText,
ContentBlockToolResult,
ContentBlockToolUse,
Message,
ModelCapabilities,
)
from opensquilla.provider import (
DoneEvent as ProviderDone,
)
from opensquilla.provider import (
TextDeltaEvent as ProviderText,
)
from opensquilla.provider import (
ToolUseEndEvent as ProviderToolUseEnd,
)
from opensquilla.provider import (
ToolUseStartEvent as ProviderToolUseStart,
)
from opensquilla.provider.types import ContentBlockImage
def test_agent_config_disables_tool_argument_projection_by_default() -> None:
assert AgentConfig().tool_use_argument_projection_enabled is False
class CapturingProvider:
provider_name = "fake"
def __init__(self) -> None:
self.calls: list[dict[str, Any]] = []
def chat(
self,
messages: list[Message],
tools: list[Any] | None = None,
config: ChatConfig | None = None,
) -> AsyncIterator[Any]:
self.calls.append({"messages": messages, "tools": tools, "config": config})
return self._stream()
async def _stream(self) -> AsyncIterator[Any]:
yield ProviderText(text="ok")
yield ProviderDone(stop_reason="end_turn", input_tokens=3, output_tokens=1)
async def list_models(self) -> list[Any]:
return []
class StaticCostProvider(CapturingProvider):
async def _stream(self) -> AsyncIterator[Any]:
yield ProviderText(text="ok")
yield ProviderDone(
stop_reason="end_turn",
input_tokens=1000,
output_tokens=1000,
billed_cost=0.0,
model="deepseek-v4-flash",
)
class ToolLoopCapturingProvider:
provider_name = "fake"
def __init__(self) -> None:
self.calls: list[dict[str, Any]] = []
def chat(
self,
messages: list[Message],
tools: list[Any] | None = None,
config: ChatConfig | None = None,
) -> AsyncIterator[Any]:
call_number = len(self.calls) + 1
self.calls.append({"messages": messages, "tools": tools, "config": config})
return self._stream(call_number)
async def _stream(self, call_number: int) -> AsyncIterator[Any]:
if call_number == 1:
yield ProviderToolUseStart(tool_use_id="tool-1", tool_name="echo")
yield ProviderToolUseEnd(
tool_use_id="tool-1",
tool_name="echo",
arguments={"value": "ok"},
)
yield ProviderDone(stop_reason="tool_use", input_tokens=3, output_tokens=1)
return
yield ProviderText(text="done")
yield ProviderDone(stop_reason="end_turn", input_tokens=4, output_tokens=1)
async def list_models(self) -> list[Any]:
return []
class ReasoningToolLoopCapturingProvider(ToolLoopCapturingProvider):
async def _stream(self, call_number: int) -> AsyncIterator[Any]:
if call_number == 1:
yield ProviderToolUseStart(tool_use_id="tool-1", tool_name="echo")
yield ProviderToolUseEnd(
tool_use_id="tool-1",
tool_name="echo",
arguments={"value": "ok"},
)
yield ProviderDone(
stop_reason="tool_use",
input_tokens=3,
output_tokens=1,
reasoning_content="I should call echo before finalizing.",
)
return
yield ProviderText(text="done")
yield ProviderDone(stop_reason="end_turn", input_tokens=4, output_tokens=1)
class LargeArgumentToolLoopCapturingProvider(ToolLoopCapturingProvider):
def __init__(self, code: str) -> None:
super().__init__()
self.code = code
async def _stream(self, call_number: int) -> AsyncIterator[Any]:
if call_number == 1:
yield ProviderToolUseStart(tool_use_id="tool-1", tool_name="execute_code")
yield ProviderToolUseEnd(
tool_use_id="tool-1",
tool_name="execute_code",
arguments={"code": self.code, "timeout": 10},
)
yield ProviderDone(stop_reason="tool_use", input_tokens=3, output_tokens=1)
return
yield ProviderText(text="done")
yield ProviderDone(stop_reason="end_turn", input_tokens=4, output_tokens=1)
class CopiedProjectionToolLoopCapturingProvider(LargeArgumentToolLoopCapturingProvider):
async def _stream(self, call_number: int) -> AsyncIterator[Any]:
if call_number == 1:
async for event in super()._stream(call_number):
yield event
return
if call_number == 2:
projection = self._legacy_projected_code_argument()
yield ProviderToolUseStart(tool_use_id="tool-2", tool_name="execute_code")
yield ProviderToolUseEnd(
tool_use_id="tool-2",
tool_name="execute_code",
arguments={"code": projection, "timeout": 99},
)
yield ProviderDone(stop_reason="tool_use", input_tokens=3, output_tokens=1)
return
yield ProviderText(text="done")
yield ProviderDone(stop_reason="end_turn", input_tokens=4, output_tokens=1)
def _legacy_projected_code_argument(self) -> str:
return (
"[tool_use_argument_projection]\n"
"tool: execute_code\n"
"tool_use_id: tool-1\n"
"field: code\n"
f"original_chars: {len(self.code)}\n"
f"original_input_chars: {len(self.code)}\n"
"sha256: " + hashlib.sha256(self.code.encode("utf-8")).hexdigest() + "\n"
"tool_argument_handle: tr-1234567890abcdef1234567890abcdef\n"
"omitted_chars: 123\n"
"reason: legacy test marker\n"
)
class CompactedToolArgumentsProvider(ToolLoopCapturingProvider):
async def _stream(self, call_number: int) -> AsyncIterator[Any]:
if call_number == 1:
yield ProviderToolUseStart(tool_use_id="tool-compact", tool_name="exec_command")
yield ProviderToolUseEnd(
tool_use_id="tool-compact",
tool_name="exec_command",
arguments={
"_opensquilla_compacted_tool_arguments": True,
"original_chars": 549,
"sha256": "0" * 64,
"argument_keys": ["command", "timeout"],
},
)
yield ProviderDone(stop_reason="tool_use", input_tokens=3, output_tokens=1)
return
yield ProviderText(text="done")
yield ProviderDone(stop_reason="end_turn", input_tokens=4, output_tokens=1)
class TextThenCompactedToolArgumentsProvider(ToolLoopCapturingProvider):
async def _stream(self, call_number: int) -> AsyncIterator[Any]:
if call_number == 1:
yield ProviderText(text="I will prepare the file, then run the tool.")
yield ProviderToolUseStart(tool_use_id="tool-compact", tool_name="write_file")
yield ProviderToolUseEnd(
tool_use_id="tool-compact",
tool_name="write_file",
arguments={
"_opensquilla_compacted_tool_arguments": True,
"tool": "write_file",
"reason": "provider_context_omitted",
},
)
yield ProviderDone(stop_reason="tool_use", input_tokens=3, output_tokens=1)
return
yield ProviderText(text="done")
yield ProviderDone(stop_reason="end_turn", input_tokens=4, output_tokens=1)
class ProviderRequestCompactedArgumentStringProvider(ToolLoopCapturingProvider):
async def _stream(self, call_number: int) -> AsyncIterator[Any]:
if call_number == 1:
yield ProviderToolUseStart(
tool_use_id="tool-provider-request",
tool_name="exec_command",
)
yield ProviderToolUseEnd(
tool_use_id="tool-provider-request",
tool_name="exec_command",
arguments={
"command": (
"[provider_request_tool_input_compacted: original_chars=987; "
"sha256=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]"
),
},
)
yield ProviderDone(stop_reason="tool_use", input_tokens=3, output_tokens=1)
return
yield ProviderText(text="done")
yield ProviderDone(stop_reason="end_turn", input_tokens=4, output_tokens=1)
class MidStringCompactedArgumentStringProvider(ToolLoopCapturingProvider):
async def _stream(self, call_number: int) -> AsyncIterator[Any]:
if call_number == 1:
yield ProviderToolUseStart(
tool_use_id="tool-mid-string",
tool_name="edit_file",
)
yield ProviderToolUseEnd(
tool_use_id="tool-mid-string",
tool_name="edit_file",
arguments={
"path": "src/example.py",
"old_text": (
"def load(self):\n"
" [provider_request_tool_result_compacted: omitted 4210 "
"chars; original_chars=4655; sha256="
+ "b" * 64
+ "]\n\n return data\n"
),
"new_text": "def load(self):\n return data\n",
},
)
yield ProviderDone(stop_reason="tool_use", input_tokens=3, output_tokens=1)
return
yield ProviderText(text="done")
yield ProviderDone(stop_reason="end_turn", input_tokens=4, output_tokens=1)
class CapturingTurnLog:
def __init__(self) -> None:
self.records: list[dict[str, Any]] = []
def write(self, kind: str, payload: dict[str, Any]) -> None:
self.records.append({"kind": kind, "payload": payload})
def test_session_sanitize_strips_block_metadata_without_compressing_content() -> None:
message = Message.model_construct(
role="user",
content=[
{
"type": "tool_result",
"tool_use_id": "call_1",
"content": "result text with details that must remain factual",
"is_error": False,
"details": {"raw_provider": "debug-only"},
"timestamp": "2026-04-28T14:35:00Z",
}
],
reasoning_content=None,
)
sanitized, result = sanitize_session_messages([message])
assert result.metadata_keys_removed == 2
block = sanitized[0].content[0]
assert isinstance(block, ContentBlockToolResult)
assert block.content == "result text with details that must remain factual"
assert "details" not in block.model_dump(mode="json")
assert "timestamp" not in block.model_dump(mode="json")
def test_historical_replay_projection_compacts_tool_payloads_and_reasoning() -> None:
large_argument = "STALE_ARGUMENT_START\n" + ("x" * 6000)
large_result = "STALE_RESULT_START\n" + ("y" * 6000)
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="write-1",
name="write_file",
input={"path": "index.html", "content": large_argument},
)
],
reasoning_content="hidden reasoning\n" + ("r" * 4000),
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="write-1",
content=large_result,
is_error=False,
)
],
),
]
projected, result = project_historical_tool_payloads(messages)
assert result.tool_uses_projected == 1
assert result.tool_results_projected == 1
assert result.reasoning_chars_removed > 0
assert projected[0].reasoning_content is None
tool_use = projected[0].content[0]
assert isinstance(tool_use, ContentBlockToolUse)
assert tool_use.input["path"] == "index.html"
assert tool_use.input["content"].startswith("[historical_tool_argument_omitted]\n")
assert large_argument not in tool_use.input["content"]
tool_result = projected[1].content[0]
assert isinstance(tool_result, ContentBlockToolResult)
assert str(tool_result.content).startswith("[historical_tool_result_compacted]")
assert large_result not in str(tool_result.content)
assert messages[0].reasoning_content is not None
assert messages[0].content[0].input["content"] == large_argument
def test_historical_replay_projection_preserves_tool_result_projection_envelope() -> None:
projection = (
"[tool_result_projection]\n"
"tool_result_handle: tr-abc123\n"
"sha256: " + ("a" * 64) + "\n"
"original_chars: 50000\n"
"preview_complete: false\n"
"retrieve_hint: use retrieve_tool_result with this tool_result_handle.\n"
+ ("body line before hints\n" * 80)
+ "search_hints:\n"
"- L42: FAILED tests/test_api.py::test_bad - AssertionError\n"
+ ("large projected body\n" * 2000)
)
messages = [
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="tool-1",
content=projection,
is_error=True,
)
],
)
]
projected, result = project_historical_tool_payloads(messages)
assert result.tool_results_projected == 1
tool_result = projected[0].content[0]
assert isinstance(tool_result, ContentBlockToolResult)
assert isinstance(tool_result.content, str)
assert tool_result.content.startswith("[tool_result_projection]\n")
assert "tool_result_handle: tr-abc123" in tool_result.content
assert "sha256: " + ("a" * 64) in tool_result.content
assert "original_chars: 50000" in tool_result.content
assert "preview_complete: false" in tool_result.content
assert "retrieve_hint:" in tool_result.content
assert "search_hints:" in tool_result.content
assert "FAILED tests/test_api.py::test_bad" in tool_result.content
assert "[historical_tool_result_projection_body_compacted]" in tool_result.content
assert tool_result.content.count("large projected body") < 50
def test_historical_replay_projection_compacts_nested_tool_payloads() -> None:
large_content = "CONTENT_START\n" + ("c" * 3000)
large_nested = {"blob": "NESTED_START\n" + ("n" * 20_000)}
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="nested-1",
name="write_file",
input={
"path": "index.html",
"content": large_content,
"metadata": large_nested,
},
)
],
)
]
projected, result = project_historical_tool_payloads(messages)
assert result.tool_uses_projected == 1
tool_use = projected[0].content[0]
assert isinstance(tool_use, ContentBlockToolUse)
assert tool_use.input["path"] == "index.html"
assert tool_use.input["content"].startswith("[historical_tool_argument_omitted]\n")
assert tool_use.input["metadata"].startswith("[historical_tool_argument_omitted]\n")
payload = json.dumps(tool_use.input, ensure_ascii=False)
assert "c" * 1000 not in payload
assert "n" * 1000 not in payload
assert messages[0].content[0].input["metadata"] == large_nested
def test_historical_replay_projection_compacts_list_tool_results() -> None:
large_result = [{"type": "text", "text": "LIST_RESULT_START\n" + ("y" * 8000)}]
messages = [
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="list-result-1",
content=large_result,
is_error=False,
)
],
)
]
projected, result = project_historical_tool_payloads(messages)
assert result.tool_results_projected == 1
tool_result = projected[0].content[0]
assert isinstance(tool_result, ContentBlockToolResult)
assert isinstance(tool_result.content, str)
assert tool_result.content.startswith("[historical_tool_result_compacted]")
assert "y" * 1000 not in tool_result.content
assert messages[0].content[0].content == large_result
def test_agent_aggregate_tool_result_budget_compacts_old_bulky_results() -> None:
raw_old_output = "old bulky output\n" + ("x" * 4000)
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=200,
),
)
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(id="old-1", name="execute_code", input={}),
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="old-1",
content=raw_old_output,
is_error=False,
)
],
),
Message(
role="assistant",
content=[
ContentBlockToolUse(id="err-1", name="execute_code", input={}),
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="err-1",
content="Traceback\n" + ("e" * 4000),
is_error=True,
)
],
),
Message(
role="assistant",
content=[
ContentBlockToolUse(id="new-1", name="execute_code", input={}),
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="new-1",
content="recent output\n" + ("r" * 4000),
is_error=False,
)
],
),
]
compacted = agent._compact_aggregate_tool_results_for_provider(messages)
old_result = compacted[1].content[0]
err_result = compacted[3].content[0]
new_result = compacted[5].content[0]
assert isinstance(old_result, ContentBlockToolResult)
assert isinstance(err_result, ContentBlockToolResult)
assert isinstance(new_result, ContentBlockToolResult)
assert "aggregate_tool_result_compacted" in old_result.content
assert "tool_result_handle:" not in old_result.content
assert len(old_result.content) < 1000
assert "Traceback" in err_result.content
assert len(err_result.content) > 4000
assert "recent output" in new_result.content
assert len(new_result.content) > 4000
assert agent.config.metadata["tool_aggregate_projection_applied"] is True
assert agent.config.metadata["tool_projection_applied"] is True
assert agent.config.metadata["tool_projection_tokens_saved"] > 0
def test_agent_large_context_compacts_old_local_tool_results_for_provider() -> None:
def _tool_pair(tool_id: str, body: str, *, is_error: bool = False) -> list[Message]:
return [
Message(
role="assistant",
content=[ContentBlockToolUse(id=tool_id, name="local_tool", input={})],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id=tool_id,
content=body,
is_error=is_error,
)
],
),
]
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=200_000,
),
)
messages = [
block
for pair in (
_tool_pair("old-1", "old local output\n" + ("x" * 70_000)),
_tool_pair(
"err-1",
"Traceback preserved\n" + ("e" * 20_000),
is_error=True,
),
_tool_pair("mid-1", "middle local output\n" + ("m" * 50_000)),
_tool_pair("new-1", "recent local output\n" + ("r" * 50_000)),
)
for block in pair
]
compacted = agent._compact_aggregate_tool_results_for_provider(messages)
old_result = compacted[1].content[0]
error_result = compacted[3].content[0]
middle_result = compacted[5].content[0]
recent_result = compacted[7].content[0]
assert isinstance(old_result, ContentBlockToolResult)
assert isinstance(error_result, ContentBlockToolResult)
assert isinstance(middle_result, ContentBlockToolResult)
assert isinstance(recent_result, ContentBlockToolResult)
assert "[tool_result_projection]" in old_result.content
assert "tool_result_handle:" not in old_result.content
assert len(old_result.content) < 5_000
assert "Traceback preserved" in error_result.content
assert len(error_result.content) > 20_000
assert "middle local output" in middle_result.content
assert "recent local output" in recent_result.content
total_result_chars = sum(
len(block.content)
for message in compacted
if isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolResult)
)
assert total_result_chars <= agent._tool_result_provider_request_max_chars()
assert agent.config.metadata["tool_provider_guard_projection_applied"] is True
@pytest.mark.asyncio
async def test_agent_single_tool_result_projection_does_not_store_raw_content(tmp_path) -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=200,
),
)
raw_output = "single bulky output\n" + ("x" * 8000)
messages = [
Message(
role="assistant",
content=[ContentBlockToolUse(id="tool-1", name="execute_code", input={})],
),
Message(
role="user",
content=[ContentBlockToolResult(tool_use_id="tool-1", content=raw_output)],
),
]
projected = agent._compact_aggregate_tool_results_for_provider(messages)
result = projected[1].content[0]
assert isinstance(result, ContentBlockToolResult)
assert "[tool_result_projection]" in result.content
assert "tool_result_handle:" not in result.content
assert raw_output not in result.content
assert not (tmp_path / "tool-results").exists()
@pytest.mark.asyncio
async def test_agent_tool_result_projection_never_writes_raw_store(
tmp_path,
) -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=200,
),
)
messages = [
Message(
role="assistant",
content=[ContentBlockToolUse(id="tool-1", name="execute_code", input={})],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="tool-1",
content="single bulky output\n" + ("x" * 8000),
)
],
),
]
projected = agent._compact_aggregate_tool_results_for_provider(messages)
result = projected[1].content[0]
assert isinstance(result, ContentBlockToolResult)
assert "[tool_result_projection]" in result.content
assert "tool_result_handle:" not in result.content
assert not list((tmp_path / "tool-results").rglob("content.txt"))
def test_agent_provider_backstop_preserves_historical_read_file_source_context() -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=1_000_000,
tool_result_provider_request_max_chars=1000,
),
)
source = "\n".join(f"{index}: important implementation detail" for index in range(600))
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="read-1",
name="read_file",
input={"path": "src/lib.rs"},
)
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="read-1",
content=source,
is_error=False,
)
],
),
]
compacted = agent._compact_aggregate_tool_results_for_provider(messages)
result = compacted[1].content[0]
assert isinstance(result, ContentBlockToolResult)
assert result.content == source
assert "[tool_result_projection]" not in result.content
assert agent.config.metadata["tool_provider_projection_semantic_preserves"] == 1
assert "tool_provider_guard_projection_applied" not in agent.config.metadata
def test_agent_provider_backstop_preserves_historical_exec_source_context() -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=1_000_000,
tool_result_provider_request_max_chars=1000,
),
)
source = "\n".join(f"{index}: fn important_{index}() {{}}" for index in range(500))
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="exec-1",
name="exec_command",
input={"command": "sed -n '1,500p' src/lib.rs"},
)
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="exec-1",
content=source,
is_error=False,
)
],
),
]
compacted = agent._compact_aggregate_tool_results_for_provider(messages)
result = compacted[1].content[0]
assert isinstance(result, ContentBlockToolResult)
assert result.content == source
assert "[tool_result_projection]" not in result.content
assert agent.config.metadata["tool_provider_projection_semantic_preserves"] == 1
assert "tool_provider_guard_projection_applied" not in agent.config.metadata
def test_agent_aggregate_tool_result_budget_uses_total_not_single_result_size() -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=1200,
),
)
messages: list[Message] = []
for index in range(5):
tool_id = f"tool-{index}"
messages.extend(
[
Message(
role="assistant",
content=[
ContentBlockToolUse(id=tool_id, name="execute_code", input={}),
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id=tool_id,
content=f"chunk {index}\n" + ("x" * 800),
is_error=False,
)
],
),
]
)
compacted = agent._compact_aggregate_tool_results_for_provider(messages)
compacted_contents = [
message.content[0].content
for message in compacted
if isinstance(message.content, list)
and message.content
and isinstance(message.content[0], ContentBlockToolResult)
]
assert any("aggregate_tool_result_compacted" in content for content in compacted_contents)
assert "recent output" not in "\n".join(compacted_contents)
def test_agent_aggregate_projection_preserves_historical_read_file_source_context() -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=1200,
tool_result_provider_request_max_chars=1_000_000,
),
)
source = "\n".join(f"{index}: important source line" for index in range(500))
messages: list[Message] = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="read-1",
name="read_file",
input={"path": "src/lib.rs"},
)
],
),
Message(
role="user",
content=[ContentBlockToolResult(tool_use_id="read-1", content=source)],
),
]
for index in range(5):
tool_id = f"tool-{index}"
messages.extend(
[
Message(
role="assistant",
content=[
ContentBlockToolUse(id=tool_id, name="execute_code", input={}),
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id=tool_id,
content=f"chunk {index}\n" + ("x" * 800),
is_error=False,
)
],
),
]
)
compacted = agent._compact_aggregate_tool_results_for_provider(messages)
projected_contents = [
block.content
for message in compacted
if isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolResult)
]
assert projected_contents[0] == source
assert "[tool_result_projection]" not in projected_contents[0]
assert any("aggregate_tool_result_compacted" in content for content in projected_contents[1:])
assert agent.config.metadata["tool_provider_projection_semantic_preserves"] >= 1
def test_agent_aggregate_tool_result_budget_keeps_projected_history_stable() -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=1200,
),
)
messages: list[Message] = []
original_contents: dict[str, str] = {}
for index in range(5):
tool_id = f"tool-{index}"
content = (
"[tool_result_projection]\n"
f"tool_use_id: {tool_id}\n"
f"sha256: {hashlib.sha256(tool_id.encode()).hexdigest()}\n"
f"head:\nprojected chunk {index}\n"
+ ("x" * 800)
)
original_contents[tool_id] = content
messages.extend(
[
Message(
role="assistant",
content=[
ContentBlockToolUse(id=tool_id, name="execute_code", input={}),
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id=tool_id,
content=content,
is_error=False,
)
],
),
]
)
compacted = agent._compact_aggregate_tool_results_for_provider(messages)
projected_contents = {
block.tool_use_id: block.content
for message in compacted
if isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolResult)
}
assert projected_contents == original_contents
def test_agent_provider_backstop_classifies_external_results_from_tool_use_names() -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=1_000_000,
tool_result_provider_request_max_chars=1300,
tool_result_external_keep_recent=2,
),
)
messages: list[Message] = []
for index in range(4):
tool_id = f"fetch-{index}"
messages.extend(
[
Message(
role="assistant",
content=[
ContentBlockToolUse(
id=tool_id,
name="web_fetch",
input={"url": f"https://example.com/{index}"},
),
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id=tool_id,
content=f"fetch {index}\n" + ("x" * 5000),
is_error=False,
)
],
),
]
)
compacted = agent._compact_aggregate_tool_results_for_provider(messages)
external_contents = [
message.content[0].content
for message in compacted
if isinstance(message.content, list)
and message.content
and isinstance(message.content[0], ContentBlockToolResult)
]
assert "fetch 3" in external_contents[-1]
assert "fetch 2" in external_contents[-2]
assert any("[tool_result_projection]" in content for content in external_contents[:2])
assert any(
"external tool result compacted for provider request context" in content
for content in external_contents[:2]
)
assert sum(len(content) for content in external_contents) < 4 * (len("fetch 0\n") + 5000)
def test_agent_provider_backstop_preserves_sessions_yield_control_json() -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=1_000_000,
tool_result_provider_request_max_chars=300,
),
)
control_payload = json.dumps(
{
"status": "yielded",
"waited": False,
"message": "Current turn yielded; wait for pushed session events.",
"yield_message": "y" * 1000,
}
)
messages = [
Message(
role="assistant",
content=[ContentBlockToolUse(id="yield-1", name="sessions_yield", input={})],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="yield-1",
content=control_payload,
is_error=False,
)
],
),
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="fetch-1", name="web_fetch", input={"url": "https://example.com"}
)
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="fetch-1",
content="fetch\n" + ("x" * 1000),
is_error=False,
)
],
),
]
compacted = agent._compact_aggregate_tool_results_for_provider(messages)
control_result = compacted[1].content[0]
assert isinstance(control_result, ContentBlockToolResult)
payload = json.loads(control_result.content)
assert payload["status"] == "yielded"
assert payload["waited"] is False
def test_agent_provider_view_keeps_large_tool_use_arguments_by_default(tmp_path) -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
tool_use_argument_provider_request_max_chars=1200,
),
)
large_code = "print('start')\n" + ("x = 1\n" * 500) + "print('end')\n"
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="code-1",
name="execute_code",
input={"code": large_code, "timeout": 10},
)
],
)
]
projected = agent._sanitize_projected_tool_use_arguments_for_provider(messages)
original_block = messages[0].content[0]
projected_block = projected[0].content[0]
assert isinstance(original_block, ContentBlockToolUse)
assert isinstance(projected_block, ContentBlockToolUse)
assert original_block.input["code"] == large_code
assert projected_block.input["code"] == large_code
assert "tool_use_argument_projection" not in projected_block.input["code"]
assert "tool_argument_projection_applied" not in agent.config.metadata
def test_agent_provider_view_derives_tool_argument_budget_above_legacy_default(
tmp_path,
) -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=200_000,
max_tokens=8192,
),
)
large_code = "print('start')\n" + ("x = 1\n" * 2500) + "print('end')\n"
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="code-derived-1",
name="execute_code",
input={"code": large_code, "timeout": 10},
)
],
)
]
projected = agent._sanitize_projected_tool_use_arguments_for_provider(messages)
projected_block = projected[0].content[0]
assert isinstance(projected_block, ContentBlockToolUse)
assert projected_block.input["code"] == large_code
assert "tool_use_argument_projection" not in projected_block.input["code"]
def test_agent_provider_view_scrubs_legacy_projected_tool_argument(tmp_path) -> None:
projection = (
"[tool_use_argument_projection]\n"
"tool: execute_code\n"
"tool_use_id: tool-legacy\n"
"field: code\n"
"sha256: missing\n"
"tool_argument_handle: tr-missing\n"
"head:\nprint('legacy')"
)
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
tool_use_argument_provider_request_max_chars=1200,
),
)
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="tool-legacy",
name="execute_code",
input={"code": projection, "timeout": 99},
)
],
)
]
projected = agent._sanitize_projected_tool_use_arguments_for_provider(messages)
block = projected[0].content[0]
assert isinstance(block, ContentBlockToolUse)
assert "tool_use_argument_projection" not in block.input["code"]
assert "invalid_provider_context_projection:execute_code.code" in block.input["code"]
stored_contents = [
path.read_text(encoding="utf-8")
for path in (tmp_path / "tool-results").rglob("content.txt")
]
assert all("tool_use_argument_projection" not in content for content in stored_contents)
def test_agent_provider_view_does_not_project_aggregate_tool_use_arguments(tmp_path) -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
tool_use_argument_provider_request_max_chars=1200,
tool_use_argument_projection_enabled=True,
),
)
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id=f"write-{index}",
name="write_file",
input={
"path": f"generated/file-{index}.html",
"content": "x" * 700,
},
)
for index in range(5)
],
)
]
projected = agent._sanitize_projected_tool_use_arguments_for_provider(messages)
projected_blocks = [
block for block in projected[0].content if isinstance(block, ContentBlockToolUse)
]
assert all(block.input["content"] == "x" * 700 for block in projected_blocks)
assert all(
original.input["content"] == "x" * 700
for original in messages[0].content
if isinstance(original, ContentBlockToolUse)
)
assert "tool_argument_projection_applied" not in agent.config.metadata
assert "tool_argument_projection_calls" not in agent.config.metadata
def test_agent_provider_view_derives_tool_result_budget_above_legacy_default(
tmp_path,
) -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=200_000,
max_tokens=8192,
),
)
messages: list[Message] = []
for index in range(3):
tool_id = f"fetch-derived-{index}"
payload = f"FETCH_DERIVED_{index}\n" + ("x" * 40_000)
messages.extend(
[
Message(
role="assistant",
content=[
ContentBlockToolUse(
id=tool_id,
name="web_fetch",
input={"url": f"https://example.com/{index}"},
)
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id=tool_id,
content=payload,
is_error=False,
)
],
),
]
)
compacted = agent._compact_aggregate_tool_results_for_provider(messages)
first_result = compacted[1].content[0]
assert isinstance(first_result, ContentBlockToolResult)
assert first_result.content.startswith("FETCH_DERIVED_0")
assert "external_tool_result_compacted" not in first_result.content
def test_agent_provider_view_does_not_project_small_aggregate_tool_use_arguments(tmp_path) -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
tool_use_argument_provider_request_max_chars=1200,
tool_use_argument_projection_enabled=True,
),
)
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id=f"write-{index}",
name="write_file",
input={
"path": f"generated/file-{index}.html",
"content": "x" * 200,
},
)
for index in range(6)
],
)
]
projected = agent._sanitize_projected_tool_use_arguments_for_provider(messages)
projected_blocks = [
block for block in projected[0].content if isinstance(block, ContentBlockToolUse)
]
assert all(block.input["content"] == "x" * 200 for block in projected_blocks)
assert all(block.input["path"].startswith("generated/") for block in projected_blocks)
assert "tool_argument_projection_applied" not in agent.config.metadata
assert "tool_argument_projection_calls" not in agent.config.metadata
def test_agent_provider_view_keeps_successful_file_write_argument_executable(tmp_path) -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
tool_use_argument_provider_request_max_chars=8000,
),
)
large_html = "<html>\n" + ("<p>word</p>\n" * 900) + "</html>\n"
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="write-1",
name="write_file",
input={"path": "index.html", "content": large_html},
)
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="write-1",
content='{"status":"ok","path":"index.html"}',
is_error=False,
)
],
),
]
projected = agent._sanitize_projected_tool_use_arguments_for_provider(messages)
projected_tool_use = next(
block for block in projected[0].content if isinstance(block, ContentBlockToolUse)
)
projected_content = projected_tool_use.input["content"]
assert projected_tool_use.id == "write-1"
assert projected_tool_use.name == "write_file"
assert projected_tool_use.input["path"] == "index.html"
assert projected_content == large_html
assert "[tool_use_argument_projection]" not in projected_content
assert "successful_file_write_projection" not in projected_content
assert "<p>word</p>" in projected_content
projected_result = next(
block for block in projected[1].content if isinstance(block, ContentBlockToolResult)
)
assert projected_result.tool_use_id == "write-1"
assert projected[-1].role == "user"
history_block = next(
block for block in messages[0].content if isinstance(block, ContentBlockToolUse)
)
assert history_block.input["content"] == large_html
assert "tool_argument_projection_applied" not in agent.config.metadata
assert "tool_argument_projection_calls" not in agent.config.metadata
def test_agent_provider_view_does_not_store_successful_file_write_snapshot(
tmp_path,
) -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
tool_use_argument_provider_request_max_chars=8000,
),
)
large_html = "<html>\n" + ("<p>word</p>\n" * 900) + "</html>\n"
messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="write-1",
name="write_file",
input={"path": "index.html", "content": large_html},
)
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="write-1",
content='{"status":"ok","path":"index.html"}',
is_error=False,
)
],
),
]
first = agent._sanitize_projected_tool_use_arguments_for_provider(messages)
second = agent._sanitize_projected_tool_use_arguments_for_provider(messages)
first_block = next(
block for block in first[0].content if isinstance(block, ContentBlockToolUse)
)
second_block = next(
block for block in second[0].content if isinstance(block, ContentBlockToolUse)
)
assert first_block.input["content"] == large_html
assert second_block.input["content"] == large_html
assert not list((tmp_path / "tool-results" / "s" / "session-1").glob("**/meta.json"))
assert "tool_argument_projection_applied" not in agent.config.metadata
assert "tool_argument_projection_calls" not in agent.config.metadata
@pytest.mark.asyncio
async def test_agent_static_cost_source_is_explicitly_distinct_from_provider_billed() -> None:
provider = StaticCostProvider()
agent = Agent(provider=provider, config=AgentConfig(model_id="deepseek-v4-flash"))
events = [event async for event in agent.run_turn("hello")]
done = next(event for event in events if event.kind == "done")
assert done.billed_cost == 0.0
assert done.cost_usd > 0.0
assert done.cost_source == "opensquilla_static_estimate"
def test_complete_response_usage_cost_is_not_provider_billed_for_direct_providers() -> None:
response = SimpleNamespace(
model="deepseek-v4-flash",
usage={
"prompt_tokens": 1000,
"completion_tokens": 1000,
"cost": 0.0123,
},
)
provider = SimpleNamespace(provider_name="deepseek")
usage = _usage_from_complete_response(response, provider)
assert usage["billed_cost"] == 0.0
assert usage["cost_source"] == "opensquilla_static_estimate"
assert usage["estimated_cost_usd"] > 0.0
@pytest.mark.asyncio
async def test_agent_uses_sanitized_request_view_and_records_context_stages() -> None:
provider = CapturingProvider()
turn_log = CapturingTurnLog()
agent = Agent(
provider=provider,
config=AgentConfig(),
turn_call_logger=turn_log, # type: ignore[arg-type]
)
agent.set_history(
[
Message.model_construct(
role="assistant",
content=[
{
"type": "text",
"text": "previous answer",
"details": {"debug": True},
}
],
reasoning_content=None,
)
]
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
assert provider.calls
sent_history_block = provider.calls[0]["messages"][0].content[0]
assert isinstance(sent_history_block, ContentBlockText)
assert sent_history_block.text == "previous answer"
assert "details" not in sent_history_block.model_dump(mode="json")
stages = [
record["payload"]["stage"]
for record in turn_log.records
if record["kind"] == "context_stage"
]
assert stages == [
"session:loaded",
"session:sanitized",
"session:limited",
"prompt:before",
"prompt:images",
"stream:context",
"session:after",
]
@pytest.mark.asyncio
async def test_agent_provider_view_omits_loaded_history_tool_arguments() -> None:
provider = CapturingProvider()
large_argument = "STALE_HISTORY_ARGUMENT\n" + ("x" * 20_000)
agent = Agent(
provider=provider,
config=AgentConfig(max_iterations=1, flush_enabled=False),
)
agent.set_history(
[
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="write-stale",
name="write_file",
input={"path": "index.html", "content": large_argument},
)
],
reasoning_content="old reasoning\n" + ("r" * 10_000),
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="write-stale",
content='{"status":"ok"}',
is_error=False,
)
],
),
]
)
events = [event async for event in agent.run_turn("new task")]
assert any(event.kind == "done" for event in events)
assert provider.calls
payload = json.dumps(
[message.model_dump(mode="json") for message in provider.calls[0]["messages"]],
ensure_ascii=False,
)
assert large_argument not in payload
assert "x" * 1000 not in payload
assert "old reasoning" not in payload
assert "historical_tool_argument_omitted" not in payload
assert "invalid_provider_context_projection:write_file.content" in payload
@pytest.mark.asyncio
async def test_agent_preserves_deepseek_reasoning_while_projecting_history_payload() -> None:
provider = CapturingProvider()
large_argument = "DEEPSEEK_STALE_ARGUMENT\n" + ("x" * 20_000)
reasoning = "I reasoned before the historical tool call."
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=1,
thinking=ThinkingLevel.HIGH,
model_id="deepseek-v4-flash",
model_capabilities=ModelCapabilities(
supports_reasoning=True,
supports_tools=True,
reasoning_format="deepseek",
),
flush_enabled=False,
),
)
agent.set_history(
[
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="deepseek-stale",
name="write_file",
input={"path": "index.html", "content": large_argument},
)
],
reasoning_content=reasoning,
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="deepseek-stale",
content='{"status":"ok"}',
is_error=False,
)
],
),
]
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
sent_assistant = provider.calls[0]["messages"][0]
assert sent_assistant.reasoning_content == reasoning
payload = json.dumps(
[message.model_dump(mode="json") for message in provider.calls[0]["messages"]],
ensure_ascii=False,
)
assert large_argument not in payload
assert "x" * 1000 not in payload
assert "historical_tool_argument_omitted" not in payload
assert "invalid_provider_context_projection:write_file.content" in payload
@pytest.mark.asyncio
async def test_agent_runtime_context_is_request_only_and_not_system_prefix() -> None:
provider = CapturingProvider()
agent = Agent(
provider=provider,
config=AgentConfig(
system_prompt="stable system",
cache_breakpoints=[{"text": "stable system", "cache": "true"}],
cache_mode="auto",
max_iterations=1,
),
)
events = [event async for event in agent.run_turn("hello")]
assert any(event.kind == "done" for event in events)
call = provider.calls[0]
assert call["config"].system == "stable system"
assert call["config"].cache_breakpoints == [{"text": "stable system", "cache": "true"}]
assert call["messages"][0].role == "user"
assert call["messages"][0].content.startswith("hello")
assert "[Runtime context for this turn]" in call["messages"][0].content
assert len(call["messages"]) == 1
assert all(
"[Runtime context for this turn]" not in message.content
for message in agent._history
if isinstance(message.content, str)
)
@pytest.mark.asyncio
async def test_agent_runtime_context_does_not_precede_current_user_text() -> None:
provider = CapturingProvider()
agent = Agent(
provider=provider,
config=AgentConfig(
system_prompt="stable system",
cache_breakpoints=[{"text": "stable system", "cache": "true"}],
cache_mode="auto",
max_iterations=1,
),
)
first_prompt = "first prompt " + ("x" * 2000)
first_events = [event async for event in agent.run_turn(first_prompt)]
second_events = [event async for event in agent.run_turn("second prompt")]
assert any(event.kind == "done" for event in first_events)
assert any(event.kind == "done" for event in second_events)
first_call = provider.calls[0]["messages"]
assert first_call[-1].role == "user"
assert first_call[-1].content.startswith(first_prompt)
assert "[Runtime context for this turn]" in first_call[-1].content
assert not any(
isinstance(message.content, str)
and message.content.startswith("[Runtime context for this turn]")
for message in first_call[:-1]
)
assert agent._history[0] == Message(role="user", content=first_prompt)
second_call = provider.calls[1]["messages"]
assert second_call[0] == Message(role="user", content=first_prompt)
assert second_call[1] == Message(
role="assistant",
content=[ContentBlockText(text="ok")],
)
assert second_call[-1].role == "user"
assert second_call[-1].content.startswith("second prompt")
assert "[Runtime context for this turn]" in second_call[-1].content
def test_limit_turns_ignores_synthetic_user_messages_when_counting_turns() -> None:
messages = [
Message(role="user", content="first real user"),
Message(role="assistant", content="first answer"),
Message(role="user", content="[Available skills for this turn]\n<skill />"),
Message(role="user", content="second real user"),
Message(role="assistant", content="second answer"),
]
assert limit_turns(messages, 2) == messages
assert limit_turns(messages, 1) == messages[3:]
def test_turn_runner_keeps_dynamic_prompt_out_of_system_when_cache_enabled() -> None:
from opensquilla.engine.runtime import TurnRunner
runner = TurnRunner.__new__(TurnRunner)
turn = SimpleNamespace(
system_prompt=("stable base", "<memory_context>volatile recall</memory_context>"),
metadata={"cache_enabled": True},
)
final_prompt, cache_breakpoints, request_context_prompt = runner._resolve_prompt_config(turn)
assert final_prompt == "stable base"
assert cache_breakpoints == [{"text": "stable base", "cache": "true"}]
assert request_context_prompt == "<memory_context>volatile recall</memory_context>"
def test_turn_runner_preserves_joined_system_prompt_when_cache_disabled() -> None:
from opensquilla.engine.runtime import TurnRunner
runner = TurnRunner.__new__(TurnRunner)
turn = SimpleNamespace(
system_prompt=("stable base", "<memory_context>volatile recall</memory_context>"),
metadata={},
)
final_prompt, cache_breakpoints, request_context_prompt = runner._resolve_prompt_config(turn)
assert final_prompt == "stable base\n\n<memory_context>volatile recall</memory_context>"
assert cache_breakpoints is None
assert request_context_prompt is None
def test_agent_adjusts_request_context_indexes_after_compaction() -> None:
entries = [
{"role": "user", "content": "old question"},
{"role": "assistant", "content": "old answer"},
{"role": "user", "content": "[Available skills for this turn]\nskill"},
{"role": "user", "content": "current question"},
]
kept_entries = [
{"role": "assistant", "content": "old answer"},
{"role": "user", "content": "current question"},
]
request_idx = Agent._adjust_compacted_insert_index(
entries,
kept_entries,
2,
summary_present=True,
)
runtime_idx = Agent._adjust_compacted_insert_index(
entries,
kept_entries,
3,
summary_present=True,
)
compacted_messages = [
Message(role="user", content="[Context summary]\nsummary"),
Message(role="assistant", content="Understood. Continuing from summary."),
Message(role="assistant", content="old answer"),
Message(role="user", content="current question"),
]
request_context = Message(role="user", content="[Request context for this turn]\nvolatile")
runtime_context = Message(role="user", content="[Runtime context for this turn]\nnow")
request_messages = Agent._with_request_context_messages(
compacted_messages,
request_context,
request_idx,
runtime_context,
runtime_idx,
)
assert [message.content for message in request_messages] == [
"[Context summary]\nsummary",
"Understood. Continuing from summary.",
"old answer",
"[Request context for this turn]\nvolatile",
"current question\n\n[Runtime context for this turn]\nnow",
]
@pytest.mark.asyncio
async def test_agent_request_context_is_request_only_after_history() -> None:
provider = CapturingProvider()
agent = Agent(
provider=provider,
config=AgentConfig(
system_prompt="stable system",
request_context_prompt="<memory_context>volatile recall</memory_context>",
skills_context_prompt="<skill id='memory'>Memory helper</skill>",
cache_breakpoints=[{"text": "stable system", "cache": "true"}],
cache_mode="auto",
max_iterations=1,
),
)
agent.set_history(
[
Message(role="user", content="old question"),
Message(role="assistant", content="old answer"),
]
)
events = [event async for event in agent.run_turn("hello")]
assert any(event.kind == "done" for event in events)
call = provider.calls[0]
assert call["config"].system == "stable system"
assert call["config"].cache_breakpoints == [{"text": "stable system", "cache": "true"}]
assert "<memory_context>volatile recall</memory_context>" not in call["config"].system
assert [message.role for message in call["messages"]] == [
"user",
"assistant",
"user",
"user",
"user",
]
assert call["messages"][0] == Message(role="user", content="old question")
assert call["messages"][1] == Message(role="assistant", content="old answer")
assert "[Available skills for this turn]" in call["messages"][2].content
assert "[Request context for this turn]" in call["messages"][3].content
assert "<memory_context>volatile recall</memory_context>" in call["messages"][3].content
assert call["messages"][4].content.startswith("hello")
assert "[Runtime context for this turn]" in call["messages"][4].content
assert all(
"<memory_context>volatile recall</memory_context>" not in message.content
for message in agent._history
if isinstance(message.content, str)
)
@pytest.mark.asyncio
async def test_agent_provider_view_prunes_non_adjacent_tool_results() -> None:
provider = CapturingProvider()
agent = Agent(provider=provider, config=AgentConfig(max_iterations=1))
agent.set_history(
[
Message(role="user", content="old task"),
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="call_lookup",
name="lookup",
input={"q": "old"},
)
],
),
Message(role="user", content="ordinary user message before the tool result"),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="call_lookup",
content="lookup result",
is_error=False,
)
],
),
]
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
replay_payload = json.dumps(
[message.model_dump(mode="json") for message in provider.calls[0]["messages"]],
ensure_ascii=False,
)
assert "call_lookup" not in replay_payload
assert "ordinary user message before the tool result" in replay_payload
@pytest.mark.asyncio
async def test_agent_provider_view_keeps_latest_duplicate_tool_result() -> None:
provider = CapturingProvider()
agent = Agent(provider=provider, config=AgentConfig(max_iterations=1))
agent.set_history(
[
Message(role="user", content="old task"),
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="call_lookup",
name="lookup",
input={"q": "old"},
)
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="call_lookup",
content='{"status":"approval_required"}',
is_error=False,
),
ContentBlockToolResult(
tool_use_id="call_lookup",
content='{"status":"approval_denied"}',
is_error=True,
),
],
),
]
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
tool_results = [
block
for message in provider.calls[0]["messages"]
if isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolResult)
]
assert len(tool_results) == 1
assert tool_results[0].tool_use_id == "call_lookup"
assert tool_results[0].content == '{"status":"approval_denied"}'
assert tool_results[0].is_error is True
@pytest.mark.asyncio
async def test_agent_provider_view_preserves_split_adjacent_tool_results() -> None:
provider = CapturingProvider()
agent = Agent(provider=provider, config=AgentConfig(max_iterations=1))
agent.set_history(
[
Message(role="user", content="old task"),
Message(
role="assistant",
content=[
ContentBlockToolUse(
id="call_alpha",
name="lookup",
input={"q": "alpha"},
),
ContentBlockToolUse(
id="call_beta",
name="lookup",
input={"q": "beta"},
),
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="call_alpha",
content="alpha result",
is_error=False,
)
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="call_beta",
content="beta result",
is_error=False,
)
],
),
]
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
replay_payload = json.dumps(
[message.model_dump(mode="json") for message in provider.calls[0]["messages"]],
ensure_ascii=False,
)
assert "call_alpha" in replay_payload
assert "alpha result" in replay_payload
assert "call_beta" in replay_payload
assert "beta result" in replay_payload
@pytest.mark.asyncio
async def test_agent_request_context_repeats_across_tool_loop_without_persisting() -> None:
provider = ToolLoopCapturingProvider()
async def tool_handler(call: Any) -> ToolResult:
return ToolResult(
tool_use_id=call.tool_use_id,
tool_name=call.tool_name,
content="tool ok",
)
agent = Agent(
provider=provider,
config=AgentConfig(
system_prompt="stable system",
request_context_prompt="<memory_context>volatile recall</memory_context>",
max_iterations=2,
),
tool_handler=tool_handler,
)
events = [event async for event in agent.run_turn("hello")]
assert any(event.kind == "done" for event in events)
assert len(provider.calls) == 2
for call in provider.calls:
request_context_messages = [
message
for message in call["messages"]
if isinstance(message.content, str)
and "<memory_context>volatile recall</memory_context>" in message.content
]
assert len(request_context_messages) == 1
assert "[Request context for this turn]" in request_context_messages[0].content
assert all(
"<memory_context>volatile recall</memory_context>" not in message.content
for message in agent._history
if isinstance(message.content, str)
)
@pytest.mark.asyncio
async def test_agent_canonicalizes_large_tool_result_for_event_history_and_provider() -> None:
provider = ToolLoopCapturingProvider()
raw_output = "single bulky output\n" + ("x" * 5000)
async def tool_handler(call: Any) -> ToolResult:
return ToolResult(
tool_use_id=call.tool_use_id,
tool_name=call.tool_name,
content=raw_output,
)
agent = Agent(
provider=provider,
config=AgentConfig(
# Window large enough that the projected (~250-token) tool result
# fits: this test exercises tool-result projection/canonicalization,
# not compaction. A 200-token window is below the projection floor,
# so inline compaction would legitimately fire and prune the result.
context_window_tokens=200_000,
max_iterations=2,
tool_result_projection_max_inline_chars=1000,
),
tool_handler=tool_handler,
)
events = [event async for event in agent.run_turn("hello")]
result_event = next(
event
for event in events
if isinstance(event, ToolResultEvent) and event.tool_use_id == "tool-1"
)
assert result_event.result != raw_output
assert "tool_result_handle:" not in result_event.result
history_result = next(
block
for message in agent._history
if message.role == "user" and isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolResult) and block.tool_use_id == "tool-1"
)
assert history_result.content == result_event.result
assert history_result.content != raw_output
assert len(provider.calls) == 2
replay_result = next(
block
for message in provider.calls[1]["messages"]
if message.role == "user" and isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolResult) and block.tool_use_id == "tool-1"
)
assert replay_result.content == result_event.result
assert replay_result.content != raw_output
assert "tool_result_handle:" not in replay_result.content
assert "single bulky output" in replay_result.content
assert len(replay_result.content) < len(raw_output)
def test_agent_provider_request_messages_project_overflow_retry_tool_results() -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=200,
),
)
raw_output = "overflow retry bulky output\n" + ("x" * 8000)
messages = [
Message(
role="assistant",
content=[ContentBlockToolUse(id="tool-1", name="execute_code", input={})],
),
Message(
role="user",
content=[ContentBlockToolResult(tool_use_id="tool-1", content=raw_output)],
),
]
request_messages = agent._provider_request_messages(
messages,
request_context_message=None,
request_context_insert_index=0,
runtime_context_message=Message(role="user", content="[Runtime context]"),
runtime_context_insert_index=len(messages),
)
original_result = messages[1].content[0]
assert isinstance(original_result, ContentBlockToolResult)
assert original_result.content == raw_output
request_result = next(
block
for message in request_messages
if message.role == "user" and isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolResult) and block.tool_use_id == "tool-1"
)
assert request_result.content != raw_output
assert "[tool_result_projection]" in request_result.content
assert "tool_result_handle:" not in request_result.content
assert len(request_result.content) < len(raw_output)
def test_agent_provider_request_guard_reuses_stable_tool_result_projection() -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=200,
),
)
raw_output = "overflow retry bulky output\n" + ("x" * 8000)
messages = [
Message(
role="assistant",
content=[ContentBlockToolUse(id="tool-1", name="execute_code", input={})],
),
Message(
role="user",
content=[ContentBlockToolResult(tool_use_id="tool-1", content=raw_output)],
),
]
first_request = agent._provider_request_messages(
messages,
request_context_message=None,
request_context_insert_index=0,
runtime_context_message=Message(role="user", content="[Runtime context]"),
runtime_context_insert_index=len(messages),
)
second_request = agent._provider_request_messages(
messages,
request_context_message=None,
request_context_insert_index=0,
runtime_context_message=Message(role="user", content="[Runtime context]"),
runtime_context_insert_index=len(messages),
)
def _result_content(request_messages: list[Message]) -> str:
return next(
block.content
for message in request_messages
if message.role == "user" and isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolResult) and block.tool_use_id == "tool-1"
)
first_content = _result_content(first_request)
second_content = _result_content(second_request)
assert first_content == second_content
assert first_content != raw_output
assert "[tool_result_projection]" in first_content
assert agent._provider_tool_result_overrides["tool-1"].content == first_content
def test_agent_provider_request_reapplies_frozen_projection_after_turn_reset() -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=200,
),
)
raw_output = "overflow retry bulky output\n" + ("x" * 8000)
messages = [
Message(
role="assistant",
content=[ContentBlockToolUse(id="tool-1", name="execute_code", input={})],
),
Message(
role="user",
content=[ContentBlockToolResult(tool_use_id="tool-1", content=raw_output)],
),
]
first_request = agent._provider_request_messages(
messages,
request_context_message=None,
request_context_insert_index=0,
runtime_context_message=Message(role="user", content="[Runtime context]"),
runtime_context_insert_index=len(messages),
)
agent._provider_tool_result_overrides = {}
second_request = agent._provider_request_messages(
messages,
request_context_message=None,
request_context_insert_index=0,
runtime_context_message=Message(role="user", content="[Runtime context]"),
runtime_context_insert_index=len(messages),
)
def _result_content(request_messages: list[Message]) -> str:
return next(
block.content
for message in request_messages
if message.role == "user" and isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolResult) and block.tool_use_id == "tool-1"
)
assert _result_content(first_request) == _result_content(second_request)
assert "[tool_result_projection]" in _result_content(second_request)
def test_agent_provider_request_does_not_project_previously_full_visible_result() -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=200,
),
)
first_raw = "first result stays full"
first_messages = [
Message(
role="assistant",
content=[ContentBlockToolUse(id="tool-1", name="execute_code", input={})],
),
Message(
role="user",
content=[ContentBlockToolResult(tool_use_id="tool-1", content=first_raw)],
),
]
first_request = agent._provider_request_messages(
first_messages,
request_context_message=None,
request_context_insert_index=0,
runtime_context_message=Message(role="user", content="[Runtime context]"),
runtime_context_insert_index=len(first_messages),
)
assert next(
block.content
for message in first_request
if message.role == "user" and isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolResult) and block.tool_use_id == "tool-1"
) == first_raw
bulky = "later bulky output\n" + ("x" * 8000)
later_messages = [
Message(
role="assistant",
content=[
ContentBlockToolUse(id="tool-1", name="execute_code", input={}),
ContentBlockToolUse(id="tool-2", name="execute_code", input={}),
ContentBlockToolUse(id="tool-3", name="execute_code", input={}),
],
),
Message(
role="user",
content=[
ContentBlockToolResult(tool_use_id="tool-1", content=first_raw),
ContentBlockToolResult(tool_use_id="tool-2", content=bulky),
ContentBlockToolResult(tool_use_id="tool-3", content=bulky),
],
),
]
later_request = agent._provider_request_messages(
later_messages,
request_context_message=None,
request_context_insert_index=0,
runtime_context_message=Message(role="user", content="[Runtime context]"),
runtime_context_insert_index=len(later_messages),
)
contents = {
block.tool_use_id: block.content
for message in later_request
if message.role == "user" and isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolResult)
}
assert contents["tool-1"] == first_raw
assert any(
"[tool_result_projection]" in value
for key, value in contents.items()
if key != "tool-1"
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"strict_flush_config",
[
{"flush_compaction_requires_safe_receipt": True},
{"flush_compaction_safety_mode": "block"},
],
)
async def test_agent_inline_strict_flush_receipt_refuses_destructive_compaction(
monkeypatch: pytest.MonkeyPatch,
strict_flush_config: dict[str, Any],
) -> None:
agent = Agent(
provider=CapturingProvider(),
config=AgentConfig(
context_window_tokens=10,
context_overflow_threshold=0.1,
flush_enabled=True,
flush_pre_compaction=True,
flush_timeout_seconds=0.1,
**strict_flush_config,
),
)
messages = [Message(role="user", content="important history")]
compact_called = False
monkeypatch.setattr(
"opensquilla.memory.flush.should_flush",
lambda **_kwargs: True,
)
monkeypatch.setattr(
"opensquilla.memory.flush.resolve_flush_plan",
lambda **_kwargs: SimpleNamespace(relative_path="flush.md"),
)
async def degraded_flush(_plan: Any, _messages: list[Message]) -> Any:
return SimpleNamespace(
mode="llm",
indexed_chunk_count=1,
integrity_status="missing_chunks",
output_coverage_status="ok",
invalid_candidate_count=0,
candidate_missing_ids=[],
obligation_status="ok",
obligation_missing_ids=[],
)
async def compact_context_should_not_run(_request: Any) -> Any:
nonlocal compact_called
compact_called = True
return SimpleNamespace(summary="", kept_entries=[], removed_count=0)
monkeypatch.setattr(agent, "_run_flush", degraded_flush)
monkeypatch.setattr(
"opensquilla.engine.agent.compact_context",
compact_context_should_not_run,
)
outcome = await agent._check_context_overflow(messages, estimated_context_tokens=100)
assert outcome is None
assert compact_called is False
assert agent._last_compaction_refusal_reason == "memory_flush_degraded_before_compaction"
@pytest.mark.asyncio
async def test_agent_keeps_large_tool_arguments_during_tool_replay(tmp_path) -> None:
large_code = "print('start')\n" + ("x = 1\n" * 500) + "print('end')\n"
provider = LargeArgumentToolLoopCapturingProvider(large_code)
async def tool_handler(call: Any) -> ToolResult:
return ToolResult(
tool_use_id=call.tool_use_id,
tool_name=call.tool_name,
content="tool ok",
)
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=2,
tool_use_argument_provider_request_max_chars=1200,
tool_use_argument_projection_enabled=True,
),
tool_handler=tool_handler,
)
events = [event async for event in agent.run_turn("hello")]
assert any(event.kind == "done" for event in events)
replay_messages = provider.calls[1]["messages"]
assistant_replay = next(
message
for message in replay_messages
if message.role == "assistant"
and isinstance(message.content, list)
and any(getattr(block, "type", None) == "tool_use" for block in message.content)
)
replay_block = next(
block for block in assistant_replay.content if isinstance(block, ContentBlockToolUse)
)
assert replay_block.input["code"] == large_code
assert "tool_use_argument_projection" not in replay_block.input["code"]
history_block = next(
block
for message in agent._history
if message.role == "assistant" and isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolUse)
)
assert history_block.input["code"] == large_code
@pytest.mark.asyncio
async def test_agent_refuses_copied_tool_argument_projection_without_dispatch(
tmp_path,
) -> None:
large_code = "print('start')\n" + ("x = 1\n" * 500) + "print('end')\n"
provider = CopiedProjectionToolLoopCapturingProvider(large_code)
dispatched_code_arguments: list[str] = []
dispatched_arguments: list[dict[str, Any]] = []
async def tool_handler(call: Any) -> ToolResult:
dispatched_code_arguments.append(call.arguments["code"])
dispatched_arguments.append(call.arguments)
return ToolResult(
tool_use_id=call.tool_use_id,
tool_name=call.tool_name,
content="tool ok",
)
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=3,
tool_use_argument_provider_request_max_chars=1200,
tool_use_argument_projection_enabled=True,
),
tool_handler=tool_handler,
)
events = [event async for event in agent.run_turn("hello")]
done_event = next(event for event in events if event.kind == "done")
assert done_event.text == "done"
assert len(provider.calls) == 3
assert dispatched_code_arguments == [large_code]
assert dispatched_arguments == [{"code": large_code, "timeout": 10}]
assert all(
not value.startswith("[tool_use_argument_projection]\n")
for value in dispatched_code_arguments
)
result_event = next(
event
for event in events
if isinstance(event, ToolResultEvent) and event.tool_use_id == "tool-2"
)
assert result_event.is_error is True
assert "provider-only compacted tool argument" not in result_event.result
assert "Projected tool argument" not in result_event.result
assert result_event.arguments["code"] != large_code
assert not result_event.arguments["code"].startswith("[tool_use_argument_projection]\n")
assert "tool_use_argument_projection" not in result_event.arguments["code"]
assert result_event.arguments["timeout"] == 99
history_block = next(
block
for message in agent._history
if message.role == "assistant" and isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolUse) and block.id == "tool-2"
)
assert history_block.input["code"] == result_event.arguments["code"]
assert not history_block.input["code"].startswith("[tool_use_argument_projection]\n")
assert "tool_use_argument_projection" not in history_block.input["code"]
assert history_block.input["timeout"] == 99
follow_up_events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in follow_up_events)
replay_payload = json.dumps(
[message.model_dump(mode="json") for message in provider.calls[-1]["messages"]],
ensure_ascii=False,
)
assert "tool-2" not in replay_payload
assert "tool_use_argument_projection" not in replay_payload
@pytest.mark.asyncio
async def test_agent_refuses_unrestorable_tool_argument_projection(tmp_path) -> None:
large_code = "print('start')\n" + ("x = 1\n" * 500) + "print('end')\n"
provider = CopiedProjectionToolLoopCapturingProvider(large_code)
dispatched_tool_ids: list[str] = []
original_legacy_projection = provider._legacy_projected_code_argument
def corrupted_projection() -> str:
projection = original_legacy_projection()
bad_hash = "0" * 64
return projection.replace(
"sha256: ",
f"sha256: {bad_hash}\nprevious_sha256: ",
1,
)
provider._legacy_projected_code_argument = corrupted_projection # type: ignore[method-assign]
async def tool_handler(call: Any) -> ToolResult:
dispatched_tool_ids.append(call.tool_use_id)
return ToolResult(
tool_use_id=call.tool_use_id,
tool_name=call.tool_name,
content="tool ok",
)
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=3,
tool_use_argument_provider_request_max_chars=1200,
tool_use_argument_projection_enabled=True,
),
tool_handler=tool_handler,
)
events = [event async for event in agent.run_turn("hello")]
result_event = next(
event
for event in events
if isinstance(event, ToolResultEvent) and event.tool_use_id == "tool-2"
)
assert dispatched_tool_ids == ["tool-1"]
assert result_event.is_error is True
assert "provider-only compacted tool argument" not in result_event.result
assert "Projected tool argument" not in result_event.result
assert not result_event.arguments["code"].startswith("[tool_use_argument_projection]\n")
assert "tool_use_argument_projection" not in result_event.arguments["code"]
history_block = next(
block
for message in agent._history
if message.role == "assistant" and isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolUse) and block.id == "tool-2"
)
assert history_block.input["code"] == result_event.arguments["code"]
assert not history_block.input["code"].startswith("[tool_use_argument_projection]\n")
assert "tool_use_argument_projection" not in history_block.input["code"]
second_events = [event async for event in agent.run_turn("hi")]
assert any(event.kind == "done" for event in second_events)
replay_payload = json.dumps(
[message.model_dump(mode="json") for message in provider.calls[-1]["messages"]],
ensure_ascii=False,
)
assert "tool_use_id: tool-2" not in replay_payload
stored_contents = [
path.read_text(encoding="utf-8")
for path in (tmp_path / "tool-results").rglob("content.txt")
]
assert all("tool_use_argument_projection" not in content for content in stored_contents)
@pytest.mark.asyncio
async def test_agent_refuses_copied_provider_compacted_tool_arguments(tmp_path) -> None:
provider = CompactedToolArgumentsProvider()
dispatched: list[dict[str, Any]] = []
async def tool_handler(call: Any) -> ToolResult:
dispatched.append(call.arguments)
return ToolResult(
tool_use_id=call.tool_use_id,
tool_name=call.tool_name,
content="tool ok",
)
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=2,
),
tool_handler=tool_handler,
)
events = [event async for event in agent.run_turn("open in chrome")]
assert any(event.kind == "done" for event in events)
done_event = next(event for event in events if event.kind == "done")
assert done_event.text == "done"
assert "provider-only compacted tool arguments" not in done_event.text
assert len(provider.calls) == 2
assert dispatched == []
result_event = next(
event
for event in events
if isinstance(event, ToolResultEvent) and event.tool_use_id == "tool-compact"
)
assert result_event.is_error is True
assert "provider-only compacted tool arguments" not in result_event.result
assert "ProjectedToolArgumentsError" not in result_event.result
assert "_opensquilla_compacted_tool_arguments" not in result_event.arguments
history_block = next(
block
for message in agent._history
if message.role == "assistant" and isinstance(message.content, list)
for block in message.content
if isinstance(block, ContentBlockToolUse) and block.id == "tool-compact"
)
assert history_block.input == result_event.arguments
assert "_opensquilla_compacted_tool_arguments" not in history_block.input
follow_up_events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in follow_up_events)
replay_payload = json.dumps(
[message.model_dump(mode="json") for message in provider.calls[-1]["messages"]],
ensure_ascii=False,
)
assert "_opensquilla_compacted_tool_arguments" not in replay_payload
assert "_invalid_provider_context_arguments" not in replay_payload
assert "provider_context_omitted" not in replay_payload
assert "tool-compact" not in replay_payload
@pytest.mark.asyncio
async def test_agent_refuses_copied_provider_request_compacted_argument_string(
tmp_path,
) -> None:
provider = ProviderRequestCompactedArgumentStringProvider()
dispatched: list[dict[str, Any]] = []
async def tool_handler(call: Any) -> ToolResult:
dispatched.append(call.arguments)
return ToolResult(
tool_use_id=call.tool_use_id,
tool_name=call.tool_name,
content="tool ok",
)
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=2,
),
tool_handler=tool_handler,
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
assert dispatched == []
result_event = next(
event
for event in events
if isinstance(event, ToolResultEvent) and event.tool_use_id == "tool-provider-request"
)
assert result_event.is_error is True
assert result_event.execution_status is not None
assert result_event.execution_status["reason"] == "provider_context_projection_reused"
assert "compaction placeholder" in result_event.result
@pytest.mark.asyncio
async def test_agent_refuses_mid_string_compacted_marker_in_tool_argument(
tmp_path,
) -> None:
provider = MidStringCompactedArgumentStringProvider()
dispatched: list[dict[str, Any]] = []
async def tool_handler(call: Any) -> ToolResult:
dispatched.append(call.arguments)
return ToolResult(
tool_use_id=call.tool_use_id,
tool_name=call.tool_name,
content="tool ok",
)
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=2,
),
tool_handler=tool_handler,
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
assert dispatched == []
result_event = next(
event
for event in events
if isinstance(event, ToolResultEvent) and event.tool_use_id == "tool-mid-string"
)
assert result_event.is_error is True
assert result_event.execution_status is not None
assert result_event.execution_status["reason"] == "provider_context_projection_reused"
assert "compaction placeholder" in result_event.result
assert "re-read" in result_event.result.lower()
@pytest.mark.asyncio
async def test_agent_repair_prompt_keeps_provider_request_from_ending_on_assistant(
tmp_path,
) -> None:
provider = TextThenCompactedToolArgumentsProvider()
async def tool_handler(call: Any) -> ToolResult:
return ToolResult(
tool_use_id=call.tool_use_id,
tool_name=call.tool_name,
content="tool ok",
)
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=2,
),
tool_handler=tool_handler,
)
events = [event async for event in agent.run_turn("make a deck")]
assert any(event.kind == "done" for event in events)
assert len(provider.calls) == 2
repair_messages = provider.calls[1]["messages"]
assert repair_messages[-1].role == "user"
assert isinstance(repair_messages[-1].content, str)
assert "Regenerate the complete tool arguments" in repair_messages[-1].content
replay_payload = json.dumps(
[message.model_dump(mode="json") for message in repair_messages],
ensure_ascii=False,
)
assert "tool-compact" not in replay_payload
assert "_invalid_provider_context_arguments" not in replay_payload
assert "provider_context_omitted" not in replay_payload
def test_agent_repair_prompt_handles_tool_use_without_tool_result() -> None:
agent = Agent(provider=CapturingProvider(), config=AgentConfig())
messages = [
Message(role="user", content="make a deck"),
Message(
role="assistant",
content=[
ContentBlockText(text="I will prepare the file."),
ContentBlockToolUse(
id="tool-compact",
name="write_file",
input={
"_opensquilla_compacted_tool_arguments": True,
"reason": "provider_context_omitted",
},
),
],
),
]
stripped = agent._strip_provider_context_marker_replay_for_provider(messages)
assert stripped[-1].role == "user"
assert isinstance(stripped[-1].content, str)
assert "Regenerate the complete tool arguments" in stripped[-1].content
replay_payload = json.dumps(
[message.model_dump(mode="json") for message in stripped],
ensure_ascii=False,
)
assert "tool-compact" not in replay_payload
assert "provider_context_omitted" not in replay_payload
def test_agent_strips_string_provider_context_marker_replay() -> None:
agent = Agent(provider=CapturingProvider(), config=AgentConfig())
messages = [
Message(role="user", content="inspect the repo"),
Message(
role="assistant",
content=[
ContentBlockText(text="I will inspect the repo."),
ContentBlockToolUse(
id="tool-compact-string",
name="exec_command",
input={
"_opensquilla_compacted_tool_arguments": "true",
"original_chars": "50",
"argument_keys": '["command"]',
},
),
],
),
Message(
role="user",
content=[
ContentBlockToolResult(
tool_use_id="tool-compact-string",
content="missing required argument command",
is_error=True,
)
],
),
]
stripped = agent._strip_provider_context_marker_replay_for_provider(messages)
replay_payload = json.dumps(
[message.model_dump(mode="json") for message in stripped],
ensure_ascii=False,
)
assert "tool-compact-string" not in replay_payload
assert "_opensquilla_compacted_tool_arguments" not in replay_payload
assert "missing required argument command" not in replay_payload
@pytest.mark.asyncio
async def test_agent_preserves_reasoning_content_for_deepseek_tool_replay() -> None:
provider = ReasoningToolLoopCapturingProvider()
async def tool_handler(call: Any) -> ToolResult:
return ToolResult(
tool_use_id=call.tool_use_id,
tool_name=call.tool_name,
content="tool ok",
)
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=2,
thinking=ThinkingLevel.HIGH,
model_id="deepseek-v4-flash",
model_capabilities=ModelCapabilities(
supports_reasoning=True,
supports_tools=True,
reasoning_format="deepseek",
),
),
tool_handler=tool_handler,
)
events = [event async for event in agent.run_turn("hello")]
assert any(event.kind == "done" for event in events)
assert len(provider.calls) == 2
replay_messages = provider.calls[1]["messages"]
assistant_replay = next(
message
for message in replay_messages
if message.role == "assistant"
and isinstance(message.content, list)
and any(getattr(block, "type", None) == "tool_use" for block in message.content)
)
assert assistant_replay.reasoning_content == "I should call echo before finalizing."
@pytest.mark.asyncio
async def test_agent_preserves_allowed_historical_image_blocks_for_vision_models() -> None:
provider = CapturingProvider()
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=1,
model_id="vision-model",
model_capabilities=ModelCapabilities(supports_vision=True),
preserve_historical_images=True,
),
)
agent.set_history(
[
Message(
role="user",
content=[
ContentBlockText(text="describe this"),
ContentBlockImage(media_type="image/png", data="aW1hZ2U="),
],
)
]
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
sent_blocks = provider.calls[0]["messages"][0].content
assert any(isinstance(block, ContentBlockImage) for block in sent_blocks)
@pytest.mark.asyncio
async def test_agent_preserves_reasoning_content_for_deepseek_text_replay() -> None:
provider = CapturingProvider()
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=1,
thinking=ThinkingLevel.HIGH,
model_id="deepseek-v4-flash",
model_capabilities=ModelCapabilities(
supports_reasoning=True,
supports_tools=True,
reasoning_format="deepseek",
),
),
)
agent.set_history(
[
Message(role="user", content="old question"),
Message(
role="assistant",
content=[ContentBlockText(text="old answer")],
reasoning_content="I reasoned before answering.",
),
]
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
assert provider.calls
sent_assistant = provider.calls[0]["messages"][1]
assert sent_assistant.reasoning_content == "I reasoned before answering."
@pytest.mark.asyncio
async def test_agent_preserves_direct_deepseek_v4_reasoning_without_capabilities() -> None:
provider = CapturingProvider()
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=1,
thinking=ThinkingLevel.HIGH,
model_id="deepseek-v4-flash",
model_capabilities=None,
),
)
agent.set_history(
[
Message(role="user", content="old question"),
Message(
role="assistant",
content=[ContentBlockText(text="old answer")],
reasoning_content="I reasoned before answering.",
),
]
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
assert provider.calls
sent_assistant = provider.calls[0]["messages"][1]
assert sent_assistant.reasoning_content == "I reasoned before answering."
@pytest.mark.asyncio
async def test_agent_preserves_reasoning_content_for_dashscope_qwen_replay() -> None:
provider = CapturingProvider()
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=1,
thinking=ThinkingLevel.HIGH,
model_id="qwen3.6-flash",
model_capabilities=ModelCapabilities(
supports_reasoning=True,
supports_tools=True,
reasoning_format="dashscope",
),
),
)
agent.set_history(
[
Message(role="user", content="old question"),
Message(
role="assistant",
content=[ContentBlockText(text="old answer")],
reasoning_content="I reasoned before answering with Qwen.",
),
]
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
assert provider.calls
sent_assistant = provider.calls[0]["messages"][1]
assert sent_assistant.reasoning_content == "I reasoned before answering with Qwen."
@pytest.mark.asyncio
async def test_agent_drops_reasoning_content_when_model_is_not_deepseek() -> None:
provider = CapturingProvider()
agent = Agent(
provider=provider,
config=AgentConfig(
max_iterations=1,
thinking=ThinkingLevel.HIGH,
model_id="custom-reasoning-model",
model_capabilities=ModelCapabilities(
supports_reasoning=True,
supports_tools=True,
reasoning_format="deepseek",
),
),
)
agent.set_history(
[
Message(role="user", content="old question"),
Message(
role="assistant",
content=[ContentBlockText(text="old answer")],
reasoning_content="I reasoned before answering.",
),
]
)
events = [event async for event in agent.run_turn("continue")]
assert any(event.kind == "done" for event in events)
assert provider.calls
sent_assistant = provider.calls[0]["messages"][1]
assert sent_assistant.reasoning_content is None