refactor: split flat core into capability packages, layer the conversations service, English defaults for every model-facing text

This commit is contained in:
hh
2026-09-02 00:13:20 +02:00
parent 253bde1b11
commit 9aaddbed75
77 changed files with 2987 additions and 2944 deletions
+23 -19
View File
@@ -21,12 +21,16 @@ from claude_agent_sdk import (
from beaver_gateway.agents.claude import ClaudeAgent, ClaudeOptions
from beaver_gateway.backends.claude_sdk import ClaudeSdkBackend
from beaver_gateway.core.bus import EventBus
from beaver_gateway.core.conversations import Conversations, ConversationTexts, parse_at
from beaver_gateway.core.gateway_tools import SAY_IN_USER_TURN, _tools
from beaver_gateway.core.registry import AgentRegistry
from beaver_gateway.core.sessions import SessionPool
from beaver_gateway.core.transcript import (
from beaver_gateway.events.bus import EventBus
from beaver_gateway.conversations.service import (
Conversations,
ConversationTexts,
parse_at,
)
from beaver_gateway.conversations.tools import SAY_IN_USER_TURN, _tools
from beaver_gateway.app import AgentRegistry
from beaver_gateway.backends.sessions import SessionPool
from beaver_gateway.backends.transcript import (
build_entries,
close_open_tool_uses,
open_tool_uses,
@@ -312,14 +316,14 @@ async def test_urgent_interrupts_and_goes_first(world: World) -> None:
("urgent", "done"),
]
assert client.prompts[0] == "first"
assert client.prompts[1].startswith("[инжект: крон")
assert "прервал предыдущий тёрн" in client.prompts[1]
assert client.prompts[1].startswith("[inject: крон")
assert "cut the previous turn" in client.prompts[1]
assert client.prompts[1].endswith("ALERT")
assert client.prompts[2] == "second"
async def test_inject_header_is_configurable(world: World) -> None:
from beaver_gateway.core.conversations import ConversationTexts
from beaver_gateway.conversations.service import ConversationTexts
world.conversations._texts = ConversationTexts( # noqa: SLF001
inject_header=lambda ctx: (
@@ -343,7 +347,7 @@ async def test_normal_injects_ride_with_the_next_user_message(world: World) -> N
await world.settle(conv, 2)
prompts = ScriptedClient.instances[0].prompts
assert len(prompts) == 1
assert prompts[0].startswith("hello\n\n[инжекты")
assert prompts[0].startswith("hello\n\n[injects")
assert "- [watch] vault changed" in prompts[0]
@@ -373,7 +377,7 @@ async def test_spawn_seeds_first_user_message(world: World) -> None:
)
await world.settle(conv, 1)
prompt = ScriptedClient.instances[0].prompts[0]
assert prompt.startswith("[сид: brief] branch «t», ")
assert prompt.startswith("[seed: brief] branch «t», ")
assert prompt.endswith("\n\ndo X")
assert ScriptedClient.instances[0].options.system_prompt == "hi"
@@ -459,8 +463,8 @@ async def test_copy_seed_forks_parent_with_window(world: World) -> None:
await world.settle(child, 1)
assert ScriptedClient.instances[0].options.resume == child.session_id
prompt = ScriptedClient.instances[0].prompts[0]
assert prompt.startswith("[сид: copy] branch, ")
assert "последние 1 тёрнов" in prompt and prompt.endswith("\n\ngo")
assert prompt.startswith("[seed: copy] branch, ")
assert "last 1 turns" in prompt and prompt.endswith("\n\ngo")
assert (await world.conversations.get(child.external_id)).flags["seed"] is None
@@ -484,7 +488,7 @@ async def test_merge_injects_summary_into_parent(world: World) -> None:
assert (await world.conversations.get(branch.external_id)).status == "merged"
assert await world.statuses(master) == [("normal", "queued")]
item = (await world.conversations.queue.recent(master.id))[0]
assert item.origin == "слив" and item.text == result.text
assert item.origin == "merge" and item.text == result.text
async def test_recover_closes_open_tool_use_and_injects_interrupted(
@@ -538,7 +542,7 @@ async def test_recover_closes_open_tool_use_and_injects_interrupted(
assert tail["message"]["content"][0] == {
"type": "tool_result",
"tool_use_id": "t9",
"content": "прервано",
"content": "interrupted",
"is_error": True,
}
assert tail["parentUuid"] == entries[-2]["uuid"]
@@ -547,8 +551,8 @@ async def test_recover_closes_open_tool_use_and_injects_interrupted(
note = (await world.conversations.queue.recent(conv.id))[0]
assert (
"turn_dead" in note.text
and "оборван" in note.text
and "1 незакрытых" in note.text
and "cut by a gateway restart" in note.text
and "1 open tool calls" in note.text
)
await asyncio.sleep(0.2)
assert ScriptedClient.instances == []
@@ -798,9 +802,9 @@ async def test_wake_injects_start_a_turn_and_take_normals_along(world: World) ->
await world.settle(conv, 2)
prompts = ScriptedClient.instances[0].prompts
assert len(prompts) == 1
assert prompts[0].startswith("[инжект: schedule")
assert prompts[0].startswith("[inject: schedule")
assert "reminder" in prompts[0]
assert "[инжект: watch" in prompts[0]
assert "[inject: watch" in prompts[0]
assert "digest" in prompts[0]
assert await world.statuses(conv) == [("normal", "done"), ("wake", "done")]