Add scoped Agent-mode pipeline as experimental Classic fork.
Wire specialist waves, Brain consolidation, and Classic-compatible reports so Agent mode can run end-to-end via OpenRouter without changing the default Classic path. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
"""Scoped extraction and orientation agents."""
|
||||
|
||||
import json
|
||||
from typing import Dict
|
||||
|
||||
from backend import config
|
||||
from backend.agents.base import AgentResult, AgentScope, AgentUsage, failure
|
||||
from backend.llm import call_json
|
||||
from backend.pipeline.extractor import _normalize_sheet
|
||||
from backend.pipeline.sheet_index import _index_input
|
||||
from backend.prompts import (
|
||||
EXTRACTOR_SYSTEM_PROMPT,
|
||||
EXTRACTOR_USER_INSTRUCTION,
|
||||
JURISDICTION_SYSTEM_PROMPT,
|
||||
JURISDICTION_USER_INSTRUCTION,
|
||||
SHEET_INDEX_SYSTEM_PROMPT,
|
||||
SHEET_INDEX_USER_INSTRUCTION,
|
||||
)
|
||||
|
||||
|
||||
class SheetExtractorAgent:
|
||||
name = "sheet_extractor"
|
||||
|
||||
def __init__(self, usage: AgentUsage) -> None:
|
||||
self.usage = usage
|
||||
|
||||
def run(self, scope: AgentScope) -> AgentResult:
|
||||
try:
|
||||
page = scope.payload["page"]
|
||||
instruction = EXTRACTOR_USER_INSTRUCTION.replace(
|
||||
"{sheet_hint}", str(scope.payload.get("sheet_hint") or "")
|
||||
)
|
||||
parsed = call_json(
|
||||
system_prompt=EXTRACTOR_SYSTEM_PROMPT,
|
||||
user_text=instruction,
|
||||
images_b64=[page["base64"]],
|
||||
max_tokens=config.EXTRACT_MAX_TOKENS,
|
||||
model=config.AGENT_EXTRACT_MODEL,
|
||||
usage_tracker=self.usage,
|
||||
usage_stage="agent.extract",
|
||||
)
|
||||
if not isinstance(parsed, dict):
|
||||
raise ValueError("no structured extraction returned")
|
||||
sheet = _normalize_sheet(parsed, page["page_number"])
|
||||
return AgentResult(scope_id=scope.scope_id, artifacts=[sheet])
|
||||
except Exception as exc:
|
||||
return failure(scope, exc)
|
||||
|
||||
|
||||
class SheetIndexAgent:
|
||||
name = "sheet_index"
|
||||
|
||||
def __init__(self, usage: AgentUsage) -> None:
|
||||
self.usage = usage
|
||||
|
||||
def run(self, scope: AgentScope) -> AgentResult:
|
||||
try:
|
||||
sheets = scope.payload.get("sheets") or []
|
||||
instruction = SHEET_INDEX_USER_INSTRUCTION.replace(
|
||||
"{sheet_index_input}",
|
||||
json.dumps(_index_input(sheets), ensure_ascii=True),
|
||||
)
|
||||
parsed = call_json(
|
||||
system_prompt=SHEET_INDEX_SYSTEM_PROMPT,
|
||||
user_text=instruction,
|
||||
max_tokens=config.SHEET_INDEX_MAX_TOKENS,
|
||||
model=config.AGENT_INDEX_MODEL,
|
||||
usage_tracker=self.usage,
|
||||
usage_stage="agent.sheet_index",
|
||||
)
|
||||
if isinstance(parsed, list):
|
||||
parsed = {"sheet_index": parsed, "missing_expected_sheets": []}
|
||||
if not isinstance(parsed, dict):
|
||||
raise ValueError("no sheet index returned")
|
||||
return AgentResult(scope_id=scope.scope_id, artifacts=[parsed])
|
||||
except Exception as exc:
|
||||
return failure(scope, exc)
|
||||
|
||||
|
||||
class JurisdictionAgent:
|
||||
name = "jurisdiction"
|
||||
|
||||
def __init__(self, usage: AgentUsage) -> None:
|
||||
self.usage = usage
|
||||
|
||||
def run(self, scope: AgentScope) -> AgentResult:
|
||||
try:
|
||||
project_input: Dict = scope.payload.get("project_input") or {}
|
||||
instruction = JURISDICTION_USER_INSTRUCTION.replace(
|
||||
"{project_input}", json.dumps(project_input, ensure_ascii=True)
|
||||
)
|
||||
parsed = call_json(
|
||||
system_prompt=JURISDICTION_SYSTEM_PROMPT,
|
||||
user_text=instruction,
|
||||
max_tokens=config.JURISDICTION_MAX_TOKENS,
|
||||
model=config.AGENT_JURISDICTION_MODEL,
|
||||
usage_tracker=self.usage,
|
||||
usage_stage="agent.jurisdiction",
|
||||
)
|
||||
if not isinstance(parsed, dict):
|
||||
raise ValueError("no jurisdiction profile returned")
|
||||
profile = parsed.get("project_code_profile")
|
||||
artifact = profile if isinstance(profile, dict) else parsed
|
||||
return AgentResult(scope_id=scope.scope_id, artifacts=[artifact])
|
||||
except Exception as exc:
|
||||
return failure(scope, exc)
|
||||
Reference in New Issue
Block a user