Skip to main content
StackOne tools integrate seamlessly with OpenAI’s function calling to build AI agents that can access business data.

Overview

  • Convert tools to OpenAI function schemas automatically
  • Execute functions with built-in handling
  • Build agents with conversational context
  • Multi-step workflows for complex tasks
import OpenAI from 'openai';
import { StackOneToolSet } from '@stackone/ai';

/**
 * Create agent with tools for a specific account.
 *
 * In production, accountId comes from:
 * - User/tenant context
 * - Authentication middleware
 * - Database lookup
 */
const accountId = getCurrentUserAccount(); // Your function

const openai = new OpenAI();
const toolset = new StackOneToolSet();

// Fetch tools dynamically for this account
const tools = await toolset.fetchTools({
  accountIds: [accountId]
});

// Convert to OpenAI format
const openAITools = tools.toOpenAI();

// Create completion with function calling
const completion = await openai.chat.completions.create({
  model: 'gpt-5',
  messages: [
    {
      role: 'system',
      content: 'You are an HR assistant with access to employee data.'
    },
    {
      role: 'user',
      content: 'How many employees do we have?'
    }
  ],
  tools: openAITools,
  tool_choice: 'auto'
});

// Execute any tool calls
const message = completion.choices[0].message;
if (message.tool_calls) {
  for (const toolCall of message.tool_calls) {
    const tool = tools.getTool(toolCall.function.name);
    if (tool) {
      const result = await tool.execute(
        JSON.parse(toolCall.function.arguments)
      );
      console.log('Result:', result.data);
    }
  }
}

Dynamic Tool Loading

Load tools based on available integrations:
import { StackOneToolSet } from '@stackone/ai';

const toolset = new StackOneToolSet();

// Load all tools for specific accounts (most common)
const tools = await toolset.fetchTools({
  accountIds: ["account-123"]
});

// Optional: Filter by operation type for security
const tools = await toolset.fetchTools({
  accountIds: ["account-123"],
  actions: ["*_list_*", "*_get_*"]  // Only list and get operations (read-only)
});

// Convert to OpenAI format
const openAITools = tools.toOpenAI();

Conversational Agents

Build multi-turn conversational agents:
import OpenAI from 'openai';

async function runConversationalAgent(accountId: string) {
  const openai = new OpenAI();
  const toolset = new StackOneToolSet();
  const tools = await toolset.fetchTools({ accountIds: [accountId] });
  const openAITools = tools.toOpenAI();

  const messages: OpenAI.Chat.ChatCompletionMessageParam[] = [
    {
      role: 'system',
      content: 'You are an HR assistant with access to employee data.'
    }
  ];

  // Multi-turn conversation loop
  while (true) {
    const userInput = await getUserInput(); // Your function
    if (userInput === 'exit') break;

    messages.push({ role: 'user', content: userInput });

    const completion = await openai.chat.completions.create({
      model: 'gpt-5',
      messages,
      tools: openAITools,
      tool_choice: 'auto'
    });

    const message = completion.choices[0].message;
    messages.push(message);

    // Execute tool calls if any
    if (message.tool_calls) {
      for (const toolCall of message.tool_calls) {
        const tool = tools.getTool(toolCall.function.name);
        if (tool) {
          const result = await tool.execute(
            JSON.parse(toolCall.function.arguments)
          );
          messages.push({
            role: 'tool',
            tool_call_id: toolCall.id,
            content: JSON.stringify(result.data)
          });
        }
      }

      // Get final response after tool execution
      const finalCompletion = await openai.chat.completions.create({
        model: 'gpt-5',
        messages,
      });

      console.log(finalCompletion.choices[0].message.content);
      messages.push(finalCompletion.choices[0].message);
    } else {
      console.log(message.content);
    }
  }
}

Best Practices

Account ID from Context

// Get from user/tenant context
const accountId = req.user.stackoneAccountId;
const accountId = await getAccountForTenant(tenantId);
// Only expose read operations (optional - for security)
const tools = await toolset.fetchTools({
  accountIds: [accountId],
  actions: ["*_list_*", "*_get_*"]  // Only list and get
});

// Or exclude dangerous operations
const tools = await toolset.fetchTools({
  accountIds: [accountId],
  actions: ["!*_delete_*"]  // Everything except deletes
});

Next Steps