Initial commit

This commit is contained in:
LZH-YS1998
2026-07-01 17:56:31 +08:00
commit d78931979d
731 changed files with 311088 additions and 0 deletions
+671
View File
@@ -0,0 +1,671 @@
from __future__ import annotations
import json
import unittest
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock
from opc.core.models import Task, TaskStatus
from opc.layer2_organization.company_mode import CompanyWorkItemExecutor
from opc.plugins.office_ui.event_adapter import EventAdapter
from opc.plugins.office_ui.snapshot_builder import (
_resolve_task_selected_execution_agent as resolve_snapshot_selected_execution_agent,
)
from opc.plugins.office_ui.ws_handler import WSHandler
class WSHandlerProgressParsingTests(unittest.TestCase):
def test_tool_progress_preserves_full_detail_and_unicode(self) -> None:
detail = json.dumps(
{
"todos": '[{"id":"1","title":"梳理需求","status":"in_progress"}]',
"note": "x" * 180,
},
ensure_ascii=False,
)
entry = WSHandler._parse_progress_entry(f"[Tool: todo_write] {detail}")
self.assertIsNotNone(entry)
self.assertEqual(entry["type"], "tool_call")
self.assertEqual(entry["summary"], "todo_write")
self.assertEqual(entry["detail"], detail)
self.assertIn("梳理需求", entry["detail"])
self.assertGreater(len(entry["detail"]), 100)
def test_external_codex_thinking_progress_maps_to_thinking_entry(self) -> None:
entry = WSHandler._parse_progress_entry("[External:codex:thinking] 我先检查 UI 渲染链路。")
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "thinking")
self.assertEqual(entry["summary"], "我先检查 UI 渲染链路。")
self.assertEqual(entry["detail"], "我先检查 UI 渲染链路。")
def test_external_codex_tool_progress_maps_to_tool_call(self) -> None:
detail = "$ git status --short\n\n M opc/plugins/office_ui/ws_handler.py"
entry = WSHandler._parse_progress_entry(f"[External:codex:tool] {detail}")
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "tool_call")
self.assertEqual(entry["summary"], "git status --short")
self.assertEqual(entry["detail"], detail)
def test_external_cursor_tool_progress_preserves_search_detail(self) -> None:
detail = (
"web search: Cursor pricing plans\n"
"- Cursor · Pricing — https://www.cursor.com/pricing"
)
entry = WSHandler._parse_progress_entry(f"[External:cursor:tool] {detail}")
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "tool_call")
self.assertEqual(entry["summary"], "web search: Cursor pricing plans")
self.assertEqual(entry["detail"], detail)
def test_delegation_progress_preserves_external_agent_name(self) -> None:
entry = WSHandler._parse_progress_entry("[Delegating to opencode] task=hello")
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "handoff")
self.assertEqual(entry["summary"], "Delegating to opencode")
def test_plain_final_reply_is_not_parsed_as_thinking_progress(self) -> None:
entry = WSHandler._parse_progress_entry(
"I've completed the implementation and validated the happy path.",
)
self.assertIsNone(entry)
def test_runtime_assistant_delta_is_not_recorded_as_progress_entry(self) -> None:
entry = WSHandler._runtime_event_to_progress_entry(
{"type": "assistant_delta", "text": "final answer token"},
)
self.assertIsNone(entry)
def test_runtime_status_snapshot_maps_to_status_change_entry(self) -> None:
entry = WSHandler._runtime_event_to_progress_entry(
{
"type": "status_snapshot",
"current_tool": "shell_exec",
"context_remaining_pct": 64,
"turn_cost_usd": 0.0123,
},
)
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "status_change")
self.assertEqual(entry["summary"], "Runtime status")
self.assertIn("tool=shell_exec", entry["detail"])
self.assertIn("context=36% used", entry["detail"])
def test_runtime_member_claimed_work_item_maps_to_started_entry(self) -> None:
entry = WSHandler._runtime_event_to_progress_entry(
{
"type": "member_claimed_work_item",
"work_item_projection_id": "engineering_execution",
"message_priority": "manager",
},
)
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "work_item_started")
self.assertEqual(entry["summary"], "Work item resumed")
self.assertEqual(entry["detail"], "Claimed from manager queue.")
self.assertEqual(entry["work_item_projection_id"], "engineering_execution")
self.assertEqual(entry["work_item_projection_title"], "Engineering Execution")
self.assertNotIn("projection_id", entry)
self.assertNotIn("legacy_title", entry)
self.assertTrue(entry["is_company_runtime"])
def test_runtime_context_usage_prefers_token_count_over_remaining_pct(self) -> None:
entry = WSHandler._runtime_event_to_progress_entry(
{
"type": "context_usage",
"context_tokens": 3200,
"context_window": 8000,
"context_remaining_pct": 70,
},
)
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "status_change")
self.assertEqual(entry["summary"], "Context usage")
self.assertEqual(entry["detail"], "3200/8000 tokens | 40% used")
def test_runtime_cost_update_maps_to_status_change_entry(self) -> None:
entry = WSHandler._runtime_event_to_progress_entry(
{
"type": "cost_update",
"turn_cost_usd": 0.0123,
"session_cost_usd": 0.0456,
},
)
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "status_change")
self.assertEqual(entry["summary"], "Cost update")
self.assertIn("turn=$0.0123", entry["detail"])
def test_task_mode_low_value_runtime_events_are_hidden(self) -> None:
for runtime_type in (
"turn_started",
"turn_completed",
"status_snapshot",
"context_usage",
"cost_update",
"durable_memory_extracted",
"tool_batch_started",
"tool_batch_completed",
"permission_predicted",
"session_memory_updated",
"unknown_new_runtime_noise",
):
entry = WSHandler._runtime_event_to_progress_entry(
{
"type": runtime_type,
"execution_mode": "task_mode",
"runtime_kind": "task_mode_agent_turn",
},
)
self.assertIsNone(entry)
def test_task_mode_legacy_projection_is_not_company_runtime(self) -> None:
entry = WSHandler._runtime_event_to_progress_entry(
{
"type": "thinking_delta",
"execution_mode": "task_mode",
"work_item_projection_id": "task_mode_execution",
"work_item_turn_type": "execute",
"turn_id": "rt-1:1",
"item_id": "rt-1:1:thinking",
"seq": 1,
"text": "我先检查。",
},
)
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "thinking")
self.assertEqual(entry["summary"], "Thinking")
self.assertEqual(entry["detail"], "我先检查。")
self.assertEqual(entry["turn_id"], "rt-1:1")
self.assertEqual(entry["item_id"], "rt-1:1:thinking")
self.assertEqual(entry["seq"], 1)
self.assertNotIn("work_item_projection_id", entry)
self.assertNotIn("is_company_runtime", entry)
def test_task_mode_tool_progress_uses_stable_tool_item_id(self) -> None:
entry = WSHandler._runtime_event_to_progress_entry(
{
"type": "tool_completed",
"execution_mode": "task_mode",
"turn_id": "rt-1:2",
"tool_call_id": "call-1",
"tool_name": "web_search",
"result_summary": "ok",
},
)
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "tool_call")
self.assertEqual(entry["item_id"], "rt-1:2:tool:call-1")
self.assertEqual(entry["stream_id"], "rt-1:2:tool:call-1")
self.assertEqual(entry["tool_call_id"], "call-1")
def test_task_mode_permission_progress_uses_stable_permission_item_id(self) -> None:
entry = WSHandler._runtime_event_to_progress_entry(
{
"type": "permission_resolved",
"execution_mode": "task_mode",
"turn_id": "rt-1:2",
"tool_call_id": "call-1",
"tool_name": "shell_exec",
"resolution": "allow",
"permission_group_key": "tool:shell_exec/python:domain:example.com",
},
)
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "autonomy")
self.assertEqual(entry["item_id"], "rt-1:2:permission:call-1")
self.assertEqual(entry["permission_group_key"], "tool:shell_exec/python:domain:example.com")
def test_task_mode_checkpoint_saved_maps_to_needs_input(self) -> None:
entry = WSHandler._runtime_event_to_progress_entry(
{
"type": "checkpoint_saved",
"execution_mode": "task_mode",
"checkpoint_type": "task_user_input",
},
)
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "needs_input")
self.assertEqual(entry["summary"], "Needs input")
self.assertEqual(entry["detail"], "task_user_input")
def test_runtime_member_inbox_updated_maps_to_status_change_entry(self) -> None:
entry = WSHandler._runtime_event_to_progress_entry(
{
"type": "member_inbox_updated",
"actionable_inbox_count": 2,
"protocol_backlog_count": 1,
"notification_backlog_count": 3,
"resident_status": "idle",
},
)
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "status_change")
self.assertEqual(entry["summary"], "Resident inbox updated")
self.assertIn("chat=2", entry["detail"])
self.assertIn("protocol=1", entry["detail"])
def test_runtime_worker_notification_maps_error_to_work_item_failed_entry(self) -> None:
entry = WSHandler._runtime_event_to_progress_entry(
{
"type": "worker_notification",
"worker_type": "native_subagent",
"notification_kind": "error",
"summary": "The worker failed.",
},
)
self.assertIsNotNone(entry)
assert entry is not None
self.assertEqual(entry["type"], "work_item_failed")
self.assertEqual(entry["summary"], "native subagent: error")
self.assertEqual(entry["detail"], "The worker failed.")
class WSHandlerRuntimeEventRoutingTests(unittest.IsolatedAsyncioTestCase):
class _MemoryChatStore:
def __init__(self) -> None:
self.messages: list[dict] = []
async def insert_message(
self,
*,
channel_id: str,
sender: str,
sender_name: str,
content: str,
metadata: dict | None = None,
project_id: str = "default",
**_kw,
) -> dict:
message = {
"channel_id": channel_id,
"sender": sender,
"sender_name": sender_name,
"content": content,
"metadata": metadata or {},
"project_id": project_id,
}
self.messages.append(message)
return message
async def get_channel_messages(
self,
channel_id: str,
*,
limit: int = 100,
project_id: str = "default",
) -> list[dict]:
matched = [
message
for message in self.messages
if message["channel_id"] == channel_id and message["project_id"] == project_id
]
return matched[-limit:]
def _make_handler_for_task(self, task: Task) -> WSHandler:
engine = MagicMock()
engine.store = SimpleNamespace(get_task=AsyncMock(return_value=task))
engine.project_id = "test-project"
engine.escalation = None
return WSHandler(engine, MagicMock(), MagicMock(), MagicMock())
async def test_forwarded_delegation_progress_uses_sanitized_summary(self) -> None:
engine = MagicMock()
engine.store = SimpleNamespace(get_task=AsyncMock(return_value=None))
engine.project_id = "test-project"
engine.escalation = None
chat_store = self._MemoryChatStore()
handler = WSHandler(engine, MagicMock(), chat_store, EventAdapter())
handler.broadcast = AsyncMock()
handler._active_runtime_children["child-task"] = "parent-task"
await handler.on_progress(
"[Delegating to codex] task=COO Intake | cmd=codex exec <prompt:16-chars>",
task_id="child-task",
agent_role_id="coo",
agent_name="COO",
)
messages = await chat_store.get_channel_messages(
"session:parent-task",
limit=20,
project_id="test-project",
)
forwarded = [message for message in messages if "Delegating to codex" in message["content"]]
self.assertEqual(len(forwarded), 1)
self.assertNotIn("FULL ROLE PROMPT", forwarded[0]["content"])
self.assertEqual(forwarded[0]["metadata"]["detail_visibility"], "summary")
self.assertEqual(forwarded[0]["metadata"]["forwarded_from"], "child-task")
async def test_task_mode_runtime_visual_event_maps_to_origin_task(self) -> None:
execution = Task(
id="execution-task",
project_id="test-project",
session_id="session-1",
metadata={
"mode": "task",
"task_mode_contract": "single_full_capability_main_agent",
"origin_task_id": "ui-task",
},
)
handler = self._make_handler_for_task(execution)
event = await handler._canonicalize_runtime_visual_event({
"type": "assistant_delta",
"data": {
"task_id": "execution-task",
"runtime_session_id": "rt-1",
"iteration": 1,
"text": "hello",
},
})
data = event["data"]
self.assertEqual(data["task_id"], "ui-task")
self.assertEqual(data["runtime_task_id"], "execution-task")
self.assertEqual(data["execution_turn_id"], "execution-task")
self.assertEqual(data["turn_id"], "rt-1:1")
async def test_assistant_delta_is_chunked_and_flushed_before_turn_completed(self) -> None:
execution = Task(
id="execution-task",
project_id="test-project",
session_id="session-1",
metadata={
"mode": "task",
"task_mode_contract": "single_full_capability_main_agent",
"origin_task_id": "ui-task",
},
)
handler = self._make_handler_for_task(execution)
handler.broadcast = AsyncMock()
await handler._broadcast_runtime_visual_event({
"type": "assistant_delta",
"data": {
"task_id": "ui-task",
"runtime_task_id": "execution-task",
"execution_turn_id": "execution-task",
"turn_id": "rt-1:1",
"text": "hello",
},
})
handler.broadcast.assert_not_awaited()
await handler._broadcast_runtime_visual_event({
"type": "turn_completed",
"data": {
"task_id": "ui-task",
"runtime_task_id": "execution-task",
"execution_turn_id": "execution-task",
"turn_id": "rt-1:1",
},
})
self.assertEqual(handler.broadcast.await_count, 2)
delta_payload = handler.broadcast.await_args_list[0].args[0]["payload"]
self.assertEqual(delta_payload["type"], "assistant_delta")
self.assertEqual(delta_payload["data"]["text"], "hello")
completed_payload = handler.broadcast.await_args_list[1].args[0]["payload"]
self.assertEqual(completed_payload["type"], "turn_completed")
async def test_task_mode_session_config_overrides_stale_agent_selection(self) -> None:
task = Task(
id="ui-task",
project_id="test-project",
session_id="session-1",
metadata={
"mode": "task",
"exec_mode": "task",
"execution_mode": "task_mode",
"preferred_agent": "native",
"selected_execution_agent": "native",
"agent_selection": {
"selected": "native",
"selection_source": "forced_native",
},
},
)
engine = MagicMock()
engine.store = SimpleNamespace(save_task=AsyncMock())
engine.memory = None
engine.project_id = "test-project"
engine.escalation = None
handler = WSHandler(engine, MagicMock(), MagicMock(), MagicMock())
await handler._persist_session_config(
task,
exec_mode="task",
company_profile="corporate",
preferred_agent="codex",
)
self.assertEqual(task.metadata["preferred_agent"], "codex")
self.assertEqual(task.metadata["selected_execution_agent"], "codex")
self.assertEqual(task.metadata["preferred_external_agent"], "codex")
self.assertFalse(task.metadata["force_native_execution"])
self.assertEqual(task.metadata["agent_selection"]["selected"], "codex")
self.assertEqual(task.metadata["agent_selection"]["selection_source"], "session_config")
self.assertEqual(handler._resolve_task_selected_execution_agent(task), "codex")
async def test_task_mode_snapshot_prefers_explicit_config_over_stale_agent_selection(self) -> None:
task = Task(
id="ui-task",
project_id="test-project",
session_id="session-1",
metadata={
"mode": "task",
"exec_mode": "task",
"execution_mode": "task_mode",
"preferred_agent": "codex",
"selected_execution_agent": "codex",
"agent_selection": {
"selected": "native",
"selection_source": "forced_native",
},
},
)
self.assertEqual(resolve_snapshot_selected_execution_agent(task), "codex")
async def test_member_claimed_work_item_broadcasts_parent_work_item_progress(self) -> None:
engine = MagicMock()
engine.project_id = "test-project"
engine.store = None
engine.escalation = None
handler = WSHandler(
engine,
MagicMock(),
MagicMock(),
MagicMock(),
)
broadcasts: list[dict] = []
handler.broadcast = AsyncMock(side_effect=lambda msg: broadcasts.append(msg))
handler._active_runtime_children["projection-task-1"] = "parent-task-1"
await handler._handle_runtime_event_progress(
{
"type": "member_claimed_work_item",
"task_id": "projection-task-1",
"work_item_projection_id": "engineering_execution",
"message_priority": "manager",
}
)
work_item_payloads = [
item["payload"]
for item in broadcasts
if item.get("type") == "work_item_progress"
]
self.assertEqual(len(work_item_payloads), 1)
self.assertEqual(work_item_payloads[0]["task_id"], "parent-task-1")
obsolete_entry_key = "work_item_" + "task_id"
self.assertNotIn(obsolete_entry_key, work_item_payloads[0])
self.assertEqual(work_item_payloads[0]["entry"]["type"], "work_item_started")
self.assertNotIn(obsolete_entry_key, work_item_payloads[0]["entry"])
self.assertEqual(work_item_payloads[0]["entry"]["execution_turn_id"], "projection-task-1")
self.assertEqual(work_item_payloads[0]["entry"]["work_item_projection_id"], "engineering_execution")
self.assertEqual(work_item_payloads[0]["entry"]["work_item_projection_title"], "Engineering Execution")
self.assertNotIn("projection_id", work_item_payloads[0]["entry"])
self.assertNotIn("legacy_title", work_item_payloads[0]["entry"])
async def test_member_claimed_work_item_enriches_work_item_role_name(self) -> None:
engine = MagicMock()
engine.project_id = "test-project"
engine.store = None
engine.escalation = None
role = MagicMock()
role.name = "CEO"
engine.org_engine.get_agent.return_value = role
handler = WSHandler(
engine,
MagicMock(),
MagicMock(),
MagicMock(),
)
broadcasts: list[dict] = []
handler.broadcast = AsyncMock(side_effect=lambda msg: broadcasts.append(msg))
handler._active_runtime_children["projection-task-1"] = "parent-task-1"
await handler._handle_runtime_event_progress(
{
"type": "member_claimed_work_item",
"task_id": "projection-task-1",
"role_id": "ceo",
"work_item_projection_id": "5ce42865-4a7d-4f27-8a3b-9c0a0f3a0c1a",
"message_priority": "manager",
}
)
work_item_payload = next(
item["payload"]
for item in broadcasts
if item.get("type") == "work_item_progress"
)
entry = work_item_payload["entry"]
self.assertEqual(entry["role_name"], "CEO")
self.assertEqual(entry["work_item_projection_title"], "CEO")
self.assertNotIn("legacy_title", entry)
async def test_company_progress_callback_includes_role_identity(self) -> None:
role = MagicMock()
role.role_id = "ceo"
role.name = "CEO"
org_engine = MagicMock()
org_engine.get_agent.return_value = role
progress_callback = AsyncMock()
executor = CompanyWorkItemExecutor(
org_engine=org_engine,
communication=None,
approval_engine=None,
memory=None,
execute_task=AsyncMock(),
save_task=AsyncMock(),
progress_callback=progress_callback,
)
task = Task(
id="projection-task-1",
title="CEO Intake",
assigned_to="ceo",
status=TaskStatus.RUNNING,
metadata={
"work_item_projection_id": "5ce42865-4a7d-4f27-8a3b-9c0a0f3a0c1a",
"work_item_role_id": "ceo",
},
)
executor._active_tasks = [task]
await executor._emit_progress(
"[Company:5ce42865-4a7d-4f27-8a3b-9c0a0f3a0c1a] starting CEO Intake",
task_id=task.id,
)
_, kwargs = progress_callback.await_args
self.assertEqual(kwargs["task_id"], task.id)
self.assertEqual(kwargs["agent_role_id"], "ceo")
self.assertEqual(kwargs["agent_name"], "CEO")
async def test_worker_notification_broadcasts_dedicated_event_and_session_message(self) -> None:
engine = MagicMock()
engine.project_id = "test-project"
engine.store = None
engine.escalation = None
chat_store = MagicMock()
chat_store.create_session_channel = AsyncMock()
chat_store.insert_message = AsyncMock(return_value={
"message_id": "msg-1",
"channel_id": "session:task-1",
"sender": "system",
"sender_name": "Native Subagent",
"content": "ready",
"created_at": 123.0,
"reply_to_id": None,
"mentions": [],
"metadata": {},
})
event_adapter = MagicMock()
event_adapter.translate.return_value = []
handler = WSHandler(
engine,
MagicMock(),
chat_store,
event_adapter,
)
broadcasts: list[dict] = []
handler.broadcast = AsyncMock(side_effect=lambda msg: broadcasts.append(msg))
await handler.on_opc_event(MagicMock(
event_type="runtime_event",
payload={
"type": "worker_notification",
"task_id": "task-1",
"worker_id": "na_123",
"worker_type": "native_subagent",
"notification_kind": "idle",
"summary": "ready",
},
))
broadcast_types = [item.get("type") for item in broadcasts]
self.assertIn("worker_notification", broadcast_types)
self.assertIn("session_message", broadcast_types)
self.assertIn("session_progress", broadcast_types)
chat_store.create_session_channel.assert_awaited()
chat_store.insert_message.assert_awaited()
if __name__ == "__main__":
unittest.main()