Introduce Devii agents subsystem with supervisor, policy, and evals
- Add agents package: controller, runner, store, tools, actions, evals, policy - Wire agents into Devii service, session, registry, CLI, and dispatcher - Extend database schema and config for agent persistence - Add news and telegram bridge updates plus landing UI and docs - Cover agents, news, and telegram flows with unit tests
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
import asyncio
|
||||
|
||||
from devplacepy.database import get_setting, set_setting
|
||||
from devplacepy.services.devii.agents.runner import SUBAGENT_BASE_PROMPT
|
||||
from devplacepy.services.devii.config import FIELD_AGENTS_ENABLED
|
||||
from devplacepy.services.devii.session import ORCHESTRATION_FRAGMENT
|
||||
from devplacepy.services.manager import service_manager
|
||||
from devplacepy.services.devii import DeviiService
|
||||
from tests.conftest import run_async
|
||||
|
||||
|
||||
def _hub():
|
||||
if service_manager.get_service("devii") is None:
|
||||
service_manager.register(DeviiService())
|
||||
svc = service_manager.get_service("devii")
|
||||
return svc.hub(), svc
|
||||
|
||||
|
||||
def _session(channel, owner_id):
|
||||
hub, svc = _hub()
|
||||
return hub.get_or_create(
|
||||
"guest", owner_id, "guest", "", svc.instance_base_url(), is_admin=False, channel=channel
|
||||
)
|
||||
|
||||
|
||||
class _Conn:
|
||||
def __init__(self):
|
||||
self.frames = []
|
||||
|
||||
async def send_json(self, payload):
|
||||
self.frames.append(payload)
|
||||
|
||||
|
||||
def test_orchestration_block_follows_flag(local_db):
|
||||
previous = get_setting(FIELD_AGENTS_ENABLED, "")
|
||||
try:
|
||||
set_setting(FIELD_AGENTS_ENABLED, "")
|
||||
main = _session("main", "prompt-off")
|
||||
assert "# ORCHESTRATION" not in main._compose_system_prompt()
|
||||
set_setting(FIELD_AGENTS_ENABLED, "1")
|
||||
assert "# ORCHESTRATION" in main._compose_system_prompt()
|
||||
assert "agent_start" in main._compose_system_prompt()
|
||||
assert "needs_user" in main._compose_system_prompt()
|
||||
docs = _session("docs", "prompt-docs")
|
||||
assert "# ORCHESTRATION" not in docs._compose_system_prompt()
|
||||
finally:
|
||||
set_setting(FIELD_AGENTS_ENABLED, previous or "")
|
||||
|
||||
|
||||
def test_fragments_cover_contract_and_relay():
|
||||
assert "four-part contract" in ORCHESTRATION_FRAGMENT
|
||||
assert "budget_hint" in ORCHESTRATION_FRAGMENT
|
||||
assert "agent_result" in ORCHESTRATION_FRAGMENT
|
||||
assert "ui_prompt" in ORCHESTRATION_FRAGMENT
|
||||
assert "ask_user" in SUBAGENT_BASE_PROMPT
|
||||
assert "Confirmation-gated" in SUBAGENT_BASE_PROMPT
|
||||
|
||||
|
||||
def test_trace_agent_emits_labelled_frame(local_db):
|
||||
session = _session("main", "trace-agent")
|
||||
conn = _Conn()
|
||||
|
||||
async def flow():
|
||||
session.attach(conn)
|
||||
try:
|
||||
session.trace_agent("uid-1", "sg", "call", "fetch_url", "example.com")
|
||||
await asyncio.sleep(0.2)
|
||||
finally:
|
||||
session.detach(conn)
|
||||
|
||||
run_async(flow())
|
||||
assert conn.frames
|
||||
frame = conn.frames[-1]
|
||||
assert frame["type"] == "trace"
|
||||
assert frame["agent"] == "sg"
|
||||
assert frame["uid"] == "uid-1"
|
||||
assert frame["name"] == "fetch_url"
|
||||
|
||||
|
||||
def test_emit_agent_buffers_for_web_not_telegram(local_db):
|
||||
main = _session("main", "emit-main")
|
||||
telegram = _session("telegram", "emit-tg")
|
||||
|
||||
async def flow():
|
||||
assert await main.emit_agent({"type": "agent", "kind": "done"}) is False
|
||||
assert await telegram.emit_agent({"type": "agent", "kind": "done"}) is False
|
||||
|
||||
run_async(flow())
|
||||
assert [f["type"] for f in main._buffer] == ["agent"]
|
||||
assert telegram._buffer == []
|
||||
Reference in New Issue
Block a user