Skip to content

Latest commit

History

278 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

StackOne AI SDK

A unified interface for performing actions on SaaS tools through AI-friendly APIs.

npm versionDeepWikiCoverage

StackOneToolSet

The StackOne AI SDK provides the StackOneToolSet class, which fetches tools dynamically from StackOne's MCP (Model Context Protocol) endpoint. This ensures you always have access to the latest tool definitions.

Installation

# Using npm
npm install @stackone/ai zod
# Using yarn
yarn add @stackone/ai zod
# Using pnpm
pnpm add @stackone/ai zod
# Using bun
bun add @stackone/ai zod

Note:zod is a peer dependency required for AI SDK integrations and internal schema validation. Version >=3.25.0 <5 is supported.

Usage

import{StackOneToolSet}from'@stackone/ai';// Reads STACKONE_API_KEY and STACKONE_ACCOUNT_ID from environmentconsttoolset=newStackOneToolSet();consttools=awaittoolset.fetchTools();constemployeeTool=tools.getTool('workday_list_workers');constemployees=awaitemployeeTool.execute();

Authentication

Set the STACKONE_API_KEY environment variable:

export STACKONE_API_KEY=<your-api-key>

or load from a .env file using your preferred environment variable library.

Account IDs

StackOne uses account IDs to identify different integrations. You can specify the account ID at different levels:

import{StackOneToolSet}from'@stackone/ai';// Simplest: set STACKONE_ACCOUNT_ID environment variableconsttoolset=newStackOneToolSet();consttools=awaittoolset.fetchTools();// Explicit single accountconstexplicitToolset=newStackOneToolSet({accountId: 'your-workday-account'});constexplicitTools=awaitexplicitToolset.fetchTools();// Multiple accounts - returns tools from both integrationsconstmultiAccountToolset=newStackOneToolSet();constallTools=awaitmultiAccountToolset.fetchTools({accountIds: ['workday-account-123','hibob-account-456'],});// Filter to specific integration when using multiple accountsconstworkdayOnly=awaitmultiAccountToolset.fetchTools({accountIds: ['workday-account-123','hibob-account-456'],actions: ['workday_*'],// Only Workday tools});// Set directly on a tool instancetools.setAccountId('direct-account-id');constcurrentAccountId=tools.getAccountId();// Get the current account ID

Integrations

The StackOneToolSet makes it super easy to use StackOne APIs as tools in your AI applications.

With OpenAI Chat Completions API
npm install @stackone/ai openai # or: yarn/pnpm/bun add
import{OpenAI}from'openai';import{StackOneToolSet}from'@stackone/ai';// Reads STACKONE_API_KEY and STACKONE_ACCOUNT_ID from environmentconsttoolset=newStackOneToolSet();consttools=awaittoolset.fetchTools();awaitopenai.chat.completions.create({model: 'gpt-5.1',messages: [{role: 'system',content: 'You are a helpful HR assistant using Workday.',},{role: 'user',content: 'Create a time-off request for employee id cxIQ5764hj2',},],tools: tools.toOpenAI(),});

View full example

With OpenAI Responses API
npm install @stackone/ai openai # or: yarn/pnpm/bun add
importOpenAIfrom'openai';import{StackOneToolSet}from'@stackone/ai';// Reads STACKONE_API_KEY and STACKONE_ACCOUNT_ID from environmentconsttoolset=newStackOneToolSet();consttools=awaittoolset.fetchTools();constopenai=newOpenAI();awaitopenai.responses.create({model: 'gpt-5.1',instructions: 'You are a helpful HR assistant.',input: 'What is the phone number for employee c28xIQ?',tools: tools.toOpenAIResponses(),});

View full example

With Anthropic Claude
npm install @stackone/ai @anthropic-ai/sdk # or: yarn/pnpm/bun add
importAnthropicfrom'@anthropic-ai/sdk';import{StackOneToolSet}from'@stackone/ai';// Reads STACKONE_API_KEY and STACKONE_ACCOUNT_ID from environmentconsttoolset=newStackOneToolSet();consttools=awaittoolset.fetchTools();constanthropic=newAnthropic();awaitanthropic.messages.create({model: 'claude-haiku-4-5-20241022',max_tokens: 1024,system: 'You are a helpful HR assistant.',messages: [{role: 'user',content: 'What is the phone number for employee c28xIQ?',},],tools: tools.toAnthropic(),});

View full example

With AI SDK by Vercel
npm install @stackone/ai ai @ai-sdk/openai # or: yarn/pnpm/bun add

