Developer docs · Browse & search
Agents and conversations
Sessions that remember, runs that ask for something, plans you give, tools, skills and subagents an agent finds as it needs them, and tools added when you start.
Conversations
A session remembers what came before. Its turns are ordinary runs.
const session = agent.session();
await session.send('My name is Sam.');
const { text } = await session.send('What is my name?');
const later = await jwtson.sessions.get(session.id); // Pick it up again
for await (const text of (await later.start('And my job?')).textStream()) process.stdout.write(text);
await later.close();A session starts on the first message, so id is null until that's finished. It takes text, for agents whose input is text.
When a run needs something
Most runs just answer. Some ask a question or need a decision, and you can handle that in code:
const result = await workflow.run(input, {
onInput: wait => askSomeone(wait.prompt), // Return the answer, or nothing to leave it for someone else
onApproval: approval => approval.approve(),
});With no handler, run() waits until someone answers elsewhere, so pass timeoutMs if you'd rather not wait. It looks often at first and then every 2 seconds, which pollMs changes. To work through what's waiting on people:
for await (const item of jwtson.inbox.list()) {
if (item.type === 'approval') await item.reject('Over budget');
else await item.answer('Blue');
}An approval counts only for what you read: if the proposal changed since, deciding throws ConflictError.
Giving it a plan
A run plans its own steps unless you give them. Given steps, it follows them in order:
const run = await reviewer.start(contract, { plan: ['Read the contract', 'List the risks', { description: 'Suggest wording', required: false }] });
for await (const plan of run.plans()) console.log(plan.steps); // how many are doneSteps are step-1, step-2 and so on unless you give { id }. An agent the SDK creates takes a plan; one set up with allow_supplied_plan: false refuses it.
Discovering capabilities
New agents discover platform actions, authorized registered tools, skills, and their bound subagents through capabilities_search and capabilities_activate. The platform supplies these helpers and their instructions automatically. Only selected schemas and skill instructions enter the model's context. You can bind tools and skills to pin them, or let the agent find authorized ones as needed.
The agent can browse a complete inventory with an empty search query and follow next_cursor through its pages. Results distinguish available actions from public platform features that need setup. For example, file-writing metadata explains that Workspace files needs write access in Capabilities; discovery and activation never enable access themselves. Browsing does not activate tools or load their schemas.
const reviewer = await jwtson.agents.create({
name: 'Report reviewer', model: provider, instructions: 'Review the supplied report.',
});
const agent = await jwtson.agents.create({
name: 'Report monitor', model: provider,
instructions: 'Check the report until ready, sleeping between checks, then ask the reviewer.',
tools: [{ name: 'check_report', always: true }],
skills: ['Report procedure'], // { name: 'Report procedure', always: true } loads it immediately
agents: [{ role: 'reviewer', agent: reviewer, whenToUse: 'Review a completed report.' }],
capabilities: {
scope: 'authorized', // Default. Use 'bound' for only bindings and enabled platform actions.
alwaysLoaded: ['platform:sleep_until'],
maximumActive: 16, // Default optional action schemas loaded together.
},
});Tools and subagents default to discovery too; { always: true } loads their schemas from the first turn. agents[].agent accepts an Agent, family id or name, and must already be published. Only bound subagents are discoverable, and each child uses its own policy and context. alwaysLoaded accepts namespaced binding keys such as tool:check_report, skill:review, and agent:reviewer; kind:* loads that kind's bindings.
Activation checks existing permissions and loads a skill's required authorized tools. The agent can use replace: true when activating to switch its optional working set. Its selected capabilities survive compaction, sleep and worker restart. Existing published versions without this policy keep their previous behavior until updated and republished. Search/activation add tool calls; use always-loaded settings for frequently needed actions. See ADR 0045.
Adding tools and skills when you start
An agent keeps what it was published with, and a run or session turn can add more. Whoever starts it needs a grant on each.
await agent.run('Refund order 42', { tools: ['issue_refund'], skills: [{ name: 'Refunds', always: true }] });
await session.send('Now check the stock', { tools: ['stock_level'] }); // Later turns keep itA workflow does this with rules on an agent step, so no model decides:
{ id: 'answer', type: 'agent', version_id: agent.versionId, task: { ref: 'input.text' }, next: 'done',
add: { skills: [{ skill: refundsId, when: { op: 'eq', left: { ref: 'input.topic' }, right: { value: 'refund' } } }] } }Every tool and skill a step lists is checked when the run starts, whichever way its rules go.
From the @jwtson/sdk README, as the code stands.