Skip to content

Decision Evidence

Decision evidence describes a completed evaluation without replacing its typed result. It is available only when the selected model integration supplies it; Kedi does not fabricate probability metadata for ordinary generated booleans.

Capture Completed Calls

import kedi


@kedi.query(adapter="pydantic", model="typesafe/jev-latest")
def review(ticket: str) -> bool:
    """kedi
    >> It is [duplicate: bool] that <ticket> describes a duplicate charge.
    = `duplicate`
    """
    ...


with kedi.capture_decisions() as capture:
    duplicate = review("The same invoice was charged twice.")

for info in capture.decisions:
    print(info.field_path, info.probability, info.threshold)

This live example requires kedi[typesafe] and TYPESAFE_API_KEY. capture_decisions() -> ContextManager[DecisionCapture] makes no additional request. DecisionCapture.decisions is a tuple of immutable DecisionInfo views in completion order, one per output binding. Sibling fields share a call_id. Nested captures also contribute to the enclosing capture.

Use regular with around awaited calls and await all intended work before exit. Exiting stops collection; it neither starts nor joins pending work. Response-cache hits and outputs without evidence add no records. A later failure does not remove earlier successful records. Implicit control-flow claims and arbitrary direct SDK calls are not captured template bindings.

Inspect a Binding

decision_info(name: str) -> DecisionInfo | None is for active embedded Kedi Python execution. Outside a fragment, use InteractiveSession.decision_info(name) for a top-level session binding. Unknown names raise NameError; known values without evidence return None. Calling the root helper outside Kedi execution raises RuntimeError.

Information Fields

Fields Meaning
call_id, field_path Shared evaluation identity and this output's path
provider, model Evidence source, with model optional
source DecisionSource(path, line, column), each location component optional
prompt_fingerprint, inputs Rendered prompt identity and named input fingerprints
request_fingerprint, state_fingerprint, criteria_fingerprint, config_fingerprint Optional identities reported by the integration
answers Immutable matching provider answers, including nested output paths
probability, threshold, comparator A single compatible boolean/probability answer's evidence, otherwise None
confidence, distribution, rubric Optional single-answer evidence; not inferred when absent

Historical Identity, Not Automatic Re-Evaluation

info.matches_inputs(**inputs) -> bool compares the explicit named inputs locally. It makes no model request. Supply exactly the recorded input names. Computed substitutions, unsupported values, or incomplete input coverage raise ValueError rather than pretending to match.

Changing an input leaves historical evidence intact. Reassigning its output clears evidence from the current binding. For supported fingerprintable output values, a later in-place mutation also makes binding lookup return None. An already captured DecisionInfo remains a historical snapshot. No operation here applies a new threshold or certifies that external state is unchanged.

Fingerprints are versioned one-way identities, not copies of original inputs, encryption, or anonymization. Unknown object graphs cannot be assumed comparable. Session persistence remains subject to the full snapshot restrictions in Incremental Execution.