@sirmrmarty/n8n-nodes-tmux-orchestrator
Version:
n8n nodes for orchestrating Claude AI agents through tmux sessions
171 lines (147 loc) • 4.7 kB
text/typescript
/**
* Dynamic Claude Model Manager
* Provides up-to-date Claude model options with fallback to static list
*/
export interface ClaudeModel {
name: string;
value: string;
description?: string;
isRecommended?: boolean;
}
export interface ModelManagerConfig {
includeDeprecated?: boolean;
includeExperimental?: boolean;
cacheDuration?: number; // in minutes
}
export class ModelManager {
private static instance: ModelManager;
private cachedModels: ClaudeModel[] | null = null;
private lastFetch: Date | null = null;
private readonly cacheDuration: number;
// Claude Code available models - simplified list
private readonly knownModels: ClaudeModel[] = [
{
name: 'Sonnet (Latest)',
value: 'sonnet',
description: 'Latest Sonnet model',
isRecommended: true,
},
{
name: 'Opus (Latest)',
value: 'opus',
description: 'Latest Opus model',
isRecommended: true,
},
];
private readonly legacyModels: ClaudeModel[] = [];
private constructor(config: ModelManagerConfig = {}) {
this.cacheDuration = config.cacheDuration || 60; // 1 hour default
}
public static getInstance(config?: ModelManagerConfig): ModelManager {
if (!ModelManager.instance) {
ModelManager.instance = new ModelManager(config);
}
return ModelManager.instance;
}
/**
* Get all available Claude models
*/
public async getAvailableModels(config: ModelManagerConfig = {}): Promise<ClaudeModel[]> {
// Check cache first
if (this.isCacheValid()) {
return this.cachedModels!;
}
try {
// Try to fetch latest models (placeholder for future API integration)
const models = await this.fetchLatestModels(config);
this.cachedModels = models;
this.lastFetch = new Date();
return models;
} catch (error) {
console.warn('Failed to fetch latest models, using known models:', error.message);
// Fallback to known models
return this.getKnownModels(config);
}
}
/**
* Get models for n8n node options format
*/
public async getModelOptions(config: ModelManagerConfig = {}): Promise<Array<{ name: string; value: string }>> {
const models = await this.getAvailableModels(config);
return models.map(model => ({
name: model.name,
value: model.value,
}));
}
/**
* Validate if a model is available
*/
public async isValidModel(modelValue: string): Promise<boolean> {
const models = await this.getAvailableModels();
return models.some(model => model.value === modelValue);
}
/**
* Get recommended model
*/
public async getRecommendedModel(): Promise<ClaudeModel> {
const models = await this.getAvailableModels();
const recommended = models.find(model => model.isRecommended);
return recommended || models[0]; // Fallback to first model
}
/**
* Get model by value
*/
public async getModelByValue(value: string): Promise<ClaudeModel | null> {
const models = await this.getAvailableModels();
return models.find(model => model.value === value) || null;
}
private isCacheValid(): boolean {
if (!this.cachedModels || !this.lastFetch) {
return false;
}
const now = new Date();
const diffInMinutes = (now.getTime() - this.lastFetch.getTime()) / (1000 * 60);
return diffInMinutes < this.cacheDuration;
}
private async fetchLatestModels(config: ModelManagerConfig): Promise<ClaudeModel[]> {
// Future implementation: Could fetch from Anthropic API or configuration service
// For now, simulate API call and return known models
await new Promise(resolve => setTimeout(resolve, 100)); // Simulate network call
// This would be replaced with actual API call in the future
return this.getKnownModels(config);
}
private getKnownModels(config: ModelManagerConfig = {}): ClaudeModel[] {
let models = [...this.knownModels];
// Add legacy models if requested
if (config.includeDeprecated !== false) {
models = [...models, ...this.legacyModels];
}
// Sort by recommendation and then by name
models.sort((a, b) => {
if (a.isRecommended && !b.isRecommended) return -1;
if (!a.isRecommended && b.isRecommended) return 1;
return a.name.localeCompare(b.name);
});
return models;
}
/**
* Clear cache and force refresh on next request
*/
public clearCache(): void {
this.cachedModels = null;
this.lastFetch = null;
}
/**
* Get Claude Command Options string for the given model
*/
public getClaudeCommandOptions(model: string): string {
// Map model values to Claude CLI options
const modelMappings: Record<string, string> = {
'sonnet': '--model sonnet',
'opus': '--model opus',
};
return modelMappings[model] || `--model ${model}`;
}
}
// Export singleton instance
export const modelManager = ModelManager.getInstance();