How to pause your agent for human input
Some tasks reach a decision point the agent cannot resolve on its own — a target environment, an approval threshold, a destructive step that needs sign-off. murmur-tool-request-input gives the model a ready-made tool to pause at that point, surface a question to the operator, and resume exactly where it left off once the operator replies.
The relevant manifest options are:
| Option | Controls |
|---|---|
| artifacts[].runtime | Whether a WASM artifact is a model-visible tool, inference driver, or hook |
| lifecycle.input_timeout_secs | Maximum seconds to wait before failing the task if no reply arrives |
Step 1 — write the manifest
Create a murmur.yaml file. Add murmur-tool-request-input to artifacts with runtime: tool, and write a system_prompt that tells the model when to pause:
name: my-agent
version: "0.1.0"
network:
internal_port: 52222
artifacts:
- name: murmur-driver-anthropic
version: "1.0.0"
runtime: driver
- name: murmur-tool-request-input
version: "1.0.0"
runtime: tool
capabilities:
network:
allow:
- https://api.anthropic.com
inference:
transport: http
endpoint: https://api.anthropic.com
model: claude-sonnet-5
api_key: ${ANTHROPIC_API_KEY}
driver:
artifact: murmur-driver-anthropic
system_prompt: |
You are a deployment agent. When you reach a decision you cannot make on your own —
such as which environment to target or whether to proceed with a destructive step —
call murmur-tool-request-input with a clear, specific question for the operator.
name: my-agent
version: "0.1.0"
network:
internal_port: 52222
artifacts:
- name: murmur-driver-openai
version: "1.0.0"
runtime: driver
- name: murmur-tool-request-input
version: "1.0.0"
runtime: tool
capabilities:
network:
allow:
- https://api.openai.com
inference:
transport: http
endpoint: https://api.openai.com
model: o3-mini-high
api_key: ${OPENAI_API_KEY}
driver:
artifact: murmur-driver-openai
system_prompt: |
You are a deployment agent. When you reach a decision you cannot make on your own —
such as which environment to target or whether to proceed with a destructive step —
call murmur-tool-request-input with a clear, specific question for the operator.
name: my-agent
version: "0.1.0"
network:
internal_port: 52222
artifacts:
- name: murmur-driver-deepseek
version: "1.0.0"
runtime: driver
- name: murmur-tool-request-input
version: "1.0.0"
runtime: tool
capabilities:
network:
allow:
- https://api.deepseek.com
inference:
transport: http
endpoint: https://api.deepseek.com
model: deepseek-r1
api_key: ${DEEPSEEK_API_KEY}
driver:
artifact: murmur-driver-deepseek
system_prompt: |
You are a deployment agent. When you reach a decision you cannot make on your own —
such as which environment to target or whether to proceed with a destructive step —
call murmur-tool-request-input with a clear, specific question for the operator.
network.internal_port pins the worker capsule to a fixed port on every run. Without it the runtime picks an OS-assigned port at startup, which changes between runs and would invalidate the orchestrator capsule's allow list entry.
runtime: tool registers the WASM component with the capsule runtime. The model sees it as a callable tool named murmur-tool-request-input with one parameter:
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt |
string | yes | The question to present to the operator |
The system prompt controls when the model pauses. A vague instruction ("ask when unsure") produces over-cautious behavior; a concrete rule ("call the tool before any destructive step") produces predictable escalation.
Step 2 — install dependencies
With murmur.yaml in place, fetch all declared artifacts:
mur install
Different ways to install artifacts
mur install needs to know where to fetch artifacts from. You have two options:
Option A — configure a registry source in ~/.murmur/config.yaml:
registry:
default: official
sources:
- name: official
type: github
repo: <owner>/<repo>
token: "${GITHUB_TOKEN}"
Then install by artifact name and version:
mur install <artifact-name@version>
Option B — pass a full GitHub reference and skip configuration entirely:
mur install github:<username>/<repo>@<tag>
See Installing artifacts to learn more.
murmur-tool-request-input is a WASM artifact — no platform tag is required. mur install resolves the correct variant for every artifact in the manifest automatically.
Step 3 — run the capsule and send a task
Start the capsule:
mur run
murmur: url localhost:52222
session: ses_019ed2af53da75c2aefee84ee10c34af
Note the URL. Set a shell variable for convenience, replacing 52222 with the port you see:
PORT=52222
Send a task that will require a human decision:
curl -s -X POST http://localhost:$PORT \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"messageId": "msg-001",
"role": "user",
"parts": [{"text": "Deploy the latest build. Confirm the target environment before proceeding."}]
}
}
}'
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "tsk_01jw...",
"contextId": "ctx_01jw...",
"status": { "state": "submitted" }
}
}
Save the task id — you will need it to detect the pause.
Step 4 — detect when the agent is waiting
Poll tasks/get with the task ID until the state changes to input-required:
curl -s -X POST http://localhost:$PORT \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tasks/get","params":{"id":"<your_task_id>"}}'
While the agent is waiting, the response includes the question it formed:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"id": "tsk_01jw...",
"contextId": "ctx_01jw...",
"status": { "state": "input-required" },
"artifacts": [
{
"name": "prompt",
"parts": [{ "text": "Which environment should I deploy to? (staging, production)" }]
}
]
}
}
The agent's question is at result.artifacts[0].parts[0].text. Read it and decide your answer.
Step 5 — send your answer
Send a message to the same capsule URL:
curl -s -X POST http://localhost:$PORT \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "message/send",
"params": {
"message": {
"messageId": "reply-001",
"role": "user",
"parts": [{"text": "staging"}]
}
}
}'
The answer is delivered directly to the suspended tool call. The agent receives "staging" as the tool result and the loop resumes immediately:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"id": "tsk_01jw...",
"contextId": "ctx_01jw...",
"status": { "state": "working" }
}
}
Poll tasks/get again until state reaches completed or failed.
Optional — set an input timeout
To fail the task automatically if no reply arrives within a deadline, add lifecycle.input_timeout_secs to the manifest:
lifecycle:
task_acceptance: single
input_timeout_secs: 300
When the deadline passes, the task transitions to state: "failed" with message "input-timeout". Omit the field to wait indefinitely.
Summary
| Feature / setting | How it works |
|---|---|
murmur-tool-request-input |
WASM tool artifact; runtime: tool; platform-independent |
prompt parameter |
The question the model asks the operator; string, required |
| Task state while waiting | "input-required" |
| Where to read the question | result.artifacts[0].parts[0].text from tasks/get |
| How to resume the agent | Send a message to the same capsule URL |
| State after reply | "working" immediately; poll until "completed" |
lifecycle.input_timeout_secs |
Integer seconds to wait for a reply; absent = wait indefinitely |