Skip to navigation

Agent Recipes

Copy-paste snippets for creating, running and equipping agents

Short, self-contained recipes for working with agents. Every agent is model agnostic: set model to any OpenRouter-compatible identifier and the rest of the code is identical. Each snippet assumes const r = new Recursiv(), which reads RECURSIV_API_KEY from the environment.

Create an agent

Spin up a named agent backed by any LLM with a system prompt that defines its behavior.

import { Recursiv } from '@recursiv/sdk';
const r = new Recursiv();
const { data: agent } = await r.agents.create({
name: 'Research Bot',
username: 'researcher',
model: 'anthropic/claude-sonnet-4.6',
system_prompt: 'You are a thorough research assistant. Always cite sources.',
});
console.log(agent.id, agent.username);

Chat and get a full reply

Send one message and read the whole response back. Pass conversation_id on the next call to keep context.

const { data: reply } = await r.agents.chat(agent.id, {
message: 'Summarize the latest trends in vector databases.',
});
console.log(reply.content);
console.log(reply.conversation_id); // reuse this to continue the thread

Stream a reply token by token

Render output as it generates instead of waiting for the full response. The stream yields typed chunks.

for await (const chunk of r.agents.chatStream(agent.id, {
message: 'Explain how transformers work.',
})) {
if (chunk.type === 'text_delta') process.stdout.write(chunk.delta ?? '');
}

Give an agent tools

Flip an agent into tool-using mode. autonomous runs tools without asking; permission pauses for human approval before each call.

const { data: agent } = await r.agents.create({
name: 'Ops Agent',
username: 'ops_agent',
model: 'anthropic/claude-sonnet-4.6',
tool_mode: 'autonomous', // or 'permission' to gate each tool call
});

Connect hundreds of integrations

Recursiv ships hundreds of data integrations through one connection layer. Enable a connected integration (Gmail, Slack, Linear and more) for an agent and scope exactly which tools it may call.

const orgId = 'org_123';
// What is connected for this org
const { data: connections } = await r.integrations.listConnections(orgId);
const gmail = connections.find((c) => c.provider === 'gmail');
// Enable it for the agent, allowing only specific tools
await r.integrations.updateAgentIntegration(agent.id, {
user_integration_id: gmail!.id,
enabled: true,
allowed_tools: ['GMAIL_FETCH_EMAILS', 'GMAIL_SEND_EMAIL'],
});

Persist memory across runs

Store facts and decisions so an agent remembers context between sessions. Memory is searchable and scoped per project.

const PROJECT_ID = 'proj_123';
// Write what the agent learned
await r.memory.facts.add({
fact: 'Customer prefers async email over Slack for approvals.',
project_id: PROJECT_ID,
agent_id: agent.id,
tags: ['preferences'],
});
// Load relevant context before the next run
const { data: { context } } = await r.memory.context({
message: 'Draft an approval request for the customer.',
project_id: PROJECT_ID,
agent_id: agent.id,
});
await r.agents.chat(agent.id, {
message: `Context from memory:\n${context}\n\nDraft the approval request.`,
});

Run the same agent on a different model

Model choice is one field. Swap providers without touching any other logic.

await r.agents.update(agent.id, { model: 'openai/gpt-5.4' });
// next chat call runs on the new model, same prompt and tools
await r.agents.update(agent.id, { model: 'google/gemini-3.1-pro-preview' });

List and inspect conversations

Pull an agent’s conversation history to audit what it has been doing.

const { data: conversations } = await r.agents.conversations(agent.id);
for (const conv of conversations) {
console.log(conv.id, conv.last_message?.content ?? '(empty)');
}

Hand work from one agent to another

Agents can message each other directly to delegate tasks and return results.

await r.agents.sendMessage('target_agent_id', {
from_agent_id: agent.id,
type: 'delegation',
content: 'Analyze the deployment logs for proj_123 and report failures.',
project_id: 'proj_123',
});
// The receiving agent reads its inbox
const { data: messages } = await r.agents.inbox('target_agent_id', {
unread_only: true,
});