Reviewed Evidence Workflow¶
This example connects the whole boundary: a parent delegates, a child reads a local fixture, the child returns a typed result, and the parent writes a report through an approval handler. The parent cannot read the fixture directly; the child cannot write the report.
Download both files into one directory: reviewed_evidence.kedi and reviewed_evidence.py.
The Kedi Program¶
~Review(failures: list[str], may_release: bool)
> profile: reviewer:
###
Read the named test suite and report failures without inventing results.
###
> adapter: pydantic
> use: read_evidence
> output: Review
> system:
Read evidence for the requested suite.
Release only if no tests failed.
> profile: coordinator:
> adapter: pydantic
> subagent: reviewer
> max_agents: 2
> use: write_report
> approval: `approve_report`
> system:
Delegate the review and use its validated result.
Write failure names and the release decision to requested.txt.
Use write_report and return the actual saved path.
Never treat missing evidence as success.
> use: coordinator
[receipt] << Review suite parser and save its report.
= <receipt>
The Python companion supplies all three referenced callables through
runtime_globals. There are no hidden network tools: read_evidence returns
12 passing tests and one failure named unicode_identifier from a local fixture.
Host Responsibilities¶
run_review(adapter, output_dir) builds the runtime and closes it in finally.
Its child tool calls current_subagent_execution() to record the child run,
profile, and conversation identity. It raises if invoked outside a child.
The report approval handler accepts only write_report and replaces its path
with the application's fixed output_dir/review.txt. The writer independently
checks that destination before performing I/O. Kedi revalidates edited arguments
before calling it. The original model-provided path is never the write target.
The function returns the model's receipt plus native observations, approval
requests, and actual writes. These make the effect inspectable without treating
the final model sentence as proof that it happened.
Run With a Provider¶
Install Kedi with its Pydantic provider support and configure the provider's credentials. From the directory containing the two downloaded files:
from kedi.agent_adapter import PydanticAdapter
from reviewed_evidence import run_review
result = run_review(
PydanticAdapter("openai:gpt-5.6-luna"),
output_dir="reports",
)
print(result["receipt"])
print(result["writes"])
This makes real model calls. Tool selection and prose can vary. Expected behavior
is a report that names unicode_identifier and does not approve release. An
empty writes list is not success, regardless of what the model claims.
Deterministic Verification¶
The documentation tests run these exact files with a local Pydantic
FunctionModel. They assert the parent delegates, the child's tools exclude the
writer, the parent's tools exclude the reader, the returned child schema is
used, run IDs agree with the child tool's context, and the parent consumes that
result before writing. They also check that approval changes the destination
without changing the report text.
This establishes the program/runtime contract, not a model-accuracy result. Separate negative tests exercise unavailable children, invalid results, denied writes, and lifecycle failures. No external model or credentials are needed for the deterministic test suite.
Adapter Boundary¶
The downloadable program selects Pydantic explicitly. To use LangChain, change
both profile declarations to > adapter: langchain and supply a configured
LangChainAdapter to the same embedding function. The tools, approval handler,
child result envelope, and limits remain Kedi contracts; do not retain an
explicit Pydantic profile and assume that injecting a different adapter changes
its backend selection. The deterministic tutorial checks use Pydantic, while
the shared adapter regression suite covers the corresponding LangChain surfaces.
Dynamic Variant¶
Add > workflow: dynamic to the coordinator. Its child call then happens inside
run_workflow, for example:
The parent receives this structured workflow result and still calls its approved writer afterward. Do not move writing into the Monty snippet: only declared child functions exist there. The test suite runs both variants.