Implement plans
This commit is contained in:
193
core/tests/test_codex_commands_phase1.py
Normal file
193
core/tests/test_codex_commands_phase1.py
Normal file
@@ -0,0 +1,193 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
from django.test import TestCase
|
||||
|
||||
from core.commands.base import CommandContext
|
||||
from core.commands.engine import process_inbound_message
|
||||
from core.commands.handlers.codex import parse_codex_command
|
||||
from core.models import (
|
||||
ChatSession,
|
||||
CommandChannelBinding,
|
||||
CommandProfile,
|
||||
CodexPermissionRequest,
|
||||
CodexRun,
|
||||
DerivedTask,
|
||||
ExternalSyncEvent,
|
||||
Message,
|
||||
Person,
|
||||
PersonIdentifier,
|
||||
TaskProject,
|
||||
TaskProviderConfig,
|
||||
User,
|
||||
)
|
||||
|
||||
|
||||
class CodexCommandParserTests(TestCase):
|
||||
def test_parse_variants(self):
|
||||
self.assertEqual("default", parse_codex_command("#codex# run this").command)
|
||||
self.assertEqual("plan", parse_codex_command("#codex plan# run this").command)
|
||||
self.assertEqual("status", parse_codex_command("#codex status#").command)
|
||||
parsed = parse_codex_command("#codex approve abc123#")
|
||||
self.assertEqual("approve", parsed.command)
|
||||
self.assertEqual("abc123", parsed.approval_key)
|
||||
self.assertEqual("default", parse_codex_command(".codex run this").command)
|
||||
self.assertEqual("plan", parse_codex_command(".CODEX plan run this").command)
|
||||
self.assertEqual("status", parse_codex_command(".codex status").command)
|
||||
parsed_dot = parse_codex_command(".codex approve abc123")
|
||||
self.assertEqual("approve", parsed_dot.command)
|
||||
self.assertEqual("abc123", parsed_dot.approval_key)
|
||||
|
||||
|
||||
class CodexCommandExecutionTests(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user("codex-cmd-user", "codex-cmd@example.com", "x")
|
||||
self.person = Person.objects.create(user=self.user, name="Codex Cmd")
|
||||
self.identifier = PersonIdentifier.objects.create(
|
||||
user=self.user,
|
||||
person=self.person,
|
||||
service="web",
|
||||
identifier="web-chan-1",
|
||||
)
|
||||
self.session = ChatSession.objects.create(user=self.user, identifier=self.identifier)
|
||||
self.project = TaskProject.objects.create(user=self.user, name="Project A")
|
||||
self.task = DerivedTask.objects.create(
|
||||
user=self.user,
|
||||
project=self.project,
|
||||
epic=None,
|
||||
title="Task A",
|
||||
source_service="web",
|
||||
source_channel="web-chan-1",
|
||||
reference_code="1",
|
||||
status_snapshot="open",
|
||||
)
|
||||
self.profile = CommandProfile.objects.create(
|
||||
user=self.user,
|
||||
slug="codex",
|
||||
name="Codex",
|
||||
enabled=True,
|
||||
trigger_token="#codex#",
|
||||
reply_required=False,
|
||||
exact_match_only=False,
|
||||
)
|
||||
CommandChannelBinding.objects.create(
|
||||
profile=self.profile,
|
||||
direction="ingress",
|
||||
service="web",
|
||||
channel_identifier="web-chan-1",
|
||||
enabled=True,
|
||||
)
|
||||
TaskProviderConfig.objects.create(
|
||||
user=self.user,
|
||||
provider="codex_cli",
|
||||
enabled=True,
|
||||
settings={
|
||||
"command": "codex",
|
||||
"workspace_root": "",
|
||||
"default_profile": "",
|
||||
"timeout_seconds": 60,
|
||||
"chat_link_mode": "task-sync",
|
||||
"instance_label": "default",
|
||||
"approver_mode": "channel",
|
||||
"approver_service": "web",
|
||||
"approver_identifier": "approver-chan",
|
||||
},
|
||||
)
|
||||
|
||||
def _msg(self, text: str, *, source_chat_id: str = "web-chan-1", reply_to=None):
|
||||
return Message.objects.create(
|
||||
user=self.user,
|
||||
session=self.session,
|
||||
sender_uuid="",
|
||||
text=text,
|
||||
ts=1000 + Message.objects.filter(user=self.user).count(),
|
||||
source_service="web",
|
||||
source_chat_id=source_chat_id,
|
||||
reply_to=reply_to,
|
||||
message_meta={},
|
||||
)
|
||||
|
||||
def test_default_submission_creates_run_and_event(self):
|
||||
trigger = self._msg("#codex# please update #1")
|
||||
results = async_to_sync(process_inbound_message)(
|
||||
CommandContext(
|
||||
service="web",
|
||||
channel_identifier="web-chan-1",
|
||||
message_id=str(trigger.id),
|
||||
user_id=self.user.id,
|
||||
message_text=str(trigger.text),
|
||||
payload={},
|
||||
)
|
||||
)
|
||||
self.assertEqual(1, len(results))
|
||||
self.assertTrue(results[0].ok)
|
||||
run = CodexRun.objects.order_by("-created_at").first()
|
||||
self.assertIsNotNone(run)
|
||||
self.assertEqual("queued", run.status)
|
||||
event = ExternalSyncEvent.objects.order_by("-created_at").first()
|
||||
self.assertEqual("pending", event.status)
|
||||
self.assertEqual("default", str((event.payload or {}).get("provider_payload", {}).get("mode") or ""))
|
||||
|
||||
def test_plan_requires_reply_anchor(self):
|
||||
trigger = self._msg("#codex plan# #1")
|
||||
results = async_to_sync(process_inbound_message)(
|
||||
CommandContext(
|
||||
service="web",
|
||||
channel_identifier="web-chan-1",
|
||||
message_id=str(trigger.id),
|
||||
user_id=self.user.id,
|
||||
message_text=str(trigger.text),
|
||||
payload={},
|
||||
)
|
||||
)
|
||||
self.assertEqual(1, len(results))
|
||||
self.assertFalse(results[0].ok)
|
||||
self.assertEqual("reply_required_for_codex_plan", results[0].error)
|
||||
|
||||
def test_approve_command_queues_resume_event(self):
|
||||
run = CodexRun.objects.create(
|
||||
user=self.user,
|
||||
task=self.task,
|
||||
project=self.project,
|
||||
source_service="web",
|
||||
source_channel="web-chan-1",
|
||||
status="waiting_approval",
|
||||
request_payload={"action": "append_update", "provider_payload": {"task_id": str(self.task.id)}},
|
||||
result_payload={},
|
||||
)
|
||||
req = CodexPermissionRequest.objects.create(
|
||||
user=self.user,
|
||||
codex_run=run,
|
||||
approval_key="ak-123",
|
||||
summary="Need approval",
|
||||
requested_permissions={"items": ["write"]},
|
||||
resume_payload={"resume": True},
|
||||
status="pending",
|
||||
)
|
||||
CommandChannelBinding.objects.create(
|
||||
profile=self.profile,
|
||||
direction="ingress",
|
||||
service="web",
|
||||
channel_identifier="approver-chan",
|
||||
enabled=True,
|
||||
)
|
||||
trigger = self._msg("#codex approve ak-123#", source_chat_id="approver-chan")
|
||||
results = async_to_sync(process_inbound_message)(
|
||||
CommandContext(
|
||||
service="web",
|
||||
channel_identifier="approver-chan",
|
||||
message_id=str(trigger.id),
|
||||
user_id=self.user.id,
|
||||
message_text=str(trigger.text),
|
||||
payload={},
|
||||
)
|
||||
)
|
||||
self.assertEqual(1, len(results))
|
||||
self.assertTrue(results[0].ok)
|
||||
req.refresh_from_db()
|
||||
run.refresh_from_db()
|
||||
self.assertEqual("approved", req.status)
|
||||
self.assertEqual("approved_waiting_resume", run.status)
|
||||
self.assertTrue(
|
||||
ExternalSyncEvent.objects.filter(idempotency_key="codex_approval:ak-123:approved", status="pending").exists()
|
||||
)
|
||||
Reference in New Issue
Block a user