#!/usr/bin/env python3 """Small ACP JSON-RPC peer used by the subprocess integration tests.""" from __future__ import annotations import json import os import subprocess import sys import time def read_message() -> dict: line = sys.stdin.readline() if not line: raise EOFError return json.loads(line) def send(message: dict) -> None: sys.stdout.write(json.dumps(message, separators=(",", ":")) + "\n") sys.stdout.flush() def respond(request: dict, result: dict) -> None: send({"jsonrpc": "2.0", "id": request["id"], "result": result}) def main() -> int: scenario = sys.argv[1] if len(sys.argv) > 1 else "normal" if pid_file := os.environ.get("FAKE_ACP_PID_FILE"): with open(pid_file, "w", encoding="utf-8") as file: file.write(str(os.getpid())) initialize = read_message() capabilities = initialize["params"]["clientCapabilities"] assert capabilities["fs"] == { "readTextFile": False, "writeTextFile": False, } respond(initialize, {"protocolVersion": 1, "agentCapabilities": {}}) new_session = read_message() cwd = new_session["params"]["cwd"] assert os.path.isdir(cwd) respond(new_session, {"sessionId": "session-test"}) prompt = read_message() assert prompt["params"]["sessionId"] == "session-test" if scenario == "environment": content = ( "leaked" if os.environ.get("AI_TRIAGE_GITHUB_TOKEN") else "not present" ) elif scenario == "hang": if child_pid_file := os.environ.get("FAKE_ACP_CHILD_PID_FILE"): child = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(60)"]) with open(child_pid_file, "w", encoding="utf-8") as file: file.write(str(child.pid)) time.sleep(60) return 0 elif scenario == "exit": return 7 elif scenario == "malformed": sys.stdout.write("not-json\n") sys.stdout.flush() return 0 elif scenario == "oversize": content = "x" * 20_000 elif scenario == "permission": send( { "jsonrpc": "2.0", "id": "permission-1", "method": "session/request_permission", "params": { "sessionId": "session-test", "options": [{"optionId": "allow", "kind": "allow_once"}], "toolCall": {"toolCallId": "tool-1", "title": "shell"}, }, } ) permission_response = read_message() assert permission_response["id"] == "permission-1" assert permission_response["result"] == { "outcome": {"outcome": "cancelled"} } content = "permission rejected" else: content = json.dumps( { "category": "product_error", "confidence": 0.91, "summary": "backend returned an unexpected response", "evidence": ["HTTP 500 instead of 200"], "root_cause": "service regression", "recommendations": ["inspect the trace ID"], "observed_cwd": cwd, } ) midpoint = len(content) // 2 for chunk in (content[:midpoint], content[midpoint:]): send( { "jsonrpc": "2.0", "method": "session/update", "params": { "sessionId": "session-test", "update": { "sessionUpdate": "agent_message_chunk", "content": {"type": "text", "text": chunk}, }, }, } ) respond(prompt, {"stopReason": "end_turn"}) return 0 if __name__ == "__main__": raise SystemExit(main())