Claude
Skills
Sign in
Back

openai-assistants

Included with Lifetime
$97 forever

OpenAI Assistants API v2 for stateful chatbots with Code Interpreter, File Search, RAG. Use for threads, vector stores, or encountering active run errors, indexing delays. ⚠️ Sunset August 26, 2026.

Backend & APIsscripts

What this skill does

# OpenAI Assistants API v2

**Status**: Production Ready (Deprecated H1 2026) | **Package**: [email protected]
**Last Updated**: 2025-11-21 | **v2 Sunset**: H1 2026

---

## ⚠️ Important: Deprecation Notice

**OpenAI announced that the Assistants API will be deprecated in favor of the Responses API.**

**Timeline:**
- ✅ **Dec 18, 2024**: Assistants API v1 deprecated
- ⏳ **H1 2026**: Planned sunset of Assistants API v2
- ✅ **Now**: Responses API available (recommended for new projects)

**Should you still use this skill?**
- ✅ **Yes, if**: You have existing Assistants API code (12-18 month migration window)
- ✅ **Yes, if**: You need to maintain legacy applications
- ✅ **Yes, if**: Planning migration from Assistants → Responses
- ❌ **No, if**: Starting a new project (use openai-responses skill instead)

**Migration Path:** See `references/migration-to-responses.md` for complete migration guide.

---

## Quick Start (5 Minutes)

### 1. Installation

```bash
bun add [email protected]  # preferred
# or: npm install [email protected]
```

### 2. Environment Setup

```bash
export OPENAI_API_KEY="sk-..."
```

### 3. Basic Assistant

```typescript
import OpenAI from 'openai'

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })

// 1. Create an assistant
const assistant = await openai.beta.assistants.create({
  name: "Math Tutor",
  instructions: "You are a helpful math tutor. Answer math questions clearly.",
  model: "gpt-4-1106-preview",
})

// 2. Create a thread (conversation)
const thread = await openai.beta.threads.create()

// 3. Add a message
await openai.beta.threads.messages.create(thread.id, {
  role: "user",
  content: "What is 12 * 34?",
})

// 4. Create and poll run
const run = await openai.beta.threads.runs.createAndPoll(thread.id, {
  assistant_id: assistant.id,
})

// 5. Get messages
if (run.status === 'completed') {
  const messages = await openai.beta.threads.messages.list(thread.id)
  console.log(messages.data[0].content[0].text.value)
}
```

