Choose how to run this agent
Download Agent
Choose how you want to use this agent:
Use Security Settings Key (Recommended)
Use the API key you've already saved in Security Settings. Quick and convenient!
- No need to re-enter API key
- Works offline after download
- Centralized key management
No API key found in Security Settings. Add one now
Enter API Key Manually
Enter your API key now for this specific agent download.
- Use different key for this agent
- One-time use (not saved)
- Works offline after download
Configure Agent Encryption
Description
Upload a contract and get it explained in plain language — obligations, fees, deadlines, exit clauses, and red flags — with every answer grounded in the actual text, fully in your browser.
Source Code
# How many contract passages to retrieve per question. Deliberately higher than
# a generic document agent: clause-heavy questions (termination, fees, renewal)
# often span several sections, and current local defaults (8K+ token context)
# leave room for the richer grounding.
RAG_TOP_K = [[[RAG_TOP_K|6]]]
# Session context set from the page: what kind of contract, and whose side the
# explanation should take. Both optional.
_CONTEXT = {"contract_type": "", "role": "", "sources": []}
def _set_context(contract_type, role):
"""(JS-callable) Remember the contract type and the user's side.
Underscore-prefixed so it is never exposed to the LLM as a tool.
"""
_CONTEXT["contract_type"] = (contract_type or "").strip()
_CONTEXT["role"] = (role or "").strip()
return "ok"
def _extract_pdf_text(pdf_bytes):
"""(JS-callable) Extract plain text from a PDF's raw bytes via pypdf."""
import io
from pypdf import PdfReader
reader = PdfReader(io.BytesIO(pdf_bytes))
return "\n\n".join((page.extract_text() or "") for page in reader.pages)
async def _ingest_contract(source, text):
"""(JS-callable) Chunk + embed + index one contract document or amendment.
Returns the number of passages stored, as a string (for the UI).
"""
count = await agentop_rag.add_document(source, text)
_CONTEXT["sources"].append(source)
return str(count)
def _framing():
bits = []
if _CONTEXT["contract_type"]:
bits.append(f"The document is a {_CONTEXT['contract_type']}.")
if _CONTEXT["role"]:
bits.append(
f"Explain everything from the perspective of the {_CONTEXT['role']}."
)
return " ".join(bits)
async def process_user_query(query):
"""Plain-language contract answering, grounded in retrieved clauses.
Overrides the default router so retrieval is deterministic (small local
models are unreliable at deciding to call a search tool themselves).
"""
hits = await agentop_rag.search(query, RAG_TOP_K)
if not hits:
return (
"I don't have a contract to read yet — upload it above (PDF or "
"text) and I'll explain it in plain language."
)
excerpts = "\n\n".join(
f"[{i + 1}] (from {h['source']}) {h['text']}" for i, h in enumerate(hits)
)
grounded_prompt = (
"You are explaining a contract to someone who is not a lawyer. "
f"{_framing()} Use ONLY the CONTRACT EXCERPTS below.\n"
"Answer in plain everyday language: give the short answer first, then "
"what the contract actually says, citing excerpt numbers like [1]. "
"If the excerpts mention deadlines, fees, penalties, or automatic "
"renewal, point them out. If the excerpts do not contain the answer, "
"say so plainly instead of guessing.\n\n"
f"CONTRACT EXCERPTS:\n{excerpts}\n\nQUESTION: {query}"
)
# TEMPLATE_SYSTEM_PROMPT only exists as a JS global; the query bridge falls
# back to it when custom_prompt is empty (same idiom as the base template).
return await process_user_query_wllama(
grounded_prompt, globals().get("TEMPLATE_SYSTEM_PROMPT", "")
)
More by ozzo
New Hire Handbook Q&A
Based on the New Hire Handbook Q&A template.
WhatsApp Sales Copilot
Turn a raw WhatsApp chat export into a mini CRM — typed quotes, bookings, payments and boarding pas…
Private Quote & Material Estimator
Drop competing contractor quotes and compare them side by side — totals, inclusions, exclusions — t…
Messy Itinerary Travel Planner
Drop your messy pile of booking PDFs and trip notes and get a clean day-by-day itinerary — plus war…
Semantic Search
Search your own notes or documents by meaning, not keywords — instant results with no LLM download.
Meeting Minutes
Turn a meeting recording into a summary, key decisions, and action items, then ask follow-up questi…