Limits
They’re exported as constants, so you can read them instead of guessing:
import { PLUGIN_TOOL_TIMEOUT_MS, // 10_000 PLUGIN_JOB_DEFAULT_TIMEOUT_MS, // 60_000 PLUGIN_JOB_MAX_TIMEOUT_MS, // 600_000 PLUGIN_HTTP_TIMEOUT_MS, // 8_000 PLUGIN_HTTP_MAX_RESPONSE_BYTES, // 2 MiB} from "@prezzando/plugin-sdk";| Limit | Value | What happens |
|---|---|---|
| Tool run | 10 s | The call is aborted and the model is told the tool failed. The conversation carries on. |
| Job run | 60 s by default, up to 10 min with timeoutMs |
Aborted and retried; the day isn’t skipped. |
| HTTP request | 8 s | ctx.http.fetchJson rejects. An app can’t hang indefinitely on someone else’s server. |
| HTTP response | 2 MiB | Refused. A price list bigger than that has to be fetched in pieces. |
The network
Section titled “The network”ctx.http is the only way out, and it only reaches the hosts in
allowedHosts. A request to anywhere else is refused before it leaves — not
filtered afterwards, refused.
There is no way to make a raw fetch: in-process apps are reviewed, and when
they run elsewhere the host is what talks to the network on their behalf.
Storage
Section titled “Storage”ctx.storage is private to your app and to the organisation it’s working
for. ctx.shared is private to your app but common to everyone, which is where
a daily quote belongs — and where a customer’s data never does, because it
isn’t protected by the database’s row-level security precisely since, by
definition, it belongs to nobody in particular.
Both take a ttlSeconds on write. Use it: a cache with no expiry is a value
that will be wrong one day without anyone noticing.
Failure
Section titled “Failure”An app that throws doesn’t take anything down with it. A tool failure is
reported to the model, a job failure is retried, a summary that throws draws
an empty panel. What an app can’t do is stay broken quietly: repeated failures
suspend the installation, and the panel says why.