@shareai-lab/kode 1.1.13 → 1.1.16-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entrypoints/cli.js +59 -38
- package/dist/entrypoints/cli.js.map +3 -3
- package/dist/index.js +5 -26
- package/dist/package.json +4 -1
- package/package.json +11 -104
- package/dist/test/testAdapters.js +0 -88
- package/dist/test/testAdapters.js.map +0 -1
- package/src/ProjectOnboarding.tsx +0 -198
- package/src/Tool.ts +0 -83
- package/src/commands/agents.tsx +0 -3416
- package/src/commands/approvedTools.ts +0 -53
- package/src/commands/bug.tsx +0 -20
- package/src/commands/clear.ts +0 -43
- package/src/commands/compact.ts +0 -120
- package/src/commands/config.tsx +0 -19
- package/src/commands/cost.ts +0 -18
- package/src/commands/ctx_viz.ts +0 -209
- package/src/commands/doctor.ts +0 -24
- package/src/commands/help.tsx +0 -19
- package/src/commands/init.ts +0 -37
- package/src/commands/listen.ts +0 -42
- package/src/commands/login.tsx +0 -51
- package/src/commands/logout.tsx +0 -40
- package/src/commands/mcp.ts +0 -41
- package/src/commands/model.tsx +0 -40
- package/src/commands/modelstatus.tsx +0 -20
- package/src/commands/onboarding.tsx +0 -34
- package/src/commands/pr_comments.ts +0 -59
- package/src/commands/refreshCommands.ts +0 -54
- package/src/commands/release-notes.ts +0 -34
- package/src/commands/resume.tsx +0 -31
- package/src/commands/review.ts +0 -49
- package/src/commands/terminalSetup.ts +0 -221
- package/src/commands.ts +0 -139
- package/src/components/ApproveApiKey.tsx +0 -93
- package/src/components/AsciiLogo.tsx +0 -13
- package/src/components/AutoUpdater.tsx +0 -148
- package/src/components/Bug.tsx +0 -367
- package/src/components/Config.tsx +0 -293
- package/src/components/ConsoleOAuthFlow.tsx +0 -327
- package/src/components/Cost.tsx +0 -23
- package/src/components/CostThresholdDialog.tsx +0 -46
- package/src/components/CustomSelect/option-map.ts +0 -42
- package/src/components/CustomSelect/select-option.tsx +0 -78
- package/src/components/CustomSelect/select.tsx +0 -152
- package/src/components/CustomSelect/theme.ts +0 -45
- package/src/components/CustomSelect/use-select-state.ts +0 -414
- package/src/components/CustomSelect/use-select.ts +0 -35
- package/src/components/FallbackToolUseRejectedMessage.tsx +0 -15
- package/src/components/FileEditToolUpdatedMessage.tsx +0 -66
- package/src/components/Help.tsx +0 -215
- package/src/components/HighlightedCode.tsx +0 -33
- package/src/components/InvalidConfigDialog.tsx +0 -113
- package/src/components/Link.tsx +0 -32
- package/src/components/LogSelector.tsx +0 -86
- package/src/components/Logo.tsx +0 -170
- package/src/components/MCPServerApprovalDialog.tsx +0 -100
- package/src/components/MCPServerDialogCopy.tsx +0 -25
- package/src/components/MCPServerMultiselectDialog.tsx +0 -109
- package/src/components/Message.tsx +0 -221
- package/src/components/MessageResponse.tsx +0 -15
- package/src/components/MessageSelector.tsx +0 -211
- package/src/components/ModeIndicator.tsx +0 -88
- package/src/components/ModelConfig.tsx +0 -301
- package/src/components/ModelListManager.tsx +0 -227
- package/src/components/ModelSelector.tsx +0 -3387
- package/src/components/ModelStatusDisplay.tsx +0 -230
- package/src/components/Onboarding.tsx +0 -274
- package/src/components/PressEnterToContinue.tsx +0 -11
- package/src/components/PromptInput.tsx +0 -760
- package/src/components/SentryErrorBoundary.ts +0 -39
- package/src/components/Spinner.tsx +0 -129
- package/src/components/StickerRequestForm.tsx +0 -16
- package/src/components/StructuredDiff.tsx +0 -191
- package/src/components/TextInput.tsx +0 -259
- package/src/components/TodoItem.tsx +0 -47
- package/src/components/TokenWarning.tsx +0 -31
- package/src/components/ToolUseLoader.tsx +0 -40
- package/src/components/TrustDialog.tsx +0 -106
- package/src/components/binary-feedback/BinaryFeedback.tsx +0 -63
- package/src/components/binary-feedback/BinaryFeedbackOption.tsx +0 -111
- package/src/components/binary-feedback/BinaryFeedbackView.tsx +0 -172
- package/src/components/binary-feedback/utils.ts +0 -220
- package/src/components/messages/AssistantBashOutputMessage.tsx +0 -22
- package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +0 -49
- package/src/components/messages/AssistantRedactedThinkingMessage.tsx +0 -19
- package/src/components/messages/AssistantTextMessage.tsx +0 -144
- package/src/components/messages/AssistantThinkingMessage.tsx +0 -40
- package/src/components/messages/AssistantToolUseMessage.tsx +0 -132
- package/src/components/messages/TaskProgressMessage.tsx +0 -32
- package/src/components/messages/TaskToolMessage.tsx +0 -58
- package/src/components/messages/UserBashInputMessage.tsx +0 -28
- package/src/components/messages/UserCommandMessage.tsx +0 -30
- package/src/components/messages/UserKodingInputMessage.tsx +0 -28
- package/src/components/messages/UserPromptMessage.tsx +0 -35
- package/src/components/messages/UserTextMessage.tsx +0 -39
- package/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx +0 -12
- package/src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx +0 -36
- package/src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx +0 -31
- package/src/components/messages/UserToolResultMessage/UserToolResultMessage.tsx +0 -57
- package/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx +0 -35
- package/src/components/messages/UserToolResultMessage/utils.tsx +0 -56
- package/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +0 -121
- package/src/components/permissions/FallbackPermissionRequest.tsx +0 -153
- package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +0 -182
- package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +0 -77
- package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +0 -164
- package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +0 -83
- package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +0 -240
- package/src/components/permissions/PermissionRequest.tsx +0 -101
- package/src/components/permissions/PermissionRequestTitle.tsx +0 -69
- package/src/components/permissions/hooks.ts +0 -44
- package/src/components/permissions/toolUseOptions.ts +0 -59
- package/src/components/permissions/utils.ts +0 -23
- package/src/constants/betas.ts +0 -5
- package/src/constants/claude-asterisk-ascii-art.tsx +0 -238
- package/src/constants/figures.ts +0 -4
- package/src/constants/keys.ts +0 -3
- package/src/constants/macros.ts +0 -11
- package/src/constants/modelCapabilities.ts +0 -179
- package/src/constants/models.ts +0 -1025
- package/src/constants/oauth.ts +0 -18
- package/src/constants/product.ts +0 -17
- package/src/constants/prompts.ts +0 -168
- package/src/constants/releaseNotes.ts +0 -7
- package/src/context/PermissionContext.tsx +0 -149
- package/src/context.ts +0 -278
- package/src/cost-tracker.ts +0 -84
- package/src/entrypoints/cli.tsx +0 -1561
- package/src/entrypoints/mcp.ts +0 -175
- package/src/history.ts +0 -25
- package/src/hooks/useApiKeyVerification.ts +0 -59
- package/src/hooks/useArrowKeyHistory.ts +0 -55
- package/src/hooks/useCanUseTool.ts +0 -138
- package/src/hooks/useCancelRequest.ts +0 -39
- package/src/hooks/useDoublePress.ts +0 -41
- package/src/hooks/useExitOnCtrlCD.ts +0 -31
- package/src/hooks/useInterval.ts +0 -25
- package/src/hooks/useLogMessages.ts +0 -16
- package/src/hooks/useLogStartupTime.ts +0 -12
- package/src/hooks/useNotifyAfterTimeout.ts +0 -65
- package/src/hooks/usePermissionRequestLogging.ts +0 -44
- package/src/hooks/useTerminalSize.ts +0 -49
- package/src/hooks/useTextInput.ts +0 -317
- package/src/hooks/useUnifiedCompletion.ts +0 -1405
- package/src/index.ts +0 -34
- package/src/messages.ts +0 -38
- package/src/permissions.ts +0 -268
- package/src/query.ts +0 -720
- package/src/screens/ConfigureNpmPrefix.tsx +0 -197
- package/src/screens/Doctor.tsx +0 -219
- package/src/screens/LogList.tsx +0 -68
- package/src/screens/REPL.tsx +0 -813
- package/src/screens/ResumeConversation.tsx +0 -68
- package/src/services/adapters/base.ts +0 -38
- package/src/services/adapters/chatCompletions.ts +0 -90
- package/src/services/adapters/responsesAPI.ts +0 -170
- package/src/services/browserMocks.ts +0 -66
- package/src/services/claude.ts +0 -2197
- package/src/services/customCommands.ts +0 -704
- package/src/services/fileFreshness.ts +0 -377
- package/src/services/gpt5ConnectionTest.ts +0 -340
- package/src/services/mcpClient.ts +0 -564
- package/src/services/mcpServerApproval.tsx +0 -50
- package/src/services/mentionProcessor.ts +0 -273
- package/src/services/modelAdapterFactory.ts +0 -69
- package/src/services/notifier.ts +0 -40
- package/src/services/oauth.ts +0 -357
- package/src/services/openai.ts +0 -1359
- package/src/services/responseStateManager.ts +0 -90
- package/src/services/sentry.ts +0 -3
- package/src/services/statsig.ts +0 -172
- package/src/services/statsigStorage.ts +0 -86
- package/src/services/systemReminder.ts +0 -507
- package/src/services/vcr.ts +0 -161
- package/src/test/testAdapters.ts +0 -96
- package/src/tools/ArchitectTool/ArchitectTool.tsx +0 -135
- package/src/tools/ArchitectTool/prompt.ts +0 -15
- package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +0 -576
- package/src/tools/BashTool/BashTool.tsx +0 -243
- package/src/tools/BashTool/BashToolResultMessage.tsx +0 -38
- package/src/tools/BashTool/OutputLine.tsx +0 -49
- package/src/tools/BashTool/prompt.ts +0 -174
- package/src/tools/BashTool/utils.ts +0 -56
- package/src/tools/FileEditTool/FileEditTool.tsx +0 -319
- package/src/tools/FileEditTool/prompt.ts +0 -51
- package/src/tools/FileEditTool/utils.ts +0 -58
- package/src/tools/FileReadTool/FileReadTool.tsx +0 -404
- package/src/tools/FileReadTool/prompt.ts +0 -7
- package/src/tools/FileWriteTool/FileWriteTool.tsx +0 -301
- package/src/tools/FileWriteTool/prompt.ts +0 -10
- package/src/tools/GlobTool/GlobTool.tsx +0 -119
- package/src/tools/GlobTool/prompt.ts +0 -8
- package/src/tools/GrepTool/GrepTool.tsx +0 -147
- package/src/tools/GrepTool/prompt.ts +0 -11
- package/src/tools/MCPTool/MCPTool.tsx +0 -107
- package/src/tools/MCPTool/prompt.ts +0 -3
- package/src/tools/MemoryReadTool/MemoryReadTool.tsx +0 -127
- package/src/tools/MemoryReadTool/prompt.ts +0 -3
- package/src/tools/MemoryWriteTool/MemoryWriteTool.tsx +0 -89
- package/src/tools/MemoryWriteTool/prompt.ts +0 -3
- package/src/tools/MultiEditTool/MultiEditTool.tsx +0 -388
- package/src/tools/MultiEditTool/prompt.ts +0 -45
- package/src/tools/NotebookEditTool/NotebookEditTool.tsx +0 -298
- package/src/tools/NotebookEditTool/prompt.ts +0 -3
- package/src/tools/NotebookReadTool/NotebookReadTool.tsx +0 -258
- package/src/tools/NotebookReadTool/prompt.ts +0 -3
- package/src/tools/StickerRequestTool/StickerRequestTool.tsx +0 -107
- package/src/tools/StickerRequestTool/prompt.ts +0 -19
- package/src/tools/TaskTool/TaskTool.tsx +0 -438
- package/src/tools/TaskTool/constants.ts +0 -1
- package/src/tools/TaskTool/prompt.ts +0 -92
- package/src/tools/ThinkTool/ThinkTool.tsx +0 -54
- package/src/tools/ThinkTool/prompt.ts +0 -12
- package/src/tools/TodoWriteTool/TodoWriteTool.tsx +0 -313
- package/src/tools/TodoWriteTool/prompt.ts +0 -63
- package/src/tools/URLFetcherTool/URLFetcherTool.tsx +0 -178
- package/src/tools/URLFetcherTool/cache.ts +0 -55
- package/src/tools/URLFetcherTool/htmlToMarkdown.ts +0 -55
- package/src/tools/URLFetcherTool/prompt.ts +0 -17
- package/src/tools/WebSearchTool/WebSearchTool.tsx +0 -103
- package/src/tools/WebSearchTool/prompt.ts +0 -13
- package/src/tools/WebSearchTool/searchProviders.ts +0 -66
- package/src/tools/lsTool/lsTool.tsx +0 -272
- package/src/tools/lsTool/prompt.ts +0 -2
- package/src/tools.ts +0 -67
- package/src/types/PermissionMode.ts +0 -120
- package/src/types/RequestContext.ts +0 -72
- package/src/types/common.d.ts +0 -2
- package/src/types/conversation.ts +0 -51
- package/src/types/logs.ts +0 -58
- package/src/types/modelCapabilities.ts +0 -64
- package/src/types/notebook.ts +0 -87
- package/src/utils/Cursor.ts +0 -436
- package/src/utils/PersistentShell.ts +0 -552
- package/src/utils/advancedFuzzyMatcher.ts +0 -290
- package/src/utils/agentLoader.ts +0 -278
- package/src/utils/agentStorage.ts +0 -97
- package/src/utils/array.ts +0 -3
- package/src/utils/ask.tsx +0 -99
- package/src/utils/auth.ts +0 -13
- package/src/utils/autoCompactCore.ts +0 -223
- package/src/utils/autoUpdater.ts +0 -458
- package/src/utils/betas.ts +0 -20
- package/src/utils/browser.ts +0 -14
- package/src/utils/cleanup.ts +0 -72
- package/src/utils/commands.ts +0 -261
- package/src/utils/commonUnixCommands.ts +0 -161
- package/src/utils/config.ts +0 -945
- package/src/utils/conversationRecovery.ts +0 -55
- package/src/utils/debugLogger.ts +0 -1235
- package/src/utils/diff.ts +0 -42
- package/src/utils/env.ts +0 -57
- package/src/utils/errors.ts +0 -21
- package/src/utils/exampleCommands.ts +0 -109
- package/src/utils/execFileNoThrow.ts +0 -51
- package/src/utils/expertChatStorage.ts +0 -136
- package/src/utils/file.ts +0 -405
- package/src/utils/fileRecoveryCore.ts +0 -71
- package/src/utils/format.tsx +0 -44
- package/src/utils/fuzzyMatcher.ts +0 -328
- package/src/utils/generators.ts +0 -62
- package/src/utils/git.ts +0 -92
- package/src/utils/globalLogger.ts +0 -77
- package/src/utils/http.ts +0 -10
- package/src/utils/imagePaste.ts +0 -38
- package/src/utils/json.ts +0 -13
- package/src/utils/log.ts +0 -382
- package/src/utils/markdown.ts +0 -213
- package/src/utils/messageContextManager.ts +0 -294
- package/src/utils/messages.tsx +0 -945
- package/src/utils/model.ts +0 -914
- package/src/utils/permissions/filesystem.ts +0 -127
- package/src/utils/responseState.ts +0 -23
- package/src/utils/ripgrep.ts +0 -167
- package/src/utils/secureFile.ts +0 -564
- package/src/utils/sessionState.ts +0 -49
- package/src/utils/state.ts +0 -25
- package/src/utils/style.ts +0 -29
- package/src/utils/terminal.ts +0 -50
- package/src/utils/theme.ts +0 -127
- package/src/utils/thinking.ts +0 -144
- package/src/utils/todoStorage.ts +0 -431
- package/src/utils/tokens.ts +0 -43
- package/src/utils/toolExecutionController.ts +0 -163
- package/src/utils/unaryLogging.ts +0 -26
- package/src/utils/user.ts +0 -37
- package/src/utils/validate.ts +0 -165
package/src/utils/model.ts
DELETED
|
@@ -1,914 +0,0 @@
|
|
|
1
|
-
import { memoize } from 'lodash-es'
|
|
2
|
-
import { getDynamicConfig, getExperimentValue } from '../services/statsig'
|
|
3
|
-
import { logError } from './log'
|
|
4
|
-
import {
|
|
5
|
-
getGlobalConfig,
|
|
6
|
-
ModelProfile,
|
|
7
|
-
ModelPointerType,
|
|
8
|
-
saveGlobalConfig,
|
|
9
|
-
} from './config'
|
|
10
|
-
|
|
11
|
-
export const USE_BEDROCK = !!process.env.CLAUDE_CODE_USE_BEDROCK
|
|
12
|
-
export const USE_VERTEX = !!process.env.CLAUDE_CODE_USE_VERTEX
|
|
13
|
-
|
|
14
|
-
export interface ModelConfig {
|
|
15
|
-
bedrock: string
|
|
16
|
-
vertex: string
|
|
17
|
-
firstParty: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const DEFAULT_MODEL_CONFIG: ModelConfig = {
|
|
21
|
-
bedrock: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',
|
|
22
|
-
vertex: 'claude-3-7-sonnet@20250219',
|
|
23
|
-
firstParty: 'claude-sonnet-4-20250514',
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Helper to get the model config from statsig or defaults
|
|
28
|
-
* Relies on the built-in caching from StatsigClient
|
|
29
|
-
*/
|
|
30
|
-
async function getModelConfig(): Promise<ModelConfig> {
|
|
31
|
-
try {
|
|
32
|
-
return await getDynamicConfig<ModelConfig>(
|
|
33
|
-
'tengu-capable-model-config',
|
|
34
|
-
DEFAULT_MODEL_CONFIG,
|
|
35
|
-
)
|
|
36
|
-
} catch (error) {
|
|
37
|
-
logError(error)
|
|
38
|
-
return DEFAULT_MODEL_CONFIG
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const getSlowAndCapableModel = memoize(async (): Promise<string> => {
|
|
43
|
-
const config = await getGlobalConfig()
|
|
44
|
-
|
|
45
|
-
// Use ModelManager for proper model resolution
|
|
46
|
-
const modelManager = new ModelManager(config)
|
|
47
|
-
const model = modelManager.getMainAgentModel()
|
|
48
|
-
|
|
49
|
-
if (model) {
|
|
50
|
-
return model
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Final fallback to default model
|
|
54
|
-
const modelConfig = await getModelConfig()
|
|
55
|
-
if (USE_BEDROCK) return modelConfig.bedrock
|
|
56
|
-
if (USE_VERTEX) return modelConfig.vertex
|
|
57
|
-
return modelConfig.firstParty
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
export async function isDefaultSlowAndCapableModel(): Promise<boolean> {
|
|
61
|
-
return (
|
|
62
|
-
!process.env.ANTHROPIC_MODEL ||
|
|
63
|
-
process.env.ANTHROPIC_MODEL === (await getSlowAndCapableModel())
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Get the region for a specific Vertex model
|
|
69
|
-
* Checks for hardcoded model-specific environment variables first,
|
|
70
|
-
* then falls back to CLOUD_ML_REGION env var or default region
|
|
71
|
-
*/
|
|
72
|
-
export function getVertexRegionForModel(
|
|
73
|
-
model: string | undefined,
|
|
74
|
-
): string | undefined {
|
|
75
|
-
if (model?.startsWith('claude-3-5-haiku')) {
|
|
76
|
-
return process.env.VERTEX_REGION_CLAUDE_3_5_HAIKU
|
|
77
|
-
} else if (model?.startsWith('claude-3-5-sonnet')) {
|
|
78
|
-
return process.env.VERTEX_REGION_CLAUDE_3_5_SONNET
|
|
79
|
-
} else if (model?.startsWith('claude-3-7-sonnet')) {
|
|
80
|
-
return process.env.VERTEX_REGION_CLAUDE_3_7_SONNET
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Comprehensive ModelManager class for centralized model selection and management.
|
|
86
|
-
* Provides a clean interface for model selection across the application.
|
|
87
|
-
*/
|
|
88
|
-
export class ModelManager {
|
|
89
|
-
private config: any // Using any to handle legacy properties
|
|
90
|
-
private modelProfiles: ModelProfile[]
|
|
91
|
-
|
|
92
|
-
constructor(config: any) {
|
|
93
|
-
this.config = config
|
|
94
|
-
this.modelProfiles = config.modelProfiles || []
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Get the current terminal model (for interactive CLI sessions)
|
|
99
|
-
*/
|
|
100
|
-
getCurrentModel(): string | null {
|
|
101
|
-
// Use main pointer from new ModelProfile system
|
|
102
|
-
const mainModelName = this.config.modelPointers?.main
|
|
103
|
-
if (mainModelName) {
|
|
104
|
-
const profile = this.findModelProfile(mainModelName)
|
|
105
|
-
if (profile && profile.isActive) {
|
|
106
|
-
return profile.modelName
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Fallback to main agent model
|
|
111
|
-
return this.getMainAgentModel()
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Get the main agent default model (for non-terminal mode and MCP calls)
|
|
116
|
-
*/
|
|
117
|
-
getMainAgentModel(): string | null {
|
|
118
|
-
// Use main pointer from new ModelProfile system
|
|
119
|
-
const mainModelName = this.config.modelPointers?.main
|
|
120
|
-
if (mainModelName) {
|
|
121
|
-
const profile = this.findModelProfile(mainModelName)
|
|
122
|
-
if (profile && profile.isActive) {
|
|
123
|
-
return profile.modelName
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Fallback to first active profile
|
|
128
|
-
const activeProfile = this.modelProfiles.find(p => p.isActive)
|
|
129
|
-
if (activeProfile) {
|
|
130
|
-
return activeProfile.modelName
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return null
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Get the task tool default model (for Task tool sub-agents)
|
|
138
|
-
*/
|
|
139
|
-
getTaskToolModel(): string | null {
|
|
140
|
-
// Use task pointer from new ModelProfile system
|
|
141
|
-
const taskModelName = this.config.modelPointers?.task
|
|
142
|
-
if (taskModelName) {
|
|
143
|
-
const profile = this.findModelProfile(taskModelName)
|
|
144
|
-
if (profile && profile.isActive) {
|
|
145
|
-
return profile.modelName
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Fallback to main agent model
|
|
150
|
-
return this.getMainAgentModel()
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Switch to the next available model with simple context overflow handling
|
|
155
|
-
* If target model can't handle current context, shows warning and reverts after delay
|
|
156
|
-
*
|
|
157
|
-
* @param currentContextTokens - Current conversation token count for validation
|
|
158
|
-
* @returns Object with model name and context status information
|
|
159
|
-
*/
|
|
160
|
-
switchToNextModelWithContextCheck(currentContextTokens: number = 0): {
|
|
161
|
-
success: boolean
|
|
162
|
-
modelName: string | null
|
|
163
|
-
previousModelName: string | null
|
|
164
|
-
contextOverflow: boolean
|
|
165
|
-
usagePercentage: number
|
|
166
|
-
} {
|
|
167
|
-
// Use ALL configured models, not just active ones
|
|
168
|
-
const allProfiles = this.getAllConfiguredModels()
|
|
169
|
-
if (allProfiles.length === 0) {
|
|
170
|
-
return {
|
|
171
|
-
success: false,
|
|
172
|
-
modelName: null,
|
|
173
|
-
previousModelName: null,
|
|
174
|
-
contextOverflow: false,
|
|
175
|
-
usagePercentage: 0,
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Sort by createdAt for consistent cycling order (don't use lastUsed)
|
|
180
|
-
// Using lastUsed causes the order to change each time, preventing proper cycling
|
|
181
|
-
allProfiles.sort((a, b) => {
|
|
182
|
-
return a.createdAt - b.createdAt // Oldest first for consistent order
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
const currentMainModelName = this.config.modelPointers?.main
|
|
186
|
-
const currentModel = currentMainModelName
|
|
187
|
-
? this.findModelProfile(currentMainModelName)
|
|
188
|
-
: null
|
|
189
|
-
const previousModelName = currentModel?.name || null
|
|
190
|
-
|
|
191
|
-
if (!currentMainModelName) {
|
|
192
|
-
// No current main model, select first available (activate if needed)
|
|
193
|
-
const firstModel = allProfiles[0]
|
|
194
|
-
if (!firstModel.isActive) {
|
|
195
|
-
firstModel.isActive = true
|
|
196
|
-
}
|
|
197
|
-
this.setPointer('main', firstModel.modelName)
|
|
198
|
-
this.updateLastUsed(firstModel.modelName)
|
|
199
|
-
|
|
200
|
-
const analysis = this.analyzeContextCompatibility(
|
|
201
|
-
firstModel,
|
|
202
|
-
currentContextTokens,
|
|
203
|
-
)
|
|
204
|
-
return {
|
|
205
|
-
success: true,
|
|
206
|
-
modelName: firstModel.name,
|
|
207
|
-
previousModelName: null,
|
|
208
|
-
contextOverflow: !analysis.compatible,
|
|
209
|
-
usagePercentage: analysis.usagePercentage,
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Find current model index in ALL models
|
|
214
|
-
const currentIndex = allProfiles.findIndex(
|
|
215
|
-
p => p.modelName === currentMainModelName,
|
|
216
|
-
)
|
|
217
|
-
if (currentIndex === -1) {
|
|
218
|
-
// Current model not found, select first available (activate if needed)
|
|
219
|
-
const firstModel = allProfiles[0]
|
|
220
|
-
if (!firstModel.isActive) {
|
|
221
|
-
firstModel.isActive = true
|
|
222
|
-
}
|
|
223
|
-
this.setPointer('main', firstModel.modelName)
|
|
224
|
-
this.updateLastUsed(firstModel.modelName)
|
|
225
|
-
|
|
226
|
-
const analysis = this.analyzeContextCompatibility(
|
|
227
|
-
firstModel,
|
|
228
|
-
currentContextTokens,
|
|
229
|
-
)
|
|
230
|
-
return {
|
|
231
|
-
success: true,
|
|
232
|
-
modelName: firstModel.name,
|
|
233
|
-
previousModelName,
|
|
234
|
-
contextOverflow: !analysis.compatible,
|
|
235
|
-
usagePercentage: analysis.usagePercentage,
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Check if only one model is available
|
|
240
|
-
if (allProfiles.length === 1) {
|
|
241
|
-
return {
|
|
242
|
-
success: false,
|
|
243
|
-
modelName: null,
|
|
244
|
-
previousModelName,
|
|
245
|
-
contextOverflow: false,
|
|
246
|
-
usagePercentage: 0,
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Get next model in cycle (from ALL models)
|
|
251
|
-
const nextIndex = (currentIndex + 1) % allProfiles.length
|
|
252
|
-
const nextModel = allProfiles[nextIndex]
|
|
253
|
-
|
|
254
|
-
// Activate the model if it's not already active
|
|
255
|
-
const wasInactive = !nextModel.isActive
|
|
256
|
-
if (!nextModel.isActive) {
|
|
257
|
-
nextModel.isActive = true
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Analyze context compatibility for next model
|
|
261
|
-
const analysis = this.analyzeContextCompatibility(
|
|
262
|
-
nextModel,
|
|
263
|
-
currentContextTokens,
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
// Always switch to next model, but return context status
|
|
267
|
-
this.setPointer('main', nextModel.modelName)
|
|
268
|
-
this.updateLastUsed(nextModel.modelName)
|
|
269
|
-
|
|
270
|
-
// Save configuration if we activated a new model
|
|
271
|
-
if (wasInactive) {
|
|
272
|
-
this.saveConfig()
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return {
|
|
276
|
-
success: true,
|
|
277
|
-
modelName: nextModel.name,
|
|
278
|
-
previousModelName,
|
|
279
|
-
contextOverflow: !analysis.compatible,
|
|
280
|
-
usagePercentage: analysis.usagePercentage,
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Simple model switching for UI components (compatible interface)
|
|
286
|
-
* @param currentContextTokens - Current conversation token count for validation
|
|
287
|
-
* @returns Compatible interface for PromptInput component
|
|
288
|
-
*/
|
|
289
|
-
switchToNextModel(currentContextTokens: number = 0): {
|
|
290
|
-
success: boolean
|
|
291
|
-
modelName: string | null
|
|
292
|
-
blocked?: boolean
|
|
293
|
-
message?: string
|
|
294
|
-
} {
|
|
295
|
-
// Use the enhanced context check method for consistency
|
|
296
|
-
const result = this.switchToNextModelWithContextCheck(currentContextTokens)
|
|
297
|
-
|
|
298
|
-
if (!result.success) {
|
|
299
|
-
const allModels = this.getAllConfiguredModels()
|
|
300
|
-
if (allModels.length === 0) {
|
|
301
|
-
return {
|
|
302
|
-
success: false,
|
|
303
|
-
modelName: null,
|
|
304
|
-
blocked: false,
|
|
305
|
-
message: '❌ No models configured. Use /model to add models.',
|
|
306
|
-
}
|
|
307
|
-
} else if (allModels.length === 1) {
|
|
308
|
-
return {
|
|
309
|
-
success: false,
|
|
310
|
-
modelName: null,
|
|
311
|
-
blocked: false,
|
|
312
|
-
message: `⚠️ Only one model configured (${allModels[0].modelName}). Use /model to add more models for switching.`,
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// Convert the detailed result to the simple interface
|
|
318
|
-
const currentModel = this.findModelProfile(this.config.modelPointers?.main)
|
|
319
|
-
const allModels = this.getAllConfiguredModels()
|
|
320
|
-
const currentIndex = allModels.findIndex(m => m.modelName === currentModel?.modelName)
|
|
321
|
-
const totalModels = allModels.length
|
|
322
|
-
|
|
323
|
-
return {
|
|
324
|
-
success: result.success,
|
|
325
|
-
modelName: result.modelName,
|
|
326
|
-
blocked: result.contextOverflow,
|
|
327
|
-
message: result.success
|
|
328
|
-
? result.contextOverflow
|
|
329
|
-
? `⚠️ Context usage: ${result.usagePercentage.toFixed(1)}% - ${result.modelName}`
|
|
330
|
-
: `✅ Switched to ${result.modelName} (${currentIndex + 1}/${totalModels})${currentModel?.provider ? ` [${currentModel.provider}]` : ''}`
|
|
331
|
-
: `❌ Failed to switch models`,
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Revert to previous model (used when context overflow requires rollback)
|
|
337
|
-
*/
|
|
338
|
-
revertToPreviousModel(previousModelName: string): boolean {
|
|
339
|
-
const previousModel = this.modelProfiles.find(
|
|
340
|
-
p => p.name === previousModelName && p.isActive,
|
|
341
|
-
)
|
|
342
|
-
if (!previousModel) {
|
|
343
|
-
return false
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
this.setPointer('main', previousModel.modelName)
|
|
347
|
-
this.updateLastUsed(previousModel.modelName)
|
|
348
|
-
return true
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Enhanced context validation with different severity levels
|
|
353
|
-
*/
|
|
354
|
-
analyzeContextCompatibility(
|
|
355
|
-
model: ModelProfile,
|
|
356
|
-
contextTokens: number,
|
|
357
|
-
): {
|
|
358
|
-
compatible: boolean
|
|
359
|
-
severity: 'safe' | 'warning' | 'critical'
|
|
360
|
-
usagePercentage: number
|
|
361
|
-
recommendation: string
|
|
362
|
-
} {
|
|
363
|
-
const usableContext = Math.floor(model.contextLength * 0.8) // Reserve 20% for output
|
|
364
|
-
const usagePercentage = (contextTokens / usableContext) * 100
|
|
365
|
-
|
|
366
|
-
if (usagePercentage <= 70) {
|
|
367
|
-
return {
|
|
368
|
-
compatible: true,
|
|
369
|
-
severity: 'safe',
|
|
370
|
-
usagePercentage,
|
|
371
|
-
recommendation: 'Full context preserved',
|
|
372
|
-
}
|
|
373
|
-
} else if (usagePercentage <= 90) {
|
|
374
|
-
return {
|
|
375
|
-
compatible: true,
|
|
376
|
-
severity: 'warning',
|
|
377
|
-
usagePercentage,
|
|
378
|
-
recommendation: 'Context usage high, consider compression',
|
|
379
|
-
}
|
|
380
|
-
} else {
|
|
381
|
-
return {
|
|
382
|
-
compatible: false,
|
|
383
|
-
severity: 'critical',
|
|
384
|
-
usagePercentage,
|
|
385
|
-
recommendation: 'Auto-compression or message truncation required',
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Switch to next model with enhanced context analysis
|
|
392
|
-
*/
|
|
393
|
-
switchToNextModelWithAnalysis(currentContextTokens: number = 0): {
|
|
394
|
-
modelName: string | null
|
|
395
|
-
contextAnalysis: ReturnType<typeof this.analyzeContextCompatibility> | null
|
|
396
|
-
requiresCompression: boolean
|
|
397
|
-
estimatedTokensAfterSwitch: number
|
|
398
|
-
} {
|
|
399
|
-
const result = this.switchToNextModel(currentContextTokens)
|
|
400
|
-
|
|
401
|
-
if (!result.success || !result.modelName) {
|
|
402
|
-
return {
|
|
403
|
-
modelName: null,
|
|
404
|
-
contextAnalysis: null,
|
|
405
|
-
requiresCompression: false,
|
|
406
|
-
estimatedTokensAfterSwitch: 0,
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const newModel = this.getModel('main')
|
|
411
|
-
if (!newModel) {
|
|
412
|
-
return {
|
|
413
|
-
modelName: result.modelName,
|
|
414
|
-
contextAnalysis: null,
|
|
415
|
-
requiresCompression: false,
|
|
416
|
-
estimatedTokensAfterSwitch: currentContextTokens,
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
const analysis = this.analyzeContextCompatibility(
|
|
421
|
-
newModel,
|
|
422
|
-
currentContextTokens,
|
|
423
|
-
)
|
|
424
|
-
|
|
425
|
-
return {
|
|
426
|
-
modelName: result.modelName,
|
|
427
|
-
contextAnalysis: analysis,
|
|
428
|
-
requiresCompression: analysis.severity === 'critical',
|
|
429
|
-
estimatedTokensAfterSwitch: currentContextTokens,
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
/**
|
|
434
|
-
* Check if a model can handle the given context size (legacy method)
|
|
435
|
-
*/
|
|
436
|
-
canModelHandleContext(model: ModelProfile, contextTokens: number): boolean {
|
|
437
|
-
const analysis = this.analyzeContextCompatibility(model, contextTokens)
|
|
438
|
-
return analysis.compatible
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Find the first model that can handle the given context size
|
|
443
|
-
*/
|
|
444
|
-
findModelWithSufficientContext(
|
|
445
|
-
models: ModelProfile[],
|
|
446
|
-
contextTokens: number,
|
|
447
|
-
): ModelProfile | null {
|
|
448
|
-
return (
|
|
449
|
-
models.find(model => this.canModelHandleContext(model, contextTokens)) ||
|
|
450
|
-
null
|
|
451
|
-
)
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Unified model getter for different contexts
|
|
456
|
-
*/
|
|
457
|
-
getModelForContext(
|
|
458
|
-
contextType: 'terminal' | 'main-agent' | 'task-tool',
|
|
459
|
-
): string | null {
|
|
460
|
-
switch (contextType) {
|
|
461
|
-
case 'terminal':
|
|
462
|
-
return this.getCurrentModel()
|
|
463
|
-
case 'main-agent':
|
|
464
|
-
return this.getMainAgentModel()
|
|
465
|
-
case 'task-tool':
|
|
466
|
-
return this.getTaskToolModel()
|
|
467
|
-
default:
|
|
468
|
-
return this.getMainAgentModel()
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* Get all active model profiles
|
|
474
|
-
*/
|
|
475
|
-
getActiveModelProfiles(): ModelProfile[] {
|
|
476
|
-
return this.modelProfiles.filter(p => p.isActive)
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
/**
|
|
480
|
-
* Check if any models are configured
|
|
481
|
-
*/
|
|
482
|
-
hasConfiguredModels(): boolean {
|
|
483
|
-
return this.getActiveModelProfiles().length > 0
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// New model pointer system methods
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Get model by pointer type (main, task, reasoning, quick)
|
|
490
|
-
*/
|
|
491
|
-
getModel(pointer: ModelPointerType): ModelProfile | null {
|
|
492
|
-
const pointerId = this.config.modelPointers?.[pointer]
|
|
493
|
-
if (!pointerId) {
|
|
494
|
-
return this.getDefaultModel()
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
const profile = this.findModelProfile(pointerId)
|
|
498
|
-
return profile && profile.isActive ? profile : this.getDefaultModel()
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* Get model name by pointer type
|
|
503
|
-
*/
|
|
504
|
-
getModelName(pointer: ModelPointerType): string | null {
|
|
505
|
-
const profile = this.getModel(pointer)
|
|
506
|
-
return profile ? profile.modelName : null
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
/**
|
|
510
|
-
* Get reasoning model (with fallback)
|
|
511
|
-
*/
|
|
512
|
-
getReasoningModel(): string | null {
|
|
513
|
-
return this.getModelName('reasoning') || this.getModelName('main')
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
* Get quick model (with fallback)
|
|
518
|
-
*/
|
|
519
|
-
getQuickModel(): string | null {
|
|
520
|
-
return (
|
|
521
|
-
this.getModelName('quick') ||
|
|
522
|
-
this.getModelName('task') ||
|
|
523
|
-
this.getModelName('main')
|
|
524
|
-
)
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* Add a new model profile with duplicate validation
|
|
529
|
-
*/
|
|
530
|
-
async addModel(
|
|
531
|
-
config: Omit<ModelProfile, 'createdAt' | 'isActive'>,
|
|
532
|
-
): Promise<string> {
|
|
533
|
-
// Check for duplicate modelName (actual model identifier)
|
|
534
|
-
const existingByModelName = this.modelProfiles.find(
|
|
535
|
-
p => p.modelName === config.modelName,
|
|
536
|
-
)
|
|
537
|
-
if (existingByModelName) {
|
|
538
|
-
throw new Error(
|
|
539
|
-
`Model with modelName '${config.modelName}' already exists: ${existingByModelName.name}`,
|
|
540
|
-
)
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// Check for duplicate friendly name
|
|
544
|
-
const existingByName = this.modelProfiles.find(p => p.name === config.name)
|
|
545
|
-
if (existingByName) {
|
|
546
|
-
throw new Error(`Model with name '${config.name}' already exists`)
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
const newModel: ModelProfile = {
|
|
550
|
-
...config,
|
|
551
|
-
createdAt: Date.now(),
|
|
552
|
-
isActive: true,
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
this.modelProfiles.push(newModel)
|
|
556
|
-
|
|
557
|
-
// If this is the first model, set all pointers to it
|
|
558
|
-
if (this.modelProfiles.length === 1) {
|
|
559
|
-
this.config.modelPointers = {
|
|
560
|
-
main: config.modelName,
|
|
561
|
-
task: config.modelName,
|
|
562
|
-
reasoning: config.modelName,
|
|
563
|
-
quick: config.modelName,
|
|
564
|
-
}
|
|
565
|
-
this.config.defaultModelName = config.modelName
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
this.saveConfig()
|
|
569
|
-
return config.modelName
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
/**
|
|
573
|
-
* Set model pointer assignment
|
|
574
|
-
*/
|
|
575
|
-
setPointer(pointer: ModelPointerType, modelName: string): void {
|
|
576
|
-
if (!this.findModelProfile(modelName)) {
|
|
577
|
-
throw new Error(`Model '${modelName}' not found`)
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
if (!this.config.modelPointers) {
|
|
581
|
-
this.config.modelPointers = {
|
|
582
|
-
main: '',
|
|
583
|
-
task: '',
|
|
584
|
-
reasoning: '',
|
|
585
|
-
quick: '',
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
this.config.modelPointers[pointer] = modelName
|
|
590
|
-
this.saveConfig()
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* Get all active models for pointer assignment
|
|
595
|
-
*/
|
|
596
|
-
getAvailableModels(): ModelProfile[] {
|
|
597
|
-
return this.modelProfiles.filter(p => p.isActive)
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* Get all configured models (both active and inactive) for switching
|
|
602
|
-
*/
|
|
603
|
-
getAllConfiguredModels(): ModelProfile[] {
|
|
604
|
-
return this.modelProfiles
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
/**
|
|
608
|
-
* Get all available model names (modelName field) - active only
|
|
609
|
-
*/
|
|
610
|
-
getAllAvailableModelNames(): string[] {
|
|
611
|
-
return this.getAvailableModels().map(p => p.modelName)
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
/**
|
|
615
|
-
* Get all configured model names (both active and inactive)
|
|
616
|
-
*/
|
|
617
|
-
getAllConfiguredModelNames(): string[] {
|
|
618
|
-
return this.getAllConfiguredModels().map(p => p.modelName)
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
/**
|
|
622
|
-
* Debug method to get detailed model switching information
|
|
623
|
-
*/
|
|
624
|
-
getModelSwitchingDebugInfo(): {
|
|
625
|
-
totalModels: number
|
|
626
|
-
activeModels: number
|
|
627
|
-
inactiveModels: number
|
|
628
|
-
currentMainModel: string | null
|
|
629
|
-
availableModels: Array<{
|
|
630
|
-
name: string
|
|
631
|
-
modelName: string
|
|
632
|
-
provider: string
|
|
633
|
-
isActive: boolean
|
|
634
|
-
lastUsed?: number
|
|
635
|
-
}>
|
|
636
|
-
modelPointers: Record<string, string | undefined>
|
|
637
|
-
} {
|
|
638
|
-
const availableModels = this.getAvailableModels()
|
|
639
|
-
const currentMainModelName = this.config.modelPointers?.main
|
|
640
|
-
|
|
641
|
-
return {
|
|
642
|
-
totalModels: this.modelProfiles.length,
|
|
643
|
-
activeModels: availableModels.length,
|
|
644
|
-
inactiveModels: this.modelProfiles.length - availableModels.length,
|
|
645
|
-
currentMainModel: currentMainModelName || null,
|
|
646
|
-
availableModels: this.modelProfiles.map(p => ({
|
|
647
|
-
name: p.name,
|
|
648
|
-
modelName: p.modelName,
|
|
649
|
-
provider: p.provider,
|
|
650
|
-
isActive: p.isActive,
|
|
651
|
-
lastUsed: p.lastUsed,
|
|
652
|
-
})),
|
|
653
|
-
modelPointers: this.config.modelPointers || {},
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
/**
|
|
658
|
-
* Remove a model profile
|
|
659
|
-
*/
|
|
660
|
-
removeModel(modelName: string): void {
|
|
661
|
-
this.modelProfiles = this.modelProfiles.filter(
|
|
662
|
-
p => p.modelName !== modelName,
|
|
663
|
-
)
|
|
664
|
-
|
|
665
|
-
// Clean up pointers that reference deleted model
|
|
666
|
-
if (this.config.modelPointers) {
|
|
667
|
-
Object.keys(this.config.modelPointers).forEach(pointer => {
|
|
668
|
-
if (
|
|
669
|
-
this.config.modelPointers[pointer as ModelPointerType] === modelName
|
|
670
|
-
) {
|
|
671
|
-
this.config.modelPointers[pointer as ModelPointerType] =
|
|
672
|
-
this.config.defaultModelName || ''
|
|
673
|
-
}
|
|
674
|
-
})
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
this.saveConfig()
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
/**
|
|
681
|
-
* Get default model profile
|
|
682
|
-
*/
|
|
683
|
-
private getDefaultModel(): ModelProfile | null {
|
|
684
|
-
if (this.config.defaultModelId) {
|
|
685
|
-
const profile = this.findModelProfile(this.config.defaultModelId)
|
|
686
|
-
if (profile && profile.isActive) {
|
|
687
|
-
return profile
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
return this.modelProfiles.find(p => p.isActive) || null
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
/**
|
|
694
|
-
* Save configuration changes
|
|
695
|
-
*/
|
|
696
|
-
private saveConfig(): void {
|
|
697
|
-
const updatedConfig = {
|
|
698
|
-
...this.config,
|
|
699
|
-
modelProfiles: this.modelProfiles,
|
|
700
|
-
}
|
|
701
|
-
saveGlobalConfig(updatedConfig)
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
/**
|
|
705
|
-
* Get a fallback model when no specific model is configured
|
|
706
|
-
*/
|
|
707
|
-
async getFallbackModel(): Promise<string> {
|
|
708
|
-
const modelConfig = await getModelConfig()
|
|
709
|
-
if (USE_BEDROCK) return modelConfig.bedrock
|
|
710
|
-
if (USE_VERTEX) return modelConfig.vertex
|
|
711
|
-
return modelConfig.firstParty
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
/**
|
|
715
|
-
* 统一的模型解析方法:支持指针、model ID 和真实模型名称
|
|
716
|
-
* @param modelParam - 可以是模型指针 ('main', 'task', etc.)、内部model ID 或真实模型名称 ('gpt-4o', 'claude-3-5-sonnet')
|
|
717
|
-
* @returns ModelProfile 或 null
|
|
718
|
-
*/
|
|
719
|
-
resolveModel(modelParam: string | ModelPointerType): ModelProfile | null {
|
|
720
|
-
// 首先检查是否是模型指针
|
|
721
|
-
if (['main', 'task', 'reasoning', 'quick'].includes(modelParam)) {
|
|
722
|
-
const pointerId =
|
|
723
|
-
this.config.modelPointers?.[modelParam as ModelPointerType]
|
|
724
|
-
if (pointerId) {
|
|
725
|
-
// pointerId 可能是内部ID或真实模型名称,尝试两种查找方式
|
|
726
|
-
let profile = this.findModelProfile(pointerId) // 按内部ID查找
|
|
727
|
-
if (!profile) {
|
|
728
|
-
profile = this.findModelProfileByModelName(pointerId) // 按真实模型名查找
|
|
729
|
-
}
|
|
730
|
-
if (profile && profile.isActive) {
|
|
731
|
-
return profile
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
// 指针无效时,尝试 fallback 到默认模型
|
|
735
|
-
return this.getDefaultModel()
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
// 不是指针,尝试多种查找方式
|
|
739
|
-
// 1. 尝试按内部 model ID 查找
|
|
740
|
-
let profile = this.findModelProfile(modelParam)
|
|
741
|
-
if (profile && profile.isActive) {
|
|
742
|
-
return profile
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
// 2. 尝试按真实模型名称查找
|
|
746
|
-
profile = this.findModelProfileByModelName(modelParam)
|
|
747
|
-
if (profile && profile.isActive) {
|
|
748
|
-
return profile
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
// 3. 尝试按友好名称查找
|
|
752
|
-
profile = this.findModelProfileByName(modelParam)
|
|
753
|
-
if (profile && profile.isActive) {
|
|
754
|
-
return profile
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
// 所有查找方式都失败,尝试 fallback 到默认模型
|
|
758
|
-
return this.getDefaultModel()
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
/**
|
|
762
|
-
* 解析模型参数并返回完整信息
|
|
763
|
-
*/
|
|
764
|
-
resolveModelWithInfo(modelParam: string | ModelPointerType): {
|
|
765
|
-
success: boolean
|
|
766
|
-
profile: ModelProfile | null
|
|
767
|
-
error?: string
|
|
768
|
-
} {
|
|
769
|
-
const isPointer = ['main', 'task', 'reasoning', 'quick'].includes(
|
|
770
|
-
modelParam,
|
|
771
|
-
)
|
|
772
|
-
|
|
773
|
-
if (isPointer) {
|
|
774
|
-
const pointerId =
|
|
775
|
-
this.config.modelPointers?.[modelParam as ModelPointerType]
|
|
776
|
-
if (!pointerId) {
|
|
777
|
-
return {
|
|
778
|
-
success: false,
|
|
779
|
-
profile: null,
|
|
780
|
-
error: `Model pointer '${modelParam}' is not configured. Use /model to set up models.`,
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
// pointerId 可能是内部ID或真实模型名称
|
|
785
|
-
let profile = this.findModelProfile(pointerId)
|
|
786
|
-
if (!profile) {
|
|
787
|
-
profile = this.findModelProfileByModelName(pointerId)
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
if (!profile) {
|
|
791
|
-
return {
|
|
792
|
-
success: false,
|
|
793
|
-
profile: null,
|
|
794
|
-
error: `Model pointer '${modelParam}' points to invalid model '${pointerId}'. Use /model to reconfigure.`,
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
if (!profile.isActive) {
|
|
799
|
-
return {
|
|
800
|
-
success: false,
|
|
801
|
-
profile: null,
|
|
802
|
-
error: `Model '${profile.name}' (pointed by '${modelParam}') is inactive. Use /model to activate it.`,
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
return {
|
|
807
|
-
success: true,
|
|
808
|
-
profile,
|
|
809
|
-
}
|
|
810
|
-
} else {
|
|
811
|
-
// 直接的 model ID 或模型名称,尝试多种查找方式
|
|
812
|
-
let profile = this.findModelProfile(modelParam)
|
|
813
|
-
if (!profile) {
|
|
814
|
-
profile = this.findModelProfileByModelName(modelParam)
|
|
815
|
-
}
|
|
816
|
-
if (!profile) {
|
|
817
|
-
profile = this.findModelProfileByName(modelParam)
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
if (!profile) {
|
|
821
|
-
return {
|
|
822
|
-
success: false,
|
|
823
|
-
profile: null,
|
|
824
|
-
error: `Model '${modelParam}' not found. Use /model to add models.`,
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
if (!profile.isActive) {
|
|
829
|
-
return {
|
|
830
|
-
success: false,
|
|
831
|
-
profile: null,
|
|
832
|
-
error: `Model '${profile.name}' is inactive. Use /model to activate it.`,
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
return {
|
|
837
|
-
success: true,
|
|
838
|
-
profile,
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
// Private helper methods
|
|
844
|
-
private findModelProfile(modelName: string): ModelProfile | null {
|
|
845
|
-
return this.modelProfiles.find(p => p.modelName === modelName) || null
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
private findModelProfileByModelName(modelName: string): ModelProfile | null {
|
|
849
|
-
return this.modelProfiles.find(p => p.modelName === modelName) || null
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
private findModelProfileByName(name: string): ModelProfile | null {
|
|
853
|
-
return this.modelProfiles.find(p => p.name === name) || null
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
private updateLastUsed(modelName: string): void {
|
|
857
|
-
const profile = this.findModelProfile(modelName)
|
|
858
|
-
if (profile) {
|
|
859
|
-
profile.lastUsed = Date.now()
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
// Global ModelManager instance to avoid config read/write race conditions
|
|
865
|
-
let globalModelManager: ModelManager | null = null
|
|
866
|
-
|
|
867
|
-
/**
|
|
868
|
-
* Get the global ModelManager instance (singleton pattern to fix race conditions)
|
|
869
|
-
*/
|
|
870
|
-
export const getModelManager = (): ModelManager => {
|
|
871
|
-
try {
|
|
872
|
-
if (!globalModelManager) {
|
|
873
|
-
const config = getGlobalConfig()
|
|
874
|
-
if (!config) {
|
|
875
|
-
console.warn(
|
|
876
|
-
'No global config available, creating ModelManager with empty config',
|
|
877
|
-
)
|
|
878
|
-
globalModelManager = new ModelManager({
|
|
879
|
-
modelProfiles: [],
|
|
880
|
-
modelPointers: { main: '', task: '', reasoning: '', quick: '' },
|
|
881
|
-
})
|
|
882
|
-
} else {
|
|
883
|
-
globalModelManager = new ModelManager(config)
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
return globalModelManager
|
|
887
|
-
} catch (error) {
|
|
888
|
-
console.error('Error creating ModelManager:', error)
|
|
889
|
-
// Return a fallback ModelManager with empty configuration
|
|
890
|
-
return new ModelManager({
|
|
891
|
-
modelProfiles: [],
|
|
892
|
-
modelPointers: { main: '', task: '', reasoning: '', quick: '' },
|
|
893
|
-
})
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
/**
|
|
898
|
-
* Force reload of the global ModelManager instance
|
|
899
|
-
* Used when configuration changes to ensure fresh data
|
|
900
|
-
*/
|
|
901
|
-
export const reloadModelManager = (): void => {
|
|
902
|
-
globalModelManager = null
|
|
903
|
-
// Force creation of new instance with fresh config
|
|
904
|
-
getModelManager()
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
/**
|
|
908
|
-
* Get the quick model for fast operations
|
|
909
|
-
*/
|
|
910
|
-
export const getQuickModel = (): string => {
|
|
911
|
-
const manager = getModelManager()
|
|
912
|
-
const quickModel = manager.getModel('quick')
|
|
913
|
-
return quickModel?.modelName || 'quick' // Return pointer if model not resolved
|
|
914
|
-
}
|