Sisyphus agent recreated in LangChain to figure out how it works and how to use it
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
Shared state schema for the Sisyphus orchestrator graph.
|
||||
|
||||
In LangGraph, state is the single source of truth that flows through every node.
|
||||
This is analogous to Loki's per-agent session context, but unified into one typed
|
||||
dictionary that the entire graph shares.
|
||||
|
||||
Loki Concept Mapping:
|
||||
- Loki session context → SisyphusState (TypedDict)
|
||||
- Loki todo__init / todo__add → SisyphusState.todos list
|
||||
- Loki agent__spawn outputs → SisyphusState.agent_outputs dict
|
||||
- Loki intent classification → SisyphusState.intent field
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Annotated, Literal
|
||||
|
||||
from langchain_core.messages import BaseMessage
|
||||
from langgraph.graph.message import add_messages
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Intent types — mirrors Loki's Sisyphus classification table
|
||||
# ---------------------------------------------------------------------------
|
||||
IntentType = Literal[
|
||||
"trivial", # Single file, known location, typo fix → handle yourself
|
||||
"exploration", # "Find X", "Where is Y" → spawn explore
|
||||
"implementation", # "Add feature", "Fix bug" → spawn coder
|
||||
"architecture", # Design questions, oracle triggers → spawn oracle
|
||||
"ambiguous", # Unclear scope → ask user
|
||||
]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Todo item — mirrors Loki's built-in todo system
|
||||
# ---------------------------------------------------------------------------
|
||||
@dataclass
|
||||
class TodoItem:
|
||||
"""A single task in the orchestrator's todo list."""
|
||||
id: int
|
||||
task: str
|
||||
done: bool = False
|
||||
|
||||
|
||||
def _merge_todos(existing: list[TodoItem], new: list[TodoItem]) -> list[TodoItem]:
|
||||
"""
|
||||
Reducer for the todos field.
|
||||
|
||||
LangGraph requires a reducer for any state field that can be written by
|
||||
multiple nodes. This merges by id: if a todo with the same id already
|
||||
exists, the incoming version wins (allows marking done).
|
||||
"""
|
||||
by_id = {t.id: t for t in existing}
|
||||
for t in new:
|
||||
by_id[t.id] = t
|
||||
return list(by_id.values())
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Core graph state
|
||||
# ---------------------------------------------------------------------------
|
||||
class SisyphusState(TypedDict):
|
||||
"""
|
||||
The shared state that flows through every node in the Sisyphus graph.
|
||||
|
||||
Annotated fields use *reducers* — functions that merge concurrent writes.
|
||||
Without reducers, parallel node outputs would overwrite each other.
|
||||
"""
|
||||
|
||||
# Conversation history — the `add_messages` reducer appends new messages
|
||||
# instead of replacing the list. This is critical: every node adds its
|
||||
# response here, and downstream nodes see the full history.
|
||||
#
|
||||
# Loki equivalent: each agent's chat session accumulates messages the same
|
||||
# way, but messages are scoped per-agent. In LangGraph the shared message
|
||||
# list IS the inter-agent communication channel.
|
||||
messages: Annotated[list[BaseMessage], add_messages]
|
||||
|
||||
# Classified intent for the current request
|
||||
intent: IntentType
|
||||
|
||||
# Which agent the supervisor routed to last
|
||||
next_agent: str
|
||||
|
||||
# Iteration counter — safety valve analogous to Loki's max_auto_continues
|
||||
iteration_count: int
|
||||
|
||||
# Todo list for multi-step tracking (mirrors Loki's todo__* tools)
|
||||
todos: Annotated[list[TodoItem], _merge_todos]
|
||||
|
||||
# Accumulated outputs from sub-agent nodes, keyed by agent name.
|
||||
# The supervisor reads these to decide what to do next.
|
||||
agent_outputs: dict[str, str]
|
||||
|
||||
# Final synthesized answer to return to the user
|
||||
final_output: str
|
||||
|
||||
# The working directory / project path (mirrors Loki's project_dir variable)
|
||||
project_dir: str
|
||||
Reference in New Issue
Block a user