Supports AI SDK v5–v7 (ai>=5.0.108 <8.0.0). AI SDK v7 requires Node.js 22+.

import{openai}from'@ai-sdk/openai';import{generateText,stepCountIs}from'ai';import{StackOneToolSet}from'@stackone/ai';// Reads STACKONE_API_KEY and STACKONE_ACCOUNT_ID from environmentconsttoolset=newStackOneToolSet();consttools=awaittoolset.fetchTools();awaitgenerateText({model: openai('gpt-5.1'),tools: awaittools.toAISDK(),stopWhen: stepCountIs(3),});

View full example

With Claude Agent SDK
npm install @stackone/ai @anthropic-ai/claude-agent-sdk zod # or: yarn/pnpm/bun add
import{query}from'@anthropic-ai/claude-agent-sdk';import{StackOneToolSet}from'@stackone/ai';// Reads STACKONE_API_KEY and STACKONE_ACCOUNT_ID from environmentconsttoolset=newStackOneToolSet();// Fetch tools and convert to Claude Agent SDK formatconsttools=awaittoolset.fetchTools();constmcpServer=awaittools.toClaudeAgentSdk();// Use with Claude Agent SDK queryconstresult=query({prompt: 'Get the employee with id: abc123',options: {model: 'claude-sonnet-4-5-20250929',mcpServers: {'stackone-tools': mcpServer},tools: [],// Disable built-in toolsmaxTurns: 3,},});forawait(constmessageofresult){// Process streaming messages}

View full example

Features

Filtering Tools with fetchTools()

You can filter tools by account IDs, providers, and action patterns:

// Filter by account IDstoolset.setAccounts(['account-123','account-456']);consttools=awaittoolset.fetchTools();// ORconsttools=awaittoolset.fetchTools({accountIds: ['account-123','account-456'],});// Filter by providersconsttools=awaittoolset.fetchTools({providers: ['hibob','workday']});// Filter by actions with exact matchconsttools=awaittoolset.fetchTools({actions: ['hibob_list_employees','hibob_create_employees'],});// Filter by actions with glob patternsconsttools=awaittoolset.fetchTools({actions: ['*_list_employees']});// Combine multiple filtersconsttools=awaittoolset.fetchTools({accountIds: ['account-123'],providers: ['hibob'],actions: ['*_list_*'],});

This is especially useful when you want to:

  • Limit tools to specific linked accounts
  • Focus on specific HR/CRM/ATS providers
  • Get only certain types of operations (e.g., all "list" operations)

Search Tool

Search for tools using natural language queries. Works with both semantic (cloud) and local BM25+TF-IDF search.

Basic Usage

import{StackOneToolSet}from'@stackone/ai';// Reads STACKONE_API_KEY and STACKONE_ACCOUNT_ID from environmentconsttoolset=newStackOneToolSet();constsearchTool=toolset.getSearchTool();// Search for relevant tools — returns a Tools collectionconsttools=awaitsearchTool.search('manage employees',{topK: 5});// Execute a discovered tool directlyconstlistTool=tools.getTool('workday_list_workers');constresult=awaitlistTool.execute({query: {limit: 10}});

Semantic Search

Discover tools using natural language instead of exact names. Queries like "onboard new hire" resolve to the right actions even when the tool is called workday_create_employee.

import{StackOneToolSet}from'@stackone/ai';// Reads STACKONE_API_KEY and STACKONE_ACCOUNT_ID from environmentconsttoolset=newStackOneToolSet();// Search by intent — returns Tools collection ready for any frameworkconsttools=awaittoolset.searchTools('manage employee records',{topK: 5});constopenAITools=tools.toOpenAI();// Lightweight: inspect results without fetching full tool definitionsconstresults=awaittoolset.searchActionNames('time off requests',{topK: 5});

Search Modes

Control which search backend searchTools() uses via the search option:

// 'auto' (default) — tries semantic search first, falls back to localconsttools=awaittoolset.searchTools('manage employees',{search: 'auto'});// 'semantic' — semantic API only, throws if unavailableconsttools=awaittoolset.searchTools('manage employees',{search: 'semantic'});// 'local' — local BM25+TF-IDF only, no semantic API callconsttools=awaittoolset.searchTools('manage employees',{search: 'local'});

Results are automatically scoped to connectors in your linked accounts. See Search Tools Example for SearchTool (getSearchTool) integration, AI SDK, and agent loop patterns.

Custom Base URL

import{StackOneToolSet}from'@stackone/ai';consttoolset=newStackOneToolSet({baseUrl: 'https://api.example-dev.com'});

