import subprocess import json import sys import time import os class GeminiCliAdapter: def __init__(self, binary_path="gemini"): self.binary_path = binary_path self.last_usage = None self.session_id = None self.last_latency = 0.0 def send(self, message): """ Sends a message to the Gemini CLI and processes the streaming JSON output. """ start_time = time.time() # 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}' accumulated_text = "" env = os.environ.copy() env["GEMINI_CLI_HOOK_CONTEXT"] = "manual_slop" process = subprocess.Popen( command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True, env=env ) 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 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() except Exception as e: process.kill() raise e finally: self.last_latency = time.time() - start_time return accumulated_text