Skip to content

Python API

Everything the CLI does is available as a library. The high-level entry points are async.

import asyncio
from agentvision import analyze, load_settings

async def main():
    report = await analyze("dist/index.html", settings=load_settings(vision_backend="local"))
    print(report.verdict, [i.message for i in report.issues])

asyncio.run(main())

Confidential inputs (ephemeral cache)

Wrap any call in ephemeral_cache() so renders/sessions go to a throwaway temp dir that's wiped on exit — nothing touches the on-disk cache. Use it for confidential artifacts:

from agentvision import analyze, ephemeral_cache, load_settings

async def main():
    with ephemeral_cache(load_settings()) as settings:
        report = await analyze("confidential.pptx", settings=settings)
        # ... use report ...
    # temp cache dir is removed here, even on error

Core functions

analyze async

analyze(source: str, *, settings: Settings | None = None, backend: str | None = None, instructions: str | None = None, expected: str | None = None, brief: Brief | None = None, use_ocr: bool = True, source_type: str = 'auto', viewport: Viewport | None = None, full_page: bool | None = None, wait_for: str | None = None, out_dir: Path | None = None) -> Report

Full visual analysis: structural grounding + vision-backend critique.

When brief is given, the render is also graded for intent conformance — does it match what the agent set out to build — and the verdict is gated on it.

Motion sources (a video file or an animated GIF) are automatically routed to the temporal grader (watch) — sampled over time, never flattened to a single frame or mis-rendered by the browser.

check async

check(source: str, *, settings: Settings | None = None, brief: Brief | None = None, source_type: str = 'auto', viewport: Viewport | None = None, full_page: bool | None = None, wait_for: str | None = None, use_ocr: bool = True, out_dir: Path | None = None) -> Report

Classic checks only — no LLM, no API key, no egress (incl. OCR spell-check).

With a brief, also grades text requirements deterministically via OCR; non-text requirements are reported uncertain (the offline path cannot judge visual intent).

Motion sources route to the temporal grader with the vision pass off (deterministic motion/black/dead-export signals only — still no LLM, no egress).

watch async

watch(source: str, *, settings: Settings | None = None, backend: str | None = None, frames: int | None = None, interval_ms: int | None = None, brief: Brief | None = None, instructions: str | None = None, use_vision: bool = True, source_type: str = 'auto', out_dir: Path | None = None) -> Report

Watch source over time and report temporal behavior (playback/loading/liveness).

render async

render(source: str, *, settings: Settings | None = None, source_type: str = 'auto', viewports: list[Viewport] | None = None, full_page: bool | None = None, wait_for: str | None = None, device_scale: float | None = None, settle_ms: int | None = None, freeze: bool | None = None, out_dir: Path | None = None) -> RenderResult

Render source and return image(s) plus trustworthy DOM/CV signals.

compute_diff

compute_diff(baseline_path: str | Path, candidate_path: str | Path, out_path: str | Path | None = None) -> DiffResult

Sessions

LoopSession

Drive the visual feedback loop for one artifact across iterations.

Agents call :meth:iterate after each fix attempt (optionally passing an updated source). The session persists state under the workspace so it can be resumed.

run async

run(max_iter: int = 5) -> list[IterationResult]

Convenience: iterate the SAME source up to max_iter times.

Useful for demonstrating stuck-detection on an unchanged artifact. Real agents drive :meth:iterate themselves, editing the source between calls.

IterationResult

Bases: BaseModel

GenerativeLoopSession

Drive generate → perceive → refine until the output matches the brief.

Intent

Brief

Bases: BaseModel

The intended product — the thought the artifact is graded against.

from_inputs classmethod

from_inputs(*, text: str | None = None, expect: list[str] | None = None, reference_image: str | None = None) -> Brief

Build a brief from CLI/REST-style inputs (--brief + repeated --expect).

IntentClaim

Bases: BaseModel

A single checkable requirement extracted from the intent.

parse classmethod

parse(raw: str, *, default: Importance = Importance.MUST) -> IntentClaim

Parse "must: the title reads AgentVision" → claim + importance.

The report contract

The verdict/report/intent types — Report, Issue, Brief, Conformance, Handoff, BBox and friends — are the shared agentsensory contract, re-exported from agentvision since 0.9.0. Every organ in the eyes/ears/brain trio speaks this one language, so a Report the eyes grade drops straight onto the same verdict bus the brain (Verel) consumes — no per-organ translation. from agentvision import Report keeps working unchanged; the import surface is identical.

Report

Bases: ReportBase

A vision report: shared fields + the render-specific surface.

Issue

Bases: IssueBase

A vision issue: kind/source narrowed to the closed vision enums.

Conformance

Bases: BaseModel

score property

score: float

Fraction of claims satisfied (0..1); 1.0 when there are no claims.

matches_intent

matches_intent() -> bool

True only when no must requirement is violated or left uncertain.

ClaimResult

Bases: BaseModel

One requirement (a piece of the thought) graded against the artifact.

The handoff

Handoff

Bases: BaseModel

The afferent signal: what a sense perceived, shaped for the brain to act on.

from_report classmethod

from_report(report) -> Handoff

Distill any sense's Report into the actionable signal (duck-typed).

Backends

VisionBackend

Bases: Protocol

complete_text async

complete_text(system: str, user: str) -> str

Text-only completion (no image) — for checklist extraction + prompt refinement.

Backends that cannot do this (e.g. the offline local backend) return "".

AnalysisRequest

Bases: BaseModel

Configuration

Settings

Bases: BaseSettings

Runtime settings. Environment prefix: AGENTVISION_.

Provider API keys use their conventional env names (not the prefix) so they match what the provider SDKs already expect.

load_settings

load_settings(**overrides) -> Settings

Build a Settings object, applying any explicit overrides last.

ephemeral_cache

ephemeral_cache(settings: Settings) -> Iterator[Settings]

Yield a copy of settings whose cache lives in a throwaway temp dir, wiped on exit.

Use for confidential inputs so renders/sessions are never written to the persistent on-disk cache. The temp dir is created with private (0700) permissions and removed in a finally so it's cleaned up even on error.

with ephemeral_cache(load_settings()) as s:
    report = await analyze("/path/to/confidential.pptx", settings=s)