Defender

The SDK includes built-in prompt injection protection via StackOne Defender. It runs on every tool call result before the content reaches your LLM, detecting and sanitizing injection attacks hidden in external data (emails, documents, CRM notes, etc.).

By default, the SDK defers to your project's dashboard defender setting. Pass an explicit defender config to override the project setting per toolset.

defender optionEffective behavior
omitted (default)Project dashboard setting controls — SDK adds nothing
{ useProjectSettings: true }Same as omitting; explicit, self-documenting form
{ enabled, blockHighRisk, ... }SDK-level config wins, overrides the project setting
nullDefender forcibly disabled, overrides the project setting

When passing an explicit object, missing fields fall back to DEFAULT_DEFENDER_CONFIG (exported from @stackone/ai): enabled: true, blockHighRisk: false, both tiers on.

Configuration modes

import{StackOneToolSet,DEFAULT_DEFENDER_CONFIG}from'@stackone/ai';// Default — defer to project dashboard settingconsttoolset=newStackOneToolSet({apiKey: '...'});// Same as default, explicit formconsttoolset=newStackOneToolSet({apiKey: '...',defender: {useProjectSettings: true},});// Explicitly disabled — overrides any project settingconsttoolset=newStackOneToolSet({apiKey: '...',defender: null,});// Opt in with safe defaults, but block on HIGH/CRITICAL — overrides project settingconsttoolset=newStackOneToolSet({apiKey: '...',defender: { ...DEFAULT_DEFENDER_CONFIG,blockHighRisk: true},});// Fully explicit SDK-level configconsttoolset=newStackOneToolSet({apiKey: '...',defender: {enabled: true,blockHighRisk: true,// throw on HIGH or CRITICAL riskuseTier1Classification: true,// pattern-based (regex, role markers)useTier2Classification: true,// ML-based (ONNX model)},});

Inspecting and observing the resolved mode

Use the defenderMode getter to check how a toolset will behave at runtime:

consttoolset=newStackOneToolSet({apiKey: '...',defender: null});toolset.defenderMode;// 'disabled' | 'explicit' | 'project'

When the SDK overrides the project dashboard (mode disabled or explicit), it emits a yellow console.warn line once per process per distinct override shape so the override is visible at runtime without spamming logs. Pass NO_COLOR=1 to suppress color, or FORCE_COLOR=1 to force it when piping output. The project mode is silent.

Risk levels

Defender assigns a risk level to each scanned result:

LevelMeaning
lowNo threats detected
mediumSuspicious patterns detected, role markers stripped
highInjection patterns found, content redacted
criticalSevere injection attempt with multiple indicators

When blockHighRisk: false (default), high and critical results are annotated and returned — the LLM sees the sanitized content. When blockHighRisk: true, those results are blocked entirely.

View full example

For more detail on how the detection pipeline works, see the @stackone/defender package.

Testing with dryRun

You can use the dryRun option to return the api arguments from a tool call without making the actual api call:

import{StackOneToolSet}from'@stackone/ai';// Initialize the toolsetconsttoolset=newStackOneToolSet();consttools=awaittoolset.fetchTools();constemployeeTool=tools.getTool('workday_list_workers');// Use dryRun to see the request detailsconstdryRunResult=awaitemployeeTool.execute({query: {limit: 5}},{dryRun: true});console.log(dryRunResult);// {// url: "https://api.stackone.com/actions/rpc",// method: "POST",// headers: { ... },// body: "...",// mappedParams: { ... }// }

The dryRun option returns an object containing:

  • url: The full URL with query parameters
  • method: The HTTP method
  • headers: The request headers
  • body: The request body
  • mappedParams: The parameters after mapping and derivation

File Downloads

Actions that download a file (for example googledrive_unified_download_file, documents_download_file, or any *_unified_download_file) return raw bytes plus metadata instead of parsed JSON. The SDK decides from the response Content-Type: JSON media types (application/json and +json suffixes) are parsed as usual, and anything else is treated as a file download.

Use the exported isBinaryDownloadResult type guard to narrow the result — no casts needed:

