AI Package
An AI integration package providing unified access to multiple AI providers including Anthropic (Claude), OpenAI, Ollama, and AWS Bedrock.
Installation
bun add @stacksjs/ai
Basic Usage
import { anthropic, openai, ollama } from '@stacksjs/ai'
const response = await anthropic.chat({
messages: [{ role: 'user', content: 'Hello, Claude!' }]
})
const gptResponse = await openai.chat({
messages: [{ role: 'user', content: 'Hello, GPT!' }]
})
const localResponse = await ollama.chat({
model: 'llama2',
messages: [{ role: 'user', content: 'Hello, Llama!' }]
})
Configuration
Configure AI providers in config/ai.ts:
export default {
default: 'anthropic',
anthropic: {
apiKey: process.env.ANTHROPIC_API_KEY,
model: 'claude-3-opus-20240229',
maxTokens: 4096,
},
openai: {
apiKey: process.env.OPENAI_API_KEY,
model: 'gpt-4-turbo-preview',
maxTokens: 4096,
organization: process.env.OPENAI_ORG_ID,
},
ollama: {
host: 'http://localhost:11434',
model: 'llama2',
},
bedrock: {
region: process.env.AWS_DEFAULT_REGION || 'us-east-1',
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
model: 'anthropic.claude-3-sonnet-20240229-v1:0',
},
}
Anthropic (Claude)
Basic Chat
import { anthropic } from '@stacksjs/ai'
const response = await anthropic.chat({
model: 'claude-3-opus-20240229',
messages: [
{ role: 'user', content: 'Explain quantum computing in simple terms.' }
],
maxTokens: 1024,
})
console.log(response.content)
Streaming Responses
import { anthropic } from '@stacksjs/ai'
const stream = await anthropic.stream({
model: 'claude-3-sonnet-20240229',
messages: [
{ role: 'user', content: 'Write a short story about a robot.' }
],
})
for await (const chunk of stream) {
process.stdout.write(chunk.content || '')
}
System Prompts
import { anthropic } from '@stacksjs/ai'
const response = await anthropic.chat({
model: 'claude-3-opus-20240229',
system: 'You are a helpful coding assistant. Provide concise, accurate answers.',
messages: [
{ role: 'user', content: 'How do I sort an array in TypeScript?' }
],
})
Multi-turn Conversations
import { anthropic } from '@stacksjs/ai'
const conversation = [
{ role: 'user', content: 'What is the capital of France?' },
{ role: 'assistant', content: 'The capital of France is Paris.' },
{ role: 'user', content: 'What is its population?' }
]
const response = await anthropic.chat({
messages: conversation,
})
Vision (Image Analysis)
import { anthropic } from '@stacksjs/ai'
import { readFile } from 'node:fs/promises'
const imageData = await readFile('image.png')
const base64Image = imageData.toString('base64')
const response = await anthropic.chat({
model: 'claude-3-opus-20240229',
messages: [
{
role: 'user',
content: [
{
type: 'image',
source: {
type: 'base64',
media_type: 'image/png',
data: base64Image,
},
},
{
type: 'text',
text: 'What do you see in this image?',
},
],
},
],
})
OpenAI
Basic Chat
import { openai } from '@stacksjs/ai'
const response = await openai.chat({
model: 'gpt-4-turbo-preview',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'What is the meaning of life?' }
],
})
console.log(response.choices[0].message.content)
Streaming
import { openai } from '@stacksjs/ai'
const stream = await openai.stream({
model: 'gpt-4-turbo-preview',
messages: [
{ role: 'user', content: 'Tell me a joke.' }
],
})
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content
if (content) process.stdout.write(content)
}
Function Calling
import { openai } from '@stacksjs/ai'
const response = await openai.chat({
model: 'gpt-4-turbo-preview',
messages: [
{ role: 'user', content: 'What is the weather in San Francisco?' }
],
tools: [
{
type: 'function',
function: {
name: 'get_weather',
description: 'Get the current weather in a location',
parameters: {
type: 'object',
properties: {
location: {
type: 'string',
description: 'The city and state, e.g. San Francisco, CA',
},
unit: {
type: 'string',
enum: ['celsius', 'fahrenheit'],
},
},
required: ['location'],
},
},
},
],
})
if (response.choices[0].message.tool_calls) {
const toolCall = response.choices[0].message.tool_calls[0]
const args = JSON.parse(toolCall.function.arguments)
const weather = await getWeather(args.location, args.unit)
const followUp = await openai.chat({
model: 'gpt-4-turbo-preview',
messages: [
...messages,
response.choices[0].message,
{
role: 'tool',
tool_call_id: toolCall.id,
content: JSON.stringify(weather),
},
],
})
}
Embeddings
import { openai } from '@stacksjs/ai'
const embedding = await openai.embed({
model: 'text-embedding-3-small',
input: 'The quick brown fox jumps over the lazy dog.',
})
console.log(embedding.data[0].embedding)
Ollama (Local Models)
Basic Chat
import { ollama } from '@stacksjs/ai'
const response = await ollama.chat({
model: 'llama2',
messages: [
{ role: 'user', content: 'Hello! How are you?' }
],
})
console.log(response.message.content)
Available Models
import { ollama } from '@stacksjs/ai'
const models = await ollama.list()
console.log(models)
await ollama.pull('mistral')
const response = await ollama.chat({
model: 'codellama',
messages: [
{ role: 'user', content: 'Write a Python function to reverse a string.' }
],
})
Streaming with Ollama
import { ollama } from '@stacksjs/ai'
const stream = await ollama.stream({
model: 'llama2',
messages: [
{ role: 'user', content: 'Explain machine learning.' }
],
})
for await (const chunk of stream) {
process.stdout.write(chunk.message?.content || '')
}
AWS Bedrock
Using Bedrock Client
import {
createBedrockClient,
createBedrockRuntimeClient,
invokeModel,
checkModelAccess
} from '@stacksjs/ai'
const client = createBedrockClient({
region: 'us-east-1',
})
const hasAccess = await checkModelAccess(client, 'anthropic.claude-3-sonnet-20240229-v1:0')
const runtimeClient = createBedrockRuntimeClient({
region: 'us-east-1',
})
const response = await invokeModel(runtimeClient, {
modelId: 'anthropic.claude-3-sonnet-20240229-v1:0',
body: JSON.stringify({
anthropic_version: 'bedrock-2023-05-31',
max_tokens: 1024,
messages: [
{ role: 'user', content: 'Hello!' }
],
}),
})
AI Agents
Creating Agents
import { createAgent } from '@stacksjs/ai'
const agent = createAgent({
name: 'ResearchAssistant',
model: 'claude-3-opus-20240229',
systemPrompt: `You are a research assistant. You help users find and summarize information.
You have access to web search and can analyze documents.`,
tools: [
{
name: 'web_search',
description: 'Search the web for information',
execute: async (query: string) => {
return searchResults
},
},
{
name: 'read_document',
description: 'Read and analyze a document',
execute: async (path: string) => {
return documentContent
},
},
],
})
const result = await agent.run('Research the latest AI developments in 2024')
Agent Memory
import { createAgent, MemoryStore } from '@stacksjs/ai'
const memory = new MemoryStore()
const agent = createAgent({
name: 'PersonalAssistant',
model: 'claude-3-sonnet-20240229',
memory,
})
await agent.run('My name is John')
await agent.run('What is my name?')
Buddy - Voice AI Assistant
Using Buddy
import { Buddy, createBuddy } from '@stacksjs/ai'
const buddy = createBuddy({
name: 'CodeAssistant',
voice: {
enabled: true,
model: 'whisper-1',
},
})
const transcription = await buddy.listen()
const response = await buddy.respond(transcription)
await buddy.speak(response)
Text Utilities
Text Generation
import { generateText, summarize, translate } from '@stacksjs/ai'
const generated = await generateText({
prompt: 'Write a product description for a smart watch',
maxTokens: 200,
})
const summary = await summarize({
text: longArticle,
maxLength: 100,
})
const translated = await translate({
text: 'Hello, how are you?',
from: 'en',
to: 'es',
})
Sentiment Analysis
import { analyzeSentiment } from '@stacksjs/ai'
const sentiment = await analyzeSentiment(
'I absolutely love this product! It exceeded all my expectations.'
)
Error Handling
import { anthropic } from '@stacksjs/ai'
try {
const response = await anthropic.chat({
messages: [{ role: 'user', content: 'Hello' }],
})
} catch (error) {
if (error.status === 429) {
console.log('Too many requests, waiting...')
await delay(error.headers['retry-after'] _ 1000)
} else if (error.status === 401) {
console.error('Invalid API key')
} else if (error.status === 500) {
console.error('AI provider error')
}
}
Edge Cases
Handling Long Conversations
import { anthropic } from '@stacksjs/ai'
function trimConversation(messages: Message[], maxTokens: number) {
const systemMessage = messages.find(m => m.role === 'system')
const recentMessages = messages.slice(-10)
return systemMessage
? [systemMessage, ...recentMessages]
: recentMessages
}
const trimmedMessages = trimConversation(conversation, 4096)
const response = await anthropic.chat({ messages: trimmedMessages })
Retrying Failed Requests
import { anthropic } from '@stacksjs/ai'
async function chatWithRetry(
messages: Message[],
maxRetries = 3
) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await anthropic.chat({ messages })
} catch (error) {
if (attempt === maxRetries) throw error
const delay = Math.pow(2, attempt) _ 1000
await new Promise(r => setTimeout(r, delay))
}
}
}
Timeout Handling
import { anthropic } from '@stacksjs/ai'
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 30000)
try {
const response = await anthropic.chat({
messages: [{ role: 'user', content: 'Complex question...' }],
signal: controller.signal,
})
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request timed out')
}
} finally {
clearTimeout(timeoutId)
}
API Reference
Provider Functions
| Function | Description |
anthropic.chat(options) | Chat with Claude |
anthropic.stream(options) | Stream Claude response |
openai.chat(options) | Chat with GPT |
openai.stream(options) | Stream GPT response |
openai.embed(options) | Generate embeddings |
ollama.chat(options) | Chat with local model |
ollama.stream(options) | Stream local model |
ollama.list() | List installed models |
ollama.pull(model) | Download model |
Bedrock Functions
| Function | Description |
createBedrockClient(config) | Create Bedrock client |
createBedrockRuntimeClient(config) | Create runtime client |
invokeModel(client, params) | Invoke model |
checkModelAccess(client, modelId) | Check access |
Text Utilities
| Function | Description |
generateText(options) | Generate text |
summarize(options) | Summarize text |
translate(options) | Translate text |
analyzeSentiment(text) | Analyze sentiment |