Files
manual_slop/gemini_cli_adapter.py

94 lines
3.1 KiB
Python

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 = ""
tool_calls = []
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
# Support both mock ('usage') and real ('stats') keys
self.last_usage = data.get("usage") or data.get("stats")
self.session_id = data.get("session_id")
elif msg_type == "tool_use":
# Collect tool_use messages
tool_calls.append(data)
# Log status/tool_use to stderr for debugging
sys.stderr.write(f"GeminiCliAdapter [{msg_type}]: {line}\n")
sys.stderr.flush()
elif msg_type == "status":
# Log status 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 {
"text": accumulated_text,
"tool_calls": tool_calls
}