import{writeFileSync}from'node:fs';import{isBinaryDownloadResult,StackOneToolSet}from'@stackone/ai';consttoolset=newStackOneToolSet();consttools=awaittoolset.fetchTools({actions: ['googledrive_*']});constdownload=tools.getTool('googledrive_unified_download_file');constresult=awaitdownload.execute({id: 'file-id'});if(isBinaryDownloadResult(result)){// result.content is a Buffer; result.fileName is string | nullwriteFileSync(result.fileName??'download.bin',result.content);}

The download result (typed BinaryDownloadResult) contains:

  • content: Buffer — the raw file bytes (not a JsonValue; see note)
  • contentType: string — the file's MIME type (e.g. application/pdf), or application/octet-stream
  • statusCode: number — HTTP status of the download response
  • headers: Record<string, string> — the response headers
  • fileName: string | null — filename from Content-Disposition (RFC 5987 filename* aware), or null

Note:content is a raw Buffer, not a JsonValue. JSON.stringify turns it into a { type: 'Buffer', data: [...] } byte array (not the file, and potentially huge), so if you forward tool results to an LLM — or anything that re-serializes to JSON — strip or transform the content key first (for example, base64-encode it on the LLM-facing path).

Feedback Collection Tool

The StackOne AI SDK includes a built-in feedback collection tool (tool_feedback) that allows users to provide feedback on their experience with StackOne tools. This tool is automatically included when using fetchTools() and helps improve the SDK based on user input.

How It Works

The feedback tool:

  • Requires explicit user consent before submitting feedback
  • Collects user feedback about their experience with StackOne tools
  • Tracks tool usage by recording which tools were used
  • Submits to StackOne via the /ai/tool-feedback endpoint
  • Uses the same API key as other SDK operations for authentication

Usage

The feedback tool is automatically available when using StackOneToolSet:

import{StackOneToolSet}from'@stackone/ai';consttoolset=newStackOneToolSet();consttools=awaittoolset.fetchTools();// The feedback tool is automatically includedconstfeedbackTool=tools.getTool('tool_feedback');// Use with AI agents - they will ask for user consent firstconstopenAITools=tools.toOpenAI();// orconstaiSdkTools=awaittools.toAISDK();

Manual Usage

You can also use the feedback tool directly:

// Get the feedback toolconstfeedbackTool=tools.getTool('tool_feedback');// Submit feedback (after getting user consent)constresult=awaitfeedbackTool.execute({feedback: 'The tools worked great! Very easy to use.',account_id: 'acc_123456',tool_names: ['workday_list_workers','workday_create_time_off_request'],});

Multiple Account Support

The feedback tool supports both single and multiple account IDs. When you provide an array of account IDs, the feedback will be sent to each account individually:

// Single account ID (string)awaitfeedbackTool.execute({feedback: 'The tools worked great! Very easy to use.',account_id: 'acc_123456',tool_names: ['workday_list_workers','workday_create_time_off_request'],});// Multiple account IDs (array)awaitfeedbackTool.execute({feedback: 'The tools worked great! Very easy to use.',account_id: ['acc_123456','acc_789012'],tool_names: ['workday_list_workers','workday_create_time_off_request'],});

Response Format: When using multiple account IDs, the tool returns a summary of all submissions:

{message: "Feedback sent to 2 account(s)",total_accounts: 2,successful: 2,failed: 0,results: [{account_id: "acc_123456",status: "success",result: {message: "Feedback successfully stored", ... }},{account_id: "acc_789012",status: "success",result: {message: "Feedback successfully stored", ... }}]}

AI Agent Integration

When AI agents use this tool, they will:

  1. Ask for user consent: "Are you ok with sending feedback to StackOne?"
  2. Collect feedback: Get the user's verbatim feedback
  3. Track tool usage: Record which tools were used in the session
  4. Submit to all accounts: Send the same feedback to each account ID provided
  5. Report results: Show which accounts received the feedback successfully

The tool description includes clear instructions for AI agents to always ask for explicit user consent before submitting feedback.

Examples

Running Examples

# 1. Set up credentials
cp .env.example .env
# Edit .env with your API keys# 2. Install dependencies
pnpm install
# 3. Run any example
pnpm run:example examples/openai-integration.ts

See the examples/ directory for the full list.

Development Environment

Using Nix Flake

This project includes a Nix flake for reproducible development environments. All development tools are defined in flake.nix and provided via Nix.

Installing Nix

# Install Nix with flakes enabled (if not already installed)
curl --proto '=https' --tlsv1.2 -sSf -L https://artifacts.nixos.org/experimental-installer | \
sh -s -- install
# If flakes are not enabled, enable them with:
mkdir -p ~/.config/nix &&echo"experimental-features = nix-command flakes">>~/.config/nix/nix.conf

Activating the Development Environment

# Automatic activation with direnv (recommended)
direnv allow
# Or manual activation
nix develop

The flake provides all necessary development dependencies including Node.js, pnpm, and other build tools.

About

integrations for ai agents

Resources

Stars

31 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages