Passing data to a scheduled agent run: input is data, not instructions

What the input field on a Sume Scheduled run does, its 64-property and 2 MiB limits, and why caller text cannot rewrite the saved instructions.

5 min readSume
All posts

To pass data into a Sume Scheduled run, put it in the input object of POST /v1/actions/{action_id}/runs. Sume hands it to the agent as data, not as instructions, so what the run does still comes from the instructions saved on the schedule.

That split is deliberate. Advanced: run a schedule via API states that caller-supplied text is untrusted and that you should not design an Action that lets input redirect what it does.

What are the limits on input?

input must be an object. It accepts at most 64 properties and 2097152 UTF-8 bytes (2 MiB). Anything over that, or a non-object value, returns 400 invalid_request.

The body accepts the documented properties and nothing else. Unknown top-level properties are silently dropped, not rejected, so a misspelled field name will not error; it will just have no effect. Check names against the table in the docs.

Two sizes are worth remembering when you build the caller. A flat object of a few strings is far under both limits. A transcript or a long product description can approach the byte cap, and a large JSON array flattened into many top-level keys can hit the 64-property cap long before the size cap. If you need to pass something big, send a URL or an identifier in input and let the saved instructions say where to fetch it, rather than inlining the content.

Also decide early whether the value is meant to be read by the agent or by your own code after the run. The agent reads input; your code reads the run receipt and result.

How does the agent see it?

For a Scheduled run, input is serialized into a fenced JSON block in the prompt. For an Agent Completion, the same idea is implemented differently: the input is written whole to /workspace/inputs/sume-action-input.json and the prompt carries a bounded pointer to it. In both cases it is treated as data.

So an input like the one below gives the agent a product name and campaign to work with, while a string inside it that says to ignore earlier instructions is just text in a data field.

Because input is part of the request, it is also part of the idempotency payload. Replaying an Idempotency-Key with the same body returns the original receipt with idempotency_hit: true and starts no second run. Reusing the key with a different input returns 409 idempotency_conflict. That is the behavior you want for a retry after a timeout, and it means a key should be derived from the event that caused the run, for example an order id, not generated fresh on every retry.

{
  "input": {
    "product_name": "Aurora Headphones",
    "campaign": "summer-2026"
  },
  "generation_spend_cap_usd": 1
}

How do you design the saved instructions around it?

Write the schedule's instructions to refer to the fields you expect, for example: use the product name and campaign from the input data. Keep anything that decides what the run may do, such as which outputs to make and which tools to avoid, in the instructions, not in the payload.

Then keep the blast radius small with the controls around it:

A concrete pattern: the schedule's instructions say to make a ten-second product teaser using the product name and campaign from the input data, to use only the brand assets already attached, and to stop if a field is missing. The caller then supplies only the two values. If a user types free text into the campaign field, the worst that text can do is appear as a campaign name, because it is data in a fenced block.

  • Set a per-run generation_spend_cap_usd; a caller can lower the schedule's cap for one run but never raise it.
  • Send an Idempotency-Key so a retried call does not start a second run.
  • Use on_active_run: "reject" if a dropped trigger should surface as an error in your caller.
  • Bind an output_schema so the result has a fixed shape you can validate.

What does Sume not do here?

Sume does not scan input for malicious text for you, and the docs do not claim it does. Treating it as data lowers the risk; it does not remove the need to validate what your own caller forwards. If the payload comes from end users, filter it before it reaches the run, the same way you would before putting it in a database query.

For the wider picture on limiting what an agent can be talked into, see MCP prompt injection and Sume's Safe automation page.

Sources

Related posts

More in Agents

All Agents posts

Written by Sume