Every part of @playcode/sdk in tables. The package's types describe each option too, so your editor shows them as you type.
| Import |
Holds |
Where it runs |
@playcode/sdk |
Playcode, tool, memoryStore, memoryEventBus, verifyWebhook, the errors and every type |
Your server |
@playcode/sdk/ai |
playcode.ai on its own: createAiNamespace, tool |
Your server |
@playcode/sdk/email, @playcode/sdk/media |
sendEmail; generateImage, generateVideo |
Your server |
@playcode/sdk/client |
createAgentChat, prepareImage: the chat for any framework |
The browser |
@playcode/sdk/react |
useAgentChat. React 18 or newer is an optional peer dependency |
The browser |
@playcode/sdk/testing |
fakeModel, record, replay, fakeCard, agentStoreContract |
Your tests |
The browser entries know only your endpoint's address, never a key.
new Playcode(options) reads each option from its environment variable when you leave it out, at the moment a call needs it:
| Option |
Environment variable |
What it is |
apiKey |
PLAYCODE_SECRET_KEY |
The app's secret key, pcsk_..., for AI, email and media |
apiToken |
PLAYCODE_TOKEN |
An access token, pc_live_..., for playcode.api |
aiUrl, emailUrl, mediaUrl |
PLAYCODE_AI_URL, PLAYCODE_EMAIL_URL, PLAYCODE_MEDIA_URL |
The services' addresses. Set them only for a test environment |
apiOrigin |
PLAYCODE_API_ORIGIN |
The API's address; https://playcode.io by default |
timeoutMs |
|
How long a request waits: 10 seconds for email and video; on an AI call, 120 seconds for the answer to start. playcode.api calls have none: pass signal |
fetch |
|
The fetch every call goes through: a test double or a proxy's |
A call: generate and stream
#
| Option |
What it does |
model |
A model id from models(), or a list of ids in fallback order |
system |
The instructions |
prompt or messages |
One user message, or the conversation so far, ending with the user's message |
files |
Images and PDFs for the last user message |
schema |
A zod schema or JSON Schema: the answer comes back as a checked object |
tools |
Your functions the model may call |
maxSteps |
The most model calls: 10 with tools, 1 without |
budget |
{ credits }: stop once the calls cost this much |
maxOutputTokens |
The longest answer one model call may write |
thinking |
off, low, medium, high or max; the model's default when left out |
user |
Your own id for the end user the call serves |
cache |
Prompt-cache marks on Claude models: on with tools, off without |
brakes, context, hooks |
See Agent controls |
signal |
An AbortSignal that stops the call |
playcode.ai.agent(config) takes the options of a call except prompt, messages, files, user and signal, which belong to each run, and adds these:
| Option |
What it does |
limits |
{ user: { creditsPerDay } }, counted in the store |
store, name |
Where conversations and durable runs live, and the agent's name in it |
executor |
Who runs a durable run's work; this process by default |
durable |
{ leaseMs, heartbeatMs, maxAttempts } |
events |
The bus a durable run's events travel on; this process's memory by default |
A run takes thread, user, history, files, onEvent, signal and limits.
| Method |
What it does |
run(message, options) |
One turn; run(null, { history }) continues a saved conversation |
resume(state, decisions) |
Goes on after an approval |
start(message, options) |
A durable run: returns its id at once |
get(runId), cancel(runId), events(runId) |
Reads, stops or follows a durable run |
resumeRun(runId, decisions) |
Goes on with a durable run that paused for approval |
recover(), execute(runId) |
Picks up runs a crash left; runs a queued run by its id |
history(thread, { user }) |
A thread's messages |
handler({ user, limits }) |
The chat endpoint |
asTool({ description }) |
The agent as a tool of another agent |
| Event |
When |
text |
Answer text as it streams |
toolCall |
A complete tool call, before it runs |
toolResult |
A tool's result, as soon as it lands |
usage |
A model call's usage, and the running total |
step |
A model call and its tools are complete |
compaction |
Old tool results were cleared, and a brief written if brief |
fallback |
A model failed without a charge, and the next one takes over |
subagent |
A sub-agent finished, with its whole run |
done |
The end, with the result |
The events of a durable run also carry a status event when its status changes.
| Error |
When |
PlaycodeApiError |
Playcode, or the model's maker, said no: status, code, message in Playcode's own words, requestId, source, remainingCredits, retryAfterMs, usageId |
PlaycodeConnectionError |
No answer came (the network, TLS or a timeout), or a stream broke off mid-answer, which may be charged. cause has the original error |
PlaycodeConfigError |
The call could not be built: no key or token, no webhook secret, a file the model cannot read |
ThreadBusyError, ThreadOwnerError, RunNotPausedError |
A thread has a run in progress; a thread is another user's; a decision came after another one |
PlaycodeWebhookError |
A delivery failed its check |
PrepareImageError |
The browser could not read a photo |
The codes of a PlaycodeApiError, and what to do about each:
| Code |
Means |
Do |
402 insufficient_balance |
The workspace is out of credits |
Add credits. Never retry it in a loop |
402 budget_exceeded |
The app's monthly AI budget is spent |
The owner raises or clears it; it resets on the 1st (UTC) |
429 rate_limited |
A per-minute limit |
The SDK waits out 30 seconds or less and retries; past that, wait retryAfterMs |
429 daily_cap |
A daily ceiling on the model's maker is spent |
It resets at 00:00 UTC. A fallback model from another maker goes on |
413 request_too_large |
The request is over 32 MiB |
Shrink photos, split PDFs, send less text |
400 server_tool_not_supported |
A tool the model's maker runs itself |
Write it as one of your functions |
422 invalid_output |
The answer did not match the schema; it was paid |
Make the schema or the instructions clearer |
403 missing_scope |
The app's key lacks the service |
Ask Playcode's agent to switch on AI, or media, for the app |
401 invalid_key |
An old or wrong key |
Remove a stale PLAYCODE_SECRET_KEY line from .env.local: it hides the current key |
403 killed |
Playcode stopped this traffic on purpose |
Ask Playcode (Get help from a person); do not work around it. A model list moves on to its next model |
An error with source: "provider" is the model maker's own, passed on as it was: fix the request it names.
| What |
Default or limit |
| Model calls per run |
10 (maxSteps) |
| One tool call |
60 seconds (timeoutMs) |
| What the model reads of a result |
50,000 characters (maxResultChars) |
| Tool calls of one step at once |
4 |
| Retries of an AI call that charged nothing |
2; Playcode's rate limit only when it asks for 30 seconds or less |
| A request's wait |
10 seconds for email and video; 120 seconds for an AI answer to start |
job.wait() for a video |
15 minutes |
Retries of playcode.api |
2, with the same Idempotency-Key |
| A webhook delivery's age |
300 seconds |
| A durable run |
A lease of 20 seconds, renewed every 5 seconds; it fails after 3 attempts |
| Compaction |
Starts at 112,000 tokens of the 160,000-token ceiling; at most 2 folds a run |
| One AI request |
32 MiB, files included |
| One chat message |
25 MB, 10 files, 200,000 characters of text |
| An id: a user, an agent, a thread, a tool |
1 to 64 characters |
prepareImage |
At most 2,000 px on the long edge, JPEG |
| Node.js |
22 or newer |