Client
The supyagent() client — fetch tools, skills, and account info from Supyagent Cloud.
Client
The supyagent() factory creates a client that connects your app to Supyagent Cloud. It provides three methods: tools(), skills(), and me().
import { supyagent } from '@supyagent/sdk';
const client = supyagent({
apiKey: process.env.SUPYAGENT_API_KEY!,
baseUrl: 'https://app.supyagent.com', // optional, this is the default
});client.tools(options?)
Fetches all available integration tools and converts them to Vercel AI SDK Tool objects. Each tool maps to an API endpoint on Supyagent Cloud.
const tools = await client.tools();
// => Record<string, Tool>
// Filter to specific providers or services
const googleTools = await client.tools({ only: ['google'] });
const noSlack = await client.tools({ except: ['slack'] });
// Enable caching (recommended for production)
const tools = await client.tools({ cache: 300 }); // 5 minute TTLOptions
| Option | Type | Description |
|---|---|---|
only | string[] | Only include tools matching these providers, services, or names |
except | string[] | Exclude tools matching these providers, services, or names |
cache | boolean | number | true = 60s cache, number = custom TTL in seconds |
The returned tools are ready to pass directly to streamText() or generateText():
import { streamText } from 'ai';
const result = streamText({
model: yourModel,
messages,
tools: await client.tools({ cache: 300 }),
});Tool Metadata & connected Status
Every tool returned by the API includes a metadata object with a connected field indicating whether the user has the required integration active:
{
"metadata": {
"provider": "google",
"service": "gmail",
"permission": "gmail.send",
"method": "POST",
"path": "/api/v1/gmail/send",
"connected": true
}
}When using client.tools(), only connected tools are returned by default. To fetch all tools (connected and disconnected), use the REST API directly with ?all=true — see Tool Discovery below.
client.skills(options?)
Fetches skill documentation from Supyagent Cloud and returns a system prompt plus two tools (loadSkill and apiCall). This is the recommended approach for production — it's more token-efficient than tools() because the agent only loads documentation for skills it actually needs.
const { systemPrompt, tools } = await client.skills({ cache: 300 });
// systemPrompt: string — lists available skills for the LLM
// tools: { loadSkill: Tool, apiCall: Tool }Use it with streamText:
const { systemPrompt, tools: skillTools } = await client.skills({ cache: 300 });
const result = streamText({
model: yourModel,
system: `You are a helpful assistant.\n\n${systemPrompt}`,
messages,
tools: skillTools,
});How Skills Work
- The system prompt tells the LLM which skills are available (e.g., "Gmail", "Slack", "Calendar")
- The LLM calls
loadSkill({ name: "Gmail" })to get detailed API documentation - The LLM calls
apiCall({ method: "GET", path: "/api/v1/google/gmail/messages" })to make authenticated requests
This two-step approach means the full API docs for every provider don't need to be in the context window — only the ones the agent actually uses.
Options
| Option | Type | Description |
|---|---|---|
cache | boolean | number | true = 60s cache, number = custom TTL in seconds |
client.me(options?)
Returns account information, connected integrations, and usage stats.
const me = await client.me({ cache: 60 });Response
interface MeResponse {
email: string | null;
tier: string;
usage: {
current: number;
limit: number; // -1 = unlimited (enterprise)
};
integrations: Array<{
provider: string; // "google", "slack", etc.
status: string; // "active", "expired", etc.
}>;
dashboardUrl: string;
}client.asAccount(externalId)
Returns a ScopedClient that automatically sends the X-Account-Id header on every request. Use this when acting on behalf of a connected account (the partner/platform pattern).
const userClient = client.asAccount('user_123');
// All requests include X-Account-Id: user_123
const tools = await userClient.tools({ cache: 300 });
const skills = await userClient.skills({ cache: 300 });
const me = await userClient.me();ScopedClient
The scoped client has tools(), skills(), and me() — but not accounts or asAccount(). This prevents accidental nesting and keeps management operations on the parent client.
interface ScopedClient {
readonly accountId: string;
tools(options?: ToolFilterOptions): Promise<Record<string, Tool>>;
skills(options?: SkillsOptions): Promise<SkillsResult>;
me(options?: MeOptions): Promise<MeResponse>;
}Each scoped client gets its own cache, separate from the parent. Scoped and unscoped calls return different data, so they don't share cache entries.
See the Partner Guide for end-to-end examples.
Tool Discovery
The client includes methods for searching and filtering tools. These return raw tool descriptors (with metadata.connected and relevance scores) — useful for building dynamic UIs, tool pickers, or letting users explore available integrations.
client.searchTools(query)
Fuzzy search across tool names and descriptions. Returns results ranked by relevance score (0–1):
const { tools, total } = await client.searchTools('send email');
for (const tool of tools) {
console.log(tool.function.name, tool.score, tool.metadata.connected);
}
// gmail_send_message 0.42 true
// slack_send_message 0.3 false
// resend_send_email 0.6 falseclient.toolsByProvider(provider)
Returns all tools for a specific provider (e.g. google, slack, linear, platform):
const { tools } = await client.toolsByProvider('google');
// All Google tools (Gmail, Calendar, Drive, Sheets, etc.)client.toolsByService(service)
Returns all tools for a specific service (e.g. gmail, calendar, drive):
const { tools } = await client.toolsByService('gmail');
// gmail_list_messages, gmail_get_message, gmail_send_message, etc.Response Types
import type { ToolSearchResponse, ToolListResponse, ScoredTool } from '@supyagent/sdk';
// searchTools() returns ToolSearchResponse
interface ToolSearchResponse {
tools: ScoredTool[]; // OpenAITool + score
total: number;
}
// toolsByProvider() and toolsByService() return ToolListResponse
interface ToolListResponse {
tools: OpenAITool[];
total: number;
}All discovery methods also work on scoped clients:
const userClient = client.asAccount('user_123');
const { tools } = await userClient.searchTools('calendar');See the Cloud API Reference for the REST API endpoints and full response schema.
Caching
All three methods support caching to avoid redundant API calls:
// No cache (default) — fetches every time
await client.tools();
// 60-second cache
await client.tools({ cache: true });
// Custom TTL (5 minutes)
await client.tools({ cache: 300 });In a typical Next.js API route, you create the client once at module scope and use caching to keep tools fresh without fetching on every request:
const client = supyagent({ apiKey: process.env.SUPYAGENT_API_KEY! });
export async function POST(req: Request) {
// This hits Supyagent Cloud at most once every 5 minutes
const { systemPrompt, tools } = await client.skills({ cache: 300 });
// ...
}What's Next
- Partner Guide — Full guide for acting on behalf of connected accounts
- Built-in Tools — Bash, image viewing, and lower-level skill tools
- Persistence — Save chat history with Prisma
- Full API Route Example — See all pieces working together