Interrupts & Human-in-the-Loop
Pause an agent for human input mid-run and resume the session safely.
#Interrupts and follow-up questions
The SDK has two related human-input surfaces:
@depends_on_interrupt(...)supplies a specific tool argument at execution time.agent.allow_followup_questions(...)orswarm.allow_followup_questions(...)lets the runtime ask typed clarification questions during one invocation.
Both surfaces keep the input handler local. Only serializable prompt and policy metadata crosses the wire.
#Tool-argument interrupts
from typing import Literal
from maivn import Agent, default_terminal_interrupt, depends_on_interrupt
agent = Agent(name='deployer', api_key='your-api-key')
@agent.toolify(description='Deploy after a human chooses the environment')
@depends_on_interrupt(
arg_name='environment',
input_handler=default_terminal_interrupt,
prompt='Environment (staging/production):',
)
def deploy(environment: Literal['staging', 'production']) -> dict[str, str]:
return {'environment': environment}depends_on_interrupt accepts arg_name, input_handler, optional prompt, optional input_type, and optional choices. A Literal[...] annotation infers a choice prompt; bool infers boolean; int and float infer number; other annotations use text.
The default handler reads one terminal line. A custom handler has the shape Callable[[str], object] and may close over UI or request state:
def collect_from_ui(prompt: str) -> str:
publish_prompt(prompt)
return wait_for_answer()The decorated argument must be a real function parameter. The dependency is transported with the tool schema, and the SDK submits the returned answer before local tool execution continues.
#Runtime-authored follow-up questions
Follow-ups are opt-in per invocation through a chainable builder. There is no persistent enabled switch.
from maivn import Agent, FollowupQuestion
agent = Agent(name='planner', api_key='your-api-key')
def answer_followup(
question: FollowupQuestion,
response_schema: dict[str, object],
) -> object:
print(question.question)
for option in question.options:
print(option.label, '-', option.description)
return 'US East'
response = agent.allow_followup_questions(
input_handler=answer_followup,
max_questions=3,
max_questions_per_thread=10,
response_schema={'type': 'string'},
timeout=60,
).invoke('Plan the deployment.', thread_id='thread-42')The same builder supports invoke, ainvoke, stream, and astream and preserves the normal invocation keyword surface. When an agent_followup checkpoint arrives, the builder calls the handler, submits its typed answer through the current client, and continues the same stream and thread.
The public question models are FollowupQuestion and FollowupOption. A question carries checkpoint_id, thread_id, session_id, optional short header, question, optional explanation, up to three options, and multi_select/required flags.
default_terminal_followup prints the question and options. It converts boolean, object, array/multi-select, option-number, and free-text answers according to the supplied response schema. Install no extra dependency for this plain terminal path.
#Model-authored tool prompts
Use the exported AgentGenerated singleton as the prompt when the runtime, rather than application copy, should author a tool interrupt question:
from maivn import AgentGenerated, depends_on_interrupt
@agent.toolify(description='Collect a deployment note')
@depends_on_interrupt(
arg_name='note',
input_handler=default_terminal_interrupt,
prompt=AgentGenerated,
)
def collect_note(note: str) -> str:
return note#Manual client submission
Applications that manage the event loop themselves can submit a typed non-approval answer with Client.submit_interrupt_response(thread_id, interrupt_id, answer=..., responded_by=..., surface='sdk'); use asubmit_interrupt_response in async code. Approval checkpoints use the separate submit_approval/asubmit_approval methods and ApprovalDecision model.
For stream shapes, see Events. For private values collected during a turn, see Private Data; privacy controls reduce exposure but do not certify the deployment.