import subprocess import json import sys class GeminiCliAdapter: def __init__(self, binary_path="gemini"): self.binary_path = binary_path self.last_usage = None self.session_id = None def send(self, message): """ Sends a message to the Gemini CLI and processes the streaming JSON output. """ # On Windows, using shell=True allows executing .cmd/.bat files and # handles command strings with arguments more gracefully. # We pass the message via stdin to avoid command-line length limits. command = f'{self.binary_path} run --output-format stream-json' if self.session_id: command += f' --resume {self.session_id}' print(f"[DEBUG] GeminiCliAdapter: Executing command: {command}") accumulated_text = "" process = subprocess.Popen( command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True ) try: # Send message to stdin and close it process.stdin.write(message) process.stdin.close() # Read stdout line by line for line in process.stdout: line = line.strip() if not line: continue print(f"[DEBUG] GeminiCliAdapter stdout: {line}") try: data = json.loads(line) msg_type = data.get("type") if msg_type == "message": # Append message text to results accumulated_text += data.get("text", "") elif msg_type == "result": # Capture final usage and session persistence self.last_usage = data.get("usage") self.session_id = data.get("session_id") elif msg_type in ("status", "tool_use"): # Log status/tool_use to stderr for debugging sys.stderr.write(f"GeminiCliAdapter [{msg_type}]: {line}\n") sys.stderr.flush() except json.JSONDecodeError: # Skip lines that are not valid JSON continue process.wait() if process.returncode != 0: err = process.stderr.read() print(f"[DEBUG] GeminiCliAdapter failed with exit code {process.returncode}. stderr: {err}") except Exception as e: process.kill() print(f"[DEBUG] GeminiCliAdapter exception: {e}") raise e return accumulated_text