feat(agents,backends,conversations,frontends,ui): progress thinking is told apart by its agent, raycast reasoning stays collapsed, read_conversation keeps progress

This commit is contained in:
hh committed 2026-09-22 20:51:23 +02:00
1 parent 13873f857b
commit 120985deab
18 files changed
+374 -110

No files matched your search

+62 -4
View File
@@ -24,7 +24,7 @@ from anthropic.types import TextBlock as AnthropicTextBlock
from anthropic.types import ThinkingBlock
from beaver_gateway.agents.claude import ClaudeAgent, ClaudeOptions
from beaver_gateway.conversations.turns import reply_text
from beaver_gateway.agents.raycast import RaycastAgent
from beaver_gateway.backends.claude_sdk import ClaudeSdkBackend
from beaver_gateway.events.bus import EventBus
from beaver_gateway.conversations.service import (
@@ -40,6 +40,7 @@ from beaver_gateway.backends.transcript import (
close_open_tool_uses,
open_tool_uses,
render_messages,
reply_text,
strip_tool_entries,
window_entries,
)
@@ -718,12 +719,68 @@ def test_transcript_helpers() -> None:
assert windowed[0]["message"]["content"] == "q2" and len(windowed) == 2
assert (
render_messages(
[{"role": "user", "content": "q"}, {"role": "assistant", "content": "a"}]
[{"role": "user", "content": "q"}, {"role": "assistant", "content": "a"}],
thinking_is_progress=True,
)
== "user:\nq\n\nassistant:\na"
)
def test_read_conversation_keeps_progress_and_drops_reasoning() -> None:
history = [
{"role": "user", "content": "status?"},
{
"role": "assistant",
"content": [
{"type": "text", "text": "Checking."},
{"type": "thinking", "thinking": "", "signature": "s"},
{"type": "tool_use", "id": "t1", "name": "komodo", "input": {}},
],
},
{
"role": "user",
"content": [{"type": "tool_result", "tool_use_id": "t1", "content": "ok"}],
},
{
"role": "assistant",
"content": [
{
"type": "thinking",
"thinking": "All up, reading logs.",
"signature": "s",
},
{"type": "tool_use", "id": "t2", "name": "komodo", "input": {}},
],
},
{
"role": "user",
"content": [{"type": "tool_result", "tool_use_id": "t2", "content": "ok"}],
},
{"role": "assistant", "content": [{"type": "text", "text": "Healthy."}]},
]
assert render_messages(history, thinking_is_progress=True) == (
"user:\nstatus?\n\nassistant:\nChecking.\n\nAll up, reading logs.\n\n"
"Healthy.\n(tools: komodo, komodo)"
)
assert render_messages(history, thinking_is_progress=False) == (
"user:\nstatus?\n\nassistant:\nChecking.\n\nHealthy.\n(tools: komodo, komodo)"
)
def test_only_claude_agents_read_their_thinking_as_progress(tmp_path: Path) -> None:
raycast = RaycastAgent(name="r", model="google-gemini-3.1-pro", system_prompt="")
claude = ClaudeAgent(name="c", model="claude-opus-5-5", cwd=tmp_path)
summarized = ClaudeAgent(
name="s",
model="claude-opus-5-5",
cwd=tmp_path,
options=ClaudeOptions(thinking={"type": "adaptive", "display": "summarized"}),
)
assert not raycast.thinking_is_progress
assert claude.thinking_is_progress
assert not summarized.thinking_is_progress
async def test_agent_kinds_gate_create(world: World) -> None:
with pytest.raises(ValueError, match="does not serve kind 'deep'"):
await world.conversations.create(kind="deep", agent="a", origin="test")
@@ -970,9 +1027,10 @@ def test_reply_text_keeps_progress_updates_and_drops_hidden_reasoning() -> None:
ThinkingBlock(type="thinking", thinking="looking it up", signature="s"),
AnthropicTextBlock(type="text", text="found it"),
]
assert reply_text(blocks) == "looking it up\n\nfound it"
assert reply_text(blocks, thinking_is_progress=True) == "looking it up\n\nfound it"
assert reply_text(blocks, thinking_is_progress=False) == "found it"
def test_reply_text_on_a_plain_answer_is_unchanged() -> None:
blocks = [AnthropicTextBlock(type="text", text=" just an answer ")]
assert reply_text(blocks) == "just an answer"
assert reply_text(blocks, thinking_is_progress=True) == "just an answer"