Reimplement compose and add tiling windows

This commit is contained in:
2026-03-12 22:03:30 +00:00
parent 79766d279d
commit 6ceff63b71
126 changed files with 5111 additions and 10796 deletions

View File

@@ -3,7 +3,6 @@ from __future__ import annotations
import re
from core.models import ChatTaskSource, TaskProject
from core.tasks.codex_support import channel_variants
SAFE_TASK_FLAGS_DEFAULTS = {
"derive_enabled": True,
@@ -28,6 +27,33 @@ SIGNAL_PHONE_RE = re.compile(r"^\+\d+$")
SIGNAL_INTERNAL_ID_RE = re.compile(r"^[A-Za-z0-9+/=]+$")
def channel_variants(service: str, channel: str) -> list[str]:
value = str(channel or "").strip()
if not value:
return []
variants = [value]
service_key = str(service or "").strip().lower()
if service_key == "whatsapp":
bare = value.split("@", 1)[0].strip()
if bare and bare not in variants:
variants.append(bare)
direct = f"{bare}@s.whatsapp.net" if bare else ""
if direct and direct not in variants:
variants.append(direct)
group = f"{bare}@g.us" if bare else ""
if group and group not in variants:
variants.append(group)
if service_key == "signal":
digits = re.sub(r"[^0-9]", "", value)
if digits and digits not in variants:
variants.append(digits)
if digits:
plus = f"+{digits}"
if plus not in variants:
variants.append(plus)
return variants
def _normalize_whatsapp_identifier(identifier: str) -> str:
value = str(identifier or "").strip()
if not value:

View File

@@ -1,99 +0,0 @@
from __future__ import annotations
import hashlib
from asgiref.sync import async_to_sync
from core.clients.transport import send_message_raw
from core.models import CodexPermissionRequest, ExternalSyncEvent, TaskProviderConfig
def _deterministic_approval_key(idempotency_key: str) -> str:
digest = hashlib.sha1(str(idempotency_key or "").encode("utf-8")).hexdigest()[:12]
return f"pre-{digest}"
def queue_codex_event_with_pre_approval(
*,
user,
run,
task,
task_event,
action: str,
provider_payload: dict,
idempotency_key: str,
provider: str = "codex_cli",
) -> tuple[ExternalSyncEvent, CodexPermissionRequest]:
provider = str(provider or "codex_cli").strip() or "codex_cli"
approval_key = _deterministic_approval_key(idempotency_key)
waiting_event, _ = ExternalSyncEvent.objects.update_or_create(
idempotency_key=f"codex_waiting:{idempotency_key}",
defaults={
"user": user,
"task": task,
"task_event": task_event,
"provider": provider,
"status": "waiting_approval",
"payload": {
"action": str(action or "append_update"),
"provider_payload": dict(provider_payload or {}),
},
"error": "",
},
)
run.status = "waiting_approval"
run.error = ""
run.save(update_fields=["status", "error", "updated_at"])
provider_label = "Claude" if provider == "claude_cli" else "Codex"
xmpp_cmd = ".claude" if provider == "claude_cli" else ".codex"
request, _ = CodexPermissionRequest.objects.update_or_create(
approval_key=approval_key,
defaults={
"user": user,
"codex_run": run,
"external_sync_event": waiting_event,
"summary": f"Pre-submit approval required before sending to {provider_label}",
"requested_permissions": {
"type": "pre_submit",
"provider": provider,
"action": str(action or "append_update"),
},
"resume_payload": {
"gate_type": "pre_submit",
"action": str(action or "append_update"),
"provider_payload": dict(provider_payload or {}),
"idempotency_key": str(idempotency_key or ""),
},
"status": "pending",
"resolved_at": None,
"resolved_by_identifier": "",
"resolution_note": "",
},
)
cfg = TaskProviderConfig.objects.filter(
user=user, provider=provider, enabled=True
).first()
settings_payload = dict(getattr(cfg, "settings", {}) or {})
approver_service = (
str(settings_payload.get("approver_service") or "").strip().lower()
)
approver_identifier = str(settings_payload.get("approver_identifier") or "").strip()
if approver_service and approver_identifier:
try:
async_to_sync(send_message_raw)(
approver_service,
approver_identifier,
text=(
f"[{provider} approval] key={approval_key}\n"
f"summary=Pre-submit approval required before sending to {provider_label}\n"
"requested=pre_submit\n"
f"use: {xmpp_cmd} approve {approval_key} or {xmpp_cmd} deny {approval_key}"
),
attachments=[],
metadata={"origin_tag": f"codex-pre-approval:{approval_key}"},
)
except Exception:
pass
return waiting_event, request

View File

@@ -1,73 +0,0 @@
from __future__ import annotations
import re
from typing import Any
from django.db.models import Q
from core.models import ExternalChatLink, PersonIdentifier
def channel_variants(service: str, channel: str) -> list[str]:
value = str(channel or "").strip()
if not value:
return []
variants = [value]
service_key = str(service or "").strip().lower()
if service_key == "whatsapp":
bare = value.split("@", 1)[0].strip()
if bare and bare not in variants:
variants.append(bare)
direct = f"{bare}@s.whatsapp.net" if bare else ""
if direct and direct not in variants:
variants.append(direct)
group = f"{bare}@g.us" if bare else ""
if group and group not in variants:
variants.append(group)
if service_key == "signal":
digits = re.sub(r"[^0-9]", "", value)
if digits and digits not in variants:
variants.append(digits)
if digits:
plus = f"+{digits}"
if plus not in variants:
variants.append(plus)
return variants
def resolve_external_chat_id(*, user, provider: str, service: str, channel: str) -> str:
variants = channel_variants(service, channel)
if not variants:
return ""
person_identifier = (
PersonIdentifier.objects.filter(
user=user,
service=service,
identifier__in=variants,
)
.select_related("person")
.order_by("-id")
.first()
)
if person_identifier is None:
return ""
link = (
ExternalChatLink.objects.filter(
user=user,
provider=provider,
enabled=True,
)
.filter(
Q(person_identifier=person_identifier) | Q(person=person_identifier.person)
)
.order_by("-updated_at", "-id")
.first()
)
return str(getattr(link, "external_chat_id", "") or "").strip()
def compact_json_snippet(payload: Any, limit: int = 800) -> str:
text = str(payload or "").strip()
if len(text) <= limit:
return text
return text[:limit].rstrip() + "..."

View File

@@ -13,7 +13,6 @@ from core.models import (
AI,
Chat,
ChatTaskSource,
CodexRun,
DerivedTask,
DerivedTaskEvent,
ExternalSyncEvent,
@@ -27,8 +26,6 @@ from core.tasks.chat_defaults import (
ensure_default_source_for_chat,
resolve_message_scope,
)
from core.tasks.codex_approval import queue_codex_event_with_pre_approval
from core.tasks.codex_support import resolve_external_chat_id
from core.tasks.providers import get_provider
_TASK_HINT_RE = re.compile(r"\b(todo|task|action|need to|please)\b", re.IGNORECASE)
@@ -506,21 +503,30 @@ async def _derive_title_with_flags(message: Message, flags: dict) -> str:
async def _emit_sync_event(
task: DerivedTask, event: DerivedTaskEvent, action: str
) -> None:
cfg = await sync_to_async(
lambda: TaskProviderConfig.objects.filter(user=task.user, enabled=True)
.order_by("provider")
.first()
)()
provider_name = str(getattr(cfg, "provider", "mock") or "mock")
provider_settings = dict(getattr(cfg, "settings", {}) or {})
def _select_provider_config():
enabled_cfg = (
TaskProviderConfig.objects.filter(user=task.user, enabled=True)
.order_by("provider")
.first()
)
if enabled_cfg is not None:
return enabled_cfg
any_cfg_exists = TaskProviderConfig.objects.filter(user=task.user).exists()
if any_cfg_exists:
return None
return False
cfg = await sync_to_async(_select_provider_config)()
if cfg is None:
return
if cfg is False:
provider_name = "mock"
provider_settings = {}
else:
provider_name = str(getattr(cfg, "provider", "mock") or "mock")
provider_settings = dict(getattr(cfg, "settings", {}) or {})
provider = get_provider(provider_name)
idempotency_key = f"{provider_name}:{task.id}:{event.id}"
external_chat_id = await sync_to_async(resolve_external_chat_id)(
user=task.user,
provider=provider_name,
service=str(task.source_service or ""),
channel=str(task.source_channel or ""),
)
cached_project = task._state.fields_cache.get("project")
cached_epic = task._state.fields_cache.get("epic")
project_name = str(getattr(cached_project, "name", "") or "")
@@ -545,7 +551,6 @@ async def _emit_sync_event(
"epic_name": epic_name,
"source_service": str(task.source_service or ""),
"source_channel": str(task.source_channel or ""),
"external_chat_id": external_chat_id,
"origin_message_id": str(getattr(task, "origin_message_id", "") or ""),
"trigger_message_id": str(
getattr(event, "source_message_id", "")
@@ -556,56 +561,6 @@ async def _emit_sync_event(
"payload": event.payload,
"memory_context": memory_context,
}
codex_run = await sync_to_async(CodexRun.objects.create)(
user=task.user,
task_id=task.id,
derived_task_event_id=event.id,
source_message_id=(event.source_message_id or task.origin_message_id),
project_id=task.project_id,
epic_id=task.epic_id,
source_service=str(task.source_service or ""),
source_channel=str(task.source_channel or ""),
external_chat_id=external_chat_id,
status="queued",
request_payload={
"action": action,
"provider_payload": dict(request_payload),
"idempotency_key": idempotency_key,
},
result_payload={},
error="",
)
request_payload["codex_run_id"] = str(codex_run.id)
# Worker-backed providers are queued and executed by `manage.py codex_worker`.
if bool(getattr(provider, "run_in_worker", False)):
if provider_name == "codex_cli":
await sync_to_async(queue_codex_event_with_pre_approval)(
user=task.user,
run=codex_run,
task=task,
task_event=event,
action=action,
provider_payload=dict(request_payload),
idempotency_key=idempotency_key,
)
return
await sync_to_async(ExternalSyncEvent.objects.update_or_create)(
idempotency_key=idempotency_key,
defaults={
"user": task.user,
"task": task,
"task_event": event,
"provider": provider_name,
"status": "pending",
"payload": {
"action": action,
"provider_payload": dict(request_payload),
},
"error": "",
},
)
return
if action == "create":
result = provider.create_task(provider_settings, dict(request_payload))
@@ -623,16 +578,14 @@ async def _emit_sync_event(
"task_event": event,
"provider": provider_name,
"status": status,
"payload": dict(result.payload or {}),
"payload": {
"action": action,
"provider_payload": dict(request_payload),
"result_payload": dict(result.payload or {}),
},
"error": str(result.error or ""),
},
)
codex_run.status = status
codex_run.result_payload = dict(result.payload or {})
codex_run.error = str(result.error or "")
await sync_to_async(codex_run.save)(
update_fields=["status", "result_payload", "error", "updated_at"]
)
if result.ok and result.external_key and not task.external_key:
task.external_key = str(result.external_key)
await sync_to_async(task.save)(update_fields=["external_key"])

View File

@@ -1,73 +0,0 @@
from __future__ import annotations
import re
from typing import Any
from django.db.models import Q
from core.models import ExternalChatLink, PersonIdentifier
def channel_variants(service: str, channel: str) -> list[str]:
value = str(channel or "").strip()
if not value:
return []
variants = [value]
service_key = str(service or "").strip().lower()
if service_key == "whatsapp":
bare = value.split("@", 1)[0].strip()
if bare and bare not in variants:
variants.append(bare)
direct = f"{bare}@s.whatsapp.net" if bare else ""
if direct and direct not in variants:
variants.append(direct)
group = f"{bare}@g.us" if bare else ""
if group and group not in variants:
variants.append(group)
if service_key == "signal":
digits = re.sub(r"[^0-9]", "", value)
if digits and digits not in variants:
variants.append(digits)
if digits:
plus = f"+{digits}"
if plus not in variants:
variants.append(plus)
return variants
def resolve_external_chat_id(*, user, provider: str, service: str, channel: str) -> str:
variants = channel_variants(service, channel)
if not variants:
return ""
person_identifier = (
PersonIdentifier.objects.filter(
user=user,
service=service,
identifier__in=variants,
)
.select_related("person")
.order_by("-id")
.first()
)
if person_identifier is None:
return ""
link = (
ExternalChatLink.objects.filter(
user=user,
provider=provider,
enabled=True,
)
.filter(
Q(person_identifier=person_identifier) | Q(person=person_identifier.person)
)
.order_by("-updated_at", "-id")
.first()
)
return str(getattr(link, "external_chat_id", "") or "").strip()
def compact_json_snippet(payload: Any, limit: int = 800) -> str:
text = str(payload or "").strip()
if len(text) <= limit:
return text
return text[:limit].rstrip() + "..."

View File

@@ -1,14 +1,10 @@
from __future__ import annotations
from .base import TaskProvider
from .claude_cli import ClaudeCLITaskProvider
from .codex_cli import CodexCLITaskProvider
from .mock import MockTaskProvider
PROVIDERS = {
"mock": MockTaskProvider(),
"codex_cli": CodexCLITaskProvider(),
"claude_cli": ClaudeCLITaskProvider(),
}

View File

@@ -1,231 +0,0 @@
from __future__ import annotations
import json
import subprocess
from hashlib import sha1
from .base import ProviderResult, TaskProvider
class ClaudeCLITaskProvider(TaskProvider):
name = "claude_cli"
run_in_worker = True
def _timeout(self, config: dict) -> int:
try:
return max(1, int(config.get("timeout_seconds") or 60))
except Exception:
return 60
def _command(self, config: dict) -> str:
return str(config.get("command") or "claude").strip() or "claude"
def _workspace(self, config: dict) -> str:
return str(config.get("workspace_root") or "").strip()
def _profile(self, config: dict) -> str:
return str(config.get("default_profile") or "").strip()
def _is_task_sync_contract_mismatch(self, stderr: str) -> bool:
text = str(stderr or "").lower()
if "unexpected argument '--op'" in text:
return True
if "unexpected argument 'create'" in text and "usage: claude" in text:
return True
if "unexpected argument 'append_update'" in text and "usage: claude" in text:
return True
if "unexpected argument 'mark_complete'" in text and "usage: claude" in text:
return True
if "unexpected argument 'link_task'" in text and "usage: claude" in text:
return True
if "unrecognized subcommand 'create'" in text and "usage: claude" in text:
return True
if (
"unrecognized subcommand 'append_update'" in text
and "usage: claude" in text
):
return True
if (
"unrecognized subcommand 'mark_complete'" in text
and "usage: claude" in text
):
return True
return False
def _builtin_stub_result(
self, op: str, payload: dict, stderr: str
) -> ProviderResult:
mode = str(payload.get("mode") or "default").strip().lower()
external_key = (
str(payload.get("external_key") or "").strip()
or str(payload.get("task_id") or "").strip()
)
if mode == "approval_response":
return ProviderResult(
ok=True,
external_key=external_key,
payload={
"op": op,
"status": "ok",
"summary": "approval acknowledged; resumed by builtin claude stub",
"requires_approval": False,
"output": "",
"fallback_mode": "builtin_task_sync_stub",
"fallback_reason": str(stderr or "")[:4000],
},
)
task_id = str(payload.get("task_id") or "").strip()
key_basis = f"{op}:{task_id}:{payload.get('trigger_message_id') or payload.get('origin_message_id') or ''}"
approval_key = sha1(key_basis.encode("utf-8")).hexdigest()[:12]
summary = "Claude approval required (builtin stub fallback)"
return ProviderResult(
ok=True,
external_key=external_key,
payload={
"op": op,
"status": "requires_approval",
"requires_approval": True,
"summary": summary,
"approval_key": approval_key,
"permission_request": {
"summary": summary,
"requested_permissions": ["workspace_write"],
},
"resume_payload": {
"task_id": task_id,
"op": op,
},
"fallback_mode": "builtin_task_sync_stub",
"fallback_reason": str(stderr or "")[:4000],
},
)
def _run(self, config: dict, op: str, payload: dict) -> ProviderResult:
base_cmd = [self._command(config), "task-sync"]
workspace = self._workspace(config)
profile = self._profile(config)
command_timeout = self._timeout(config)
data = json.dumps(dict(payload or {}), separators=(",", ":"))
common_args: list[str] = []
if workspace:
common_args.extend(["--workspace", workspace])
if profile:
common_args.extend(["--profile", profile])
primary_cmd = [*base_cmd, "--op", str(op), *common_args, "--payload-json", data]
fallback_cmd = [*base_cmd, str(op), *common_args, "--payload-json", data]
try:
completed = subprocess.run(
primary_cmd,
capture_output=True,
text=True,
timeout=command_timeout,
check=False,
cwd=workspace if workspace else None,
)
stderr_probe = str(completed.stderr or "").lower()
if (
completed.returncode != 0
and "unexpected argument '--op'" in stderr_probe
):
completed = subprocess.run(
fallback_cmd,
capture_output=True,
text=True,
timeout=command_timeout,
check=False,
cwd=workspace if workspace else None,
)
except subprocess.TimeoutExpired:
return ProviderResult(
ok=False,
error=f"claude_cli_timeout_{command_timeout}s",
payload={"op": op, "timeout_seconds": command_timeout},
)
except Exception as exc:
return ProviderResult(
ok=False, error=f"claude_cli_exec_error:{exc}", payload={"op": op}
)
stdout = str(completed.stdout or "").strip()
stderr = str(completed.stderr or "").strip()
parsed = {}
if stdout:
try:
parsed = json.loads(stdout)
if not isinstance(parsed, dict):
parsed = {"raw_stdout": stdout}
except Exception:
parsed = {"raw_stdout": stdout}
parsed_status = str(parsed.get("status") or "").strip().lower()
permission_request = parsed.get("permission_request")
requires_approval = bool(
parsed.get("requires_approval")
or parsed_status in {"requires_approval", "waiting_approval"}
or permission_request
)
ext = (
str(parsed.get("external_key") or "").strip()
or str(parsed.get("task_id") or "").strip()
or str(payload.get("external_key") or "").strip()
)
ok = completed.returncode == 0
out_payload = {
"op": op,
"returncode": int(completed.returncode),
"stdout": stdout[:4000],
"stderr": stderr[:4000],
"parsed_status": parsed_status,
"requires_approval": requires_approval,
}
out_payload.update(parsed)
if (not ok) and self._is_task_sync_contract_mismatch(stderr):
return self._builtin_stub_result(op, dict(payload or {}), stderr)
return ProviderResult(
ok=ok,
external_key=ext,
error=("" if ok else stderr[:4000]),
payload=out_payload,
)
def healthcheck(self, config: dict) -> ProviderResult:
command = self._command(config)
try:
completed = subprocess.run(
[command, "--version"],
capture_output=True,
text=True,
timeout=max(1, min(20, self._timeout(config))),
check=False,
)
except Exception as exc:
return ProviderResult(ok=False, error=f"claude_cli_unavailable:{exc}")
return ProviderResult(
ok=(completed.returncode == 0),
payload={
"returncode": int(completed.returncode),
"stdout": str(completed.stdout or "").strip()[:1000],
"stderr": str(completed.stderr or "").strip()[:1000],
},
error=(
""
if completed.returncode == 0
else str(completed.stderr or "").strip()[:1000]
),
)
def create_task(self, config: dict, payload: dict) -> ProviderResult:
return self._run(config, "create", payload)
def append_update(self, config: dict, payload: dict) -> ProviderResult:
return self._run(config, "append_update", payload)
def mark_complete(self, config: dict, payload: dict) -> ProviderResult:
return self._run(config, "mark_complete", payload)
def link_task(self, config: dict, payload: dict) -> ProviderResult:
return self._run(config, "link_task", payload)

View File

@@ -1,225 +0,0 @@
from __future__ import annotations
import json
import subprocess
from hashlib import sha1
from .base import ProviderResult, TaskProvider
class CodexCLITaskProvider(TaskProvider):
name = "codex_cli"
run_in_worker = True
def _timeout(self, config: dict) -> int:
try:
return max(1, int(config.get("timeout_seconds") or 60))
except Exception:
return 60
def _command(self, config: dict) -> str:
return str(config.get("command") or "codex").strip() or "codex"
def _workspace(self, config: dict) -> str:
return str(config.get("workspace_root") or "").strip()
def _profile(self, config: dict) -> str:
return str(config.get("default_profile") or "").strip()
def _is_task_sync_contract_mismatch(self, stderr: str) -> bool:
text = str(stderr or "").lower()
if "unexpected argument '--op'" in text:
return True
if "unexpected argument 'create'" in text and "usage: codex" in text:
return True
if "unexpected argument 'append_update'" in text and "usage: codex" in text:
return True
if "unexpected argument 'mark_complete'" in text and "usage: codex" in text:
return True
if "unexpected argument 'link_task'" in text and "usage: codex" in text:
return True
if "unrecognized subcommand 'create'" in text and "usage: codex" in text:
return True
if "unrecognized subcommand 'append_update'" in text and "usage: codex" in text:
return True
if "unrecognized subcommand 'mark_complete'" in text and "usage: codex" in text:
return True
return False
def _builtin_stub_result(
self, op: str, payload: dict, stderr: str
) -> ProviderResult:
mode = str(payload.get("mode") or "default").strip().lower()
external_key = (
str(payload.get("external_key") or "").strip()
or str(payload.get("task_id") or "").strip()
)
if mode == "approval_response":
return ProviderResult(
ok=True,
external_key=external_key,
payload={
"op": op,
"status": "ok",
"summary": "approval acknowledged; resumed by builtin codex stub",
"requires_approval": False,
"output": "",
"fallback_mode": "builtin_task_sync_stub",
"fallback_reason": str(stderr or "")[:4000],
},
)
task_id = str(payload.get("task_id") or "").strip()
key_basis = f"{op}:{task_id}:{payload.get('trigger_message_id') or payload.get('origin_message_id') or ''}"
approval_key = sha1(key_basis.encode("utf-8")).hexdigest()[:12]
summary = "Codex approval required (builtin stub fallback)"
return ProviderResult(
ok=True,
external_key=external_key,
payload={
"op": op,
"status": "requires_approval",
"requires_approval": True,
"summary": summary,
"approval_key": approval_key,
"permission_request": {
"summary": summary,
"requested_permissions": ["workspace_write"],
},
"resume_payload": {
"task_id": task_id,
"op": op,
},
"fallback_mode": "builtin_task_sync_stub",
"fallback_reason": str(stderr or "")[:4000],
},
)
def _run(self, config: dict, op: str, payload: dict) -> ProviderResult:
base_cmd = [self._command(config), "task-sync"]
workspace = self._workspace(config)
profile = self._profile(config)
command_timeout = self._timeout(config)
data = json.dumps(dict(payload or {}), separators=(",", ":"))
common_args: list[str] = []
if workspace:
common_args.extend(["--workspace", workspace])
if profile:
common_args.extend(["--profile", profile])
primary_cmd = [*base_cmd, "--op", str(op), *common_args, "--payload-json", data]
fallback_cmd = [*base_cmd, str(op), *common_args, "--payload-json", data]
try:
completed = subprocess.run(
primary_cmd,
capture_output=True,
text=True,
timeout=command_timeout,
check=False,
cwd=workspace if workspace else None,
)
stderr_probe = str(completed.stderr or "").lower()
if (
completed.returncode != 0
and "unexpected argument '--op'" in stderr_probe
):
completed = subprocess.run(
fallback_cmd,
capture_output=True,
text=True,
timeout=command_timeout,
check=False,
cwd=workspace if workspace else None,
)
except subprocess.TimeoutExpired:
return ProviderResult(
ok=False,
error=f"codex_cli_timeout_{command_timeout}s",
payload={"op": op, "timeout_seconds": command_timeout},
)
except Exception as exc:
return ProviderResult(
ok=False, error=f"codex_cli_exec_error:{exc}", payload={"op": op}
)
stdout = str(completed.stdout or "").strip()
stderr = str(completed.stderr or "").strip()
parsed = {}
if stdout:
try:
parsed = json.loads(stdout)
if not isinstance(parsed, dict):
parsed = {"raw_stdout": stdout}
except Exception:
parsed = {"raw_stdout": stdout}
parsed_status = str(parsed.get("status") or "").strip().lower()
permission_request = parsed.get("permission_request")
requires_approval = bool(
parsed.get("requires_approval")
or parsed_status in {"requires_approval", "waiting_approval"}
or permission_request
)
ext = (
str(parsed.get("external_key") or "").strip()
or str(parsed.get("task_id") or "").strip()
or str(payload.get("external_key") or "").strip()
)
ok = completed.returncode == 0
out_payload = {
"op": op,
"returncode": int(completed.returncode),
"stdout": stdout[:4000],
"stderr": stderr[:4000],
"parsed_status": parsed_status,
"requires_approval": requires_approval,
}
out_payload.update(parsed)
if (not ok) and self._is_task_sync_contract_mismatch(stderr):
return self._builtin_stub_result(op, dict(payload or {}), stderr)
return ProviderResult(
ok=ok,
external_key=ext,
error=("" if ok else stderr[:4000]),
payload=out_payload,
)
def healthcheck(self, config: dict) -> ProviderResult:
command = self._command(config)
try:
completed = subprocess.run(
[command, "--version"],
capture_output=True,
text=True,
timeout=max(1, min(20, self._timeout(config))),
check=False,
)
except Exception as exc:
return ProviderResult(ok=False, error=f"codex_cli_unavailable:{exc}")
return ProviderResult(
ok=(completed.returncode == 0),
payload={
"returncode": int(completed.returncode),
"stdout": str(completed.stdout or "").strip()[:1000],
"stderr": str(completed.stderr or "").strip()[:1000],
},
error=(
""
if completed.returncode == 0
else str(completed.stderr or "").strip()[:1000]
),
)
def create_task(self, config: dict, payload: dict) -> ProviderResult:
return self._run(config, "create", payload)
def append_update(self, config: dict, payload: dict) -> ProviderResult:
return self._run(config, "append_update", payload)
def mark_complete(self, config: dict, payload: dict) -> ProviderResult:
return self._run(config, "mark_complete", payload)
def link_task(self, config: dict, payload: dict) -> ProviderResult:
return self._run(config, "link_task", payload)