seanpedrickcase's picture
Sync: Slightly cleaner interface by default. Timing on malware scans go to logs
acb3ee1
Raw
History Blame Contribute Delete
3.98 kB
"""LangGraph ReAct agent for document redaction orchestration."""
from __future__ import annotations
import os
from langchain_core.messages import SystemMessage
from langgraph.prebuilt import create_react_agent
_SYSTEM_PROMPT = """You are a document redaction assistant for the doc_redaction application.
Use only the provided tools β€” never run shell commands or access paths outside the session workspace.
**Do not read `.pi/skills/` or `skills/` files** β€” skill playbooks are for the Pi coding agent only.
Start with `list_workspace_files` and `doc_redact` when the user prompt includes a document path.
**Pass 1 is not complete after doc_redact.** You must finish the full workflow in this turn unless the user
explicitly asks to stop:
1. list_workspace_files β€” locate the uploaded PDF
2. doc_redact β€” initial redaction; artifacts land under redact/<document>/output_redact/
3. Edit the review CSV to satisfy **User redaction requirements**:
- read_workspace_text / write_workspace_text for small edits, or
- write_workspace_text a fix_policy.py script, then run_workspace_python_script
- Preserve CSV headers, utf-8-sig encoding, and bbox values in [0, 1]
4. verify_coverage β€” pre-apply check on the review CSV (+ auto-discovered word OCR CSV).
Fix issues until pass_strict is true (or report why it cannot be reached).
5. review_apply β€” **once** on the original PDF + edited review CSV; save under
redact/<document>/review/output_review_final/
6. verify_coverage again on the **post-apply** *_redacted.pdf from review_apply
Do not stop after step 2 or after a failed verify_coverage β€” read tool errors, fix paths/CSV, and continue.
After write_workspace_text saves a .py script, call run_workspace_python_script immediately β€” never rewrite the same script.
Tool arguments must be plain strings (relative_path="fix_review.py", content="import csv...") β€” not nested {"relative_path": {"relative_path": ...}} objects.
Prefer relative paths within the session workspace. Download artifacts via tool results; never assume shared disk
with the remote doc_redaction server except files already saved in your workspace.
"""
def _build_llm():
from langchain_openai import ChatOpenAI
provider = (os.environ.get("AGENT_DEFAULT_PROVIDER") or "llama-cpp").strip().lower()
if provider in {"amazon-bedrock", "bedrock"}:
from langchain_aws import ChatBedrockConverse
model_id = (
os.environ.get("AGENT_DEFAULT_MODEL") or "anthropic.claude-sonnet-4-6"
).strip()
return ChatBedrockConverse(
model=model_id, region_name=os.environ.get("AWS_REGION")
)
if provider in {"google-gemini", "gemini"}:
from langchain_google_genai import ChatGoogleGenerativeAI
model_id = (
os.environ.get("AGENT_DEFAULT_MODEL") or "gemini-flash-latest"
).strip()
return ChatGoogleGenerativeAI(
model=model_id, google_api_key=os.environ.get("GEMINI_API_KEY")
)
base_url = (
os.environ.get("AGENT_LLAMA_BASE_URL") or "http://127.0.0.1:8080/v1"
).rstrip("/")
model_id = (
os.environ.get("AGENT_LLAMA_MODEL_ID")
or os.environ.get("AGENT_DEFAULT_MODEL")
or "local"
).strip()
return ChatOpenAI(
base_url=base_url,
api_key=os.environ.get("OPENAI_API_KEY") or "not-needed",
model=model_id,
temperature=0.2,
)
def build_redaction_agent(session_hash: str | None):
"""Compile a ReAct agent with session-scoped tools."""
from redaction_langgraph.tools import build_langgraph_tools
llm = _build_llm()
tools = build_langgraph_tools(session_hash)
graph = create_react_agent(llm, tools)
return graph, SystemMessage(content=_SYSTEM_PROMPT)
def graph_recursion_limit() -> int:
raw = (os.environ.get("LANGGRAPH_RECURSION_LIMIT") or "50").strip()
try:
return max(10, int(raw))
except ValueError:
return 50