core / uncertainty.py — UncertaintyTracker
Metacognitive monitor that records unknowns and assumptions so the agent can decide when to ask the user vs. proceed.
Data shapes
| Type | Fields |
|---|---|
Unknown (line 21) | what · impact (1-5) · resolution · resolved · resolved_value · timestamp |
Assumption (line 40) | claim · confidence (0.0-1.0) · basis · verified · was_correct · timestamp |
Methods
| Method | Purpose |
|---|---|
flag_unknown(what, impact=3, resolution="ask user") -> Unknown | Record an unknown the agent encountered. Returns the Unknown object so the caller can resolve it later without tracking indices. |
resolve_unknown(index_or_unknown, value) -> bool | Mark an unknown resolved. Accepts EITHER an int index into self.unknowns OR the Unknown object returned by flag_unknown. Returns False on out-of-range int, orphan object, or unexpected types — never raises. |
flag_assumption(claim, confidence=0.5, basis="") -> Assumption | Record an unverified belief. Returns the Assumption. |
verify_assumption(index_or_assumption, was_correct) -> bool | Same dual-dispatch shape as resolve_unknown: int index or returned Assumption. |
should_ask_user() -> Optional[str] | Returns the question to ask if any unknown has impact ≥ 4 and resolution=="ask user". |
get_risk_summary() -> str | Human-readable summary appended to the agent's final response. |
get_context_for_prompt() -> str | Markdown for prompt injection (critical unknowns + risky assumptions). |
Dual-dispatch API (object-or-index)
Before the fix, flag_unknown returned an Unknown but resolve_unknown only accepted an int. Holding the returned object and passing it back — the natural call shape — raised TypeError: '<=' not supported between instances of 'int' and 'Unknown'.
# Both now work, pick whichever is natural for the caller:
u = tracker.flag_unknown("timezone?", impact=4)
tracker.resolve_unknown(u, "UTC") # object form (preferred)
tracker.resolve_unknown(0, "UTC") # index form (backwards-compat)
a = tracker.flag_assumption("user wants python", confidence=0.4)
tracker.verify_assumption(a, was_correct=True)
Matching uses identity (is), NOT equality — two legitimately-distinct unknowns with the same what text are separate entries and must not both resolve on one call. Covered by tests/test_uncertainty_object_api.py (13 cases including orphan rejection, negative-index rejection, type-coercion rejection, duplicate-text identity check, mixed-mode usage).
Concurrency
Synchronous; per-process tracker (no persistence between sessions).