Sources and Patterns¶
This page covers how to create sources, choose between run() and
run_many(), and interpret the result envelope.
Source Constructors¶
| Constructor | Input | Notes |
|---|---|---|
Source.from_text(text) |
Plain string | Identifier defaults to first 50 chars |
Source.from_file(path) |
Local file path | Supports PDF, images, video, audio, text |
Source.from_youtube(url) |
YouTube URL | URL reference (no download); Gemini-native, limited on OpenAI in v1.0 |
Source.from_arxiv(ref) |
arXiv ID or URL | Normalizes to canonical PDF URL (no download at construction time) |
Source.from_uri(uri, mime_type=...) |
Remote URI | Generic fallback for any hosted content |
Examples:
from pollux import Source
text = Source.from_text("Caching reduces repeated token cost.")
paper = Source.from_file("paper.pdf")
video = Source.from_youtube("https://youtube.com/watch?v=dQw4w9WgXcQ")
arxiv = Source.from_arxiv("2301.00001")
remote = Source.from_uri("https://example.com/data.csv", mime_type="text/csv")
Single Prompt: run()¶
Use run() when you have one prompt and at most one source.
import asyncio
from pollux import Config, Source, run
async def main() -> None:
config = Config(provider="gemini", model="gemini-2.5-flash-lite")
result = await run(
"What are the main conclusions?",
source=Source.from_file("paper.pdf"),
config=config,
)
print(result["status"]) # "ok"
print(result["answers"][0])
asyncio.run(main())
Output:
ok
The paper concludes that context caching reduces repeated token cost by up to
90% for fan-out workloads, with diminishing returns below 3 prompts per source.
Multiple Prompts: run_many()¶
Use run_many() when prompts or sources are plural. It handles upload reuse,
concurrency, and cache identity automatically.
import asyncio
from pollux import Config, Source, run_many
async def main() -> None:
config = Config(provider="gemini", model="gemini-2.5-flash-lite")
sources = [
Source.from_file("paper1.pdf"),
Source.from_file("paper2.pdf"),
]
prompts = [
"Summarize the main argument.",
"List key findings.",
]
envelope = await run_many(prompts, sources=sources, config=config)
print(envelope["status"])
for i, answer in enumerate(envelope["answers"], 1):
print(f"Q{i}: {answer[:80]}...")
asyncio.run(main())
Output:
ok
Q1: Paper 1 argues that multimodal orchestration layers reduce boilerplate by...
Q2: Key findings: (1) fan-out caching saves 85-92% of input tokens; (2) broad...
Structured Output¶
Pass a Pydantic model (or JSON schema dict) via Options(response_schema=...)
to get typed, validated output in envelope["structured"].
import asyncio
from pydantic import BaseModel
from pollux import Config, Options, Source, run
class PaperSummary(BaseModel):
title: str
findings: list[str]
async def main() -> None:
config = Config(provider="openai", model="gpt-5-nano")
options = Options(response_schema=PaperSummary)
result = await run(
"Extract a structured summary.",
source=Source.from_text("Title: Caching Study. Findings: tokens saved, latency reduced."),
config=config,
options=options,
)
summary = result["structured"][0]
print(summary.title) # "Caching Study"
print(summary.findings) # ["tokens saved", "latency reduced"]
asyncio.run(main())
When response_schema is set, the structured field contains one parsed
object per prompt. The raw text is still available in answers.
Choosing run() vs run_many()¶
| Situation | Use | Why |
|---|---|---|
| One question, optional source | run() |
Smallest surface area |
| Multiple questions on shared source(s) | run_many() |
Fan-out efficiency |
| Same question across many sources | run_many() |
Fan-in analysis |
| Many questions across many sources | run_many() |
Broadcast pattern |
Rule of thumb: if prompts or sources are plural, use run_many().
run() is a convenience wrapper that delegates to run_many() with a single
prompt.
ResultEnvelope Reference¶
Every call returns a ResultEnvelope dict. Here are all fields:
| Field | Type | Always present | Description |
|---|---|---|---|
status |
"ok" \| "partial" \| "error" |
Yes | ok = all answers populated; partial = some empty; error = all empty |
answers |
list[str] |
Yes | One string per prompt |
structured |
list[Any] |
Only with response_schema |
Parsed objects matching your schema |
reasoning |
list[str \| None] |
No | Provider reasoning traces (when available) |
confidence |
float |
Yes | 0.9 for ok, 0.5 otherwise |
extraction_method |
str |
Yes | Always "text" in v1.0 |
usage |
dict[str, int] |
Yes | Token counts (input_tokens, output_tokens, total_tokens) |
metrics |
dict[str, Any] |
Yes | duration_s, n_calls, cache_used |
Example of a complete envelope:
{
"status": "ok",
"answers": ["The paper concludes that..."],
"confidence": 0.9,
"extraction_method": "text",
"usage": {"input_tokens": 1250, "output_tokens": 89, "total_tokens": 1339},
"metrics": {"duration_s": 1.42, "n_calls": 1, "cache_used": False},
}
v1.0 Notes¶
- Conversation continuity (
history,continue_from) is reserved and disabled in v1.0. delivery_mode="deferred"is reserved and disabled in v1.0.- Provider feature support varies. See Provider Capabilities.