Skip to content

solvi.core.knowledge.agenda

Goals with done checks in code, gates that block actions and goals, the order between goals — journaled in the knowledge store; a dry run that validates gates on recorded successes.

The agenda: goals with done checks written in code, gates that block actions or goals, and the order between goals — kept in the knowledge store's journal.

from solvi.core.knowledge import Agenda, KnowledgeStore
ag = Agenda(KnowledgeStore("agent.jsonl"))
ag.goal("authenticated", done=lambda s: s.get("user_id") is not None)
ag.goal("order_changed", done=lambda s: s.get("order_status") == "exchange requested", requires=["authenticated"])
ag.gate("auth_first", lambda s: s.get("user_id") is not None, blocks=["modify_*", "exchange_*", "cancel_*"])

ag.update(state)                    # runs the done checks; every change of a goal's state is journaled
ag.open(state), ag.blocked(state), ag.done()
ok, why = ag.allows(state, "exchange_delivered_order_items")    # no action past a gate
ag.dry_run(recorded_successes)      # how often each gate would have blocked actions that worked

A goal is done only when its code check says so over the state, never because a model claims it. A gate is a hard check: allows refuses an action it blocks while its check is False, and a goal it blocks is not open; a person may override a gate with a recorded reason. requires orders goals (a tech tree): a goal is open when every goal it requires is done and no gate blocks it. Goals and gates are rule items of the knowledge store (source "spec"), the goals' states are fact items (source "outcome": what the done check observed), so a decision can say which goal it served and which gates held, and the journal shows the progress.

Validate gates before making them hard. A gate written from policy text can block correct calls: on a support-agent stream, a gate taken from the policy's "remind the customer to confirm they listed all items" blocked mostly calls the store would accept and the customer wanted, and some right calls were never made. dry_run(records) replays recorded successful (state, action) pairs through the gates and reports, per gate, how often it would have blocked them — run it on your logs before you install a gate. Where the gates are an environment's written rules, "no action past a gate" and "no wrong block" hold by construction (benchmarks/knowledge/toy_crafting.py: the agenda arms fail no attempt).

Agenda

Agenda(store=None, *, scope=None, sticky=True)

See the module docstring. store: a KnowledgeStore the goals, gates and state changes are written to (None: an in-memory list, history); scope: the scope of those items (default {"agenda": "agenda"}); sticky: a done goal stays done (achievements) — False re-checks it on every update (an order whose state can change back).

goal

goal(name, *, done, requires=(), gates=())

A goal: done(state) → bool is its check in code; requires: goals done first; gates: gates that must pass for it to be open (a gate may also name it in blocks).

gate

gate(name, check, *, blocks)

A gate: check(state) → True when actions / goals it blocks may go ahead (False or a Fail: blocked, with the reason). blocks: action names (glob patterns like "modify_*"), goal names, or a function(action) → bool.

override

override(gate, *, by, why)

A person lets a gate's blocks through (until clear_override), with a recorded reason.

gates_on

gates_on(target)

The gates that apply to an action or a goal.

allows

allows(state, action)

May action be taken in state? → (True, []) or (False, ["gate: reason", ...]) — every gate that blocks it and whose check is False.

update

update(state)

Run every done check on state; journal each goal whose state changed. → {goal: (old, new)}.

done

done()

The goals whose done check said so (as of the last update).

open

open(state=None)

Goals that can be worked on now: not done, every required goal done, no gate blocking them (on state).

blocked

blocked(state=None)

{goal: [reasons]} for the goals that are not done and cannot be worked on now.

snapshot

snapshot(state=None)

The agenda as a plain fact for a decision: done, open, blocked (with reasons).

dry_run

dry_run(records, *, examples=3)

Replay recorded successful actions — an iterable of (state, action) that worked — through the gates, without changing anything. → {"records": n, "blocked_any": k, "gates": {gate: {"applies", "would_block", "share", "examples": [record index, ...]}}}: a gate that would have blocked many actions that worked is not ready to be hard (see the module docstring).