Skip to content

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.

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.

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.

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.