Initial commit
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from opc.core.company_tools import (
|
||||
COLLAB_PROFILE_COORDINATOR_DEFAULT,
|
||||
COLLAB_PROFILE_MANAGER_DEFAULT,
|
||||
COLLAB_PROFILE_WORKER_DEFAULT,
|
||||
REVIEW_EXECUTE_TURN_MODE,
|
||||
resolve_allowed_collaboration_tools,
|
||||
)
|
||||
from opc.core.events import EventBus
|
||||
from opc.core.models import (
|
||||
ExecutionCheckpoint,
|
||||
ExecutionMode,
|
||||
Task,
|
||||
TaskStatus,
|
||||
)
|
||||
from opc.database.store import OPCStore
|
||||
from opc.engine import OPCEngine
|
||||
from opc.layer2_organization.communication import CommunicationManager
|
||||
from opc.layer2_organization.work_item_links import set_linked_work_item_id
|
||||
from opc.layer4_tools.collaboration import build_external_cli_tool_contract_lines, create_collaboration_tools
|
||||
from opc.layer4_tools.collaboration_dispatch import dispatch_collaboration_tool
|
||||
from opc.layer4_tools.user_input import request_user_input
|
||||
|
||||
|
||||
class RequestUserInputCollabTests(unittest.IsolatedAsyncioTestCase):
|
||||
async def test_request_user_input_normalizes_legacy_and_choice_questions(self) -> None:
|
||||
result = await request_user_input(
|
||||
reason="Need deployment input.",
|
||||
questions=[
|
||||
"Which region should we deploy to?",
|
||||
{
|
||||
"id": "deployment_region",
|
||||
"header": "Deployment region",
|
||||
"question": "Which region should I target?",
|
||||
"options": [
|
||||
{"label": "US East", "description": "Use us-east-1"},
|
||||
{"label": "EU West", "description": "Use eu-west-1"},
|
||||
{"label": "Asia", "description": "Use ap-east-1"},
|
||||
{"label": "Overflow option"},
|
||||
],
|
||||
},
|
||||
],
|
||||
required_fields=["deployment_region"],
|
||||
)
|
||||
|
||||
self.assertTrue(result["requires_user_input"])
|
||||
self.assertEqual(
|
||||
result["questions"],
|
||||
["Which region should we deploy to?", "Which region should I target?"],
|
||||
)
|
||||
self.assertEqual(result["input_questions"][0]["id"], "question_1")
|
||||
self.assertEqual(result["input_questions"][0]["options"], [])
|
||||
self.assertTrue(result["input_questions"][0]["allow_freeform"])
|
||||
structured = result["input_questions"][1]
|
||||
self.assertEqual(structured["id"], "deployment_region")
|
||||
self.assertEqual([option["id"] for option in structured["options"]], ["a", "b", "c"])
|
||||
self.assertEqual(len(structured["options"]), 3)
|
||||
self.assertTrue(structured["allow_freeform"])
|
||||
self.assertTrue(structured["required"])
|
||||
|
||||
def test_company_toolsets_do_not_include_request_user_input(self) -> None:
|
||||
for profile in (
|
||||
COLLAB_PROFILE_WORKER_DEFAULT,
|
||||
COLLAB_PROFILE_MANAGER_DEFAULT,
|
||||
COLLAB_PROFILE_COORDINATOR_DEFAULT,
|
||||
):
|
||||
with self.subTest(profile=profile):
|
||||
self.assertNotIn("request_user_input", resolve_allowed_collaboration_tools(profile))
|
||||
|
||||
review_task = Task(
|
||||
metadata={
|
||||
"runtime_model": "multi_team_org",
|
||||
"current_turn_mode": REVIEW_EXECUTE_TURN_MODE,
|
||||
}
|
||||
)
|
||||
self.assertNotIn(
|
||||
"request_user_input",
|
||||
resolve_allowed_collaboration_tools(COLLAB_PROFILE_WORKER_DEFAULT, task=review_task),
|
||||
)
|
||||
|
||||
def test_close_human_review_is_only_added_for_delivery_review_followup(self) -> None:
|
||||
task = Task(
|
||||
metadata={
|
||||
"execution_mode": ExecutionMode.COMPANY_MODE.value,
|
||||
"runtime_model": "multi_team_org",
|
||||
"current_turn_mode": "dispatch_required",
|
||||
},
|
||||
)
|
||||
self.assertNotIn(
|
||||
"close_human_review",
|
||||
resolve_allowed_collaboration_tools(COLLAB_PROFILE_MANAGER_DEFAULT, task=task),
|
||||
)
|
||||
task.metadata["human_review_close_allowed"] = True
|
||||
self.assertIn(
|
||||
"close_human_review",
|
||||
resolve_allowed_collaboration_tools(COLLAB_PROFILE_MANAGER_DEFAULT, task=task),
|
||||
)
|
||||
|
||||
def test_external_contract_omits_request_user_input_for_company_collab(self) -> None:
|
||||
lines = build_external_cli_tool_contract_lines({"request_user_input"})
|
||||
rendered = "\n".join(lines)
|
||||
self.assertNotIn("`request_user_input` arguments", rendered)
|
||||
self.assertIn("Use the exact argument names", rendered)
|
||||
|
||||
async def test_company_collaboration_tools_do_not_register_request_user_input(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
store = OPCStore(Path(tmpdir) / "tasks.db")
|
||||
await store.initialize()
|
||||
try:
|
||||
communication = CommunicationManager(store, EventBus())
|
||||
tool_names = {tool.name for tool in create_collaboration_tools(communication)}
|
||||
self.assertNotIn("request_user_input", tool_names)
|
||||
finally:
|
||||
await store.close()
|
||||
|
||||
async def test_opc_collab_dispatch_request_user_input_is_unknown(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
store = OPCStore(Path(tmpdir) / "tasks.db")
|
||||
await store.initialize()
|
||||
try:
|
||||
task = Task(
|
||||
id="task-cli-input",
|
||||
title="CLI scoped work",
|
||||
project_id="proj1",
|
||||
session_id="child-session",
|
||||
parent_session_id="parent-session",
|
||||
assigned_to="cto",
|
||||
status=TaskStatus.RUNNING,
|
||||
metadata={
|
||||
"execution_mode": ExecutionMode.COMPANY_MODE.value,
|
||||
"work_item_projection_id": "cto_plan",
|
||||
"delegation_seat_id": "seat::team::ceo::cto",
|
||||
},
|
||||
)
|
||||
set_linked_work_item_id(task, "work-item-cli")
|
||||
await store.save_task(task)
|
||||
env = {
|
||||
"OPC_COMMS_FROM": "cto",
|
||||
"OPC_COMMS_PROJECT": "proj1",
|
||||
"OPC_COMMS_SESSION": "parent-session",
|
||||
"OPC_WORKSPACE_ROOT": tmpdir,
|
||||
"OPC_TASK_ID": task.id,
|
||||
"OPC_WORK_ITEM_ID": "work-item-cli",
|
||||
"OPC_PROJECT_DB_PATH": str(store.db_path),
|
||||
"OPC_ALLOWED_COLLAB_TOOLS": json.dumps(["request_user_input"]),
|
||||
}
|
||||
|
||||
payload, is_error = await dispatch_collaboration_tool(
|
||||
"request_user_input",
|
||||
{"reason": "Need approval.", "target_task_id": "other-task"},
|
||||
env=env,
|
||||
)
|
||||
self.assertTrue(is_error)
|
||||
self.assertIn("unknown tool: request_user_input", payload["error"])
|
||||
finally:
|
||||
await store.close()
|
||||
|
||||
async def test_engine_does_not_coerce_external_user_input_markers(self) -> None:
|
||||
engine = OPCEngine.__new__(OPCEngine)
|
||||
self.assertFalse(hasattr(engine, "_coerce_external_user_input_pause"))
|
||||
|
||||
async def test_resume_task_checkpoint_stores_plain_user_input(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
store = OPCStore(Path(tmpdir) / "tasks.db")
|
||||
await store.initialize()
|
||||
try:
|
||||
pause_request = (await request_user_input(
|
||||
reason="Need deployment region.",
|
||||
questions=[
|
||||
{
|
||||
"id": "deployment_region",
|
||||
"header": "Deployment region",
|
||||
"question": "Which region?",
|
||||
"options": [{"id": "a", "label": "US East"}],
|
||||
}
|
||||
],
|
||||
))
|
||||
task = Task(
|
||||
id="task-resume-input",
|
||||
title="Resume input",
|
||||
project_id="proj1",
|
||||
session_id="session-1",
|
||||
assigned_to="engineer",
|
||||
status=TaskStatus.AWAITING_HUMAN,
|
||||
)
|
||||
await store.save_task(task)
|
||||
checkpoint = ExecutionCheckpoint(
|
||||
checkpoint_id="cp-resume-input",
|
||||
project_id="proj1",
|
||||
session_id="session-1",
|
||||
checkpoint_type="task_user_input",
|
||||
task_id=task.id,
|
||||
payload={
|
||||
"task_id": task.id,
|
||||
"task_ids": [task.id],
|
||||
"execution_mode": ExecutionMode.SINGLE_AGENT.value,
|
||||
"pause_request": pause_request,
|
||||
"runtime_v2": {"runtime_session_id": "rt-1"},
|
||||
},
|
||||
)
|
||||
await store.save_execution_checkpoint(checkpoint)
|
||||
engine = OPCEngine.__new__(OPCEngine)
|
||||
engine.store = store
|
||||
engine.project_id = "proj1"
|
||||
|
||||
async def _ensure_checkpoint_runtime_v2_payload(cp: ExecutionCheckpoint) -> ExecutionCheckpoint:
|
||||
return cp
|
||||
|
||||
async def _execute_single_agent(_tasks: list[Task], _agent: str | None) -> str:
|
||||
return "resumed"
|
||||
|
||||
engine._ensure_checkpoint_runtime_v2_payload = _ensure_checkpoint_runtime_v2_payload
|
||||
engine._restore_runtime_state_from_checkpoint = lambda _task, _payload: None
|
||||
engine._execute_single_agent = _execute_single_agent
|
||||
|
||||
response = await engine._resume_task_checkpoint(
|
||||
checkpoint,
|
||||
"Selected US East.",
|
||||
)
|
||||
|
||||
self.assertEqual(response, "resumed")
|
||||
refreshed = await store.get_task(task.id)
|
||||
self.assertEqual(refreshed.context_snapshot["user_supplied_input"], "Selected US East.")
|
||||
self.assertNotIn("user_input_answers", refreshed.context_snapshot)
|
||||
checkpoints = await store.get_execution_checkpoints(project_id="proj1")
|
||||
self.assertEqual(checkpoints[0].status, "resolved")
|
||||
finally:
|
||||
await store.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user