**CRITICAL:**
- Assistants are persistent (stored server-side)
- Threads are persistent (conversation history)
- Runs execute the assistant on a thread
- Always poll or stream runs (they're async)
- Use `createAndPoll` for simplicity or streaming for real-time

---

## Core Concepts

**4 Key Objects:**

1. **Assistant** = AI agent with instructions + tools
2. **Thread** = Conversation (persists messages)
3. **Message** = Single message in thread (user or assistant)
4. **Run** = Execution of assistant on thread

**Lifecycle:**
```
Assistant (create once) + Thread (per conversation) + Message (add user input) → Run (execute) → Messages (get response)
```

**Load `references/assistants-api-v2.md`** for complete architecture, objects, workflows, and pricing details.

---

## Critical Rules

### Always Do

✅ **Poll or stream runs** - runs are async, don't assume immediate completion
✅ **Check run status** - handle `requires_action`, `failed`, `cancelled`, `expired`
✅ **Handle function calls** - submit tool outputs when `requires_action`
✅ **Store thread IDs** - reuse threads for multi-turn conversations
✅ **Set timeouts** - vector store indexing can take minutes for large files
✅ **Validate file uploads** - check supported formats and size limits
✅ **Use structured instructions** - clear, specific assistant instructions
✅ **Handle rate limits** - implement exponential backoff
✅ **Clean up unused resources** - delete old assistants/threads to save costs
✅ **Use latest API version** - Assistants API v2 (v1 deprecated Dec 2024)

### Never Do

❌ **Never skip run polling** - runs don't complete instantly
❌ **Never reuse run IDs** - create new run for each interaction
❌ **Never assume file indexing is instant** - vector stores need time
❌ **Never ignore `requires_action` status** - function calls need your response
❌ **Never hardcode assistant IDs** - use environment variables
❌ **Never create new assistant per request** - reuse assistants
❌ **Never exceed file limits** - 10,000 files per vector store, 10GB per file
❌ **Never use Code Interpreter for production** - use sandboxed execution instead
❌ **Never skip error handling** - API calls can fail
❌ **Never start new projects with Assistants API** - use Responses API instead

---

## Top 5 Errors Prevention

This skill prevents **15 documented errors**. Here are the top 5:

### Error #1: "Thread Already Has Active Run"
**Error**: `Can't create run: thread_xyz already has an active run`
**Prevention**: Check for active runs before creating new one:
```typescript
// Get runs and check status
const runs = await openai.beta.threads.runs.list(thread.id)
const activeRun = runs.data.find(r => ['in_progress', 'queued'].includes(r.status))

if (activeRun) {
  // Cancel or wait
  await openai.beta.threads.runs.cancel(thread.id, activeRun.id)
}

// Now create new run
const run = await openai.beta.threads.runs.create(thread.id, {...})
```
**See**: `references/top-errors.md` #1

### Error #2: Vector Store Indexing Timeout
**Error**: File search returns empty results immediately after upload
**Prevention**: Wait for indexing to complete:
```typescript
// Upload file
const file = await openai.files.create({
  file: fs.createReadStream('document.pdf'),
  purpose: 'assistants',
})

// Add to vector store
await openai.beta.vectorStores.files.create(vectorStore.id, {
  file_id: file.id,
})

// Wait for indexing (poll file_counts)
let vs = await openai.beta.vectorStores.retrieve(vectorStore.id)
while (vs.file_counts.in_progress > 0) {
  await new Promise(resolve => setTimeout(resolve, 1000))
  vs = await openai.beta.vectorStores.retrieve(vectorStore.id)
}
```
**See**: `references/top-errors.md` #2

### Error #3: Run Status Polling Infinite Loop
**Error**: Polling never terminates, hangs forever
**Prevention**: Add timeout and terminal status check:
```typescript
const maxAttempts = 60 // 60 seconds
let attempts = 0

while (attempts < maxAttempts) {
  const run = await openai.beta.threads.runs.retrieve(thread.id, run.id)

  if (['completed', 'failed', 'cancelled', 'expired', 'requires_action'].includes(run.status)) {
    break
  }

  await new Promise(resolve => setTimeout(resolve, 1000))
  attempts++
}

if (attempts >= maxAttempts) {
  throw new Error('Run polling timeout')
}
```
**See**: `references/top-errors.md` #3

### Error #4: Function Call Not Submitted
**Error**: Run stuck in `requires_action` status forever
**Prevention**: Submit tool outputs when required:
```typescript
const run = await openai.beta.threads.runs.createAndPoll(thread.id, {
  assistant_id: assistant.id,
})

if (run.status === 'requires_action') {
  const toolCalls = run.required_action.submit_tool_outputs.tool_calls

  const toolOutputs = toolCalls.map(call => ({
    tool_call_id: call.id,
    output: JSON.stringify(executeTool(call.function.name, call.function.arguments)),
  }))

  await openai.beta.threads.runs.submitToolOutputsAndPoll(thread.id, run.id, {
    tool_outputs: toolOutputs,
  })
}
```
**See**: `references/top-errors.md` #4

### Error #5: File Upload Format Not Supported
**Error**: `Invalid file format for Code Interpreter`
**Prevention**: Validate file format before upload:
```typescript
const supportedFormats = {
  code_interpreter: ['.c', '.cpp', '.csv', '.docx', '.html', '.java', '.json', '.md', '.pdf', '.php', '.pptx', '.py', '.rb', '.tex', '.txt', '.css', '.js', '.sh', '.ts'],
  file_search: ['.c', '.cpp', '.docx', '.html', '.java', '.json', '.md', '.pdf', '.php', '.pptx', '.py', '.rb', '.tex', '.txt', '.css', '.js', '.sh', '.ts'],
}

const fileExtension = path.extname(filePath)

if (!supportedFormats.code_interpreter.includes(fileExtension)) {
  throw new Error(`Unsupported file format: ${fileExtension}`)
}

// Now safe to upload
const file = await openai.files.create({
  file: fs.createReadStream(filePath),
  purpose: 'assistants',
})
```
**See**: `references/top-errors.md` #5

**For complete error catalog** (all 15 errors): See `references/top-errors.md`

---

## Common Use Cases

###

Related in Backend & APIs