capsule-ai-cli
Version:
The AI Model Orchestrator - Intelligent multi-model workflows with device-locked licensing
223 lines • 8.58 kB
JavaScript
import { configManager } from '../core/config.js';
import { openRouterModelsService } from './openrouter-models.js';
import { localModelsService } from './local-models.js';
export class StateService {
state;
DEFAULT_STATE = {
currentModel: 'openai/gpt-4o',
currentProvider: 'openai',
currentMode: 'agent',
commandHistory: [],
historyIndex: -1,
maxHistorySize: 100,
licenseStatus: undefined
};
constructor() {
this.state = this.loadState();
}
loadState() {
const config = configManager.getConfig();
const savedState = config.state || {};
let mode = savedState.currentMode || this.DEFAULT_STATE.currentMode;
if (mode === 'chat')
mode = 'agent';
if (mode === 'fusion')
mode = 'orchestrator';
return {
...this.DEFAULT_STATE,
currentModel: savedState.currentModel || config.providers[savedState.currentProvider || 'openai']?.defaultModel || this.DEFAULT_STATE.currentModel,
currentProvider: savedState.currentProvider || config.defaultProvider || this.DEFAULT_STATE.currentProvider,
currentMode: mode,
commandHistory: savedState.commandHistory || [],
historyIndex: -1
};
}
saveState() {
const { historyIndex, ...stateToSave } = this.state;
configManager.setConfig('state', stateToSave);
}
setModel(model) {
this.state.currentModel = model;
this.saveState();
}
getModel() {
return this.state.currentModel;
}
setProvider(provider) {
this.state.currentProvider = provider;
const models = this.getAvailableModelsSync(provider);
if (models.length > 0) {
this.state.currentModel = models[0];
}
this.saveState();
}
getProvider() {
return this.state.currentProvider;
}
setMode(mode) {
this.state.currentMode = mode;
if (!openRouterModelsService.isModelAvailable(this.state.currentModel, mode)) {
const models = this.getAvailableModelsSync(this.state.currentProvider);
if (models.length > 0) {
this.state.currentModel = models[0];
}
}
this.saveState();
}
getMode() {
return this.state.currentMode;
}
setLicenseStatus(status) {
this.state.licenseStatus = status;
}
getLicenseStatus() {
return this.state.licenseStatus;
}
addToHistory(command) {
if (this.state.commandHistory.length > 0 &&
this.state.commandHistory[this.state.commandHistory.length - 1] === command) {
return;
}
this.state.commandHistory.push(command);
if (this.state.commandHistory.length > this.state.maxHistorySize) {
this.state.commandHistory = this.state.commandHistory.slice(-this.state.maxHistorySize);
}
this.state.historyIndex = -1;
this.saveState();
}
getPreviousCommand() {
if (this.state.commandHistory.length === 0)
return null;
if (this.state.historyIndex === -1) {
this.state.historyIndex = this.state.commandHistory.length - 1;
}
else if (this.state.historyIndex > 0) {
this.state.historyIndex--;
}
return this.state.commandHistory[this.state.historyIndex];
}
getNextCommand() {
if (this.state.commandHistory.length === 0)
return null;
if (this.state.historyIndex === -1)
return null;
if (this.state.historyIndex < this.state.commandHistory.length - 1) {
this.state.historyIndex++;
return this.state.commandHistory[this.state.historyIndex];
}
else {
this.state.historyIndex = -1;
return '';
}
}
getHistory() {
return [...this.state.commandHistory];
}
clearHistory() {
this.state.commandHistory = [];
this.state.historyIndex = -1;
this.saveState();
}
async getAvailableModels(provider) {
if (['local', 'ollama', 'lmstudio', 'llamacpp'].includes(provider)) {
return localModelsService.getAvailableModels();
}
try {
await openRouterModelsService.fetchModels(false, true);
const models = openRouterModelsService.getModelsByProvider(provider);
return models.map(m => m.id);
}
catch (error) {
console.error('Failed to fetch models:', error);
const fallbackModels = {
openai: ['openai/gpt-4o', 'openai/gpt-4o-mini'],
anthropic: ['anthropic/claude-opus-4', 'anthropic/claude-sonnet-4'],
google: ['google/gemini-2.5-pro', 'google/gemini-2.5-flash'],
xai: ['x-ai/grok-4'],
deepseek: ['deepseek/deepseek-chat-v3-0324', 'deepseek/deepseek-r1-0528:free'],
moonshot: ['moonshotai/kimi-k2']
};
return fallbackModels[provider] || [];
}
}
getAvailableModelsSync(provider) {
if (['local', 'ollama', 'lmstudio', 'llamacpp'].includes(provider)) {
return localModelsService.getAvailableModels();
}
const models = openRouterModelsService.getModelsByProvider(provider);
if (models.length > 0) {
return models.map(m => m.id);
}
const fallbackModels = {
openai: ['openai/gpt-4o', 'openai/gpt-4o-mini'],
anthropic: ['anthropic/claude-opus-4', 'anthropic/claude-sonnet-4'],
google: ['google/gemini-2.5-pro', 'google/gemini-2.5-flash'],
xai: ['x-ai/grok-4'],
deepseek: ['deepseek/deepseek-chat-v3-0324', 'deepseek/deepseek-r1-0528:free'],
moonshot: ['moonshotai/kimi-k2']
};
return fallbackModels[provider] || [];
}
async getAvailableProviders() {
const providers = [];
if (await localModelsService.isAnyServerAvailable()) {
const serverStatus = localModelsService.getServerStatus();
for (const server of serverStatus) {
if (server.available) {
if (server.name === 'Ollama')
providers.push('ollama');
else if (server.name === 'LM Studio')
providers.push('lmstudio');
else if (server.name === 'llama.cpp')
providers.push('llamacpp');
}
}
if (providers.length > 0 && !providers.includes('local')) {
providers.unshift('local');
}
}
const config = configManager.getConfig();
if (config.providers.openrouter?.apiKey) {
try {
await openRouterModelsService.fetchModels();
const openRouterProviders = openRouterModelsService.getAvailableProviders();
providers.push(...openRouterProviders);
}
catch (error) {
console.error('Failed to fetch providers:', error);
providers.push('openai', 'anthropic', 'google', 'xai', 'deepseek', 'moonshot');
}
}
return [...new Set(providers)];
}
getAvailableProvidersSync() {
const providers = [];
const serverStatus = localModelsService.getServerStatus();
for (const server of serverStatus) {
if (server.available) {
if (server.name === 'Ollama')
providers.push('ollama');
else if (server.name === 'LM Studio')
providers.push('lmstudio');
else if (server.name === 'llama.cpp')
providers.push('llamacpp');
}
}
if (providers.length > 0 && !providers.includes('local')) {
providers.unshift('local');
}
const config = configManager.getConfig();
if (config.providers.openrouter?.apiKey) {
const openRouterProviders = openRouterModelsService.getAvailableProviders();
if (openRouterProviders.length > 0) {
providers.push(...openRouterProviders);
}
else {
providers.push('openai', 'anthropic', 'google', 'xai', 'deepseek', 'moonshot');
}
}
return [...new Set(providers)];
}
}
export const stateService = new StateService();
//# sourceMappingURL=state.js.map