refactor local directory agent to two-phase LLM-with-tools architecture
Replace the single-pass FE-driven agent_run/agent_data flow with a BE-orchestrated two-phase execution using LangChain tool-calling: - Phase 1 (Triage): explores directory via new filesystem tools, matches files to existing projects using PROJECT_TOOLS - Phase 2 (Processing): reads files and performs CRUD per project group with clean LLM context windows Key changes: - Add filesystem_agent.py with list_directory, read_file_content, get_file_metadata tools using execute_on_client() - Move setup journey from REST to WebSocket (journey_start/message frames) - Add batch_runs_per_day billing limit and enforce in /trigger - Remove deprecated agent_data/agent_complete frame handlers and queues Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -142,9 +142,6 @@ class WsFrameType(str, Enum):
|
||||
tool_result = "tool_result"
|
||||
final = "final"
|
||||
ping = "ping"
|
||||
agent_run = "agent_run"
|
||||
agent_data = "agent_data"
|
||||
agent_complete = "agent_complete"
|
||||
device_hello = "device_hello"
|
||||
# ── v3 frame types ─────────────────────────────────────────────────
|
||||
home_request = "home_request"
|
||||
@@ -156,6 +153,10 @@ class WsFrameType(str, Enum):
|
||||
data_request = "data_request"
|
||||
data_response = "data_response"
|
||||
mutation = "mutation"
|
||||
# ── v4 journey frame types ────────────────────────────────────────
|
||||
journey_start = "journey_start"
|
||||
journey_message = "journey_message"
|
||||
journey_reply = "journey_reply"
|
||||
|
||||
|
||||
class WsToolCall(BaseModel):
|
||||
@@ -208,31 +209,6 @@ class WsDeviceHello(BaseModel):
|
||||
agent_ids: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class WsAgentRun(BaseModel):
|
||||
"""Server → Client: trigger an agent run on the connected device."""
|
||||
|
||||
type: Literal[WsFrameType.agent_run] = WsFrameType.agent_run
|
||||
run_id: str
|
||||
agent_id: str
|
||||
config: dict[str, Any]
|
||||
|
||||
|
||||
class WsAgentData(BaseModel):
|
||||
"""Client → Server: files read by the local agent."""
|
||||
|
||||
type: Literal[WsFrameType.agent_data] = WsFrameType.agent_data
|
||||
run_id: str
|
||||
files: list[dict[str, Any]]
|
||||
|
||||
|
||||
class WsAgentComplete(BaseModel):
|
||||
"""Client → Server: Electron signals it has finished reading files."""
|
||||
|
||||
type: Literal[WsFrameType.agent_complete] = WsFrameType.agent_complete
|
||||
run_id: str
|
||||
files_read: int
|
||||
errors: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
# ── WebSocket v3 Frame Models ─────────────────────────────────────────
|
||||
|
||||
@@ -319,6 +295,7 @@ class AgentCreationCheckResponse(BaseModel):
|
||||
|
||||
class AgentTriggerRequest(BaseModel):
|
||||
directory: str = Field(min_length=1)
|
||||
device_id: str = Field(default="")
|
||||
what_to_extract: list[Literal["task", "note", "timeline", "project"]] = Field(min_length=1)
|
||||
actions_by_type: dict[
|
||||
Literal["task", "note", "timeline", "project"],
|
||||
@@ -345,18 +322,3 @@ class AgentRunLogResponse(BaseModel):
|
||||
|
||||
# ── Chatbot Journey ───────────────────────────────────────────────────
|
||||
|
||||
class JourneyStartRequest(BaseModel):
|
||||
agent_type: Literal["local", "cloud"]
|
||||
agent_id: str | None = None
|
||||
|
||||
|
||||
class JourneyMessageRequest(BaseModel):
|
||||
session_id: str
|
||||
message: str
|
||||
|
||||
|
||||
class JourneyResponse(BaseModel):
|
||||
session_id: str
|
||||
message: str
|
||||
done: bool
|
||||
prompt_template: str | None = None
|
||||
|
||||
Reference in New Issue
Block a user