> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenAI Integration

> Build AI agents with OpenAI Functions using the StackOne TypeScript AI SDK

export const GitHubCode = ({url, lang, title, children}) => {
  const urlMatch = url?.match(/https:\/\/github\.com\/([^\/]+)\/([^\/]+)\/blob\/([^\/]+)\/(.+?)(?:#L(\d+)(?:-L(\d+))?)?$/);
  const owner = urlMatch?.[1];
  const repo = urlMatch?.[2];
  const branch = urlMatch?.[3];
  const filePath = urlMatch?.[4];
  const startLine = urlMatch?.[5];
  const endLine = urlMatch?.[6];
  const getDisplayTitle = () => {
    if (title) return title;
    if (!filePath) return 'source';
    const parts = filePath.split('/');
    if (parts.length >= 2) {
      return parts.slice(-2).join('/');
    }
    return parts[parts.length - 1];
  };
  const displayPath = filePath || 'source';
  const displayTitle = getDisplayTitle();
  const lineInfo = startLine ? endLine ? `#L${startLine}-L${endLine}` : `#L${startLine}` : '';
  const fullUrl = url + (lineInfo && !url.includes('#L') ? lineInfo : '');
  const encodedUrl = encodeURIComponent(fullUrl);
  const iframeSrc = `https://emgithub.com/iframe.html?target=${encodedUrl}&style=github&type=code&showBorder=on&showLineNumbers=on&showFileMeta=on`;
  return <div style={{
    marginTop: '1.5rem',
    marginBottom: '1.5rem',
    border: '1px solid #e5e7eb',
    borderRadius: '0.75rem',
    overflow: 'hidden',
    boxShadow: '0 1px 3px 0 rgb(0 0 0 / 0.1)'
  }}>
      <div style={{
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: '1rem 1.25rem',
    backgroundColor: '#f9fafb',
    borderBottom: '1px solid #e5e7eb'
  }}>
        <div style={{
    display: 'flex',
    alignItems: 'center',
    gap: '0.75rem'
  }}>
          <svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor" style={{
    flexShrink: 0
  }}>
            <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
          </svg>
          <span style={{
    fontWeight: 600,
    fontSize: '0.9375rem'
  }}>{displayTitle}</span>
        </div>
        {url && <a href={url} target="_blank" rel="noopener noreferrer" style={{
    fontSize: '0.875rem',
    color: '#3b82f6',
    textDecoration: 'none',
    fontWeight: 500
  }}>
            View on GitHub →
          </a>}
      </div>
      <div style={{
    padding: '0.5rem',
    minHeight: '400px',
    backgroundColor: '#ffffff'
  }}>
        {children || <iframe src={iframeSrc} style={{
    width: '100%',
    height: '420px',
    border: 'none',
    borderRadius: '0.25rem'
  }} loading="lazy" />}
      </div>
    </div>;
};

StackOne tools work with OpenAI's function calling to build AI agents that 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

```typescript theme={null}
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
 */
// Get account ID from your app's auth context or StackOne dashboard
const accountId = 'your-account-id';

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.4',
  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:

```typescript theme={null}
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:

```typescript theme={null}
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.4',
      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.4',
        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

```typescript theme={null}
// Get from user/tenant context
const accountId = req.user.stackoneAccountId;
const accountId = await getAccountForTenant(tenantId);
```

```typescript theme={null}
// 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
});
```

## Example

<GitHubCode url="https://github.com/StackOneHQ/stackone-ai-node/blob/main/examples/openai-integration.ts" lang="typescript">
  <iframe src="https://emgithub.com/iframe.html?target=https%3A%2F%2Fgithub.com%2FStackOneHQ%2Fstackone-ai-node%2Fblob%2Fmain%2Fexamples%2Fopenai-integration.ts&style=github&type=code&showBorder=on&showLineNumbers=on&showFileMeta=on" style={{ width: '100%', height: '400px', border: 'none' }} loading="lazy" />
</GitHubCode>

## Agent-Driven Search

Let the LLM discover and execute tools on its own. Instead of loading all tools upfront, pass `tool_search` + `tool_execute` and the LLM finds what it needs:

```typescript theme={null}
const toolset = new StackOneToolSet({
  search: { method: 'semantic', topK: 3 },
  accountId: 'your-account-id',
});

const tools = toolset.getTools({ accountIds: ['your-account-id'] });
const openaiTools = tools.toOpenAI();

// LLM receives only 2 tools - it searches and executes autonomously
const response = await client.chat.completions.create({
  model: 'gpt-5.4',
  messages,
  tools: openaiTools,
  tool_choice: 'auto',
});
```

See [Tool Search](/agents/typescript/tool-search#agent-driven-search) for the full agent loop example.

## Next Steps

* [Basic Usage](/agents/typescript/basic-usage) for fetching and executing tools
* [Tool Search](/agents/typescript/tool-search) for search patterns
* [Tool Filtering](/agents/typescript/tool-filtering) for security
* [Vercel AI SDK](/agents/typescript/frameworks/vercel-ai-sdk) for alternative approach
