symfonic.agent.middleware.interrupt_minter¶
interrupt_minter ¶
Generic interrupt minter — Roadmap Item 9 (v7.2-bound).
Carved out of :class:SymfonicAgent so the file stays bounded while the
generic interrupt path lives in a focused module.
Responsibilities¶
- Mint a HMAC-signed pause token for a registered named interrupt.
- Build the public :class:
InterruptEventechoed back to stream consumers. - Persist the original payload to checkpoint metadata under
interrupt_payload:<interrupt_id>so the resume path can recover it without re-running the originating tool.
The minter intentionally does NOT know about ask_user -- that path
keeps its dedicated _mint_pause_token codepath in engine.py so a
regression here cannot influence the byte-identical event stream
acceptance criterion (criterion 5 in the roadmap).
load_original_payload
async
¶
Recover the payload stored at mint time so the hash can be reverified.
Returns the dict written under interrupt_payload:<interrupt_id> at
mint time, or None if the checkpoint is gone (e.g. MemorySaver
worker restart). Callers MUST handle None -- typically by
surfacing a 424 failed_dependency.
Source code in src/symfonic/agent/middleware/interrupt_minter.py
mint_interrupt_token
async
¶
mint_interrupt_token(
*,
run_id: str,
session_id: str,
scope: FrameworkTenantScope,
interrupt_data: dict[str, Any],
registration: InterruptRegistration,
config: FrameworkConfig,
checkpointer: Any,
ttl_seconds: int,
) -> InterruptEvent | None
Mint a pause token for a generic (non-ask_user) interrupt.
Parameters¶
run_id, session_id, scope
Standard run identity. session_id may be empty; in that
case the thread_id falls back to run_id.
interrupt_data
The dict surfaced by LangGraph's interrupt() call inside
:class:InterruptNode. Expected keys: name,
interrupt_id, payload, optionally tool_call_id.
registration
The :class:InterruptRegistration looked up from the agent's
_registered_interrupts dict. Used here only to validate
the payload one more time before minting -- defence-in-depth
against a faulty interrupt-marker on the wire.
config
Live FrameworkConfig -- supplied so PauseToken.encode
can read JWT_SECRET once via the same indirection used
by the ask_user path.
checkpointer
Active LangGraph saver. aget_tuple is called to recover
the freshly-minted checkpoint_id so the claims bind to a
specific checkpoint, and aput_writes stores the payload
keyed by interrupt_id for the resume path.
ttl_seconds
Token expiry. Mirrors ask_user_pause_ttl_seconds knob.
Source code in src/symfonic/agent/middleware/interrupt_minter.py
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | |