A comprehensive plugin ecosystem enabling AI agents to interact with external services through a unified gateway architecture
SperaxOS Plugin System is a modular architecture that extends AI agent capabilities through standardized plugin interfaces. It provides authentication management, function calling integration, and a gateway API for routing plugin requests. Built on Next.js with TypeScript, it supports both standalone plugins and integrated marketplace deployments.
- Node.js >= 18
- pnpm (recommended) or bun
# Clone the repository
git clone https://github.com/nirholas/SperaxOS.git
cd SperaxOS
# Install dependencies
pnpm install
# Start development server
bun run dev# Visit http://localhost:3010
# Navigate to Chat → Enable a plugin → Send message that triggers pluginExpected output: The AI agent will automatically detect relevant tools and call the plugin API when needed.
- Unified Gateway Architecture: Single API endpoint (
/api/gateway) routes all plugin requests with centralized authentication - Function Calling Integration: Plugins automatically activate when AI models return
tool_callsresponses - Authentication Management: Supports multiple auth methods (API keys, OAuth, Bearer tokens, custom headers)
- Multi-Provider Support: 40+ AI model providers including OpenAI, Anthropic, Google, and custom adapters
- Plugin Marketplace: Discover and install community plugins via the Agents Market
- Artifacts System: Display portfolio data, charts, and interactive components within chat via
<speraxArtifact>tags - Internationalization: Built-in i18n with automatic translation pipeline using sperax-i18n
Frontend:
- Next.js 15 (App Router with Route Groups)
- React 19, TypeScript
- Ant Design, @sperax/ui, antd-style
- Zustand (state management), SWR (data fetching)
Backend:
- Edge Runtime API (AI conversation logic)
- tRPC (type-safe API layer with edge/lambda/async variants)
- PostgreSQL, PGLite, Drizzle ORM
- AgentRuntime (unified model provider abstraction)
Testing:
- Vitest, Testing Library
- 97%+ coverage target for core modules
src/
├── app/ # Next.js App Router
│ ├── (backend)/ # API routes and services
│ │ ├── api/ # REST endpoints
│ │ ├── trpc/ # tRPC routes (edge/lambda/desktop)
│ │ └── webapi/ # Web API endpoints
│ └── [variants]/ # Platform variants (web/desktop/mobile)
├── components/ # Reusable UI components
├── features/ # Business feature modules
│ ├── AgentSetting/ # Agent configuration UI
│ ├── Conversation/ # Chat interface
│ └── Portal/ # Artifacts rendering
├── libs/ # Third-party integrations
│ └── agent-runtime/ # Model provider abstractions
├── services/ # Backend service interfaces
├── store/ # Zustand state management
├── types/ # TypeScript definitions
└── database/ # Drizzle schemas and migrations
- app/(backend)/webapi/chat/: Handles chat streaming and function calling
- libs/agent-runtime/: AgentRuntime class provides unified interface for 40+ AI providers
- features/Portal/Artifacts/: Renders React/HTML/SVG artifacts in chat sidebar
- services/chat.ts: Frontend ChatService orchestrates message flow
- database/schemas/: Drizzle ORM schemas for agents, sessions, and plugins
| Function/Endpoint | Purpose | Parameters | Returns |
|---|---|---|---|
POST /api/gateway |
Route plugin requests | apiName, identifier, arguments |
Plugin API response |
createAssistantMessage() |
Initiate AI chat | messages, tools, model, provider |
Streaming response |
runPluginApi() |
Execute plugin | identifier, apiName, params |
Plugin result |
fetchPresetTaskResult() |
Run preset tasks | taskPrompt, params |
Task completion |
AgentRuntime.chat() |
Unified model call | messages, model, provider, options |
Stream response |
buildFluxDevWorkflow() |
ComfyUI workflow | modelFileName, prompt, context |
PromptBuilder instance |
// Agent Configuration
interface SperaxAgentConfig {
model: string; // Model identifier
chatConfig: SperaxAgentChatConfig; // Chat settings
openingMessage?: string; // Welcome message
openingQuestions?: string[]; // Suggested prompts
params: {
frequency_penalty: number;
presence_penalty: number;
temperature: number;
top_p: number;
};
plugins?: string[]; // Enabled plugin identifiers
systemRole?: string; // System prompt
tts: SperaxAgentTTSConfig; // Text-to-speech config
}
// Plugin Authentication
interface ComfyUIKeyVault {
baseURL: string;
authType: 'none' | 'basic' | 'bearer' | 'custom';
apiKey?: string;
username?: string;
password?: string;
customHeaders?: Record<string, string>;
}import { SperaxComfyUI } from '@/libs/model-runtime/comfyui';
// Initialize plugin client
const comfyUI = new SperaxComfyUI({
baseURL: 'http://localhost:8000',
authType: 'none'
});
// Generate image via plugin
const result = await comfyUI.createImage({
model: 'flux-dev',
prompt: 'A serene mountain landscape at sunset',
size: { width: 1024, height: 1024 },
steps: 20,
seed: Math.floor(Math.random() * 1000000),
params: {
cfg: 7.0,
sampler: 'euler',
scheduler: 'normal'
}
});
console.log('Generated image URL:', result.imageUrl);// Frontend: ChatService initiates request
const chatService = new ChatService();
await chatService.createAssistantMessage({
messages: [
{ role: 'user', content: 'Search for the latest AI news' }
],
tools: enabledPluginTools,
model: 'gpt-4',
provider: 'openai',
onMessageHandle: (text) => {
console.log('Streaming text:', text);
},
onToolCall: (toolCall) => {
console.log('Tool called:', toolCall.function.name);
}
});
// Backend: AI returns tool_calls
// {
// "tool_calls": [{
// "id": "call_123",
// "function": {
// "name": "web_search",
// "arguments": "{\"query\": \"latest AI news 2025\"}"
// }
// }]
// }
// System automatically calls runPluginApi
const pluginResult = await chatService.runPluginApi({
identifier: 'web-search-plugin',
apiName: 'search',
params: { query: 'latest AI news 2025' }
});
// AI receives plugin result and generates final response// AI returns artifact in response
const artifactResponse = `
<speraxArtifact identifier="portfolio-assets" title="My Portfolio" type="application/sperax.artifacts.react">
import { Card, Statistic, Row, Col } from 'antd';
export default function PortfolioDisplay() {
return (
<div style={{ padding: 24 }}>
<Row gutter={16}>
<Col span={8}>
<Card>
<Statistic title="Total Assets" value={125430.50} prefix="$" />
</Card>
</Col>
<Col span={8}>
<Card>
<Statistic title="Total Coins" value={12} />
</Card>
</Col>
<Col span={8}>
<Card>
<Statistic title="24h Change" value={2.47} suffix="%" valueStyle={{ color: '#3f8600' }} />
</Card>
</Col>
</Row>
</div>
);
}
</speraxArtifact>
`;
// Artifacts panel automatically opens and renders the React component# Install dependencies
pnpm install
# Start development server with debug mode
DEBUG=speraxos:* bun run dev
# Run type checking
bun run type-check
# Run linting
bun run lint# Run all tests (not recommended - takes ~10 minutes)
bun run test
# Run specific test file
bunx vitest run --silent='passed-only' 'src/store/agent/slices/chat/selectors/agent.test.ts'
# Run tests for specific module
bunx vitest run --silent='passed-only' 'src/comfyui'
# View coverage
bunx vitest run --coverage 'src/comfyui'
# Update test snapshots
bunx vitest -u 'path/to/test.ts'Feature Organization:
- Global features:
src/features/<feature-name>/(used across multiple pages) - Page-specific features:
src/app/<page>/features/<feature-name>/(single-page only)
State Management:
- Use Zustand for global state
- Define selectors in
store/selectors.tsfor performance optimization - Follow slice pattern for complex stores
Code Style:
- Prefer interfaces over types for object shapes
- Use
bunto run npm scripts,bunxfor executables - Commit messages: prefix with gitmoji
- Branch format:
username/feat/feature-name
1. No Authentication
const client = new SperaxComfyUI({ baseURL: 'http://localhost:8000', authType: 'none' });2. Basic Authentication
const client = new SperaxComfyUI({
baseURL: 'https://api.example.com',
authType: 'basic',
username: 'user',
password: 'pass'
});3. Bearer Token
const client = new SperaxComfyUI({
baseURL: 'https://api.example.com',
authType: 'bearer',
apiKey: 'your-token'
});4. Custom Headers
const client = new SperaxComfyUI({
baseURL: 'https://api.example.com',
authType: 'custom',
customHeaders: {
'X-API-Key': 'key123',
'X-Custom-Auth': 'value'
}
});Add new OAuth providers via Auth.js:
// src/app/api/auth/next-auth.ts
import Okta from 'next-auth/providers/okta';
const nextAuth = NextAuth({
providers: [
Okta({
clientId: process.env.OKTA_CLIENT_ID,
clientSecret: process.env.OKTA_CLIENT_SECRET,
issuer: process.env.OKTA_ISSUER
})
]
});- Create Provider Implementation
// src/libs/agent-runtime/myprovider/index.ts
import { SperaxRuntimeAI } from '../BaseAI';
export class SperaxMyProviderAI implements SperaxRuntimeAI {
async chat(payload, options) {
// Implement chat method
}
}- Register in Runtime Map
// src/libs/agent-runtime/runtimeMap.ts
export const providerRuntimeMap = {
myprovider: SperaxMyProviderAI,
// ... other providers
};- Add Environment Variables
// src/config/server/app.ts
export const getAppConfig = () => ({
MYPROVIDER_API_KEY: z.string().optional(),
});- Update Database Schema
// src/database/schemas/agent.ts
export const agents = pgTable('agents', {
newFeature: text('new_feature'),
});- Generate Migration
npm run db:generate
# Rename and update migration file- Update Type Definitions
// src/types/agent/index.ts
export interface SperaxAgentConfig {
newFeature?: string;
}- Implement UI Component
// src/features/AgentSetting/NewFeature/index.tsx
const NewFeature = () => {
const [config, setConfig] = useStore(s => [s.config, s.setAgentConfig]);
return (
<Input
value={config.newFeature}
onChange={(e) => setConfig({ newFeature: e.target.value })}
/>
);
};- Add i18n Keys
// src/locales/default/setting.ts
export default {
agent: {
newFeature: 'New Feature Label',
newFeatureDescription: 'Description of the feature',
},
};-
State Management: Use selectors for derived state to optimize re-renders. Define selectors in dedicated files for reusability.
-
Testing Strategy: Run targeted tests during development (
bunx vitest run '[pattern]'). Never run full test suite locally - let CI handle it. -
Database Migrations: Always generate migrations with
npm run db:generateafter schema changes. Manually rename migration files with semantic names. -
Internationalization: Only translate
zh-CNlocale during development. CI automatically handles other languages viapnpm i18n. -
Plugin Development: Base workflow structures on official ComfyUI API exports. Use PromptBuilder to wrap and parameterize workflows. Never invent node structures.
Issue: Could not find 'stylelint-config-recommended' during npm install
Solution: Use pnpm or bun instead:
pnpm install
# or
bun installIssue: Tests fail with snapshot mismatches after adding optional config fields
Solution: Update snapshots for affected tests:
bunx vitest -u 'src/store/agent/slices/chat/selectors/agent.test.ts'Issue: Plugin not appearing in marketplace
Solution: Ensure plugin manifest includes required fields:
{
"identifier": "unique-plugin-id",
"api": [{ "name": "apiName", "url": "/api/endpoint" }],
"meta": { "title": "Plugin Name", "description": "..." }
}Issue: ComfyUI workflow fails with "Model file not found"
Solution: Verify model file exists in ComfyUI's models directory and filename matches exactly:
const resolver = new ModelResolverService(clientService);
const fileName = await resolver.resolveModelFileName('flux-dev');
console.log('Resolved filename:', fileName);- Full Documentation
- API Reference
- Plugin Development Guide
- Testing Guide
- Contributing Guide
- SperaxOS GitHub
MIT © Sperax