Files
Conflict_Checker/backend/agents/extractors.py
T
woogiandCursor 82a48d99cf 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>
2026-07-18 14:31:13 +00:00

107 lines
3.9 KiB
Python

"""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)