| |
| |
| |
|
|
| import type { SettingsService } from '../services/settings-service.js'; |
| import type { ContextFilesResult, ContextFileInfo } from '@automaker/utils'; |
| import { createLogger } from '@automaker/utils'; |
| import type { |
| MCPServerConfig, |
| McpServerConfig, |
| PromptCustomization, |
| ClaudeApiProfile, |
| ClaudeCompatibleProvider, |
| PhaseModelKey, |
| PhaseModelEntry, |
| Credentials, |
| } from '@automaker/types'; |
| import { DEFAULT_PHASE_MODELS } from '@automaker/types'; |
| import { |
| mergeAutoModePrompts, |
| mergeAgentPrompts, |
| mergeBacklogPlanPrompts, |
| mergeEnhancementPrompts, |
| mergeCommitMessagePrompts, |
| mergeTitleGenerationPrompts, |
| mergeIssueValidationPrompts, |
| mergeIdeationPrompts, |
| mergeAppSpecPrompts, |
| mergeContextDescriptionPrompts, |
| mergeSuggestionsPrompts, |
| mergeTaskExecutionPrompts, |
| } from '@automaker/prompts'; |
|
|
| const logger = createLogger('SettingsHelper'); |
|
|
| |
| export const DEFAULT_MAX_TURNS = 10000; |
|
|
| |
| export const MAX_ALLOWED_TURNS = 10000; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export async function getAutoLoadClaudeMdSetting( |
| projectPath: string, |
| settingsService?: SettingsService | null, |
| logPrefix = '[SettingsHelper]' |
| ): Promise<boolean> { |
| if (!settingsService) { |
| logger.info(`${logPrefix} SettingsService not available, autoLoadClaudeMd defaulting to true`); |
| return true; |
| } |
|
|
| try { |
| |
| const projectSettings = await settingsService.getProjectSettings(projectPath); |
| if (projectSettings.autoLoadClaudeMd !== undefined) { |
| logger.info( |
| `${logPrefix} autoLoadClaudeMd from project settings: ${projectSettings.autoLoadClaudeMd}` |
| ); |
| return projectSettings.autoLoadClaudeMd; |
| } |
|
|
| |
| const globalSettings = await settingsService.getGlobalSettings(); |
| const result = globalSettings.autoLoadClaudeMd ?? true; |
| logger.info(`${logPrefix} autoLoadClaudeMd from global settings: ${result}`); |
| return result; |
| } catch (error) { |
| logger.error(`${logPrefix} Failed to load autoLoadClaudeMd setting:`, error); |
| throw error; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export async function getUseClaudeCodeSystemPromptSetting( |
| projectPath: string, |
| settingsService?: SettingsService | null, |
| logPrefix = '[SettingsHelper]' |
| ): Promise<boolean> { |
| if (!settingsService) { |
| logger.info( |
| `${logPrefix} SettingsService not available, useClaudeCodeSystemPrompt defaulting to true` |
| ); |
| return true; |
| } |
|
|
| try { |
| |
| const projectSettings = await settingsService.getProjectSettings(projectPath); |
| if (projectSettings.useClaudeCodeSystemPrompt !== undefined) { |
| logger.info( |
| `${logPrefix} useClaudeCodeSystemPrompt from project settings: ${projectSettings.useClaudeCodeSystemPrompt}` |
| ); |
| return projectSettings.useClaudeCodeSystemPrompt; |
| } |
|
|
| |
| const globalSettings = await settingsService.getGlobalSettings(); |
| const result = globalSettings.useClaudeCodeSystemPrompt ?? true; |
| logger.info(`${logPrefix} useClaudeCodeSystemPrompt from global settings: ${result}`); |
| return result; |
| } catch (error) { |
| logger.error(`${logPrefix} Failed to load useClaudeCodeSystemPrompt setting:`, error); |
| throw error; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export async function getDefaultMaxTurnsSetting( |
| settingsService?: SettingsService | null, |
| logPrefix = '[SettingsHelper]' |
| ): Promise<number> { |
| if (!settingsService) { |
| logger.info( |
| `${logPrefix} SettingsService not available, using default maxTurns=${DEFAULT_MAX_TURNS}` |
| ); |
| return DEFAULT_MAX_TURNS; |
| } |
|
|
| try { |
| const globalSettings = await settingsService.getGlobalSettings(); |
| const raw = globalSettings.defaultMaxTurns; |
| const result = Number.isFinite(raw) ? (raw as number) : DEFAULT_MAX_TURNS; |
| |
| const clamped = Math.max(1, Math.min(MAX_ALLOWED_TURNS, Math.floor(result))); |
| logger.debug(`${logPrefix} defaultMaxTurns from global settings: ${clamped}`); |
| return clamped; |
| } catch (error) { |
| logger.error(`${logPrefix} Failed to load defaultMaxTurns setting:`, error); |
| return DEFAULT_MAX_TURNS; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function filterClaudeMdFromContext( |
| contextResult: ContextFilesResult, |
| autoLoadClaudeMd: boolean |
| ): string { |
| |
| if (!autoLoadClaudeMd || contextResult.files.length === 0) { |
| return contextResult.formattedPrompt; |
| } |
|
|
| |
| const nonClaudeFiles = contextResult.files.filter((f) => f.name.toLowerCase() !== 'claude.md'); |
|
|
| |
| if (nonClaudeFiles.length === 0) { |
| return ''; |
| } |
|
|
| |
| const formattedFiles = nonClaudeFiles.map((file) => formatContextFileEntry(file)); |
|
|
| return `# Project Context Files |
| |
| The following context files provide project-specific rules, conventions, and guidelines. |
| Each file serves a specific purpose - use the description to understand when to reference it. |
| If you need more details about a context file, you can read the full file at the path provided. |
| |
| **IMPORTANT**: You MUST follow the rules and conventions specified in these files. |
| - Follow ALL commands exactly as shown (e.g., if the project uses \`pnpm\`, NEVER use \`npm\` or \`npx\`) |
| - Follow ALL coding conventions, commit message formats, and architectural patterns specified |
| - Reference these rules before running ANY shell commands or making commits |
| |
| --- |
| |
| ${formattedFiles.join('\n\n---\n\n')} |
| |
| --- |
| |
| **REMINDER**: Before taking any action, verify you are following the conventions specified above. |
| `; |
| } |
|
|
| |
| |
| |
| |
| function formatContextFileEntry(file: ContextFileInfo): string { |
| const header = `## ${file.name}`; |
| const pathInfo = `**Path:** \`${file.path}\``; |
| const descriptionInfo = file.description ? `\n**Purpose:** ${file.description}` : ''; |
| return `${header}\n${pathInfo}${descriptionInfo}\n\n${file.content}`; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export async function getMCPServersFromSettings( |
| settingsService?: SettingsService | null, |
| logPrefix = '[SettingsHelper]' |
| ): Promise<Record<string, McpServerConfig>> { |
| if (!settingsService) { |
| return {}; |
| } |
|
|
| try { |
| const globalSettings = await settingsService.getGlobalSettings(); |
| const mcpServers = globalSettings.mcpServers || []; |
|
|
| |
| const enabledServers = mcpServers.filter((s) => s.enabled !== false); |
|
|
| if (enabledServers.length === 0) { |
| return {}; |
| } |
|
|
| |
| const sdkServers: Record<string, McpServerConfig> = {}; |
| for (const server of enabledServers) { |
| sdkServers[server.name] = convertToSdkFormat(server); |
| } |
|
|
| logger.info( |
| `${logPrefix} Loaded ${enabledServers.length} MCP server(s): ${enabledServers.map((s) => s.name).join(', ')}` |
| ); |
|
|
| return sdkServers; |
| } catch (error) { |
| logger.error(`${logPrefix} Failed to load MCP servers setting:`, error); |
| return {}; |
| } |
| } |
|
|
| |
| |
| |
| |
| function convertToSdkFormat(server: MCPServerConfig): McpServerConfig { |
| if (server.type === 'sse') { |
| if (!server.url) { |
| throw new Error(`SSE MCP server "${server.name}" is missing a URL.`); |
| } |
| return { |
| type: 'sse', |
| url: server.url, |
| headers: server.headers, |
| }; |
| } |
|
|
| if (server.type === 'http') { |
| if (!server.url) { |
| throw new Error(`HTTP MCP server "${server.name}" is missing a URL.`); |
| } |
| return { |
| type: 'http', |
| url: server.url, |
| headers: server.headers, |
| }; |
| } |
|
|
| |
| if (!server.command) { |
| throw new Error(`Stdio MCP server "${server.name}" is missing a command.`); |
| } |
| return { |
| type: 'stdio', |
| command: server.command, |
| args: server.args, |
| env: server.env, |
| }; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export async function getPromptCustomization( |
| settingsService?: SettingsService | null, |
| logPrefix = '[PromptHelper]' |
| ): Promise<{ |
| autoMode: ReturnType<typeof mergeAutoModePrompts>; |
| agent: ReturnType<typeof mergeAgentPrompts>; |
| backlogPlan: ReturnType<typeof mergeBacklogPlanPrompts>; |
| enhancement: ReturnType<typeof mergeEnhancementPrompts>; |
| commitMessage: ReturnType<typeof mergeCommitMessagePrompts>; |
| titleGeneration: ReturnType<typeof mergeTitleGenerationPrompts>; |
| issueValidation: ReturnType<typeof mergeIssueValidationPrompts>; |
| ideation: ReturnType<typeof mergeIdeationPrompts>; |
| appSpec: ReturnType<typeof mergeAppSpecPrompts>; |
| contextDescription: ReturnType<typeof mergeContextDescriptionPrompts>; |
| suggestions: ReturnType<typeof mergeSuggestionsPrompts>; |
| taskExecution: ReturnType<typeof mergeTaskExecutionPrompts>; |
| }> { |
| let customization: PromptCustomization = {}; |
|
|
| if (settingsService) { |
| try { |
| const globalSettings = await settingsService.getGlobalSettings(); |
| customization = globalSettings.promptCustomization || {}; |
| logger.info(`${logPrefix} Loaded prompt customization from settings`); |
| } catch (error) { |
| logger.error(`${logPrefix} Failed to load prompt customization:`, error); |
| |
| } |
| } else { |
| logger.info(`${logPrefix} SettingsService not available, using default prompts`); |
| } |
|
|
| return { |
| autoMode: mergeAutoModePrompts(customization.autoMode), |
| agent: mergeAgentPrompts(customization.agent), |
| backlogPlan: mergeBacklogPlanPrompts(customization.backlogPlan), |
| enhancement: mergeEnhancementPrompts(customization.enhancement), |
| commitMessage: mergeCommitMessagePrompts(customization.commitMessage), |
| titleGeneration: mergeTitleGenerationPrompts(customization.titleGeneration), |
| issueValidation: mergeIssueValidationPrompts(customization.issueValidation), |
| ideation: mergeIdeationPrompts(customization.ideation), |
| appSpec: mergeAppSpecPrompts(customization.appSpec), |
| contextDescription: mergeContextDescriptionPrompts(customization.contextDescription), |
| suggestions: mergeSuggestionsPrompts(customization.suggestions), |
| taskExecution: mergeTaskExecutionPrompts(customization.taskExecution), |
| }; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export async function getSkillsConfiguration(settingsService: SettingsService): Promise<{ |
| enabled: boolean; |
| sources: Array<'user' | 'project'>; |
| shouldIncludeInTools: boolean; |
| }> { |
| const settings = await settingsService.getGlobalSettings(); |
| const enabled = settings.enableSkills ?? true; |
| const sources = settings.skillsSources ?? ['user', 'project']; |
|
|
| return { |
| enabled, |
| sources, |
| shouldIncludeInTools: enabled && sources.length > 0, |
| }; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export async function getSubagentsConfiguration(settingsService: SettingsService): Promise<{ |
| enabled: boolean; |
| sources: Array<'user' | 'project'>; |
| shouldIncludeInTools: boolean; |
| }> { |
| const settings = await settingsService.getGlobalSettings(); |
| const enabled = settings.enableSubagents ?? true; |
| const sources = settings.subagentsSources ?? ['user', 'project']; |
|
|
| return { |
| enabled, |
| sources, |
| shouldIncludeInTools: enabled && sources.length > 0, |
| }; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export async function getCustomSubagents( |
| settingsService: SettingsService, |
| projectPath?: string |
| ): Promise<Record<string, import('@automaker/types').AgentDefinition> | undefined> { |
| |
| const globalSettings = await settingsService.getGlobalSettings(); |
| const globalSubagents = globalSettings.customSubagents || {}; |
|
|
| |
| if (!projectPath) { |
| return Object.keys(globalSubagents).length > 0 ? globalSubagents : undefined; |
| } |
|
|
| |
| const projectSettings = await settingsService.getProjectSettings(projectPath); |
| const projectSubagents = projectSettings.customSubagents || {}; |
|
|
| |
| const merged = { |
| ...globalSubagents, |
| ...projectSubagents, |
| }; |
|
|
| return Object.keys(merged).length > 0 ? merged : undefined; |
| } |
|
|
| |
| export interface ActiveClaudeApiProfileResult { |
| |
| profile: ClaudeApiProfile | undefined; |
| |
| credentials: import('@automaker/types').Credentials | undefined; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export async function getActiveClaudeApiProfile( |
| settingsService?: SettingsService | null, |
| logPrefix = '[SettingsHelper]', |
| projectPath?: string |
| ): Promise<ActiveClaudeApiProfileResult> { |
| if (!settingsService) { |
| return { profile: undefined, credentials: undefined }; |
| } |
|
|
| try { |
| const globalSettings = await settingsService.getGlobalSettings(); |
| const credentials = await settingsService.getCredentials(); |
| const profiles = globalSettings.claudeApiProfiles || []; |
|
|
| |
| let activeProfileId: string | null | undefined; |
| let isProjectOverride = false; |
|
|
| if (projectPath) { |
| const projectSettings = await settingsService.getProjectSettings(projectPath); |
| |
| if (projectSettings.activeClaudeApiProfileId !== undefined) { |
| activeProfileId = projectSettings.activeClaudeApiProfileId; |
| isProjectOverride = true; |
| } |
| } |
|
|
| |
| if (activeProfileId === undefined && !isProjectOverride) { |
| activeProfileId = globalSettings.activeClaudeApiProfileId; |
| } |
|
|
| |
| if (!activeProfileId) { |
| if (isProjectOverride && activeProfileId === null) { |
| logger.info(`${logPrefix} Project explicitly using Direct Anthropic API`); |
| } |
| return { profile: undefined, credentials }; |
| } |
|
|
| |
| const activeProfile = profiles.find((p) => p.id === activeProfileId); |
|
|
| if (activeProfile) { |
| const overrideSuffix = isProjectOverride ? ' (project override)' : ''; |
| logger.info(`${logPrefix} Using Claude API profile: ${activeProfile.name}${overrideSuffix}`); |
| return { profile: activeProfile, credentials }; |
| } else { |
| logger.warn( |
| `${logPrefix} Active profile ID "${activeProfileId}" not found, falling back to direct Anthropic API` |
| ); |
| return { profile: undefined, credentials }; |
| } |
| } catch (error) { |
| logger.error(`${logPrefix} Failed to load Claude API profile:`, error); |
| return { profile: undefined, credentials: undefined }; |
| } |
| } |
|
|
| |
| |
| |
|
|
| |
| export interface ProviderByIdResult { |
| |
| provider: ClaudeCompatibleProvider | undefined; |
| |
| credentials: Credentials | undefined; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export async function getProviderById( |
| providerId: string, |
| settingsService: SettingsService, |
| logPrefix = '[SettingsHelper]' |
| ): Promise<ProviderByIdResult> { |
| try { |
| const globalSettings = await settingsService.getGlobalSettings(); |
| const credentials = await settingsService.getCredentials(); |
| const providers = globalSettings.claudeCompatibleProviders || []; |
|
|
| const provider = providers.find((p) => p.id === providerId); |
|
|
| if (provider) { |
| if (provider.enabled === false) { |
| logger.warn(`${logPrefix} Provider "${provider.name}" (${providerId}) is disabled`); |
| } else { |
| logger.debug(`${logPrefix} Found provider: ${provider.name}`); |
| } |
| return { provider, credentials }; |
| } else { |
| logger.warn(`${logPrefix} Provider not found: ${providerId}`); |
| return { provider: undefined, credentials }; |
| } |
| } catch (error) { |
| logger.error(`${logPrefix} Failed to load provider by ID:`, error); |
| return { provider: undefined, credentials: undefined }; |
| } |
| } |
|
|
| |
| export interface PhaseModelWithOverridesResult { |
| |
| phaseModel: PhaseModelEntry; |
| |
| isProjectOverride: boolean; |
| |
| provider: ClaudeCompatibleProvider | undefined; |
| |
| credentials: Credentials | undefined; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export async function getPhaseModelWithOverrides( |
| phase: PhaseModelKey, |
| settingsService?: SettingsService | null, |
| projectPath?: string, |
| logPrefix = '[SettingsHelper]' |
| ): Promise<PhaseModelWithOverridesResult> { |
| |
| if (!settingsService) { |
| logger.info(`${logPrefix} SettingsService not available, using default for ${phase}`); |
| return { |
| phaseModel: DEFAULT_PHASE_MODELS[phase] || { model: 'sonnet' }, |
| isProjectOverride: false, |
| provider: undefined, |
| credentials: undefined, |
| }; |
| } |
|
|
| try { |
| const globalSettings = await settingsService.getGlobalSettings(); |
| const credentials = await settingsService.getCredentials(); |
| const globalPhaseModels = globalSettings.phaseModels || {}; |
|
|
| |
| let phaseModel = globalPhaseModels[phase]; |
| let isProjectOverride = false; |
|
|
| |
| if (projectPath) { |
| const projectSettings = await settingsService.getProjectSettings(projectPath); |
| const projectOverrides = projectSettings.phaseModelOverrides || {}; |
|
|
| if (projectOverrides[phase]) { |
| phaseModel = projectOverrides[phase]; |
| isProjectOverride = true; |
| logger.debug(`${logPrefix} Using project override for ${phase}`); |
| } |
| } |
|
|
| |
| if (!phaseModel) { |
| phaseModel = DEFAULT_PHASE_MODELS[phase] || { model: 'sonnet' }; |
| logger.debug(`${logPrefix} No ${phase} configured, using default: ${phaseModel.model}`); |
| } |
|
|
| |
| let provider: ClaudeCompatibleProvider | undefined; |
| if (phaseModel.providerId) { |
| const providers = globalSettings.claudeCompatibleProviders || []; |
| provider = providers.find((p) => p.id === phaseModel.providerId); |
|
|
| if (provider) { |
| if (provider.enabled === false) { |
| logger.warn( |
| `${logPrefix} Provider "${provider.name}" for ${phase} is disabled, falling back to direct API` |
| ); |
| provider = undefined; |
| } else { |
| logger.debug(`${logPrefix} Using provider "${provider.name}" for ${phase}`); |
| } |
| } else { |
| logger.warn( |
| `${logPrefix} Provider ${phaseModel.providerId} not found for ${phase}, falling back to direct API` |
| ); |
| } |
| } |
|
|
| return { |
| phaseModel, |
| isProjectOverride, |
| provider, |
| credentials, |
| }; |
| } catch (error) { |
| logger.error(`${logPrefix} Failed to get phase model with overrides:`, error); |
| |
| return { |
| phaseModel: { model: 'sonnet' }, |
| isProjectOverride: false, |
| provider: undefined, |
| credentials: undefined, |
| }; |
| } |
| } |
|
|
| |
| export interface ProviderByModelIdResult { |
| |
| provider: ClaudeCompatibleProvider | undefined; |
| |
| modelConfig: import('@automaker/types').ProviderModel | undefined; |
| |
| credentials: Credentials | undefined; |
| |
| resolvedModel: string | undefined; |
| } |
|
|
| |
| export interface ProviderContextResult { |
| |
| provider: ClaudeCompatibleProvider | undefined; |
| |
| credentials: Credentials | undefined; |
| |
| resolvedModel: string | undefined; |
| |
| modelConfig: import('@automaker/types').ProviderModel | undefined; |
| } |
|
|
| |
| |
| |
| |
| |
| function isProviderEnabled(provider: ClaudeCompatibleProvider): boolean { |
| return provider.enabled !== false; |
| } |
|
|
| |
| |
| |
| function findModelInProvider( |
| provider: ClaudeCompatibleProvider, |
| modelId: string |
| ): import('@automaker/types').ProviderModel | undefined { |
| return provider.models?.find( |
| (m) => m.id === modelId || m.id.toLowerCase() === modelId.toLowerCase() |
| ); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export async function resolveProviderContext( |
| settingsService: SettingsService, |
| modelId: string, |
| providerId?: string, |
| logPrefix = '[SettingsHelper]' |
| ): Promise<ProviderContextResult> { |
| try { |
| const globalSettings = await settingsService.getGlobalSettings(); |
| const credentials = await settingsService.getCredentials(); |
| const providers = globalSettings.claudeCompatibleProviders || []; |
|
|
| logger.debug( |
| `${logPrefix} Resolving provider context: modelId="${modelId}", providerId="${providerId ?? 'none'}", providers count=${providers.length}` |
| ); |
|
|
| let provider: ClaudeCompatibleProvider | undefined; |
| let modelConfig: import('@automaker/types').ProviderModel | undefined; |
|
|
| |
| if (providerId) { |
| provider = providers.find((p) => p.id === providerId); |
| if (provider) { |
| if (!isProviderEnabled(provider)) { |
| logger.warn( |
| `${logPrefix} Explicitly requested provider "${provider.name}" (${providerId}) is disabled (enabled=${provider.enabled})` |
| ); |
| } else { |
| logger.debug( |
| `${logPrefix} Found provider "${provider.name}" (${providerId}), enabled=${provider.enabled ?? 'undefined (treated as enabled)'}` |
| ); |
| |
| modelConfig = findModelInProvider(provider, modelId); |
| if (!modelConfig && provider.models && provider.models.length > 0) { |
| logger.debug( |
| `${logPrefix} Model "${modelId}" not found in provider "${provider.name}". Available models: ${provider.models.map((m) => m.id).join(', ')}` |
| ); |
| } |
| } |
| } else { |
| logger.warn( |
| `${logPrefix} Explicitly requested provider "${providerId}" not found. Available providers: ${providers.map((p) => p.id).join(', ')}` |
| ); |
| } |
| } |
|
|
| |
| |
| if (!modelConfig) { |
| for (const p of providers) { |
| if (!isProviderEnabled(p) || p.id === providerId) continue; |
|
|
| const config = findModelInProvider(p, modelId); |
|
|
| if (config) { |
| |
| if (!provider) { |
| provider = p; |
| } |
| modelConfig = config; |
| logger.debug(`${logPrefix} Found model "${modelId}" in provider "${p.name}" (fallback)`); |
| break; |
| } |
| } |
| } |
|
|
| |
| let resolvedModel: string | undefined; |
| if (modelConfig?.mapsToClaudeModel) { |
| const { resolveModelString } = await import('@automaker/model-resolver'); |
| resolvedModel = resolveModelString(modelConfig.mapsToClaudeModel); |
| logger.debug( |
| `${logPrefix} Model "${modelId}" maps to Claude model "${modelConfig.mapsToClaudeModel}" -> "${resolvedModel}"` |
| ); |
| } |
|
|
| |
| logger.debug( |
| `${logPrefix} Provider context resolved: provider=${provider?.name ?? 'none'}, modelConfig=${modelConfig ? 'found' : 'not found'}, resolvedModel=${resolvedModel ?? modelId}` |
| ); |
|
|
| return { provider, credentials, resolvedModel, modelConfig }; |
| } catch (error) { |
| logger.error(`${logPrefix} Failed to resolve provider context:`, error); |
| return { |
| provider: undefined, |
| credentials: undefined, |
| resolvedModel: undefined, |
| modelConfig: undefined, |
| }; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export async function getProviderByModelId( |
| modelId: string, |
| settingsService: SettingsService, |
| logPrefix = '[SettingsHelper]' |
| ): Promise<ProviderByModelIdResult> { |
| try { |
| const globalSettings = await settingsService.getGlobalSettings(); |
| const credentials = await settingsService.getCredentials(); |
| const providers = globalSettings.claudeCompatibleProviders || []; |
|
|
| |
| for (const provider of providers) { |
| |
| if (provider.enabled === false) { |
| continue; |
| } |
|
|
| |
| const modelConfig = provider.models?.find( |
| (m) => m.id === modelId || m.id.toLowerCase() === modelId.toLowerCase() |
| ); |
|
|
| if (modelConfig) { |
| logger.info(`${logPrefix} Found model "${modelId}" in provider "${provider.name}"`); |
|
|
| |
| let resolvedModel: string | undefined; |
| if (modelConfig.mapsToClaudeModel) { |
| |
| const { resolveModelString } = await import('@automaker/model-resolver'); |
| resolvedModel = resolveModelString(modelConfig.mapsToClaudeModel); |
| logger.info( |
| `${logPrefix} Model "${modelId}" maps to Claude model "${modelConfig.mapsToClaudeModel}" -> "${resolvedModel}"` |
| ); |
| } |
|
|
| return { provider, modelConfig, credentials, resolvedModel }; |
| } |
| } |
|
|
| |
| logger.debug(`${logPrefix} Model "${modelId}" not found in any provider`); |
| return { |
| provider: undefined, |
| modelConfig: undefined, |
| credentials: undefined, |
| resolvedModel: undefined, |
| }; |
| } catch (error) { |
| logger.error(`${logPrefix} Failed to find provider by model ID:`, error); |
| return { |
| provider: undefined, |
| modelConfig: undefined, |
| credentials: undefined, |
| resolvedModel: undefined, |
| }; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export async function getAllProviderModels( |
| settingsService: SettingsService, |
| logPrefix = '[SettingsHelper]' |
| ): Promise< |
| Array<{ |
| providerId: string; |
| providerName: string; |
| model: import('@automaker/types').ProviderModel; |
| }> |
| > { |
| try { |
| const globalSettings = await settingsService.getGlobalSettings(); |
| const providers = globalSettings.claudeCompatibleProviders || []; |
|
|
| const allModels: Array<{ |
| providerId: string; |
| providerName: string; |
| model: import('@automaker/types').ProviderModel; |
| }> = []; |
|
|
| for (const provider of providers) { |
| |
| if (provider.enabled === false) { |
| continue; |
| } |
|
|
| for (const model of provider.models || []) { |
| allModels.push({ |
| providerId: provider.id, |
| providerName: provider.name, |
| model, |
| }); |
| } |
| } |
|
|
| logger.debug( |
| `${logPrefix} Found ${allModels.length} models from ${providers.length} providers` |
| ); |
| return allModels; |
| } catch (error) { |
| logger.error(`${logPrefix} Failed to get all provider models:`, error); |
| return []; |
| } |
| } |
|
|