
Security News
The Code You Didn't Write Is Still Yours to Defend
AI agents are pulling packages into environments no scanner is watching, creating exposure before security teams can see it.
All-In-One LLM Framework - Multi-provider LLM integration with auto-fallback, priority management, multimodal support, and XML-based tool calling
All-In-One LLM Framework - Multi-provider LLM integration với auto-fallback, priority management, multimodal support và structured outputs cho JavaScript/TypeScript.
npm install aio
import { AIO } from "aio";
const aio = new AIO({
providers: [
{
provider: "openrouter",
apiKeys: [{ key: "sk-or-v1-xxx" }],
models: [{ modelId: "arcee-ai/trinity-large-preview:free" }],
},
],
});
const response = await aio.chatCompletion({
provider: "openrouter",
model: "arcee-ai/trinity-large-preview:free",
messages: [{ role: "user", content: "Hello!" }],
});
console.log(response.choices[0].message.content);
const aio = new AIO({
providers: [
{
provider: "groq",
apiKeys: [{ key: "gsk_xxx" }],
models: [{ modelId: "llama-3.3-70b-versatile" }],
priority: 10, // Ưu tiên cao nhất
},
{
provider: "cerebras",
apiKeys: [{ key: "csk_xxx" }],
models: [{ modelId: "llama3.1-8b" }],
priority: 8, // Fallback
},
],
autoMode: true, // Bật auto mode
});
// Không cần chỉ định provider/model
const response = await aio.chatCompletion({
messages: [
{ role: "user", content: "Hello!" },
],
});
// AIO tự động chọn Groq trước, nếu fail sẽ fallback sang Cerebras
const aio = new AIO({
providers: [
{
provider: "groq",
apiKeys: [
{ key: "gsk_primary", priority: 100 }, // Key chính
{ key: "gsk_backup1", priority: 50 }, // Backup 1
{ key: "gsk_backup2", priority: 10 }, // Backup 2
],
models: [
{ modelId: "llama-3.3-70b-versatile", priority: 100 }, // Model tốt nhất
{ modelId: "llama-3.1-8b-instant", priority: 50 }, // Model nhanh hơn
],
priority: 100, // Provider priority
},
],
autoMode: true,
});
// AIO sẽ thử theo thứ tự:
// 1. groq:llama-3.3-70b-versatile với gsk_primary
// 2. Nếu fail → thử gsk_backup1
// 3. Nếu fail → thử gsk_backup2
// 4. Nếu fail → thử groq:llama-3.1-8b-instant
await aio.streamChatCompletion(
{
provider: "openrouter",
model: "arcee-ai/trinity-large-preview:free",
messages: [{ role: "user", content: "Write a poem" }],
},
(chunk) => {
process.stdout.write(chunk.choices[0]?.delta?.content || "");
},
(error) => {
if (error) console.error("Error:", error);
else console.log("\nDone!");
}
);
// Image from base64
const response = await aio.chatCompletion({
provider: "google-ai",
model: "gemini-1.5-flash",
messages: [
{
role: "user",
content: [
{ type: "text", text: "Describe this image" },
{
type: "image",
source: {
type: "base64",
media_type: "image/jpeg",
data: "base64_encoded_image_data",
},
},
],
},
],
});
// Image from URL
const response2 = await aio.chatCompletion({
provider: "google-ai",
model: "gemini-1.5-flash",
messages: [
{
role: "user",
content: [
{ type: "text", text: "What's in this image?" },
{
type: "image",
source: {
type: "url",
media_type: "image/jpeg",
url: "https://example.com/image.jpg",
},
},
],
},
],
});
// PDF, Video, Audio
const response3 = await aio.chatCompletion({
provider: "google-ai",
model: "gemini-1.5-flash",
messages: [
{
role: "user",
content: [
{ type: "text", text: "Summarize this PDF" },
{
type: "file",
source: {
type: "base64",
media_type: "application/pdf",
data: "base64_encoded_pdf_data",
},
},
],
},
],
});
// JSON Object Mode
const response = await aio.chatCompletion({
provider: "openrouter",
model: "arcee-ai/trinity-large-preview:free",
messages: [
{
role: "user",
content: "Return a JSON with name, age, city for John, 25, New York",
},
],
response_format: { type: "json_object" },
});
const data = JSON.parse(response.choices[0].message.content);
console.log(data); // { name: "John", age: 25, city: "New York" }
const response = await aio.chatCompletion({
provider: "openrouter",
model: "arcee-ai/trinity-large-preview:free",
messages: [
{
role: "user",
content: "Extract: iPhone 15 Pro - Great camera, expensive. Rating: 4.5/5",
},
],
response_format: {
type: "json_schema",
json_schema: {
name: "product_review",
strict: true,
schema: {
type: "object",
properties: {
product_name: { type: "string" },
rating: { type: "number" },
sentiment: {
type: "string",
enum: ["positive", "negative", "neutral"],
},
key_features: {
type: "array",
items: { type: "string" },
},
},
required: ["product_name", "rating", "sentiment", "key_features"],
additionalProperties: false,
},
},
},
});
const data = JSON.parse(response.choices[0].message.content);
// Guaranteed to match schema!
const response = await aio.chatCompletion({
provider: "openrouter",
model: "arcee-ai/trinity-large-preview:free",
systemPrompt: "You are a helpful assistant that always responds in JSON format",
messages: [{ role: "user", content: "What is 2+2?" }],
});
const response = await aio.chatCompletion({
provider: "google-ai",
model: "gemini-1.5-flash",
messages: [{ role: "user", content: "Tell me a story" }],
temperature: 0.7,
max_tokens: 1000,
top_p: 0.9,
top_k: 40, // Only for Google AI and OpenRouter
stop: ["END", "STOP"],
});
Nvidia cung cấp Kimi K2.5 hoàn toàn miễn phí thông qua OpenAI-compatible API:
import { AIO } from "aio";
const aio = new AIO({
providers: [
{
provider: "nvidia",
apiKeys: [{ key: process.env.NVIDIA_API_KEY }],
models: [{ modelId: "moonshotai/kimi-k2.5" }],
},
],
});
const response = await aio.chatCompletion({
provider: "nvidia",
model: "moonshotai/kimi-k2.5",
messages: [{ role: "user", content: "Explain quantum computing" }],
temperature: 0.7,
});
Đăng ký API key miễn phí:
https://integrate.api.nvidia.com/v1/chat/completionsmoonshotai/kimi-k2.5Tính năng:
AIO Framework hỗ trợ text-based tool calling với streaming real-time. Framework tự động parse [tool]...[/tool] tags, validate parameters, retry on errors, và track execution metadata.
import { AIO } from "aio";
const aio = new AIO({
providers: [
{
provider: "google-ai",
apiKeys: [{ key: "your-api-key" }],
models: [{ modelId: "gemini-flash-latest" }],
},
],
});
// 1. Define tools
const tools = [
{
name: "get_weather",
description: "Get current weather for a city",
parameters: {
city: {
type: "string",
description: "City name",
required: true,
},
unit: {
type: "string",
description: "Temperature unit",
required: false,
enum: ["celsius", "fahrenheit"],
default: "celsius", // Auto-applied if not provided
},
},
},
];
// 2. Implement tool handler
async function handleToolCall(call) {
console.log(`🔧 Calling: ${call.name}`, call.params);
if (call.name === "get_weather") {
// Your tool logic here
return {
temperature: 22,
condition: "Sunny",
unit: call.params.unit,
};
}
throw new Error(`Unknown tool: ${call.name}`);
}
// 3. Start streaming with tools
const stream = await aio.chatCompletionStream({
provider: "google-ai",
model: "gemini-flash-latest",
messages: [
{ role: "user", content: "What's the weather in Tokyo?" }
],
tools,
onToolCall: handleToolCall,
maxToolIterations: 5, // Default: 5
});
// 4. Process events
stream.on("data", (chunk) => {
const data = JSON.parse(chunk.toString().slice(6));
if (data.tool_call) {
// Tool call event: pending, executing, success, error
console.log("Tool:", data.tool_call.type);
} else if (data.choices[0].delta.content) {
// Text content
process.stdout.write(data.choices[0].delta.content);
}
});
stream.on("end", () => console.log("\n✅ Done!"));
Framework tự động validate:
// Tool definition
{
name: "set_temperature",
parameters: {
value: { type: "number", required: true },
unit: { type: "string", enum: ["C", "F"], required: true }
}
}
// AI calls with invalid enum
[tool]{"name": "set_temperature", "params": {"value": 25, "unit": "Kelvin"}}[/tool]
// Framework returns error
[tool_result]
Tool: set_temperature
Success: false
Error: Invalid value for unit. Must be one of: C, F
Suggestion: Check the tool definition and provide all required parameters.
[/tool_result]
{
parameters: {
limit: { type: "number", default: 10 },
unit: { type: "string", enum: ["celsius", "fahrenheit"], default: "celsius" }
}
}
// AI calls without defaults
{"name": "search", "params": {"query": "test"}}
// Framework applies automatically
{"name": "search", "params": {"query": "test", "limit": 10}}
Framework automatically retries up to 3 times với exponential backoff:
async function handleToolCall(call) {
// Simulate transient error
if (Math.random() < 0.5) {
throw new Error("Temporary network error");
}
return { success: true };
}
// Framework retries:
// Attempt 1: Immediate
// Attempt 2: Wait 1s
// Attempt 3: Wait 2s
// Attempt 4: Wait 4s (max 5s)
[tool_result]
Tool: get_weather
Success: true
Data: {"temperature": 22, "condition": "Sunny"}
Execution Time: 1234ms
Retries: 1
[/tool_result]
AI tự động chain tools để hoàn thành complex tasks:
const tools = [
{
name: "search_docs",
description: "Search documentation",
parameters: {
query: { type: "string", required: true }
}
},
{
name: "read_file",
description: "Read file content",
parameters: {
path: { type: "string", required: true }
}
}
];
// User: "Find and read the authentication guide"
// AI automatically:
// 1. Calls search_docs → Gets file path
// 2. Calls read_file → Gets content
// 3. Answers question with content
Framework emits SSE events cho mỗi tool call:
// 1. Tool Call Pending
{
"tool_call": {
"type": "pending"
}
}
// 2. Tool Call Executing
{
"tool_call": {
"type": "executing",
"call": {
"name": "get_weather",
"params": {"city": "Tokyo", "unit": "celsius"}
}
}
}
// 3. Tool Call Success
{
"tool_call": {
"type": "success",
"call": {...},
"result": {
"temperature": 22,
"condition": "Sunny"
}
}
}
// 4. Tool Call Error
{
"tool_call": {
"type": "error",
"call": {...},
"error": "Weather API temporarily unavailable"
}
}
{
name: "search_database",
description: "Search database with filters",
parameters: {
query: {
type: "string",
description: "Search query",
required: true,
},
limit: {
type: "number",
description: "Max results",
required: false,
default: 10, // Auto-applied
},
sort_by: {
type: "string",
description: "Sort field",
required: false,
enum: ["date", "relevance", "popularity"], // Validated
default: "relevance",
},
filters: {
type: "object",
description: "Additional filters",
required: false,
},
},
requireReasoning: true, // Force AI to explain why calling this tool
}
const stream = await aio.chatCompletionStream({
messages: [...],
tools: [...],
onToolCall: handleToolCall,
maxToolIterations: 10, // Default: 5 (max tool call loops)
signal: abortController.signal, // Cancel anytime
});
{
name: "delete_file",
parameters: {
path: { type: "string", required: true },
reasoning: {
type: "string",
description: "Explain why you need to delete this file",
required: true
}
}
}
// ✅ Good
description: "Search codebase for function definitions matching the query"
// ❌ Bad
description: "Search stuff"
{
sort_by: {
type: "string",
enum: ["date", "relevance", "popularity"],
default: "relevance"
}
}
async function handleToolCall(call) {
if (call.name === "read_file") {
if (!fs.existsSync(call.params.path)) {
throw new Error(
`File not found: ${call.params.path}. ` +
`Did you mean: ${suggestSimilarFiles(call.params.path).join(", ")}?`
);
}
}
}
examples/tool-test-simple.ts - Basic tool callingexamples/tool-calling.ts - Complex multi-tool exampleexamples/tool-test-validation.ts - Validation & retry exampleexamples/tool-test-history.ts - History management demonstration| Feature | AIO Text-based | OpenAI Function Calling |
|---|---|---|
| Provider Support | ✅ Any LLM | ❌ OpenAI, Anthropic only |
| Streaming | ✅ Yes (only) | ✅ Yes |
| Validation | ✅ Built-in | ✅ JSON Schema |
| Retry | ✅ Automatic (3x) | ❌ Manual |
| Metadata | ✅ Execution time, retry count | ❌ No |
| Default Values | ✅ Automatic | ❌ Manual |
| Format | Text tags | Native API |
AIO Classnew AIO(config: AIOConfig)
chatCompletion(request: ChatCompletionRequest): Promise<ChatCompletionResponse>chatCompletionStream(request: ChatCompletionRequest): AsyncGenerator<StreamChunk>validateApiKey(provider: Provider, apiKey: string): Promise<boolean>AIOConfiginterface AIOConfig {
providers: ProviderConfig[];
autoMode?: boolean; // Default: false
maxRetries?: number; // Default: 3
retryDelay?: number; // Default: 1000ms
}
ProviderConfiginterface ProviderConfig {
provider: Provider; // "openrouter" | "groq" | "cerebras" | "google-ai"
apiKeys: ApiKey[];
models: ModelConfig[];
priority?: number; // Default: 0 (cao hơn = ưu tiên hơn)
isActive?: boolean; // Default: true
}
ApiKeyinterface ApiKey {
key: string;
priority?: number; // Default: 0
isActive?: boolean; // Default: true
dailyLimit?: number;
requestsToday?: number;
}
ModelConfiginterface ModelConfig {
modelId: string;
priority?: number; // Default: 0
isActive?: boolean; // Default: true
}
ChatCompletionRequestinterface ChatCompletionRequest {
messages: Message[];
temperature?: number;
maxTokens?: number;
// Direct mode
provider?: Provider;
modelId?: string;
}
| Provider | Base URL | Models |
|---|---|---|
| OpenRouter | https://openrouter.ai/api/v1 | 30+ free models |
| Groq | https://api.groq.com/openai/v1 | llama-3.3-70b, llama-3.1-8b, etc. |
| Cerebras | https://api.cerebras.ai/v1 | llama3.1-8b, llama3.1-70b |
| Google AI | https://generativelanguage.googleapis.com | gemini-1.5-flash, gemini-1.5-pro |
| Nvidia | https://integrate.api.nvidia.com/v1 | moonshotai/kimi-k2.5 (FREE) |
Xem thêm examples trong thư mục examples/:
basic.ts - Basic usage với direct modeauto-mode.ts - Auto mode với fallbackpriority.ts - Priority managementstreaming.ts - Streaming responsesChạy examples:
npm run example:basic
npm run example:auto
npm run example:priority
# Install dependencies
npm install
# Build
npm run build
# Run examples
npm run dev
MIT
Contributions are welcome! Please feel free to submit a Pull Request.
const controller = new AbortController();
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
try {
const response = await aio.chatCompletion({
provider: "openrouter",
model: "openrouter/pony-alpha",
messages: [{ role: "user", content: "Long task..." }],
signal: controller.signal, // Pass abort signal
});
} catch (error) {
if (error.message.includes("cancel")) {
console.log("Request was cancelled");
}
}
const controller = new AbortController();
const stream = await aio.chatCompletionStream({
provider: "openrouter",
model: "openrouter/pony-alpha",
messages: [{ role: "user", content: "Count to 100" }],
signal: controller.signal,
});
let chunks = 0;
for await (const chunk of stream) {
chunks++;
if (chunks >= 10) {
controller.abort(); // Cancel after 10 chunks
break;
}
}
const controller = new AbortController();
controller.abort(); // Cancel before calling
try {
await aio.chatCompletion({
provider: "openrouter",
model: "openrouter/pony-alpha",
messages: [{ role: "user", content: "Test" }],
signal: controller.signal,
});
} catch (error) {
console.log("Request was pre-cancelled");
}
// Get key stats for a provider
const stats = aio.getKeyStats("openrouter");
console.log(stats);
// {
// total: 3,
// active: 2,
// disabled: 1,
// totalUsage: 150,
// totalErrors: 5
// }
// Reset daily counters (call this daily)
aio.resetDailyCounters();
// Get config summary
const summary = aio.getConfigSummary();
console.log(summary);
// {
// providers: 2,
// totalKeys: 5,
// totalModels: 8,
// autoMode: true,
// maxRetries: 3
// }
interface AIOConfig {
providers: ProviderConfig[];
autoMode?: boolean; // Default: false
maxRetries?: number; // Default: 3
retryDelay?: number; // Default: 1000ms
enableLogging?: boolean; // Default: true
enableValidation?: boolean; // Default: true
}
interface ApiKey {
key: string;
priority?: number; // Higher = preferred (default: 0)
isActive?: boolean; // Default: true
dailyLimit?: number; // Max requests per day
requestsToday?: number; // Current usage
errorCount?: number; // Consecutive errors
lastError?: string; // Last error message
lastUsed?: Date; // Last usage timestamp
}
Framework tự động phân loại lỗi:
const errorInfo = AIOError.classify(error);
console.log(errorInfo);
// {
// isRetryable: true,
// shouldRotateKey: true,
// category: "rate_limit"
// }
aio-framework/
├── src/
│ ├── aio.ts # Main AIO class (284 lines)
│ ├── types.ts # TypeScript types
│ ├── index.ts # Public exports
│ ├── core/ # Core logic modules
│ │ ├── auto-mode.ts # Auto fallback logic
│ │ ├── direct-mode.ts # Direct mode with retry
│ │ └── stream-handler.ts # Streaming logic
│ ├── providers/ # Provider implementations
│ │ ├── base.ts
│ │ ├── openrouter.ts
│ │ ├── groq.ts
│ │ ├── cerebras.ts
│ │ └── google-ai.ts
│ └── utils/ # Utilities
│ ├── logger.ts # Winston logger
│ ├── retry.ts # Retry logic
│ ├── validation.ts # Zod schemas
│ ├── key-manager.ts # Key management
│ └── abort-manager.ts # Abort controller manager
└── examples/
├── basic.ts
├── streaming.ts
├── auto-mode.ts
├── priority.ts
├── test-simple.ts
├── test-new-features.ts
└── test-abort-simple.ts
# Simple test
npm run build
npx tsx examples/test-simple.ts
# Test all new features
npx tsx examples/test-new-features.ts
# Test abort functionality
npx tsx examples/test-abort-simple.ts
MIT
FAQs
All-In-One LLM Framework - Multi-provider LLM integration with auto-fallback, priority management, multimodal support, and XML-based tool calling
The npm package aio-llm receives a total of 1 weekly downloads. As such, aio-llm popularity was classified as not popular.
We found that aio-llm demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
AI agents are pulling packages into environments no scanner is watching, creating exposure before security teams can see it.

Security News
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.