Files
loki/examples/langchain-sisyphus/sisyphus_langchain/cli.py

156 lines
3.9 KiB
Python

"""
CLI entry point for the Sisyphus LangChain agent.
This mirrors Loki's `loki --agent sisyphus` entry point.
In Loki:
loki --agent sisyphus
# Starts a REPL with the sisyphus agent loaded
In this LangChain version:
python -m sisyphus_langchain.cli
# or: sisyphus (if installed via pip)
Usage:
# Interactive REPL mode
sisyphus
# One-shot query
sisyphus "Add a health check endpoint to the API"
# With custom models
sisyphus --supervisor-model gpt-4o --explore-model gpt-4o-mini "Find auth patterns"
Environment variables:
OPENAI_API_KEY — Required for OpenAI models
ANTHROPIC_API_KEY — Required if using Anthropic models
"""
from __future__ import annotations
import argparse
import sys
import uuid
from langchain_core.messages import HumanMessage
from sisyphus_langchain.graph import build_graph
def run_query(graph, query: str, thread_id: str) -> str:
"""
Run a single query through the Sisyphus graph.
Args:
graph: Compiled LangGraph.
query: User's natural language request.
thread_id: Session identifier for checkpointing.
Returns:
The final output string.
"""
result = graph.invoke(
{
"messages": [HumanMessage(content=query)],
"intent": "ambiguous",
"next_agent": "",
"iteration_count": 0,
"todos": [],
"agent_outputs": {},
"final_output": "",
"project_dir": ".",
},
config={
"configurable": {"thread_id": thread_id},
"recursion_limit": 50,
},
)
return result.get("final_output", "(no output)")
def repl(graph, thread_id: str) -> None:
"""
Interactive REPL loop — mirrors Loki's REPL mode.
Maintains conversation across turns via the thread_id (checkpointer).
"""
print("Sisyphus (LangChain) — type 'quit' to exit")
print("=" * 50)
while True:
try:
query = input("\n> ").strip()
except (EOFError, KeyboardInterrupt):
print("\nBye.")
break
if not query:
continue
if query.lower() in ("quit", "exit", "q"):
print("Bye.")
break
try:
output = run_query(graph, query, thread_id)
print(f"\n{output}")
except Exception as e:
print(f"\nError: {e}")
def main() -> None:
"""CLI entry point."""
parser = argparse.ArgumentParser(
description="Sisyphus — multi-agent coding orchestrator (LangChain edition)"
)
parser.add_argument(
"query",
nargs="?",
help="One-shot query (omit for REPL mode)",
)
parser.add_argument(
"--supervisor-model",
default="gpt-4o",
help="Model for the supervisor (default: gpt-4o)",
)
parser.add_argument(
"--explore-model",
default="gpt-4o-mini",
help="Model for the explore agent (default: gpt-4o-mini)",
)
parser.add_argument(
"--oracle-model",
default="gpt-4o",
help="Model for the oracle agent (default: gpt-4o)",
)
parser.add_argument(
"--coder-model",
default="gpt-4o",
help="Model for the coder agent (default: gpt-4o)",
)
parser.add_argument(
"--thread-id",
default=None,
help="Session thread ID for persistence (auto-generated if omitted)",
)
args = parser.parse_args()
graph = build_graph(
supervisor_model=args.supervisor_model,
explore_model=args.explore_model,
oracle_model=args.oracle_model,
coder_model=args.coder_model,
)
thread_id = args.thread_id or f"sisyphus-{uuid.uuid4().hex[:8]}"
if args.query:
output = run_query(graph, args.query, thread_id)
print(output)
else:
repl(graph, thread_id)
if __name__ == "__main__":
main()