UNPKG

@stackone/ai

Version:

Tools for agents to perform actions on your SaaS

417 lines (302 loc) 13.2 kB
# StackOne AI SDK > A unified interface for performing actions on SaaS tools through AI-friendly APIs. [![DeepWiki](https://img.shields.io/badge/DeepWiki-StackOneHQ%2Fstackone--ai--node-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/StackOneHQ/stackone-ai-node) <!-- DeepWiki badge generated by https://deepwiki.ryoppippi.com/ --> ## Toolsets StackOne provides two toolsets: - `OpenAPIToolSet`: A toolset generated from supplied OpenAPI specifications - `StackOneToolSet`: A toolset preloaded with StackOne Unified Tools (every [StackOne Unified API endpoints](https://docs.stackone.com/hris/introduction) has its tool equivalent in this toolset) These toolsets provide functionality to filter, transform, and execute tools. The toolsets can be easily used via common AI Agent libraries. Under the hood the StackOneToolSet uses the same OpenAPIParser as the OpenAPIToolSet, but provides some convenience methods for using StackOne API keys and account IDs. ## Installation ```bash # Using npm npm install @stackone/ai # Using yarn yarn add @stackone/ai # Using bun bun add @stackone/ai ``` ## Integrations The OpenAPIToolSet and StackOneToolSet make it super easy to use these APIs as tools in your AI applications. ### With Open AI library ```typescript import { OpenAI } from "openai"; import { StackOneToolSet } from "@stackone/ai"; const toolset = new StackOneToolSet(); const tools = toolset.getTools("hris_*", "<stackone-account-id>").toOpenAI(); await openai.chat.completions.create({ model: "gpt-5", messages: [ { role: "system", content: "You are a helpful HR assistant.", }, { role: "user", content: "Create a time-off request for employee id cxIQ5764hj2", }, ], tools: tools, }); ``` [View full example](examples/openai-integration.ts) ### AI SDK by Vercel ```typescript import { openai } from "@ai-sdk/openai"; import { generateText } from "ai"; import { StackOneToolSet } from "@stackone/ai"; const toolset = new StackOneToolSet(); const aiSdkTools = toolset.getTools("hris_*").toAISDK(); await generateText({ model: openai("gpt-5"), tools: aiSdkTools, maxSteps: 3, }); ``` [View full example](examples/ai-sdk-integration.ts) ## StackOneToolSet The StackOneToolSet is an extension of the OpenAPIToolSet that adds some convenience methods for using StackOne API keys and account IDs and some other features. ```typescript import { StackOneToolSet } from "@stackone/ai"; const toolset = new StackOneToolSet(); const tools = toolset.getTools("hris_*", "your-account-id"); const employeeTool = tools.getTool("hris_list_employees"); const employees = await employeeTool.execute(); ``` [View full example](examples/index.ts) ### Authentication Set the `STACKONE_API_KEY` environment variable: ```bash 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: ```typescript import { StackOneToolSet } from "@stackone/ai"; // Method 1: Set at toolset initialization const toolset = new StackOneToolSet({ accountId: "your-account-id" }); // Method 2: Set when getting tools (overrides toolset account ID) const tools = toolset.getTools("hris_*", "override-account-id"); // Method 3: Set directly on a tool instance tools.setAccountId("direct-account-id"); const currentAccountId = tools.getAccountId(); // Get the current account ID ``` [View full example](examples/account-id-usage.ts) ### File Upload The `StackOneToolSet` comes with built-in transformations for file uploads: ```typescript import { StackOneToolSet } from "@stackone/ai"; const toolset = new StackOneToolSet(); const tools = toolset.getTools("*file_upload*"); const fileUploadTool = tools.getTool("storage_file_upload"); // Execute with just the file_path parameter // The file_content, file_name, and file_format will be derived automatically const result = await fileUploadTool.execute({ file_path: "/path/to/file.pdf" }); ``` [View full example](examples/file-uploads.ts) > Note: you can build your own custom transformations using both toolset classes. See the [Parameter Transformations](#parameter-transformations) section for more information. ## OpenAPIToolSet The OpenAPIToolSet class allows you to parse OpenAPI specifications as tools from either a local file or a remote URL. ### Loading from a File ```typescript import { OpenAPIToolSet } from "@stackone/ai"; import path from "node:path"; // Create the toolset const toolset = new OpenAPIToolSet({ filePath: path.join(import.meta.dirname, "path/to/openapi-spec.json"); }); // Get all tools const allTools = toolset.getTools(); // Get filtered tools const filteredTools = toolset.getTools("user_*"); ``` ### Loading from a URL ```typescript import { OpenAPIToolSet } from "@stackone/ai"; // Create the toolset using the factory method const toolset = await OpenAPIToolSet.fromUrl({ url: "https://example.com/path/to/openapi-spec.json", }); ``` ### Authentication Options The OpenAPIToolSet supports easy usage of bot Basic and Bearer authentication: ```typescript // Basic Authentication const toolsetWithBasicAuth = new OpenAPIToolSet({ filePath: "path/to/spec.json", authentication: { type: "basic", credentials: { username: "user", password: "pass", }, }, }); // Bearer Authentication const toolsetWithBearerAuth = await OpenAPIToolSet.fromUrl({ url: "https://example.com/spec.json", authentication: { type: "bearer", credentials: { token: "your-bearer-token", }, }, }); ``` You can also directly write to the toolset headers: ```typescript const toolsetWithHeaders = new OpenAPIToolSet({ filePath: "path/to/spec.json", headers: { Authorization: "Bearer your-bearer-token", }, }); ``` [View full example](examples/openapi-toolset.ts) ## Unified Features These are some of the features which you can use with the OpenAPIToolSet and StackOneToolSet. ### Meta Tools (Beta) Meta tools enable dynamic tool discovery and execution, allowing AI agents to search for relevant tools based on natural language queries without hardcoding tool names. > ⚠️ **Beta Feature**: Meta tools are currently in beta and the API may change in future versions. #### How Meta Tools Work Meta tools provide two core capabilities: 1. **Tool Discovery** (`meta_search_tools`): Search for tools using natural language queries 2. **Tool Execution** (`meta_execute_tool`): Execute discovered tools dynamically The tool discovery uses Orama's BM25 algorithm for relevance ranking, providing high-quality search results based on tool names, descriptions, and categories. #### Basic Usage ```typescript import { StackOneToolSet } from "@stackone/ai"; const toolset = new StackOneToolSet(); const tools = toolset.getStackOneTools("*", "account-id"); // Get meta tools for dynamic discovery const metaTools = await tools.metaTools(); // Use with OpenAI const openAITools = metaTools.toOpenAI(); // Use with AI SDK const aiSdkTools = metaTools.toAISDK(); ``` #### Example: Dynamic Tool Discovery with AI SDK ```typescript import { generateText } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ model: openai("gpt-4o-mini"), tools: aiSdkTools, prompt: "Find tools for managing employees and create a time off request", maxSteps: 3, // Allow multiple tool calls }); ``` #### Direct Usage Without AI ```typescript // Step 1: Discover relevant tools const filterTool = metaTools.getTool("meta_search_tools"); const searchResult = await filterTool.execute({ query: "employee time off vacation", limit: 5, minScore: 0.3, // Minimum relevance score (0-1) }); // Step 2: Execute a discovered tool const executeTool = metaTools.getTool("meta_execute_tool"); const result = await executeTool.execute({ toolName: "hris_create_time_off", params: { employeeId: "emp_123", startDate: "2024-01-15", endDate: "2024-01-19", }, }); ``` [View full example](examples/meta-tools.ts) ### Custom Base URL ```typescript import { StackOneToolSet } from "@stackone/ai"; const toolset = new StackOneToolSet({ baseUrl: "https://api.example-dev.com" }); ``` [View full example](examples/custom-base-url.ts) ### Advanced Parameter Transformations **⚠️ EXPERIMENTAL**: For advanced use cases, you can dynamically transform tool schemas and parameters using the experimental schema override and preExecute functionality. This two-stage transformation approach allows you to: 1. **Schema Override**: Change the tool's input schema at creation time 2. **PreExecute**: Transform parameters from the override schema back to the original API format at execution time This is particularly powerful for document handling, where you can simplify complex file upload parameters: ```typescript import { StackOneToolSet } from "@stackone/ai"; import type { Experimental_SchemaOverride, Experimental_PreExecuteFunction, } from "@stackone/ai"; // 1. Schema Override: Simplify the input schema const documentSchemaOverride: Experimental_SchemaOverride = ( originalSchema ) => { // Replace complex file parameters with simple doc_id const newProperties = { ...originalSchema.properties }; delete newProperties.content; delete newProperties.name; delete newProperties.file_format; newProperties.doc_id = { type: "string", description: "Document path or identifier", }; return { ...originalSchema, properties: newProperties }; }; // 2. PreExecute: Transform the simplified parameters back to API format const documentPreExecute: Experimental_PreExecuteFunction = async (params) => { const { doc_id, ...otherParams } = params; // Read file and convert to required API format const fileContent = readFileSync(doc_id); const base64Content = fileContent.toString("base64"); const fileName = basename(doc_id); const extension = extname(doc_id).slice(1); return { ...otherParams, content: base64Content, name: fileName, file_format: { value: extension }, }; }; // Use the experimental transformation const toolset = new StackOneToolSet(); const tools = toolset.getStackOneTools("hris_*", "account_id"); const documentTool = tools.getTool("hris_upload_employee_document", { experimental_schemaOverride: documentSchemaOverride, experimental_preExecute: documentPreExecute, }); // Now you can use the simplified schema const result = await documentTool.execute({ doc_id: "/path/to/document.pdf", // Simplified input id: "employee_123", category: { value: "shared" }, }); ``` ⚠️ **Important**: This is experimental functionality and the API may change in future versions. [View full example](examples/experimental-document-handling.ts) ### 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-node"; import assert from "node:assert"; // Initialize the toolset const toolset = new StackOneToolSet(); const fileUploadTool = toolset .getTools("*file_upload*") .getTool("storage_file_upload"); // Use dryRun to see how the file path is derived into other parameters const dryRunResult = await fileUploadTool.execute( { file_path: "/path/to/file.pdf" }, { dryRun: true } ); // Verify the derived parameters assert("file_content" in dryRunResult.mappedParams); assert("file_name" in dryRunResult.mappedParams); assert("file_format" in dryRunResult.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 (or '[FormData]' for multipart form data) - `mappedParams`: The parameters after mapping and derivation - `originalParams`: The original parameters provided to the execute method