byan-copilot-router
v1.0.1
Published
Intelligent cost-optimizing router for GitHub Copilot CLI - Save up to 54% on LLM costs
Maintainers
Readme
@byan/copilot-router
Intelligent cost-optimizing router for GitHub Copilot CLI
Automatically route tasks to cheap (worker) or expensive (agent) models based on complexity analysis. Save up to 54% on LLM costs while maintaining quality.
🎯 Why Copilot Router?
Problem: Using expensive models (gpt-4o) for all tasks wastes money. Using cheap models (gpt-4o-mini) for complex tasks produces poor results.
Solution: Automatically analyze task complexity and route to the right model.
Cost Savings
Traditional (100% gpt-4o): $0.30 per 100 calls
Smart Routing (60/40 split): $0.138 per 100 calls
─────────────────────
Savings: 54% 💰 ($162/year per 1K daily calls)Routing Logic
| Score | Route | Model | Cost/Call | Use Case | |-------|-------|-------|-----------|----------| | < 30 | Worker | gpt-4o-mini | $0.0003 | Simple edits, formatting | | 30-60 | Worker + Fallback | gpt-4o-mini → gpt-4o | $0.0003 | Medium complexity | | ≥ 60 | Agent | gpt-4o | $0.003 | Analysis, reasoning, creation |
🚀 Installation
npm install @byan/copilot-routerPrerequisites:
- Node.js >= 18.0.0
- GitHub Copilot subscription
- GitHub Copilot CLI installed
🚀 Quick Start
Installation
npm install @byan/copilot-router
# Or link for development
cd ~/copilot-router
npm linkQuick Test (30 seconds):
cd ~/copilot-router
node integrations/copilot-cli/cost-optimized-agent.js
# → See 87.5% cost savings immediately! 📖 Full integration guide: COPILOT-CLI-INTEGRATION.md
🚀 Fast track: QUICK-START.md
Prerequisites:
- Node.js ≥ 18.0.0
- GitHub Copilot subscription (optional for test mode)
- TypeScript 5.0+ (for TypeScript projects)
Basic Usage
import { CopilotRouter } from '@byan/copilot-router';
// Create router (test mode by default)
const router = new CopilotRouter();
// Simple task → Worker (cheap)
const result1 = await router.route({
input: "Fix typo in README",
type: 'simple'
});
console.log(result1.route); // 'worker'
console.log(result1.cost); // $0.0003
// Complex task → Agent (expensive)
const result2 = await router.route({
input: "Design microservices architecture with event sourcing",
type: 'reasoning',
contextSize: 5000,
steps: 5
});
console.log(result2.route); // 'agent'
console.log(result2.cost); // $0.003
// View cost savings
const stats = router.getTracker().getStatistics();
console.log(`Saved ${stats.savingsPercent}%`);
// Cleanup
await router.close();Cost Tracking
const router = new CopilotRouter();
// Route multiple tasks
for (const task of tasks) {
await router.route(task);
}
// Get detailed statistics
const stats = router.getTracker().getStatistics();
console.log(`
Total calls: ${stats.totalCalls}
Worker: ${stats.workerCalls} (${stats.workerPercent}%)
Agent: ${stats.agentCalls} (${stats.agentPercent}%)
Cost: $${stats.actualCost}
Baseline: $${stats.baselineCost}
Savings: ${stats.savingsPercent}%
`);
// Export for analysis
const json = router.getTracker().exportJSON();
const csv = router.getTracker().exportCSV();
console.log(router.getTracker().printSummary());📊 Features
Core Capabilities
- ✅ Complexity Analysis - 5-factor scoring algorithm (0-100 points)
- ✅ Automatic Routing - Worker vs Agent selection with fallback
- ✅ Cost Tracking - Real-time cost monitoring and reporting
- ✅ Retry Logic - Exponential backoff with 3 max attempts
- ✅ Test Mode - Development without GitHub authentication
- ✅ Type Safety - Full TypeScript support with strict mode
Complexity Factors
| Factor | Weight | Description | |--------|--------|-------------| | Input Length | 0-20 pts | Prompt length (< 100 → 0, ≥ 1000 → 20) | | Task Type | 0-30 pts | Simple (0), Format (5), Generate (15), Reasoning (30) | | Context Size | 0-20 pts | Code/docs size (< 1K → 5, ≥ 5K → 20) | | Steps | 0-15 pts | Multi-step tasks (1 step → 0, ≥ 4 → 15) | | Output Format | 0-15 pts | Text (0), JSON (5), Complex (15) |
Total: 0-100 points → determines routing decision
Cost Tracking Metrics
- Total calls (worker/agent distribution)
- Token usage (per call and aggregate)
- Cost analysis (actual vs baseline)
- Savings percentage
- Fallback frequency
- Export to JSON/CSV/console
🏗️ Architecture
┌─────────────────────────────────────────────────────────┐
│ Your Application │
└─────────────────────┬───────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ @byan/copilot-router │
│ │
│ ┌──────────────────┐ ┌────────────────────────┐ │
│ │ ComplexityAnalyzer│ ──▶ │ CopilotRouter │ │
│ │ 5-factor scoring│ │ Route logic │ │
│ └──────────────────┘ │ Retry + Fallback │ │
│ └────────┬───────────────┘ │
│ │ │
│ ┌──────────────────┐ ▼ │
│ │ CostTracker │ ┌────────────────────────┐ │
│ │ Track metrics │ ◀─── │ CopilotClient │ │
│ │ Export reports │ │ Test/Real SDK modes │ │
│ └──────────────────┘ └────────┬───────────────┘ │
└────────────────────────────────────┼───────────────────┘
│
▼
┌────────────────────────┐
│ GitHub Copilot CLI SDK │
│ JSON-RPC │
└────────┬───────────────┘
│
┌────────────┴────────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ gpt-4o-mini│ │ gpt-4o │
│ (Worker) │ │ (Agent) │
│ $0.0003 │ │ $0.003 │
└──────────┘ └──────────┘Components
| Component | Responsibility | |-----------|----------------| | ComplexityAnalyzer | Score tasks 0-100 based on 5 factors | | CopilotRouter | Route to worker/agent, handle retries/fallback | | CostTracker | Track costs, calculate savings, export reports | | CopilotClient | Wrap GitHub Copilot SDK, support test mode |
📚 API Reference
CopilotRouter
Main router class for task routing and execution.
Constructor
new CopilotRouter(config?: Partial<RouterConfig>)Options:
interface RouterConfig {
workerThreshold: number; // Score < this → worker (default: 30)
agentThreshold: number; // Score ≥ this → agent (default: 60)
fallbackEnabled: boolean; // Enable worker→agent fallback (default: true)
workerModel: ModelConfig; // Worker model config
agentModel: ModelConfig; // Agent model config
maxRetries: number; // Max retry attempts (default: 3)
}Methods
route(task: Task): Promise<RouteResult>
Route and execute a task.
const result = await router.route({
id: 'task-123', // Optional task ID
input: 'Analyze this code', // Prompt/input text
type: 'analysis', // Task type
contextSize: 2000, // Optional context size
steps: 3, // Optional step count
outputFormat: 'json' // Optional output format
});
// Result contains:
// - content: string (LLM response)
// - model: string (model used)
// - tokens: number (tokens consumed)
// - cost: number (cost in USD)
// - route: 'worker' | 'agent'
// - complexityScore: ComplexityScore
// - usedFallback?: booleangetTracker(): CostTracker
Get the cost tracker instance.
const tracker = router.getTracker();
const stats = tracker.getStatistics();getConfig(): RouterConfig
Get current router configuration.
updateConfig(config: Partial<RouterConfig>): void
Update router configuration.
router.updateConfig({
workerThreshold: 25,
fallbackEnabled: false
});close(): Promise<void>
Close the router and cleanup resources.
await router.close();ComplexityAnalyzer
Analyze task complexity and generate scores.
Constructor
const analyzer = new ComplexityAnalyzer();Methods
calculateComplexity(task: Task): ComplexityScore
Calculate complexity score for a task.
const score = analyzer.calculateComplexity({
input: 'Design architecture',
type: 'reasoning',
contextSize: 5000,
steps: 4,
outputFormat: 'complex'
});
// Returns:
// {
// total: 85,
// breakdown: {
// inputLength: 10,
// taskType: 30,
// contextSize: 10,
// steps: 15,
// outputFormat: 15
// },
// recommendation: 'agent'
// }getThresholds(): { worker: number, agent: number }
Get score thresholds.
CostTracker
Track costs and generate reports.
Constructor
const tracker = new CostTracker(agentCostPerCall?: number);Methods
track(record: CallRecord): void
Track a single call.
tracker.track({
taskId: 'task-1',
model: 'worker',
modelName: 'gpt-4o-mini',
tokens: 500,
cost: 0.0003,
complexityScore: 25,
fallbackUsed: false
});getStatistics(): CostStatistics
Get comprehensive statistics.
const stats = tracker.getStatistics();
// Returns: CostStatistics with all metricsgetRecords(): CallRecord[]
Get all tracked records.
reset(): void
Clear all tracked data.
exportJSON(): string
Export data as JSON.
const json = tracker.exportJSON();
fs.writeFileSync('costs.json', json);exportCSV(): string
Export data as CSV.
const csv = tracker.exportCSV();
fs.writeFileSync('costs.csv', csv);printSummary(): string
Get formatted summary for console.
console.log(tracker.printSummary());💡 Usage Examples
Example 1: Basic Routing
import { CopilotRouter } from '@byan/copilot-router';
const router = new CopilotRouter();
async function processTasks() {
const tasks = [
{ input: 'Fix typo', type: 'simple' },
{ input: 'Refactor function', type: 'generate', contextSize: 1000 },
{ input: 'Design system architecture', type: 'reasoning', steps: 5 }
];
for (const task of tasks) {
const result = await router.route(task);
console.log(`${result.route}: $${result.cost} (${result.tokens} tokens)`);
}
await router.close();
}Example 2: Cost Optimization
import { CopilotRouter } from '@byan/copilot-router';
const router = new CopilotRouter({
workerThreshold: 25, // More aggressive worker usage
fallbackEnabled: true, // Keep safety net
maxRetries: 5 // More resilient
});
// Process workload
await processLargeWorkload(router);
// Analyze results
const stats = router.getTracker().getStatistics();
if (stats.savingsPercent < 40) {
console.warn('Savings below target, consider lowering threshold');
router.updateConfig({ workerThreshold: 20 });
}
console.log(`
Distribution: ${stats.workerPercent}% worker, ${stats.agentPercent}% agent
Savings: ${stats.savingsPercent}%
ROI: $${stats.savingsAmount}
`);Example 3: Daily Cost Reports
import { CopilotRouter } from '@byan/copilot-router';
import fs from 'fs';
const router = new CopilotRouter();
async function generateDailyReport() {
// Process day's tasks
for (const task of dailyTasks) {
await router.route(task);
}
// Export report
const tracker = router.getTracker();
const timestamp = new Date().toISOString().split('T')[0];
fs.writeFileSync(
`reports/costs-${timestamp}.json`,
tracker.exportJSON()
);
fs.writeFileSync(
`reports/costs-${timestamp}.csv`,
tracker.exportCSV()
);
// Email summary
await sendEmail({
subject: `Cost Report ${timestamp}`,
body: tracker.printSummary()
});
await router.close();
}Example 4: Custom Configuration
import { CopilotRouter, ModelConfig } from '@byan/copilot-router';
// Custom model pricing
const customWorker: ModelConfig = {
model: 'gpt-4o-mini',
inputCost: 0.150 / 1_000_000,
outputCost: 0.600 / 1_000_000
};
const customAgent: ModelConfig = {
model: 'gpt-4o',
inputCost: 2.50 / 1_000_000,
outputCost: 10.00 / 1_000_000
};
const router = new CopilotRouter({
workerModel: customWorker,
agentModel: customAgent,
workerThreshold: 30,
agentThreshold: 60,
fallbackEnabled: true,
maxRetries: 3
});Example 5: Integration with Express
import express from 'express';
import { CopilotRouter } from '@byan/copilot-router';
const app = express();
const router = new CopilotRouter();
app.post('/api/complete', async (req, res) => {
try {
const result = await router.route({
input: req.body.prompt,
type: req.body.type || 'generate',
contextSize: req.body.context?.length
});
res.json({
content: result.content,
cost: result.cost,
tokens: result.tokens,
route: result.route
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.get('/api/stats', (req, res) => {
const stats = router.getTracker().getStatistics();
res.json(stats);
});
app.listen(3000);⚙️ Configuration
Environment Variables
# Optional: GitHub Copilot authentication (for real mode)
GITHUB_TOKEN=your_github_token
# Optional: Override default models
COPILOT_WORKER_MODEL=gpt-4o-mini
COPILOT_AGENT_MODEL=gpt-4oRouter Configuration
const router = new CopilotRouter({
// Complexity thresholds
workerThreshold: 30, // Score < 30 → worker
agentThreshold: 60, // Score ≥ 60 → agent
// Fallback behavior
fallbackEnabled: true, // Worker → agent on failure
// Retry settings
maxRetries: 3, // Max retry attempts
// Model configs (custom pricing)
workerModel: {
model: 'gpt-4o-mini',
inputCost: 0.150 / 1_000_000,
outputCost: 0.600 / 1_000_000
},
agentModel: {
model: 'gpt-4o',
inputCost: 2.50 / 1_000_000,
outputCost: 10.00 / 1_000_000
}
});Test Mode vs Real Mode
Test Mode (default):
- No GitHub authentication required
- Mocked LLM responses
- Fixed 500 tokens per call
- Great for development/testing
Real Mode:
- Requires GitHub Copilot subscription
- Actual API calls to Copilot SDK
- Real token usage and costs
- Production use
import { CopilotClient } from '@byan/copilot-router';
// Test mode (default)
const testClient = new CopilotClient({ testMode: true });
// Real mode (requires auth)
const realClient = new CopilotClient({ testMode: false });🔧 Troubleshooting
Common Issues
1. "Module not found: @github/copilot-sdk"
# Install dependencies
npm install @github/copilot-sdk2. "Coverage below threshold"
The module has 80% coverage because real SDK mode paths aren't tested (require GitHub auth). This is expected in test mode.
3. "All tasks routed to worker"
Check task scoring:
import { ComplexityAnalyzer } from '@byan/copilot-router';
const analyzer = new ComplexityAnalyzer();
const score = analyzer.calculateComplexity(yourTask);
console.log(score); // See breakdownAdjust thresholds:
router.updateConfig({
workerThreshold: 20, // Lower threshold
agentThreshold: 50 // Lower threshold
});4. "Costs don't match expectations"
In test mode, all calls use fixed 500 tokens. Real costs vary based on actual token usage.
5. "TypeScript compilation errors"
Ensure TypeScript 5.0+:
npm install --save-dev typescript@^5.0.0Debug Mode
// Enable detailed logging
const router = new CopilotRouter({
debug: true // Coming in v1.1.0
});🧪 Development
Setup
# Clone repository
git clone https://github.com/byan/copilot-router.git
cd copilot-router
# Install dependencies
npm install
# Build TypeScript
npm run build
# Run tests
npm testProject Structure
copilot-router/
├── src/
│ ├── types.ts # TypeScript type definitions
│ ├── analyzer.ts # Complexity scoring
│ ├── router.ts # Main routing logic
│ ├── copilot-client.ts # SDK wrapper
│ ├── cost-tracker.ts # Cost tracking
│ └── index.ts # Public exports
├── test/
│ ├── setup.test.ts # Setup validation
│ ├── analyzer.test.ts # Analyzer tests (36)
│ ├── router.test.ts # Router tests (25)
│ ├── copilot-client.test.ts # Client tests (23)
│ ├── cost-tracker.test.ts # Tracker tests (22)
│ └── integration.test.ts # Integration tests (5)
├── dist/ # Compiled JavaScript
├── package.json
├── tsconfig.json
└── README.mdTesting
# Run all tests
npm test
# Run specific test suite
npm test -- analyzer.test.ts
# Watch mode
npm run test:watch
# Coverage report
npm run test:coverage
# Verbose output
npm test -- --verboseTest Stats:
- Total: 115 tests
- Coverage: 80.19%
- All passing ✅
Building
# Build once
npm run build
# Watch mode
npm run build:watch
# Clean build
rm -rf dist && npm run buildContributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests (
npm test) - Commit (
git commit -m 'feat: add amazing feature') - Push (
git push origin feature/amazing-feature) - Open a Pull Request
Commit Convention:
feat:New featurefix:Bug fixdocs:Documentation onlytest:Adding testsrefactor:Code refactoringchore:Maintenance
📈 Roadmap
v1.0.0 (Current - Alpha 5)
- [x] Complexity Analyzer
- [x] Router Logic with Fallback
- [x] SDK Integration (test + real modes)
- [x] Cost Tracking & Reporting
- [x] Documentation
- [ ] Final polish
- [ ] NPM publish
v1.1.0 (Next)
- [ ] Debug mode with detailed logging
- [ ] Streaming response support
- [ ] Custom complexity scoring weights
- [ ] Performance metrics
- [ ] Dashboard UI for cost visualization
v1.2.0 (Future)
- [ ] Worker pool with queue management
- [ ] Context module for session state
- [ ] Multi-model support (Claude, GPT-4, etc.)
- [ ] Advanced retry strategies
- [ ] Rate limiting
📊 Performance
Benchmarks
| Operation | Time | Notes | |-----------|------|-------| | Complexity Analysis | < 1ms | Pure computation | | Route Decision | < 1ms | Score-based logic | | Test Mode Execution | ~10ms | Mocked response | | Real Mode Execution | 500-2000ms | Actual LLM call |
Optimization Tips
- Batch processing: Route multiple tasks in parallel
- Caching: Cache complexity scores for similar tasks
- Threshold tuning: Lower thresholds for more worker usage
- Fallback disabled: Disable if quality is acceptable
- Connection pooling: Reuse router instances
// Good: Parallel processing
await Promise.all(tasks.map(task => router.route(task)));
// Avoid: Sequential processing
for (const task of tasks) {
await router.route(task);
}🧪 Testing
# Run all tests
npm test
# Run specific test suite
npm test -- analyzer.test.ts
# Watch mode
npm run test:watch
# Coverage report
npm run test:coverageTest Coverage:
- 115 tests total (all passing ✅)
- 80.19% code coverage
- 36 analyzer tests
- 25 router tests
- 23 client tests
- 22 tracker tests
- 5 integration tests
- 4 setup tests
📝 License
MIT © BYAN v2
See LICENSE for details.
🙏 Acknowledgments
Built with:
- @github/copilot-sdk - GitHub Copilot CLI SDK
- TypeScript - Type safety
- Jest - Testing framework
Part of the BYAN v2 ecosystem.
📞 Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: [email protected]
🎯 Quick Links
Status: 🟢 Stable v1.0.0
Stability: Production Ready
Released: February 10, 2026
NPM: @byan/copilot-router
Made with ❤️ by BYAN v2 - Builder of YAN
