feat: one gateway port with path-mounted frontends, markdown chat, collapsible sidebars

This commit is contained in:
hh
2026-08-29 00:49:06 +02:00
parent 3ca5843868
commit 932a7a80af
32 changed files with 691 additions and 441 deletions
+9 -7
View File
@@ -14,6 +14,7 @@ from beaver_gateway.frontends.anthropic import AnthropicMessagesFrontend
from beaver_gateway.frontends.api import ApiFrontend
from beaver_gateway.frontends.base import GatewayRuntime
from beaver_gateway.frontends.markdown import MarkdownFrontend
from beaver_gateway.frontends.root import build_root_app
from test_conversations import ScriptedClient, World
AUTH = {"Authorization": "Bearer tok"}
@@ -42,10 +43,11 @@ class Stack:
for fe in frontends:
fe.configure(self.runtime)
self.mirror = asyncio.create_task(self.markdown.mirror.run())
self.root = build_root_app(frontends)
def client(self, fe) -> httpx.AsyncClient:
return httpx.AsyncClient(
transport=httpx.ASGITransport(app=fe._app), base_url="http://t"
transport=httpx.ASGITransport(app=self.root), base_url=f"http://t{fe.path}"
)
async def close(self) -> None:
@@ -83,14 +85,14 @@ async def stack() -> Stack:
async def test_api_rejects_deep_with_dispatcher(stack: Stack) -> None:
async with stack.client(stack.api) as c:
r = await c.post(
"/api/conversations", json={"kind": "deep", "agent": "a"}, headers=AUTH
"/conversations", json={"kind": "deep", "agent": "a"}, headers=AUTH
)
assert r.status_code == 400
assert "does not serve kind 'deep'" in r.json()["error"]
r = await c.post("/api/conversations", json={"kind": "job"}, headers=AUTH)
r = await c.post("/conversations", json={"kind": "job"}, headers=AUTH)
assert r.status_code == 400
assert "no default agent" in r.json()["error"]
r = await c.get("/api/agents", headers=AUTH)
r = await c.get("/agents", headers=AUTH)
agents = {a["name"]: a["kinds"] for a in r.json()["agents"]}
assert agents == {"a": ["master", "branch", "job", "fork"], "d": ["deep"]}
homes = {f["name"]: f["default_agents"] for f in r.json()["frontends"]}
@@ -103,11 +105,11 @@ async def test_api_rejects_deep_with_dispatcher(stack: Stack) -> None:
async def test_api_spawn_deep_lands_in_vault(stack: Stack) -> None:
async with stack.client(stack.api) as c:
r = await c.post("/api/conversations", json={"kind": "master"}, headers=AUTH)
r = await c.post("/conversations", json={"kind": "master"}, headers=AUTH)
assert r.status_code == 201 and r.json()["agent"] == "a"
master = r.json()["id"]
r = await c.post(
"/api/conversations",
"/conversations",
json={"kind": "deep", "seed": "brief", "text": "dig", "title": "Тема"},
headers=AUTH,
)
@@ -118,7 +120,7 @@ async def test_api_spawn_deep_lands_in_vault(stack: Stack) -> None:
rel = body["bindings"][0]["external_id"]
assert rel.endswith("_Тема.md") and rel.startswith("_logs/d/")
r = await c.post(
f"/api/conversations/{master}/bind",
f"/conversations/{master}/bind",
json={"frontend": "markdown", "external_id": "x.md"},
headers=AUTH,
)