@thenoo/adapter-openai
v0.1.0
Published
OpenAI adapter for @thenoo/agentkit with ChatCompletion, Embeddings, and cost tracking
Maintainers
Readme
@thenoo/adapter-openai
OpenAI adapter for @thenoo/agentkit
ChatCompletion, Embeddings, and automatic cost tracking with FinOps integration.
Quick Start • API Docs • FinOps Integration • Changelog
🎉 What's New in v0.2.0
@thenoo/adapter-openai is a new package in the v0.2.0 release, providing seamless OpenAI integration for @thenoo/agentkit projects.
✨ Key Features
withFinOps()Wrapper - Automatic cost tracking and budget enforcement- Model Degradation - Automatically switch to cheaper models on budget breach
- Cost Calculation - Built-in pricing for all OpenAI models (GPT-4, GPT-4o, GPT-3.5-turbo, embeddings)
- Type-Safe - Full TypeScript support with Zod validation
- Event System - Subscribe to cost alerts and updates
🚀 Quick Example
import { createOpenAIAdapter, withFinOps } from '@thenoo/adapter-openai';
const adapter = createOpenAIAdapter({
apiKey: process.env.OPENAI_API_KEY!,
});
const wrapped = withFinOps(adapter, {
sessionId: 'user-123',
budget: {
usd: 10,
perRequestCents: 50,
policy: 'degrade_model', // Auto-downgrade on budget breach
},
});
const response = await wrapped.createChatCompletion({
messages: [{ role: 'user', content: 'Hello!' }],
});🔗 Related
- @thenoo/agentkit - Core agent framework
- @thenoo/finops - FinOps cost tracking
- @thenoo/cli - Generate projects with
--adapter openai
Features
- 🤖 ChatCompletion API - Full support for GPT-4, GPT-4o, GPT-3.5-turbo
- 🔢 Embeddings API - Text embeddings with all OpenAI models
- 💰 Automatic Cost Tracking - Built-in cost calculation for all models
- 🔄 Retry Logic - Configurable retry with exponential backoff
- 🛡️ Type-Safe - Full TypeScript support with Zod validation
- 🌍 Edge Compatible - Works in edge runtimes
- 🔧 Function Calling - Native support for tool/function calling
Installation
npm install @thenoo/adapter-openaiQuick Start
import { createOpenAIAdapter } from '@thenoo/adapter-openai';
const adapter = createOpenAIAdapter({
apiKey: process.env.OPENAI_API_KEY!,
defaultModel: 'gpt-4o-mini',
});
// Chat completion
const response = await adapter.createChatCompletion({
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'What is 2+2?' },
],
});
console.log(response.choices[0].message.content);
// Calculate cost
const cost = adapter.calculateCost(
response.model,
response.usage.prompt_tokens,
response.usage.completion_tokens
);
console.log(`Cost: $${cost.totalCost.toFixed(4)}`);Configuration
OpenAIAdapterConfig
interface OpenAIAdapterConfig {
/** OpenAI API key (required) */
apiKey: string;
/** Optional organization ID */
organization?: string;
/** Custom base URL (default: https://api.openai.com/v1) */
baseURL?: string;
/** Request timeout in ms (default: 60000) */
timeout?: number;
/** Max retry attempts (default: 3) */
maxRetries?: number;
/** Default model (default: 'gpt-4o-mini') */
defaultModel?: string;
/** Enable debug logging (default: false) */
debug?: boolean;
}Usage Examples
Basic Chat Completion
const response = await adapter.createChatCompletion({
messages: [{ role: 'user', content: 'Hello!' }],
temperature: 0.7,
max_tokens: 150,
});Function Calling
const response = await adapter.createChatCompletion({
messages: [{ role: 'user', content: 'What's the weather in Boston?' }],
tools: [{
type: 'function',
function: {
name: 'get_weather',
description: 'Get the current weather',
parameters: {
type: 'object',
properties: {
location: { type: 'string' },
unit: { type: 'string', enum: ['celsius', 'fahrenheit'] },
},
required: ['location'],
},
},
}],
tool_choice: 'auto',
});
// Check if model wants to call a function
if (response.choices[0].message.tool_calls) {
const toolCall = response.choices[0].message.tool_calls[0];
console.log('Function to call:', toolCall.function.name);
console.log('Arguments:', toolCall.function.arguments);
}Embeddings
const response = await adapter.createEmbedding({
input: 'The quick brown fox jumps over the lazy dog',
model: 'text-embedding-3-small',
});
const vector = response.data[0].embedding;
console.log(`Vector dimension: ${vector.length}`);Batch Embeddings
const response = await adapter.createEmbedding({
input: [
'First sentence',
'Second sentence',
'Third sentence',
],
model: 'text-embedding-3-small',
});
response.data.forEach((embedding, i) => {
console.log(`Embedding ${i}: ${embedding.embedding.length} dimensions`);
});Cost Tracking
// Manual cost calculation
const cost = adapter.calculateCost('gpt-4', 1000, 500);
console.log(`Prompt cost: $${cost.promptCost.toFixed(4)}`);
console.log(`Completion cost: $${cost.completionCost.toFixed(4)}`);
console.log(`Total cost: $${cost.totalCost.toFixed(4)}`);
// After API call
const response = await adapter.createChatCompletion({
messages: [{ role: 'user', content: 'Hello!' }],
});
const cost = adapter.calculateCost(
response.model,
response.usage.prompt_tokens,
response.usage.completion_tokens
);Integration with @thenoo/agentkit
import { createAgent } from '@thenoo/agentkit';
import { createOpenAIAdapter } from '@thenoo/adapter-openai';
const adapter = createOpenAIAdapter({
apiKey: process.env.OPENAI_API_KEY!,
});
// Use with agent (v0.2.0+)
const agent = createAgent({
name: 'MyAgent',
adapter,
tools: [/* your tools */],
});Model Pricing
Current pricing (as of October 2025):
| Model | Prompt (per 1K tokens) | Completion (per 1K tokens) | |-------|------------------------|----------------------------| | gpt-4 | $0.03 | $0.06 | | gpt-4-turbo | $0.01 | $0.03 | | gpt-4o | $0.005 | $0.015 | | gpt-4o-mini | $0.00015 | $0.0006 | | gpt-3.5-turbo | $0.0005 | $0.0015 | | text-embedding-3-small | $0.00002 | - | | text-embedding-3-large | $0.00013 | - |
Advanced Features
Custom Base URL
const adapter = createOpenAIAdapter({
apiKey: 'your-key',
baseURL: 'https://your-proxy.com/v1',
});Debug Mode
const adapter = createOpenAIAdapter({
apiKey: 'your-key',
debug: true, // Logs all API calls and responses
});Direct Client Access
const adapter = createOpenAIAdapter({ apiKey: 'your-key' });
// Access underlying OpenAI client for advanced features
const client = adapter.getClient();
const models = await client.models.list();Error Handling
try {
const response = await adapter.createChatCompletion({
messages: [{ role: 'user', content: 'Hello!' }],
});
} catch (error) {
if (error.status === 429) {
console.error('Rate limit exceeded');
} else if (error.status === 401) {
console.error('Invalid API key');
} else {
console.error('API error:', error.message);
}
}TypeScript Support
Full TypeScript support with exported types:
import type {
ChatMessage,
ChatCompletionOptions,
ChatCompletionResponse,
TokenUsage,
CostCalculation,
} from '@thenoo/adapter-openai';FinOps Integration
Automatic Cost Tracking with withFinOps
Wrap your adapter with withFinOps() to enable automatic cost tracking, budget enforcement, and model degradation:
import { createOpenAIAdapter, withFinOps } from '@thenoo/adapter-openai';
const adapter = createOpenAIAdapter({
apiKey: process.env.OPENAI_API_KEY!,
});
const wrapped = withFinOps(adapter, {
sessionId: 'user-123',
budget: {
usd: 10, // Maximum spend per session
perRequestCents: 50, // Maximum spend per request (in cents)
policy: 'degrade_model', // What to do on budget breach
},
onAlert: (event) => {
console.warn(`Budget alert for ${event.sessionId}`);
console.warn(`Total: $${event.totalUsd} / $${event.limitUsd}`);
},
});
// Use the wrapped adapter - costs are tracked automatically
const response = await wrapped.createChatCompletion({
messages: [{ role: 'user', content: 'Hello!' }],
});Budget Policies
| Policy | Behavior |
|--------|----------|
| halt | Throw error immediately on budget breach |
| alert | Emit warning but continue requests |
| degrade_model | Automatically switch to cheaper model |
| truncate | Reduce token limits on subsequent requests |
Model Degradation
When using policy: 'degrade_model', the adapter automatically downgrades to cheaper models when budget limits are exceeded:
import { degradeModel, getDegradationChain } from '@thenoo/adapter-openai';
// Check degradation path
console.log(degradeModel('gpt-4')); // 'gpt-4o-mini'
console.log(degradeModel('gpt-4o')); // 'gpt-4o-mini'
console.log(degradeModel('gpt-4o-mini')); // 'gpt-3.5-turbo'
// See full degradation chain
console.log(getDegradationChain('gpt-4'));
// ['gpt-4', 'gpt-4o-mini', 'gpt-3.5-turbo']Degradation Rationale:
gpt-4→gpt-4o-mini: Maintains quality while reducing costs ~200xgpt-4o→gpt-4o-mini: Still capable, much cheapergpt-4o-mini→gpt-3.5-turbo: Last resort for cost controlgpt-3.5-turbo: No further degradation (cheapest option)
Custom Pricing Function
Override default pricing with your own logic (e.g., for private deployments or custom models):
const wrapped = withFinOps(adapter, {
sessionId: 'user-123',
budget: { usd: 10 },
pricing: (model: string) => {
// Custom pricing logic
if (model.startsWith('my-custom-')) {
return { perMTokenUsd: 1.5 };
}
// Fallback to OpenAI pricing
return { perMTokenUsd: 2.0 };
},
});Multi-Session Isolation
The withFinOps wrapper isolates budgets per session ID:
const wrappedSession1 = withFinOps(adapter, {
sessionId: 'user-123',
budget: { usd: 5 },
});
const wrappedSession2 = withFinOps(adapter, {
sessionId: 'user-456',
budget: { usd: 10 },
});
// Each session has independent budget tracking
await wrappedSession1.createChatCompletion({ /* ... */ });
await wrappedSession2.createChatCompletion({ /* ... */ });Accessing FinOps Context
const wrapped = withFinOps(adapter, { /* ... */ });
// Get FinOps context
const finops = wrapped.getFinOpsContext();
// Check budget state
const state = await finops.getState('user-123');
console.log(`Spent: $${state.totalUsd.toFixed(4)}`);
console.log(`Remaining: $${state.remainingUsd.toFixed(4)}`);
console.log(`Requests: ${state.requestCount}`);
// Listen to all cost events
finops.onCostUpdate((payload) => {
console.log(`Session ${payload.sessionId}: $${payload.totalUsd}`);
});Related Packages
- @thenoo/agentkit - Core agent framework
- @thenoo/adapter-azure - Azure OpenAI adapter
- @thenoo/finops - FinOps cost tracking
License
MIT © Zachery Kuykendall
