https://github.com/stackonehq/stackone-ai-node
integrations for ai agents
https://github.com/stackonehq/stackone-ai-node
Last synced: 3 months ago
JSON representation
integrations for ai agents
- Host: GitHub
- URL: https://github.com/stackonehq/stackone-ai-node
- Owner: StackOneHQ
- License: apache-2.0
- Created: 2025-02-25T20:23:40.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2026-03-19T22:53:55.000Z (4 months ago)
- Last Synced: 2026-03-20T04:50:58.273Z (4 months ago)
- Language: TypeScript
- Homepage:
- Size: 2.05 MB
- Stars: 27
- Watchers: 1
- Forks: 3
- Open Issues: 15
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
- Agents: AGENTS.md
Awesome Lists containing this project
README
# StackOne AI SDK
> A unified interface for performing actions on SaaS tools through AI-friendly APIs.
[](https://npmjs.com/package/@stackone/ai) [](https://deepwiki.com/StackOneHQ/stackone-ai-node) [](https://stackonehq.github.io/stackone-ai-node)
## 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
```bash
# 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
```typescript
import { StackOneToolSet } from '@stackone/ai';
const toolset = new StackOneToolSet({
accountId: 'your-account-id',
});
const tools = await toolset.fetchTools();
const employeeTool = tools.getTool('bamboohr_list_employees');
const employees = await employeeTool.execute();
```
### Authentication
Set the `STACKONE_API_KEY` environment variable:
```bash
export STACKONE_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:
```typescript
import { StackOneToolSet } from '@stackone/ai';
// Single account - simplest approach
const toolset = new StackOneToolSet({ accountId: 'your-bamboohr-account' });
const tools = await toolset.fetchTools();
// Multiple accounts - returns tools from both integrations
const multiAccountToolset = new StackOneToolSet();
const allTools = await multiAccountToolset.fetchTools({
accountIds: ['bamboohr-account-123', 'workday-account-456'],
});
// Filter to specific integration when using multiple accounts
const bamboohrOnly = await multiAccountToolset.fetchTools({
accountIds: ['bamboohr-account-123', 'workday-account-456'],
actions: ['bamboohr_*'], // Only BambooHR tools
});
// Set directly on a tool instance
tools.setAccountId('direct-account-id');
const currentAccountId = 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
```bash
npm install @stackone/ai openai # or: yarn/pnpm/bun add
```
```typescript
import { OpenAI } from 'openai';
import { StackOneToolSet } from '@stackone/ai';
const toolset = new StackOneToolSet({
accountId: 'your-account-id',
});
const tools = await toolset.fetchTools();
await openai.chat.completions.create({
model: 'gpt-5.1',
messages: [
{
role: 'system',
content: 'You are a helpful HR assistant using BambooHR.',
},
{
role: 'user',
content: 'Create a time-off request for employee id cxIQ5764hj2',
},
],
tools: tools.toOpenAI(),
});
```
[View full example](examples/openai-integration.ts)
With OpenAI Responses API
```bash
npm install @stackone/ai openai # or: yarn/pnpm/bun add
```
```typescript
import OpenAI from 'openai';
import { StackOneToolSet } from '@stackone/ai';
const toolset = new StackOneToolSet({
accountId: 'your-account-id',
});
const tools = await toolset.fetchTools();
const openai = new OpenAI();
await openai.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](examples/openai-responses-integration.ts)
With Anthropic Claude
```bash
npm install @stackone/ai @anthropic-ai/sdk # or: yarn/pnpm/bun add
```
```typescript
import Anthropic from '@anthropic-ai/sdk';
import { StackOneToolSet } from '@stackone/ai';
const toolset = new StackOneToolSet({
accountId: 'your-account-id',
});
const tools = await toolset.fetchTools();
const anthropic = new Anthropic();
await anthropic.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](examples/anthropic-integration.ts)
With AI SDK by Vercel
```bash
npm install @stackone/ai ai @ai-sdk/openai # or: yarn/pnpm/bun add
```
```typescript
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';
import { StackOneToolSet } from '@stackone/ai';
const toolset = new StackOneToolSet({
accountId: 'your-account-id',
});
const tools = await toolset.fetchTools();
await generateText({
model: openai('gpt-5.1'),
tools: await tools.toAISDK(),
maxSteps: 3,
});
```
[View full example](examples/ai-sdk-integration.ts)
With TanStack AI
```bash
npm install @stackone/ai @tanstack/ai @tanstack/ai-openai zod # or: yarn/pnpm/bun add
```
```typescript
import { chat } from '@tanstack/ai';
import { openai } from '@tanstack/ai-openai';
import { z } from 'zod';
import { StackOneToolSet } from '@stackone/ai';
const toolset = new StackOneToolSet({
accountId: 'your-account-id',
});
const tools = await toolset.fetchTools();
const employeeTool = tools.getTool('bamboohr_get_employee');
// TanStack AI requires Zod schemas for tool input validation
const getEmployeeTool = {
name: employeeTool.name,
description: employeeTool.description,
inputSchema: z.object({
id: z.string().describe('The employee ID'),
}),
execute: async (args: { id: string }) => {
return employeeTool.execute(args);
},
};
const adapter = openai();
const stream = chat({
adapter,
model: 'gpt-5.1',
messages: [{ role: 'user', content: 'Get employee with id: abc123' }],
tools: [getEmployeeTool],
});
for await (const chunk of stream) {
// Process streaming chunks
}
```
[View full example](examples/tanstack-ai-integration.ts)
With Claude Agent SDK
```bash
npm install @stackone/ai @anthropic-ai/claude-agent-sdk zod # or: yarn/pnpm/bun add
```
```typescript
import { query } from '@anthropic-ai/claude-agent-sdk';
import { StackOneToolSet } from '@stackone/ai';
const toolset = new StackOneToolSet({
accountId: 'your-account-id',
});
// Fetch tools and convert to Claude Agent SDK format
const tools = await toolset.fetchTools();
const mcpServer = await tools.toClaudeAgentSdk();
// Use with Claude Agent SDK query
const result = query({
prompt: 'Get the employee with id: abc123',
options: {
model: 'claude-sonnet-4-5-20250929',
mcpServers: { 'stackone-tools': mcpServer },
tools: [], // Disable built-in tools
maxTurns: 3,
},
});
for await (const message of result) {
// Process streaming messages
}
```
[View full example](examples/claude-agent-sdk-integration.ts)
## Features
### Filtering Tools with fetchTools()
You can filter tools by account IDs, providers, and action patterns:
```typescript
// Filter by account IDs
toolset.setAccounts(['account-123', 'account-456']);
const tools = await toolset.fetchTools();
// OR
const tools = await toolset.fetchTools({
accountIds: ['account-123', 'account-456'],
});
// Filter by providers
const tools = await toolset.fetchTools({ providers: ['hibob', 'bamboohr'] });
// Filter by actions with exact match
const tools = await toolset.fetchTools({
actions: ['hibob_list_employees', 'hibob_create_employees'],
});
// Filter by actions with glob patterns
const tools = await toolset.fetchTools({ actions: ['*_list_employees'] });
// Combine multiple filters
const tools = await toolset.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)
[View full example](examples/fetch-tools.ts)
### Search Tool
Search for tools using natural language queries. Works with both semantic (cloud) and local BM25+TF-IDF search.
#### Basic Usage
```typescript
import { StackOneToolSet } from '@stackone/ai';
// Get a callable search tool
const toolset = new StackOneToolSet({ accountId: 'your-account-id' });
const searchTool = toolset.getSearchTool();
// Search for relevant tools — returns a Tools collection
const tools = await searchTool.search('manage employees', { topK: 5 });
// Execute a discovered tool directly
const listTool = tools.getTool('bamboohr_list_employees');
const result = await listTool.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 `bamboohr_create_employee`.
```typescript
import { StackOneToolSet } from '@stackone/ai';
const toolset = new StackOneToolSet({ accountId: 'your-account-id' });
// Search by intent — returns Tools collection ready for any framework
const tools = await toolset.searchTools('manage employee records', { topK: 5 });
const openAITools = tools.toOpenAI();
// Lightweight: inspect results without fetching full tool definitions
const results = await toolset.searchActionNames('time off requests', { topK: 5 });
```
#### Search Modes
Control which search backend `searchTools()` uses via the `search` option:
```typescript
// 'auto' (default) — tries semantic search first, falls back to local
const tools = await toolset.searchTools('manage employees', { search: 'auto' });
// 'semantic' — semantic API only, throws if unavailable
const tools = await toolset.searchTools('manage employees', { search: 'semantic' });
// 'local' — local BM25+TF-IDF only, no semantic API call
const tools = await toolset.searchTools('manage employees', { search: 'local' });
```
Results are automatically scoped to connectors in your linked accounts. See [Search Tools Example](examples/search-tools.ts) for `SearchTool` (`getSearchTool`) integration, AI SDK, and agent loop patterns.
### Custom Base URL
```typescript
import { StackOneToolSet } from '@stackone/ai';
const toolset = new StackOneToolSet({ baseUrl: 'https://api.example-dev.com' });
```
### Testing with dryRun
You can use the `dryRun` option to return the api arguments from a tool call without making the actual api call:
```typescript
import { StackOneToolSet } from '@stackone/ai';
// Initialize the toolset
const toolset = new StackOneToolSet();
const tools = await toolset.fetchTools();
const employeeTool = tools.getTool('bamboohr_list_employees');
// Use dryRun to see the request details
const dryRunResult = await employeeTool.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
### 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`:
```typescript
import { StackOneToolSet } from '@stackone/ai';
const toolset = new StackOneToolSet();
const tools = await toolset.fetchTools();
// The feedback tool is automatically included
const feedbackTool = tools.getTool('tool_feedback');
// Use with AI agents - they will ask for user consent first
const openAITools = tools.toOpenAI();
// or
const aiSdkTools = await tools.toAISDK();
```
#### Manual Usage
You can also use the feedback tool directly:
```typescript
// Get the feedback tool
const feedbackTool = tools.getTool('tool_feedback');
// Submit feedback (after getting user consent)
const result = await feedbackTool.execute({
feedback: 'The tools worked great! Very easy to use.',
account_id: 'acc_123456',
tool_names: ['bamboohr_list_employees', 'bamboohr_create_time_off'],
});
```
#### 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:
```typescript
// Single account ID (string)
await feedbackTool.execute({
feedback: 'The tools worked great! Very easy to use.',
account_id: 'acc_123456',
tool_names: ['bamboohr_list_employees', 'bamboohr_create_time_off'],
});
// Multiple account IDs (array)
await feedbackTool.execute({
feedback: 'The tools worked great! Very easy to use.',
account_id: ['acc_123456', 'acc_789012'],
tool_names: ['bamboohr_list_employees', 'bamboohr_create_time_off'],
});
```
**Response Format**: When using multiple account IDs, the tool returns a summary of all submissions:
```typescript
{
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.
## Development Environment
### Using Nix Flake
This project includes a Nix flake for reproducible development environments. All development tools are defined in [flake.nix](./flake.nix) and provided via Nix.
#### Installing Nix
```bash
# 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
```bash
# 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.