Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ service keys.
| [Multi-model contract review with the OpenAI Agents SDK](./contract-review-agent) | Running an OpenAI Agents SDK agent whose every model call (triage, orchestration, vision, OCR, embeddings, rerank, entity extraction, text-to-SQL, reasoning, and a safety guardrail) is served by one SIE cluster, each step on the right catalog model, with per-model observability | `chat/completions`, `encode`, `score`, `extract` | GPU SIE deployment required; standalone `uv` project; real contracts fetched from CUAD (CC BY 4.0) | Runnable demo |
| [Turn difficult PDFs into Markdown](./document-to-markdown) | Preserving tables, reading order, headings, and form labels across real financial, academic, and government PDFs | `extract` | SIE endpoint with `docling`; standalone `uv` project; source PDFs fetched at run time | Runnable evaluation example |
| [Review a flood claim packet](./insurance-claims-agent) | Finding an unsigned form and a $400 evidence mismatch across a policy, estimate, inventory, and damage photograph | `extract`, `score`, `chat/completions` | GPU SIE deployment; standalone `uv` project; public FEMA documents and public-domain photograph fetched at run time | Runnable agent example |
| [Trace a restated filing figure](./financial-filing-agent) | Following one reported figure through an original filing, corrective notice, and restatement while preserving source status | `extract`, `encode`, `score` | SIE endpoint; standalone `uv` project; public SEC facts and saved verified evidence | Runnable agent example |
| [Reproduce CMS's L1851 documentation finding](./prior-authorization-review-agent) | Tracing a published six-month requirement against a seven-month face-to-face encounter and CMS's recoupment result | `extract`, `encode`, `score` | SIE endpoint; standalone `uv` project; exact CMS published example | Runnable agent example |
| [Reconstruct a bearing failure](./maintenance-triage-agent) | Turning the NTSB's three East Palestine detector readings into a cited temperature and alert sequence without adding a new causal claim | `extract`, `encode`, `score` | SIE endpoint; standalone `uv` project; exact NTSB illustrated report spread | Runnable agent example |

For docs publishing, lead with the quickest runnable demos, then use the
benchmark and evaluation examples for deeper technical users.
Expand Down
2 changes: 2 additions & 0 deletions examples/financial-filing-agent/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SIE_CLUSTER_URL=http://localhost:8080
SIE_API_KEY=
7 changes: 7 additions & 0 deletions examples/financial-filing-agent/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.env
.venv/
.pytest_cache/
.ruff_cache/
__pycache__/
*.pyc
runs/
81 changes: 81 additions & 0 deletions examples/financial-filing-agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Trace a restated figure back to the controlling filings

This example follows one Pathward Financial fact through exact table rows from
an original Form 10-Q and a restated Form 10-K/A, plus exact sentences from an
Item 4.02 Form 8-K. It returns both versions, calculates the change, and keeps
the source status and company caveat attached.

The result is narrow on purpose. It does not classify the restatement as fraud
or misconduct, and it does not make an investment recommendation.

## What runs on SIE

| Step | Model | Output |
|---|---|---|
| Parse the source packet | `docling-project/docling` | Markdown with source headings |
| Retrieve candidate passages | `BAAI/bge-m3` | Dense vectors and cosine ranking |
| Rerank against the exact question | `Qwen/Qwen3-Reranker-4B` | Ordered evidence with scores |
| Verify the cited spans | `urchade/gliner_multi-v2.1` | Exact source spans |
| Recover exact source spans | `fastino/gliner2-large-v1` | Table values, period, company and reliance-status entities |

Each stage consumes the prior stage. The result fails closed if either entity
model omits a required source span. The original values come from the original
Form 10-Q table. The restated values come from the Form 10-K/A table, and the
pipeline checks that its “As Previously Reported” column matches the Form 10-Q.
The company caveat is retained verbatim only when the reranked evidence contains
its exact source sentence. Ordinary Python code calculates the difference with
decimal arithmetic.

## Verified result

The recorded component calls ran through the public SIE server on an NVIDIA L4.
The restated passage ranked first for the question about the restated Q3 FY2023
figure.

```text
Net income attributable to parent $45.096M -> $36.080M
Change -$9.016M (-20.0%)
Diluted EPS $1.68 -> $1.34
Source status earlier affected filings should no longer be relied upon
```

Pathward's exact statement stays in the result: the accounting change does not
impact net income over the life of the portfolio, but changes when elements of
the programs are recognized.

## Run it

```bash
cd examples/financial-filing-agent
cp .env.example .env
uv sync

uv run review-filing --run-id local
uv run eval-filing runs/local
```

Set `SIE_CLUSTER_URL` and `SIE_API_KEY` to use SIE Cloud. The default points to
a local server at `http://localhost:8080`.

## Evidence bundle

Every run writes:

```text
runs/<run-id>/manifest.json endpoint, model IDs, fixture hashes, latency
runs/<run-id>/raw/parse.json complete Docling response
runs/<run-id>/raw/retrieve.json embeddings and cosine ranking
runs/<run-id>/raw/rerank.json complete reranker response
runs/<run-id>/raw/entities.json combined entity spans
runs/<run-id>/raw/gliner2-*.json raw GLiNER2 source-span responses
runs/<run-id>/raw/mapped.json validated record mapped from Docling table coordinates
runs/<run-id>/parsed.md parsed packet used downstream
runs/<run-id>/review.json source-versioned result and calculated delta
runs/<run-id>/evaluation.json deterministic checks
```

`verified-run/` contains the saved evidence used to design the example. It is
not a latency benchmark. The first request included model provisioning.

See [fixtures/SOURCES.md](fixtures/SOURCES.md) for accession numbers, URLs, and
source checksums.
16 changes: 16 additions & 0 deletions examples/financial-filing-agent/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
cluster:
url: "http://localhost:8080"
api_key: ""
provision_timeout_s: 900

models:
parse: "docling-project/docling"
retrieve: "BAAI/bge-m3"
rerank: "Qwen/Qwen3-Reranker-4B"
entities: "urchade/gliner_multi-v2.1"
extract: "fastino/gliner2-large-v1"

review:
query: "Compare Pathward's original and restated Q3 FY2023 net income and diluted EPS, then identify the superseded source and company caveat."
candidate_chunks: 8
top_k: 8
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Source-versioned financial filing review."""
102 changes: 102 additions & 0 deletions examples/financial-filing-agent/financial_filing/evaluate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from __future__ import annotations

import argparse
import hashlib
import json
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any

from rich.console import Console
from rich.table import Table

console = Console()


@dataclass(frozen=True)
class Check:
name: str
passed: bool
detail: str


def evaluate_review(review: dict[str, Any]) -> list[Check]:
change = review.get("change", {})
excluded = set(review.get("claims_excluded", []))
evidence = review.get("ranked_evidence", [])
evidence_text = "\n".join(str(row.get("text", "")) for row in evidence).casefold()
return [
Check("route", review.get("route") == "superseded_figure", str(review.get("route"))),
Check("net-income-delta", abs(float(change.get("value_millions", 0)) + 9.016) < 0.0001, str(change)),
Check("eps-delta", abs(float(change.get("diluted_eps", 0)) + 0.34) < 0.0001, str(change)),
Check("percent-delta", abs(float(change.get("percent", 0)) + 20.0) < 0.05, str(change)),
Check(
"source-lineage", len(review.get("controlling_sources", [])) == 3, str(review.get("controlling_sources"))
),
Check(
"caveat-preserved",
"over the life of the portfolio" in review.get("company_caveat", ""),
review.get("company_caveat", ""),
),
Check(
"ranked-source-evidence",
bool(evidence)
and all(
token in evidence_text
for token in (
"pathward financial",
"$45,096",
"$36,080",
"$1.68",
"$1.34",
"no longer",
"over the life of the portfolio",
)
),
str([row.get("chunk_id") for row in evidence]),
),
Check(
"unsafe-claims-excluded",
{"fraud", "misconduct", "investment recommendation"} <= excluded,
", ".join(sorted(excluded)),
),
]


def evaluate_run(run_dir: Path) -> bool:
review = json.loads((run_dir / "review.json").read_text(encoding="utf-8"))
checks = evaluate_review(review)
passed = all(check.passed for check in checks)
evaluation_path = run_dir / "evaluation.json"
evaluation_path.write_text(
json.dumps({"passed": passed, "checks": [asdict(check) for check in checks]}, indent=2) + "\n",
encoding="utf-8",
)
manifest_path = run_dir / "manifest.json"
if manifest_path.exists():
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
artifacts = [
artifact for artifact in manifest.get("artifacts", []) if artifact.get("path") != "evaluation.json"
]
artifacts.append(
{"path": "evaluation.json", "sha256": hashlib.sha256(evaluation_path.read_bytes()).hexdigest()}
)
manifest["artifacts"] = artifacts
manifest_path.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
table = Table("Check", "Result", "Detail")
for check in checks:
table.add_row(check.name, "[green]pass[/]" if check.passed else "[red]fail[/]", check.detail)
console.print(table)
return passed


def main() -> None:
parser = argparse.ArgumentParser(description="Evaluate a saved filing review")
parser.add_argument("run_dir", type=Path)
args = parser.parse_args()
if not evaluate_run(args.run_dir):
raise SystemExit(1)


if __name__ == "__main__":
main()
Loading