osrforge.convert
The end-to-end conversion and its resume: preprocess → survey → content → monsters → mapread → assemble.
Each stage writes its own run.json status; a stage failure propagates after
its failed status is written, keeping everything upstream. rerun resumes:
it re-runs the named stage and everything downstream through assemble — the
one reading that leaves a workdir artifact-consistent, since every stage
already clears or supersedes its downstream caches. on_progress receives the
stage-transitions-and-usage stream promised to hosts, covering exactly the
stages the chain runs.
KNOB_STAGES
module-attribute
KNOB_STAGES: Mapping[str, Stage] = {
"render_dpi": Stage.PREPROCESS,
"max_pages": Stage.PREPROCESS,
"max_source_bytes": Stage.PREPROCESS,
"blank_page_renders": Stage.PREPROCESS,
"survey_max_pages": Stage.SURVEY,
"content_batch_pages": Stage.CONTENT,
"monster_fuzzy_threshold": Stage.MONSTERS,
"monster_llm_top_k": Stage.MONSTERS,
"custom_monsters": Stage.MONSTERS,
"map_reading": Stage.MAPREAD,
"unresolved_fallback": Stage.ASSEMBLE,
}
Each settings knob's owning stage — the drift guard's table.
Updating a knob whose owning stage is upstream of the rerun stage is rejected:
the drifted run.json echo would otherwise claim, say, pages were rendered at
a DPI they weren't.
RUNNABLE_STAGES
module-attribute
RUNNABLE_STAGES: tuple[Stage, ...] = (
Stage.PREPROCESS,
Stage.SURVEY,
Stage.CONTENT,
Stage.MONSTERS,
Stage.MAPREAD,
Stage.ASSEMBLE,
)
The six chain steps, in order — geometry has no independent run (it lives inside assembly).
OnProgress
module-attribute
OnProgress = Callable[[StageEvent], None]
The progress callback: called synchronously with each stage transition.
ConversionResult
dataclass
ConversionResult(run: RunMeta, adventure: Adventure, report: ExtractionReport)
convert's and rerun's return: the final run metadata, the draft, and its report.
StageEvent
dataclass
StageEvent(stage: Stage, status: StageState, usage: TokenUsage | None = None)
One progress event: a stage transition, with usage on completion.
Events cover the chain steps the run drives; the geometry stage tracked
inside assemble() gets no separate event — from a host's perspective it
is an implementation detail of assembly, and its status is still readable
in run.json.
convert
convert(
pdf_path: Path,
workdir: Path,
provider: ModelProvider,
settings: ConversionSettings | None = None,
on_progress: OnProgress | None = None,
) -> ConversionResult
Convert a module PDF into a draft adventure, end to end.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pdf_path
|
Path
|
The source module PDF. |
required |
workdir
|
Path
|
The workdir root to create or rebuild. |
required |
provider
|
ModelProvider
|
The model provider for the extraction stages. |
required |
settings
|
ConversionSettings | None
|
Pipeline settings; defaults to |
None
|
on_progress
|
OnProgress | None
|
Optional callback receiving a |
None
|
Returns:
| Type | Description |
|---|---|
ConversionResult
|
The conversion result. |
Raises:
| Type | Description |
|---|---|
PdfError
|
If preprocessing rejects the source. |
ExtractionError
|
If the survey finds nothing. |
ProviderError
|
On provider transport, auth, or rate-limit exhaustion. |
SchemaValidationError
|
If the provider exhausts its schema budget. |
OverrideError
|
If an existing |
Examples:
from pathlib import Path
from osrforge import ConversionSettings, convert
from osrforge.providers.foundry import FoundryProvider, FoundrySettings
provider = FoundryProvider(FoundrySettings.from_env())
result = convert(Path("module.pdf"), Path("module.forge"), provider, ConversionSettings())
print(result.report.validation.passed)
rerun
rerun(
workdir: Path,
stage: Stage,
provider: ModelProvider | None = None,
settings_updates: Mapping[str, object] | None = None,
on_progress: OnProgress | None = None,
) -> ConversionResult
Re-run one stage — and everything downstream of it — from cached upstream outputs.
The stage argument is the skip: the user names what to redo and
everything upstream is kept verbatim (no automatic staleness detection).
rerun(…, Stage.ASSEMBLE) needs no provider and is the documented
correction-loop assemble; rerun preprocess reads the workdir's own
source.pdf.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
workdir
|
Path
|
An existing workdir (its |
required |
stage
|
Stage
|
The stage to resume from — one of |
required |
provider
|
ModelProvider | None
|
The model provider; required exactly when the resumed chain contains a model stage. |
None
|
settings_updates
|
Mapping[str, object] | None
|
Settings knobs to update in the |
None
|
on_progress
|
OnProgress | None
|
The same stage-event stream |
None
|
Returns:
| Type | Description |
|---|---|
ConversionResult
|
The conversion result. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
ValidationError
|
If a settings update names an unknown knob or an invalid value. |
Examples:
from pathlib import Path
from osrforge.contracts.run import Stage
from osrforge.convert import rerun
# The correction loop's re-assembly: no provider, no model call.
result = rerun(Path("module.forge"), Stage.ASSEMBLE)
# Re-resolve monsters with the stat-block pass off, then re-assemble.
result = rerun(
Path("module.forge"),
Stage.MONSTERS,
provider=provider,
settings_updates={"custom_monsters": "off"},
)