@shareai-lab/kode 1.1.14 → 1.1.16-dev.2
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/cli.js +77 -82
- 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/debugLogger.ts
DELETED
|
@@ -1,1235 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, appendFileSync } from 'fs'
|
|
2
|
-
import { join } from 'path'
|
|
3
|
-
import { homedir } from 'os'
|
|
4
|
-
import { randomUUID } from 'crypto'
|
|
5
|
-
import chalk from 'chalk'
|
|
6
|
-
import envPaths from 'env-paths'
|
|
7
|
-
import { PRODUCT_COMMAND } from '../constants/product'
|
|
8
|
-
import { SESSION_ID } from './log'
|
|
9
|
-
import type { Message } from '../types/conversation'
|
|
10
|
-
|
|
11
|
-
// 调试日志级别
|
|
12
|
-
export enum LogLevel {
|
|
13
|
-
TRACE = 'TRACE',
|
|
14
|
-
DEBUG = 'DEBUG',
|
|
15
|
-
INFO = 'INFO',
|
|
16
|
-
WARN = 'WARN',
|
|
17
|
-
ERROR = 'ERROR',
|
|
18
|
-
FLOW = 'FLOW',
|
|
19
|
-
API = 'API',
|
|
20
|
-
STATE = 'STATE',
|
|
21
|
-
REMINDER = 'REMINDER', // 新增:系统提醒事件
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// 调试模式检测
|
|
25
|
-
const isDebugMode = () =>
|
|
26
|
-
process.argv.includes('--debug') || process.argv.includes('--debug-verbose')
|
|
27
|
-
const isVerboseMode = () => process.argv.includes('--verbose')
|
|
28
|
-
const isDebugVerboseMode = () => process.argv.includes('--debug-verbose')
|
|
29
|
-
|
|
30
|
-
// 终端日志级别配置 - 显示关键信息
|
|
31
|
-
const TERMINAL_LOG_LEVELS = new Set([
|
|
32
|
-
LogLevel.ERROR,
|
|
33
|
-
LogLevel.WARN,
|
|
34
|
-
LogLevel.INFO, // 添加 INFO 级别,显示关键系统状态
|
|
35
|
-
LogLevel.REMINDER, // 系统提醒事件,用户应该看到
|
|
36
|
-
])
|
|
37
|
-
|
|
38
|
-
// 在调试详细模式下显示更多日志级别
|
|
39
|
-
const DEBUG_VERBOSE_TERMINAL_LOG_LEVELS = new Set([
|
|
40
|
-
LogLevel.ERROR,
|
|
41
|
-
LogLevel.WARN,
|
|
42
|
-
LogLevel.FLOW,
|
|
43
|
-
LogLevel.API,
|
|
44
|
-
LogLevel.STATE,
|
|
45
|
-
LogLevel.INFO,
|
|
46
|
-
LogLevel.REMINDER, // 系统提醒在详细模式下也显示
|
|
47
|
-
])
|
|
48
|
-
|
|
49
|
-
// 用户友好的日志级别 - 简化的高级日志
|
|
50
|
-
const USER_FRIENDLY_LEVELS = new Set([
|
|
51
|
-
'SESSION_START',
|
|
52
|
-
'QUERY_START',
|
|
53
|
-
'QUERY_PROGRESS',
|
|
54
|
-
'QUERY_COMPLETE',
|
|
55
|
-
'TOOL_EXECUTION',
|
|
56
|
-
'ERROR_OCCURRED',
|
|
57
|
-
'PERFORMANCE_SUMMARY',
|
|
58
|
-
])
|
|
59
|
-
|
|
60
|
-
// 启动时间戳用于文件命名
|
|
61
|
-
const STARTUP_TIMESTAMP = new Date().toISOString().replace(/[:.]/g, '-')
|
|
62
|
-
const REQUEST_START_TIME = Date.now()
|
|
63
|
-
|
|
64
|
-
// 路径配置 - 统一使用 ~/.kode 目录
|
|
65
|
-
const KODE_DIR = join(homedir(), '.kode')
|
|
66
|
-
function getProjectDir(cwd: string): string {
|
|
67
|
-
return cwd.replace(/[^a-zA-Z0-9]/g, '-')
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const DEBUG_PATHS = {
|
|
71
|
-
base: () => join(KODE_DIR, getProjectDir(process.cwd()), 'debug'),
|
|
72
|
-
detailed: () => join(DEBUG_PATHS.base(), `${STARTUP_TIMESTAMP}-detailed.log`),
|
|
73
|
-
flow: () => join(DEBUG_PATHS.base(), `${STARTUP_TIMESTAMP}-flow.log`),
|
|
74
|
-
api: () => join(DEBUG_PATHS.base(), `${STARTUP_TIMESTAMP}-api.log`),
|
|
75
|
-
state: () => join(DEBUG_PATHS.base(), `${STARTUP_TIMESTAMP}-state.log`),
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// 确保调试目录存在
|
|
79
|
-
function ensureDebugDir() {
|
|
80
|
-
const debugDir = DEBUG_PATHS.base()
|
|
81
|
-
if (!existsSync(debugDir)) {
|
|
82
|
-
mkdirSync(debugDir, { recursive: true })
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// 日志条目接口
|
|
87
|
-
interface LogEntry {
|
|
88
|
-
timestamp: string
|
|
89
|
-
level: LogLevel
|
|
90
|
-
phase: string
|
|
91
|
-
requestId?: string
|
|
92
|
-
data: any
|
|
93
|
-
elapsed?: number
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// 当前请求上下文
|
|
97
|
-
class RequestContext {
|
|
98
|
-
public readonly id: string
|
|
99
|
-
public readonly startTime: number
|
|
100
|
-
private phases: Map<string, number> = new Map()
|
|
101
|
-
|
|
102
|
-
constructor() {
|
|
103
|
-
this.id = randomUUID().slice(0, 8)
|
|
104
|
-
this.startTime = Date.now()
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
markPhase(phase: string) {
|
|
108
|
-
this.phases.set(phase, Date.now() - this.startTime)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
getPhaseTime(phase: string): number {
|
|
112
|
-
return this.phases.get(phase) || 0
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
getAllPhases(): Record<string, number> {
|
|
116
|
-
return Object.fromEntries(this.phases)
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// 全局请求上下文管理
|
|
121
|
-
const activeRequests = new Map<string, RequestContext>()
|
|
122
|
-
let currentRequest: RequestContext | null = null
|
|
123
|
-
|
|
124
|
-
// 核心日志记录函数
|
|
125
|
-
function writeToFile(filePath: string, entry: LogEntry) {
|
|
126
|
-
if (!isDebugMode()) return
|
|
127
|
-
|
|
128
|
-
try {
|
|
129
|
-
ensureDebugDir()
|
|
130
|
-
const logLine =
|
|
131
|
-
JSON.stringify(
|
|
132
|
-
{
|
|
133
|
-
...entry,
|
|
134
|
-
sessionId: SESSION_ID,
|
|
135
|
-
pid: process.pid,
|
|
136
|
-
uptime: Date.now() - REQUEST_START_TIME,
|
|
137
|
-
},
|
|
138
|
-
null,
|
|
139
|
-
2,
|
|
140
|
-
) + ',\n'
|
|
141
|
-
|
|
142
|
-
appendFileSync(filePath, logLine)
|
|
143
|
-
} catch (error) {
|
|
144
|
-
// 静默失败,避免调试日志影响主功能
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// 日志去重机制
|
|
149
|
-
const recentLogs = new Map<string, number>()
|
|
150
|
-
const LOG_DEDUPE_WINDOW_MS = 5000 // 5秒内相同日志视为重复
|
|
151
|
-
|
|
152
|
-
// 生成日志去重键
|
|
153
|
-
function getDedupeKey(level: LogLevel, phase: string, data: any): string {
|
|
154
|
-
// 对于配置相关的日志,使用文件路径和操作类型作为键
|
|
155
|
-
if (phase.startsWith('CONFIG_')) {
|
|
156
|
-
const file = data?.file || ''
|
|
157
|
-
return `${level}:${phase}:${file}`
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// 对于其他日志,使用阶段作为键
|
|
161
|
-
return `${level}:${phase}`
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// 检查是否应该记录日志(去重)
|
|
165
|
-
function shouldLogWithDedupe(
|
|
166
|
-
level: LogLevel,
|
|
167
|
-
phase: string,
|
|
168
|
-
data: any,
|
|
169
|
-
): boolean {
|
|
170
|
-
const key = getDedupeKey(level, phase, data)
|
|
171
|
-
const now = Date.now()
|
|
172
|
-
const lastLogTime = recentLogs.get(key)
|
|
173
|
-
|
|
174
|
-
// 如果是第一次记录,或者超过去重时间窗口,则允许记录
|
|
175
|
-
if (!lastLogTime || now - lastLogTime > LOG_DEDUPE_WINDOW_MS) {
|
|
176
|
-
recentLogs.set(key, now)
|
|
177
|
-
|
|
178
|
-
// 清理过期的日志记录
|
|
179
|
-
for (const [oldKey, oldTime] of recentLogs.entries()) {
|
|
180
|
-
if (now - oldTime > LOG_DEDUPE_WINDOW_MS) {
|
|
181
|
-
recentLogs.delete(oldKey)
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return true
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return false
|
|
189
|
-
}
|
|
190
|
-
function formatMessages(messages: any): string {
|
|
191
|
-
if (Array.isArray(messages)) {
|
|
192
|
-
// 只显示最近 5 条消息
|
|
193
|
-
const recentMessages = messages.slice(-5)
|
|
194
|
-
return recentMessages
|
|
195
|
-
.map((msg, index) => {
|
|
196
|
-
const role = msg.role || 'unknown'
|
|
197
|
-
let content = ''
|
|
198
|
-
|
|
199
|
-
if (typeof msg.content === 'string') {
|
|
200
|
-
// 每条消息最长 300 字符,超出省略
|
|
201
|
-
content =
|
|
202
|
-
msg.content.length > 300
|
|
203
|
-
? msg.content.substring(0, 300) + '...'
|
|
204
|
-
: msg.content
|
|
205
|
-
} else if (typeof msg.content === 'object') {
|
|
206
|
-
content = '[complex_content]'
|
|
207
|
-
} else {
|
|
208
|
-
content = String(msg.content || '')
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const totalIndex = messages.length - recentMessages.length + index
|
|
212
|
-
return `[${totalIndex}] ${chalk.dim(role)}: ${content}`
|
|
213
|
-
})
|
|
214
|
-
.join('\n ')
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (typeof messages === 'string') {
|
|
218
|
-
try {
|
|
219
|
-
const parsed = JSON.parse(messages)
|
|
220
|
-
if (Array.isArray(parsed)) {
|
|
221
|
-
return formatMessages(parsed) // 递归处理解析后的数组
|
|
222
|
-
}
|
|
223
|
-
} catch {
|
|
224
|
-
// 如果解析失败,返回截断的字符串
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// 对于非消息数组的长字符串,也进行截断
|
|
229
|
-
if (typeof messages === 'string' && messages.length > 200) {
|
|
230
|
-
return messages.substring(0, 200) + '...'
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return typeof messages === 'string' ? messages : JSON.stringify(messages)
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// 判断是否应该在终端显示日志
|
|
237
|
-
function shouldShowInTerminal(level: LogLevel): boolean {
|
|
238
|
-
if (!isDebugMode()) return false
|
|
239
|
-
|
|
240
|
-
// 在调试详细模式下显示更多日志级别
|
|
241
|
-
if (isDebugVerboseMode()) {
|
|
242
|
-
return DEBUG_VERBOSE_TERMINAL_LOG_LEVELS.has(level)
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// 默认只显示错误和警告
|
|
246
|
-
return TERMINAL_LOG_LEVELS.has(level)
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// 终端彩色输出
|
|
250
|
-
function logToTerminal(entry: LogEntry) {
|
|
251
|
-
// 使用新的过滤逻辑
|
|
252
|
-
if (!shouldShowInTerminal(entry.level)) return
|
|
253
|
-
|
|
254
|
-
const { level, phase, data, requestId, elapsed } = entry
|
|
255
|
-
const timestamp = new Date().toISOString().slice(11, 23) // HH:mm:ss.SSS
|
|
256
|
-
|
|
257
|
-
let prefix = ''
|
|
258
|
-
let color = chalk.gray
|
|
259
|
-
|
|
260
|
-
switch (level) {
|
|
261
|
-
case LogLevel.FLOW:
|
|
262
|
-
prefix = '🔄'
|
|
263
|
-
color = chalk.cyan
|
|
264
|
-
break
|
|
265
|
-
case LogLevel.API:
|
|
266
|
-
prefix = '🌐'
|
|
267
|
-
color = chalk.yellow
|
|
268
|
-
break
|
|
269
|
-
case LogLevel.STATE:
|
|
270
|
-
prefix = '📊'
|
|
271
|
-
color = chalk.blue
|
|
272
|
-
break
|
|
273
|
-
case LogLevel.ERROR:
|
|
274
|
-
prefix = '❌'
|
|
275
|
-
color = chalk.red
|
|
276
|
-
break
|
|
277
|
-
case LogLevel.WARN:
|
|
278
|
-
prefix = '⚠️'
|
|
279
|
-
color = chalk.yellow
|
|
280
|
-
break
|
|
281
|
-
case LogLevel.INFO:
|
|
282
|
-
prefix = 'ℹ️'
|
|
283
|
-
color = chalk.green
|
|
284
|
-
break
|
|
285
|
-
case LogLevel.TRACE:
|
|
286
|
-
prefix = '📈'
|
|
287
|
-
color = chalk.magenta
|
|
288
|
-
break
|
|
289
|
-
default:
|
|
290
|
-
prefix = '🔍'
|
|
291
|
-
color = chalk.gray
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const reqId = requestId ? chalk.dim(`[${requestId}]`) : ''
|
|
295
|
-
const elapsedStr = elapsed !== undefined ? chalk.dim(`+${elapsed}ms`) : ''
|
|
296
|
-
|
|
297
|
-
// 特殊处理一些数据格式
|
|
298
|
-
let dataStr = ''
|
|
299
|
-
if (typeof data === 'object' && data !== null) {
|
|
300
|
-
if (data.messages) {
|
|
301
|
-
// 格式化消息数组
|
|
302
|
-
const formattedMessages = formatMessages(data.messages)
|
|
303
|
-
dataStr = JSON.stringify(
|
|
304
|
-
{
|
|
305
|
-
...data,
|
|
306
|
-
messages: `\n ${formattedMessages}`,
|
|
307
|
-
},
|
|
308
|
-
null,
|
|
309
|
-
2,
|
|
310
|
-
)
|
|
311
|
-
} else {
|
|
312
|
-
dataStr = JSON.stringify(data, null, 2)
|
|
313
|
-
}
|
|
314
|
-
} else {
|
|
315
|
-
dataStr = typeof data === 'string' ? data : JSON.stringify(data)
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
console.log(
|
|
319
|
-
`${color(`[${timestamp}]`)} ${prefix} ${color(phase)} ${reqId} ${dataStr} ${elapsedStr}`,
|
|
320
|
-
)
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// 主要调试日志函数
|
|
324
|
-
export function debugLog(
|
|
325
|
-
level: LogLevel,
|
|
326
|
-
phase: string,
|
|
327
|
-
data: any,
|
|
328
|
-
requestId?: string,
|
|
329
|
-
) {
|
|
330
|
-
if (!isDebugMode()) return
|
|
331
|
-
|
|
332
|
-
// 检查是否应该记录(去重检查)
|
|
333
|
-
if (!shouldLogWithDedupe(level, phase, data)) {
|
|
334
|
-
return // 跳过重复的日志
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
const entry: LogEntry = {
|
|
338
|
-
timestamp: new Date().toISOString(),
|
|
339
|
-
level,
|
|
340
|
-
phase,
|
|
341
|
-
data,
|
|
342
|
-
requestId: requestId || currentRequest?.id,
|
|
343
|
-
elapsed: currentRequest ? Date.now() - currentRequest.startTime : undefined,
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// 写入对应的日志文件
|
|
347
|
-
writeToFile(DEBUG_PATHS.detailed(), entry)
|
|
348
|
-
|
|
349
|
-
switch (level) {
|
|
350
|
-
case LogLevel.FLOW:
|
|
351
|
-
writeToFile(DEBUG_PATHS.flow(), entry)
|
|
352
|
-
break
|
|
353
|
-
case LogLevel.API:
|
|
354
|
-
writeToFile(DEBUG_PATHS.api(), entry)
|
|
355
|
-
break
|
|
356
|
-
case LogLevel.STATE:
|
|
357
|
-
writeToFile(DEBUG_PATHS.state(), entry)
|
|
358
|
-
break
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// 终端输出(也会被过滤)
|
|
362
|
-
logToTerminal(entry)
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// 便捷的日志函数
|
|
366
|
-
export const debug = {
|
|
367
|
-
flow: (phase: string, data: any, requestId?: string) =>
|
|
368
|
-
debugLog(LogLevel.FLOW, phase, data, requestId),
|
|
369
|
-
|
|
370
|
-
api: (phase: string, data: any, requestId?: string) =>
|
|
371
|
-
debugLog(LogLevel.API, phase, data, requestId),
|
|
372
|
-
|
|
373
|
-
state: (phase: string, data: any, requestId?: string) =>
|
|
374
|
-
debugLog(LogLevel.STATE, phase, data, requestId),
|
|
375
|
-
|
|
376
|
-
info: (phase: string, data: any, requestId?: string) =>
|
|
377
|
-
debugLog(LogLevel.INFO, phase, data, requestId),
|
|
378
|
-
|
|
379
|
-
warn: (phase: string, data: any, requestId?: string) =>
|
|
380
|
-
debugLog(LogLevel.WARN, phase, data, requestId),
|
|
381
|
-
|
|
382
|
-
error: (phase: string, data: any, requestId?: string) =>
|
|
383
|
-
debugLog(LogLevel.ERROR, phase, data, requestId),
|
|
384
|
-
|
|
385
|
-
trace: (phase: string, data: any, requestId?: string) =>
|
|
386
|
-
debugLog(LogLevel.TRACE, phase, data, requestId),
|
|
387
|
-
|
|
388
|
-
// 新增UI相关的调试函数 (只记录到文件,不显示在终端)
|
|
389
|
-
ui: (phase: string, data: any, requestId?: string) =>
|
|
390
|
-
debugLog(LogLevel.STATE, `UI_${phase}`, data, requestId),
|
|
391
|
-
|
|
392
|
-
// 新增Statsig事件追踪
|
|
393
|
-
statsig: (phase: string, data: any) => debugLog(LogLevel.TRACE, phase, data),
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// 请求生命周期管理
|
|
397
|
-
export function startRequest(): RequestContext {
|
|
398
|
-
const ctx = new RequestContext()
|
|
399
|
-
currentRequest = ctx
|
|
400
|
-
activeRequests.set(ctx.id, ctx)
|
|
401
|
-
|
|
402
|
-
debug.flow('REQUEST_START', {
|
|
403
|
-
requestId: ctx.id,
|
|
404
|
-
activeRequests: activeRequests.size,
|
|
405
|
-
})
|
|
406
|
-
|
|
407
|
-
return ctx
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
export function endRequest(ctx?: RequestContext) {
|
|
411
|
-
const request = ctx || currentRequest
|
|
412
|
-
if (!request) return
|
|
413
|
-
|
|
414
|
-
debug.flow('REQUEST_END', {
|
|
415
|
-
requestId: request.id,
|
|
416
|
-
totalTime: Date.now() - request.startTime,
|
|
417
|
-
phases: request.getAllPhases(),
|
|
418
|
-
})
|
|
419
|
-
|
|
420
|
-
activeRequests.delete(request.id)
|
|
421
|
-
if (currentRequest === request) {
|
|
422
|
-
currentRequest = null
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
export function getCurrentRequest(): RequestContext | null {
|
|
427
|
-
return currentRequest
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// 阶段标记函数
|
|
431
|
-
export function markPhase(phase: string, data?: any) {
|
|
432
|
-
if (!currentRequest) return
|
|
433
|
-
|
|
434
|
-
currentRequest.markPhase(phase)
|
|
435
|
-
debug.flow(`PHASE_${phase.toUpperCase()}`, {
|
|
436
|
-
requestId: currentRequest.id,
|
|
437
|
-
elapsed: currentRequest.getPhaseTime(phase),
|
|
438
|
-
data,
|
|
439
|
-
})
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// 新增:Reminder 事件日志记录
|
|
443
|
-
export function logReminderEvent(
|
|
444
|
-
eventType: string,
|
|
445
|
-
reminderData: any,
|
|
446
|
-
agentId?: string,
|
|
447
|
-
) {
|
|
448
|
-
if (!isDebugMode()) return
|
|
449
|
-
|
|
450
|
-
debug.info('REMINDER_EVENT_TRIGGERED', {
|
|
451
|
-
eventType,
|
|
452
|
-
agentId: agentId || 'default',
|
|
453
|
-
reminderType: reminderData.type || 'unknown',
|
|
454
|
-
reminderCategory: reminderData.category || 'general',
|
|
455
|
-
reminderPriority: reminderData.priority || 'medium',
|
|
456
|
-
contentLength: reminderData.content ? reminderData.content.length : 0,
|
|
457
|
-
timestamp: Date.now(),
|
|
458
|
-
})
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// API错误日志功能
|
|
462
|
-
export function logAPIError(context: {
|
|
463
|
-
model: string
|
|
464
|
-
endpoint: string
|
|
465
|
-
status: number
|
|
466
|
-
error: any
|
|
467
|
-
request?: any
|
|
468
|
-
response?: any
|
|
469
|
-
provider?: string
|
|
470
|
-
}) {
|
|
471
|
-
const errorDir = join(KODE_DIR, 'logs', 'error', 'api')
|
|
472
|
-
|
|
473
|
-
// 确保目录存在
|
|
474
|
-
if (!existsSync(errorDir)) {
|
|
475
|
-
try {
|
|
476
|
-
mkdirSync(errorDir, { recursive: true })
|
|
477
|
-
} catch (err) {
|
|
478
|
-
console.error('Failed to create error log directory:', err)
|
|
479
|
-
return // Exit early if we can't create the directory
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
// 生成文件名
|
|
484
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
|
|
485
|
-
const sanitizedModel = context.model.replace(/[^a-zA-Z0-9-_]/g, '_')
|
|
486
|
-
const filename = `${sanitizedModel}_${timestamp}.log`
|
|
487
|
-
const filepath = join(errorDir, filename)
|
|
488
|
-
|
|
489
|
-
// 准备完整的日志内容(文件中保存所有信息)
|
|
490
|
-
const fullLogContent = {
|
|
491
|
-
timestamp: new Date().toISOString(),
|
|
492
|
-
sessionId: SESSION_ID,
|
|
493
|
-
requestId: getCurrentRequest()?.id,
|
|
494
|
-
model: context.model,
|
|
495
|
-
provider: context.provider,
|
|
496
|
-
endpoint: context.endpoint,
|
|
497
|
-
status: context.status,
|
|
498
|
-
error: context.error,
|
|
499
|
-
request: context.request, // 保存完整请求
|
|
500
|
-
response: context.response, // 保存完整响应
|
|
501
|
-
environment: {
|
|
502
|
-
nodeVersion: process.version,
|
|
503
|
-
platform: process.platform,
|
|
504
|
-
cwd: process.cwd(),
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// 写入文件(保存完整信息)
|
|
509
|
-
try {
|
|
510
|
-
appendFileSync(filepath, JSON.stringify(fullLogContent, null, 2) + '\n')
|
|
511
|
-
appendFileSync(filepath, '='.repeat(80) + '\n\n')
|
|
512
|
-
} catch (err) {
|
|
513
|
-
console.error('Failed to write API error log:', err)
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// 在调试模式下记录到系统日志
|
|
517
|
-
if (isDebugMode()) {
|
|
518
|
-
debug.error('API_ERROR', {
|
|
519
|
-
model: context.model,
|
|
520
|
-
status: context.status,
|
|
521
|
-
error: typeof context.error === 'string' ? context.error : context.error?.message || 'Unknown error',
|
|
522
|
-
endpoint: context.endpoint,
|
|
523
|
-
logFile: filename,
|
|
524
|
-
})
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
// 优雅的终端显示(仅在verbose模式下)
|
|
528
|
-
if (isVerboseMode() || isDebugVerboseMode()) {
|
|
529
|
-
console.log()
|
|
530
|
-
console.log(chalk.red('━'.repeat(60)))
|
|
531
|
-
console.log(chalk.red.bold('⚠️ API Error'))
|
|
532
|
-
console.log(chalk.red('━'.repeat(60)))
|
|
533
|
-
|
|
534
|
-
// 显示关键信息
|
|
535
|
-
console.log(chalk.white(' Model: ') + chalk.yellow(context.model))
|
|
536
|
-
console.log(chalk.white(' Status: ') + chalk.red(context.status))
|
|
537
|
-
|
|
538
|
-
// 格式化错误消息
|
|
539
|
-
let errorMessage = 'Unknown error'
|
|
540
|
-
if (typeof context.error === 'string') {
|
|
541
|
-
errorMessage = context.error
|
|
542
|
-
} else if (context.error?.message) {
|
|
543
|
-
errorMessage = context.error.message
|
|
544
|
-
} else if (context.error?.error?.message) {
|
|
545
|
-
errorMessage = context.error.error.message
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// 错误消息换行显示
|
|
549
|
-
console.log(chalk.white(' Error: ') + chalk.red(errorMessage))
|
|
550
|
-
|
|
551
|
-
// 如果有响应体,显示格式化的响应
|
|
552
|
-
if (context.response) {
|
|
553
|
-
console.log()
|
|
554
|
-
console.log(chalk.gray(' Response:'))
|
|
555
|
-
const responseStr = typeof context.response === 'string'
|
|
556
|
-
? context.response
|
|
557
|
-
: JSON.stringify(context.response, null, 2)
|
|
558
|
-
|
|
559
|
-
// 缩进显示响应内容
|
|
560
|
-
responseStr.split('\n').forEach(line => {
|
|
561
|
-
console.log(chalk.gray(' ' + line))
|
|
562
|
-
})
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
console.log()
|
|
566
|
-
console.log(chalk.dim(` 📁 Full log: ${filepath}`))
|
|
567
|
-
console.log(chalk.red('━'.repeat(60)))
|
|
568
|
-
console.log()
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
// 新增:LLM 交互核心调试信息
|
|
573
|
-
export function logLLMInteraction(context: {
|
|
574
|
-
systemPrompt: string
|
|
575
|
-
messages: any[]
|
|
576
|
-
response: any
|
|
577
|
-
usage?: { inputTokens: number; outputTokens: number }
|
|
578
|
-
timing: { start: number; end: number }
|
|
579
|
-
apiFormat?: 'anthropic' | 'openai'
|
|
580
|
-
}) {
|
|
581
|
-
if (!isDebugMode()) return
|
|
582
|
-
|
|
583
|
-
const duration = context.timing.end - context.timing.start
|
|
584
|
-
|
|
585
|
-
console.log('\n' + chalk.blue('🧠 LLM CALL DEBUG'))
|
|
586
|
-
console.log(chalk.gray('━'.repeat(60)))
|
|
587
|
-
|
|
588
|
-
// 显示上下文基本信息
|
|
589
|
-
console.log(chalk.yellow('📊 Context Overview:'))
|
|
590
|
-
console.log(` Messages Count: ${context.messages.length}`)
|
|
591
|
-
console.log(` System Prompt Length: ${context.systemPrompt.length} chars`)
|
|
592
|
-
console.log(` Duration: ${duration.toFixed(0)}ms`)
|
|
593
|
-
|
|
594
|
-
if (context.usage) {
|
|
595
|
-
console.log(
|
|
596
|
-
` Token Usage: ${context.usage.inputTokens} → ${context.usage.outputTokens}`,
|
|
597
|
-
)
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
// 显示真实发送给 LLM API 的 messages(完整还原API调用)
|
|
601
|
-
const apiLabel = context.apiFormat
|
|
602
|
-
? ` (${context.apiFormat.toUpperCase()})`
|
|
603
|
-
: ''
|
|
604
|
-
console.log(chalk.cyan(`\n💬 Real API Messages${apiLabel} (last 10):`))
|
|
605
|
-
|
|
606
|
-
// 这里展示的是真正发送给LLM API的messages,不是内部处理的版本
|
|
607
|
-
const recentMessages = context.messages.slice(-10)
|
|
608
|
-
recentMessages.forEach((msg, index) => {
|
|
609
|
-
const globalIndex = context.messages.length - recentMessages.length + index
|
|
610
|
-
const roleColor =
|
|
611
|
-
msg.role === 'user'
|
|
612
|
-
? 'green'
|
|
613
|
-
: msg.role === 'assistant'
|
|
614
|
-
? 'blue'
|
|
615
|
-
: msg.role === 'system'
|
|
616
|
-
? 'yellow'
|
|
617
|
-
: 'gray'
|
|
618
|
-
|
|
619
|
-
let content = ''
|
|
620
|
-
let isReminder = false
|
|
621
|
-
|
|
622
|
-
if (typeof msg.content === 'string') {
|
|
623
|
-
// 检查是否是 system-reminder
|
|
624
|
-
if (msg.content.includes('<system-reminder>')) {
|
|
625
|
-
isReminder = true
|
|
626
|
-
// 提取 reminder 的核心内容,显示更多字符,记得加省略号
|
|
627
|
-
const reminderContent = msg.content
|
|
628
|
-
.replace(/<\/?system-reminder>/g, '')
|
|
629
|
-
.trim()
|
|
630
|
-
content = `🔔 ${reminderContent.length > 800 ? reminderContent.substring(0, 800) + '...' : reminderContent}`
|
|
631
|
-
} else {
|
|
632
|
-
// 增加普通消息的显示字符数 - 用户消息和系统消息显示更多
|
|
633
|
-
const maxLength =
|
|
634
|
-
msg.role === 'user' ? 1000 : msg.role === 'system' ? 1200 : 800
|
|
635
|
-
content =
|
|
636
|
-
msg.content.length > maxLength
|
|
637
|
-
? msg.content.substring(0, maxLength) + '...'
|
|
638
|
-
: msg.content
|
|
639
|
-
}
|
|
640
|
-
} else if (Array.isArray(msg.content)) {
|
|
641
|
-
// Anthropic格式:content是对象数组
|
|
642
|
-
const textBlocks = msg.content.filter(
|
|
643
|
-
(block: any) => block.type === 'text',
|
|
644
|
-
)
|
|
645
|
-
const toolBlocks = msg.content.filter(
|
|
646
|
-
(block: any) => block.type === 'tool_use',
|
|
647
|
-
)
|
|
648
|
-
if (textBlocks.length > 0) {
|
|
649
|
-
const text = textBlocks[0].text || ''
|
|
650
|
-
// Assistant消息显示更多内容
|
|
651
|
-
const maxLength = msg.role === 'assistant' ? 1000 : 800
|
|
652
|
-
content =
|
|
653
|
-
text.length > maxLength ? text.substring(0, maxLength) + '...' : text
|
|
654
|
-
}
|
|
655
|
-
if (toolBlocks.length > 0) {
|
|
656
|
-
content += ` [+ ${toolBlocks.length} tool calls]`
|
|
657
|
-
}
|
|
658
|
-
if (textBlocks.length === 0 && toolBlocks.length === 0) {
|
|
659
|
-
content = `[${msg.content.length} blocks: ${msg.content.map(b => b.type || 'unknown').join(', ')}]`
|
|
660
|
-
}
|
|
661
|
-
} else {
|
|
662
|
-
content = '[complex_content]'
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
// 根据消息类型使用不同的显示样式 - 更友好的视觉格式
|
|
666
|
-
if (isReminder) {
|
|
667
|
-
console.log(
|
|
668
|
-
` [${globalIndex}] ${chalk.magenta('🔔 REMINDER')}: ${chalk.dim(content)}`,
|
|
669
|
-
)
|
|
670
|
-
} else {
|
|
671
|
-
// 为不同角色添加图标
|
|
672
|
-
const roleIcon =
|
|
673
|
-
msg.role === 'user'
|
|
674
|
-
? '👤'
|
|
675
|
-
: msg.role === 'assistant'
|
|
676
|
-
? '🤖'
|
|
677
|
-
: msg.role === 'system'
|
|
678
|
-
? '⚙️'
|
|
679
|
-
: '📄'
|
|
680
|
-
console.log(
|
|
681
|
-
` [${globalIndex}] ${(chalk as any)[roleColor](roleIcon + ' ' + msg.role.toUpperCase())}: ${content}`,
|
|
682
|
-
)
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// 显示工具调用信息(Anthropic格式)- 更清晰的格式
|
|
686
|
-
if (msg.role === 'assistant' && Array.isArray(msg.content)) {
|
|
687
|
-
const toolCalls = msg.content.filter(
|
|
688
|
-
(block: any) => block.type === 'tool_use',
|
|
689
|
-
)
|
|
690
|
-
if (toolCalls.length > 0) {
|
|
691
|
-
console.log(
|
|
692
|
-
chalk.cyan(
|
|
693
|
-
` 🔧 → Tool calls (${toolCalls.length}): ${toolCalls.map((t: any) => t.name).join(', ')}`,
|
|
694
|
-
),
|
|
695
|
-
)
|
|
696
|
-
// 显示每个工具的详细参数
|
|
697
|
-
toolCalls.forEach((tool: any, idx: number) => {
|
|
698
|
-
const inputStr = JSON.stringify(tool.input || {})
|
|
699
|
-
const maxLength = 200
|
|
700
|
-
const displayInput =
|
|
701
|
-
inputStr.length > maxLength
|
|
702
|
-
? inputStr.substring(0, maxLength) + '...'
|
|
703
|
-
: inputStr
|
|
704
|
-
console.log(
|
|
705
|
-
chalk.dim(` [${idx}] ${tool.name}: ${displayInput}`),
|
|
706
|
-
)
|
|
707
|
-
})
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
// OpenAI格式的工具调用
|
|
711
|
-
if (msg.tool_calls && msg.tool_calls.length > 0) {
|
|
712
|
-
console.log(
|
|
713
|
-
chalk.cyan(
|
|
714
|
-
` 🔧 → Tool calls (${msg.tool_calls.length}): ${msg.tool_calls.map((t: any) => t.function.name).join(', ')}`,
|
|
715
|
-
),
|
|
716
|
-
)
|
|
717
|
-
msg.tool_calls.forEach((tool: any, idx: number) => {
|
|
718
|
-
const inputStr = tool.function.arguments || '{}'
|
|
719
|
-
const maxLength = 200
|
|
720
|
-
const displayInput =
|
|
721
|
-
inputStr.length > maxLength
|
|
722
|
-
? inputStr.substring(0, maxLength) + '...'
|
|
723
|
-
: inputStr
|
|
724
|
-
console.log(
|
|
725
|
-
chalk.dim(` [${idx}] ${tool.function.name}: ${displayInput}`),
|
|
726
|
-
)
|
|
727
|
-
})
|
|
728
|
-
}
|
|
729
|
-
})
|
|
730
|
-
|
|
731
|
-
// 显示 LLM 响应核心信息 - 更详细友好的格式
|
|
732
|
-
console.log(chalk.magenta('\n🤖 LLM Response:'))
|
|
733
|
-
|
|
734
|
-
// Handle different response formats (Anthropic vs OpenAI)
|
|
735
|
-
let responseContent = ''
|
|
736
|
-
let toolCalls: any[] = []
|
|
737
|
-
|
|
738
|
-
if (Array.isArray(context.response.content)) {
|
|
739
|
-
// Anthropic format: content is array of blocks
|
|
740
|
-
const textBlocks = context.response.content.filter(
|
|
741
|
-
(block: any) => block.type === 'text',
|
|
742
|
-
)
|
|
743
|
-
responseContent = textBlocks.length > 0 ? textBlocks[0].text || '' : ''
|
|
744
|
-
toolCalls = context.response.content.filter(
|
|
745
|
-
(block: any) => block.type === 'tool_use',
|
|
746
|
-
)
|
|
747
|
-
} else if (typeof context.response.content === 'string') {
|
|
748
|
-
// OpenAI format: content might be string
|
|
749
|
-
responseContent = context.response.content
|
|
750
|
-
// Tool calls are separate in OpenAI format
|
|
751
|
-
toolCalls = context.response.tool_calls || []
|
|
752
|
-
} else {
|
|
753
|
-
responseContent = JSON.stringify(context.response.content || '')
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
// 显示更多响应内容
|
|
757
|
-
const maxResponseLength = 1000
|
|
758
|
-
const displayContent =
|
|
759
|
-
responseContent.length > maxResponseLength
|
|
760
|
-
? responseContent.substring(0, maxResponseLength) + '...'
|
|
761
|
-
: responseContent
|
|
762
|
-
console.log(` Content: ${displayContent}`)
|
|
763
|
-
|
|
764
|
-
if (toolCalls.length > 0) {
|
|
765
|
-
const toolNames = toolCalls.map(
|
|
766
|
-
(t: any) => t.name || t.function?.name || 'unknown',
|
|
767
|
-
)
|
|
768
|
-
console.log(
|
|
769
|
-
chalk.cyan(
|
|
770
|
-
` 🔧 Tool Calls (${toolCalls.length}): ${toolNames.join(', ')}`,
|
|
771
|
-
),
|
|
772
|
-
)
|
|
773
|
-
toolCalls.forEach((tool: any, index: number) => {
|
|
774
|
-
const toolName = tool.name || tool.function?.name || 'unknown'
|
|
775
|
-
const toolInput = tool.input || tool.function?.arguments || '{}'
|
|
776
|
-
const inputStr =
|
|
777
|
-
typeof toolInput === 'string' ? toolInput : JSON.stringify(toolInput)
|
|
778
|
-
// 显示更多工具参数内容
|
|
779
|
-
const maxToolInputLength = 300
|
|
780
|
-
const displayInput =
|
|
781
|
-
inputStr.length > maxToolInputLength
|
|
782
|
-
? inputStr.substring(0, maxToolInputLength) + '...'
|
|
783
|
-
: inputStr
|
|
784
|
-
console.log(chalk.dim(` [${index}] ${toolName}: ${displayInput}`))
|
|
785
|
-
})
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
console.log(
|
|
789
|
-
` Stop Reason: ${context.response.stop_reason || context.response.finish_reason || 'unknown'}`,
|
|
790
|
-
)
|
|
791
|
-
console.log(chalk.gray('━'.repeat(60)))
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
// 新增:系统提示构建过程调试
|
|
795
|
-
export function logSystemPromptConstruction(construction: {
|
|
796
|
-
basePrompt: string
|
|
797
|
-
kodeContext?: string
|
|
798
|
-
reminders: string[]
|
|
799
|
-
finalPrompt: string
|
|
800
|
-
}) {
|
|
801
|
-
if (!isDebugMode()) return
|
|
802
|
-
|
|
803
|
-
console.log('\n' + chalk.yellow('📝 SYSTEM PROMPT CONSTRUCTION'))
|
|
804
|
-
console.log(` Base Prompt: ${construction.basePrompt.length} chars`)
|
|
805
|
-
|
|
806
|
-
if (construction.kodeContext) {
|
|
807
|
-
console.log(` + Kode Context: ${construction.kodeContext.length} chars`)
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
if (construction.reminders.length > 0) {
|
|
811
|
-
console.log(
|
|
812
|
-
` + Dynamic Reminders: ${construction.reminders.length} items`,
|
|
813
|
-
)
|
|
814
|
-
construction.reminders.forEach((reminder, index) => {
|
|
815
|
-
console.log(chalk.dim(` [${index}] ${reminder.substring(0, 80)}...`))
|
|
816
|
-
})
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
console.log(` = Final Length: ${construction.finalPrompt.length} chars`)
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
// 新增:上下文压缩过程调试
|
|
823
|
-
export function logContextCompression(compression: {
|
|
824
|
-
beforeMessages: number
|
|
825
|
-
afterMessages: number
|
|
826
|
-
trigger: string
|
|
827
|
-
preservedFiles: string[]
|
|
828
|
-
compressionRatio: number
|
|
829
|
-
}) {
|
|
830
|
-
if (!isDebugMode()) return
|
|
831
|
-
|
|
832
|
-
console.log('\n' + chalk.red('🗜️ CONTEXT COMPRESSION'))
|
|
833
|
-
console.log(` Trigger: ${compression.trigger}`)
|
|
834
|
-
console.log(
|
|
835
|
-
` Messages: ${compression.beforeMessages} → ${compression.afterMessages}`,
|
|
836
|
-
)
|
|
837
|
-
console.log(
|
|
838
|
-
` Compression Ratio: ${(compression.compressionRatio * 100).toFixed(1)}%`,
|
|
839
|
-
)
|
|
840
|
-
|
|
841
|
-
if (compression.preservedFiles.length > 0) {
|
|
842
|
-
console.log(` Preserved Files: ${compression.preservedFiles.join(', ')}`)
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
// 新增:用户友好的日志显示
|
|
847
|
-
export function logUserFriendly(type: string, data: any, requestId?: string) {
|
|
848
|
-
if (!isDebugMode()) return
|
|
849
|
-
|
|
850
|
-
const timestamp = new Date().toLocaleTimeString()
|
|
851
|
-
let message = ''
|
|
852
|
-
let color = chalk.gray
|
|
853
|
-
let icon = '•'
|
|
854
|
-
|
|
855
|
-
switch (type) {
|
|
856
|
-
case 'SESSION_START':
|
|
857
|
-
icon = '🚀'
|
|
858
|
-
color = chalk.green
|
|
859
|
-
message = `Session started with ${data.model || 'default model'}`
|
|
860
|
-
break
|
|
861
|
-
case 'QUERY_START':
|
|
862
|
-
icon = '💭'
|
|
863
|
-
color = chalk.blue
|
|
864
|
-
message = `Processing query: "${data.query?.substring(0, 50)}${data.query?.length > 50 ? '...' : ''}"`
|
|
865
|
-
break
|
|
866
|
-
case 'QUERY_PROGRESS':
|
|
867
|
-
icon = '⏳'
|
|
868
|
-
color = chalk.yellow
|
|
869
|
-
message = `${data.phase} (${data.elapsed}ms)`
|
|
870
|
-
break
|
|
871
|
-
case 'QUERY_COMPLETE':
|
|
872
|
-
icon = '✅'
|
|
873
|
-
color = chalk.green
|
|
874
|
-
message = `Query completed in ${data.duration}ms - Cost: $${data.cost} - ${data.tokens} tokens`
|
|
875
|
-
break
|
|
876
|
-
case 'TOOL_EXECUTION':
|
|
877
|
-
icon = '🔧'
|
|
878
|
-
color = chalk.cyan
|
|
879
|
-
message = `${data.toolName}: ${data.action} ${data.target ? '→ ' + data.target : ''}`
|
|
880
|
-
break
|
|
881
|
-
case 'ERROR_OCCURRED':
|
|
882
|
-
icon = '❌'
|
|
883
|
-
color = chalk.red
|
|
884
|
-
message = `${data.error} ${data.context ? '(' + data.context + ')' : ''}`
|
|
885
|
-
break
|
|
886
|
-
case 'PERFORMANCE_SUMMARY':
|
|
887
|
-
icon = '📊'
|
|
888
|
-
color = chalk.magenta
|
|
889
|
-
message = `Session: ${data.queries} queries, $${data.totalCost}, ${data.avgResponseTime}ms avg`
|
|
890
|
-
break
|
|
891
|
-
default:
|
|
892
|
-
message = JSON.stringify(data)
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
const reqId = requestId ? chalk.dim(`[${requestId.slice(0, 8)}]`) : ''
|
|
896
|
-
console.log(`${color(`[${timestamp}]`)} ${icon} ${color(message)} ${reqId}`)
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
// 初始化日志系统
|
|
900
|
-
export function initDebugLogger() {
|
|
901
|
-
if (!isDebugMode()) return
|
|
902
|
-
|
|
903
|
-
debug.info('DEBUG_LOGGER_INIT', {
|
|
904
|
-
startupTimestamp: STARTUP_TIMESTAMP,
|
|
905
|
-
sessionId: SESSION_ID,
|
|
906
|
-
debugPaths: {
|
|
907
|
-
detailed: DEBUG_PATHS.detailed(),
|
|
908
|
-
flow: DEBUG_PATHS.flow(),
|
|
909
|
-
api: DEBUG_PATHS.api(),
|
|
910
|
-
state: DEBUG_PATHS.state(),
|
|
911
|
-
},
|
|
912
|
-
})
|
|
913
|
-
|
|
914
|
-
// 显示终端输出过滤信息
|
|
915
|
-
const terminalLevels = isDebugVerboseMode()
|
|
916
|
-
? Array.from(DEBUG_VERBOSE_TERMINAL_LOG_LEVELS).join(', ')
|
|
917
|
-
: Array.from(TERMINAL_LOG_LEVELS).join(', ')
|
|
918
|
-
|
|
919
|
-
console.log(
|
|
920
|
-
chalk.dim(`[DEBUG] Terminal output filtered to: ${terminalLevels}`),
|
|
921
|
-
)
|
|
922
|
-
console.log(
|
|
923
|
-
chalk.dim(`[DEBUG] Complete logs saved to: ${DEBUG_PATHS.base()}`),
|
|
924
|
-
)
|
|
925
|
-
if (!isDebugVerboseMode()) {
|
|
926
|
-
console.log(
|
|
927
|
-
chalk.dim(
|
|
928
|
-
`[DEBUG] Use --debug-verbose for detailed system logs (FLOW, API, STATE)`,
|
|
929
|
-
),
|
|
930
|
-
)
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
// 新增:错误诊断和恢复建议系统
|
|
935
|
-
interface ErrorDiagnosis {
|
|
936
|
-
errorType: string
|
|
937
|
-
category:
|
|
938
|
-
| 'NETWORK'
|
|
939
|
-
| 'API'
|
|
940
|
-
| 'PERMISSION'
|
|
941
|
-
| 'CONFIG'
|
|
942
|
-
| 'SYSTEM'
|
|
943
|
-
| 'USER_INPUT'
|
|
944
|
-
severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
|
|
945
|
-
description: string
|
|
946
|
-
suggestions: string[]
|
|
947
|
-
debugSteps: string[]
|
|
948
|
-
relatedLogs?: string[]
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
export function diagnoseError(error: any, context?: any): ErrorDiagnosis {
|
|
952
|
-
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
953
|
-
const errorStack = error instanceof Error ? error.stack : undefined
|
|
954
|
-
|
|
955
|
-
// AbortController 相关错误
|
|
956
|
-
if (
|
|
957
|
-
errorMessage.includes('aborted') ||
|
|
958
|
-
errorMessage.includes('AbortController')
|
|
959
|
-
) {
|
|
960
|
-
return {
|
|
961
|
-
errorType: 'REQUEST_ABORTED',
|
|
962
|
-
category: 'SYSTEM',
|
|
963
|
-
severity: 'MEDIUM',
|
|
964
|
-
description:
|
|
965
|
-
'Request was aborted, often due to user cancellation or timeout',
|
|
966
|
-
suggestions: [
|
|
967
|
-
'检查是否按下了 ESC 键取消请求',
|
|
968
|
-
'检查网络连接是否稳定',
|
|
969
|
-
'验证 AbortController 状态: isActive 和 signal.aborted 应该一致',
|
|
970
|
-
'查看是否有重复的请求导致冲突',
|
|
971
|
-
],
|
|
972
|
-
debugSteps: [
|
|
973
|
-
'使用 --debug-verbose 模式查看详细的请求流程',
|
|
974
|
-
'检查 debug 日志中的 BINARY_FEEDBACK_* 事件',
|
|
975
|
-
'验证 REQUEST_START 和 REQUEST_END 日志配对',
|
|
976
|
-
'查看 QUERY_ABORTED 事件的触发原因',
|
|
977
|
-
],
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
// API 密钥相关错误
|
|
982
|
-
if (
|
|
983
|
-
errorMessage.includes('api-key') ||
|
|
984
|
-
errorMessage.includes('authentication') ||
|
|
985
|
-
errorMessage.includes('401')
|
|
986
|
-
) {
|
|
987
|
-
return {
|
|
988
|
-
errorType: 'API_AUTHENTICATION',
|
|
989
|
-
category: 'API',
|
|
990
|
-
severity: 'HIGH',
|
|
991
|
-
description: 'API authentication failed - invalid or missing API key',
|
|
992
|
-
suggestions: [
|
|
993
|
-
'运行 /login 重新设置 API 密钥',
|
|
994
|
-
'检查 ~/.kode/ 配置文件中的 API 密钥',
|
|
995
|
-
'验证 API 密钥是否已过期或被撤销',
|
|
996
|
-
'确认使用的 provider 设置正确 (anthropic/opendev/bigdream)',
|
|
997
|
-
],
|
|
998
|
-
debugSteps: [
|
|
999
|
-
'检查 CONFIG_LOAD 日志中的 provider 和 API 密钥状态',
|
|
1000
|
-
'运行 kode doctor 检查系统健康状态',
|
|
1001
|
-
'查看 API_ERROR 日志了解详细错误信息',
|
|
1002
|
-
'使用 kode config 命令查看当前配置',
|
|
1003
|
-
],
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
// 网络连接错误
|
|
1008
|
-
if (
|
|
1009
|
-
errorMessage.includes('ECONNREFUSED') ||
|
|
1010
|
-
errorMessage.includes('ENOTFOUND') ||
|
|
1011
|
-
errorMessage.includes('timeout')
|
|
1012
|
-
) {
|
|
1013
|
-
return {
|
|
1014
|
-
errorType: 'NETWORK_CONNECTION',
|
|
1015
|
-
category: 'NETWORK',
|
|
1016
|
-
severity: 'HIGH',
|
|
1017
|
-
description: 'Network connection failed - unable to reach API endpoint',
|
|
1018
|
-
suggestions: [
|
|
1019
|
-
'检查网络连接是否正常',
|
|
1020
|
-
'确认防火墙没有阻止相关端口',
|
|
1021
|
-
'检查 proxy 设置是否正确',
|
|
1022
|
-
'尝试切换到不同的网络环境',
|
|
1023
|
-
'验证 baseURL 配置是否正确',
|
|
1024
|
-
],
|
|
1025
|
-
debugSteps: [
|
|
1026
|
-
'检查 API_REQUEST_START 和相关网络日志',
|
|
1027
|
-
'查看 LLM_REQUEST_ERROR 中的详细错误信息',
|
|
1028
|
-
'使用 ping 或 curl 测试 API 端点连通性',
|
|
1029
|
-
'检查企业网络是否需要代理设置',
|
|
1030
|
-
],
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
// 权限相关错误
|
|
1035
|
-
if (
|
|
1036
|
-
errorMessage.includes('permission') ||
|
|
1037
|
-
errorMessage.includes('EACCES') ||
|
|
1038
|
-
errorMessage.includes('denied')
|
|
1039
|
-
) {
|
|
1040
|
-
return {
|
|
1041
|
-
errorType: 'PERMISSION_DENIED',
|
|
1042
|
-
category: 'PERMISSION',
|
|
1043
|
-
severity: 'MEDIUM',
|
|
1044
|
-
description: 'Permission denied - insufficient access rights',
|
|
1045
|
-
suggestions: [
|
|
1046
|
-
'检查文件和目录的读写权限',
|
|
1047
|
-
'确认当前用户有足够的系统权限',
|
|
1048
|
-
'查看是否需要管理员权限运行',
|
|
1049
|
-
'检查工具权限设置是否正确配置',
|
|
1050
|
-
],
|
|
1051
|
-
debugSteps: [
|
|
1052
|
-
'查看 PERMISSION_* 日志了解权限检查过程',
|
|
1053
|
-
'检查文件系统权限: ls -la',
|
|
1054
|
-
'验证工具审批状态',
|
|
1055
|
-
'查看 TOOL_* 相关的调试日志',
|
|
1056
|
-
],
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
// LLM 响应格式错误
|
|
1061
|
-
if (
|
|
1062
|
-
errorMessage.includes('substring is not a function') ||
|
|
1063
|
-
errorMessage.includes('content')
|
|
1064
|
-
) {
|
|
1065
|
-
return {
|
|
1066
|
-
errorType: 'RESPONSE_FORMAT',
|
|
1067
|
-
category: 'API',
|
|
1068
|
-
severity: 'MEDIUM',
|
|
1069
|
-
description: 'LLM response format mismatch between different providers',
|
|
1070
|
-
suggestions: [
|
|
1071
|
-
'检查当前使用的 provider 是否与期望一致',
|
|
1072
|
-
'验证响应格式处理逻辑',
|
|
1073
|
-
'确认不同 provider 的响应格式差异',
|
|
1074
|
-
'检查是否需要更新响应解析代码',
|
|
1075
|
-
],
|
|
1076
|
-
debugSteps: [
|
|
1077
|
-
'查看 LLM_CALL_DEBUG 中的响应格式',
|
|
1078
|
-
'检查 provider 配置和实际使用的 API',
|
|
1079
|
-
'对比 Anthropic 和 OpenAI 响应格式差异',
|
|
1080
|
-
'验证 logLLMInteraction 函数的格式处理',
|
|
1081
|
-
],
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
// 上下文窗口溢出
|
|
1086
|
-
if (
|
|
1087
|
-
errorMessage.includes('too long') ||
|
|
1088
|
-
errorMessage.includes('context') ||
|
|
1089
|
-
errorMessage.includes('token')
|
|
1090
|
-
) {
|
|
1091
|
-
return {
|
|
1092
|
-
errorType: 'CONTEXT_OVERFLOW',
|
|
1093
|
-
category: 'SYSTEM',
|
|
1094
|
-
severity: 'MEDIUM',
|
|
1095
|
-
description: 'Context window exceeded - conversation too long',
|
|
1096
|
-
suggestions: [
|
|
1097
|
-
'运行 /compact 手动压缩对话历史',
|
|
1098
|
-
'检查自动压缩设置是否正确配置',
|
|
1099
|
-
'减少单次输入的内容长度',
|
|
1100
|
-
'清理不必要的上下文信息',
|
|
1101
|
-
],
|
|
1102
|
-
debugSteps: [
|
|
1103
|
-
'查看 AUTO_COMPACT_* 日志检查压缩触发',
|
|
1104
|
-
'检查 token 使用量和阈值',
|
|
1105
|
-
'查看 CONTEXT_COMPRESSION 相关日志',
|
|
1106
|
-
'验证模型的最大 token 限制',
|
|
1107
|
-
],
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
// 配置相关错误
|
|
1112
|
-
if (
|
|
1113
|
-
errorMessage.includes('config') ||
|
|
1114
|
-
(errorMessage.includes('undefined') && context?.configRelated)
|
|
1115
|
-
) {
|
|
1116
|
-
return {
|
|
1117
|
-
errorType: 'CONFIGURATION',
|
|
1118
|
-
category: 'CONFIG',
|
|
1119
|
-
severity: 'MEDIUM',
|
|
1120
|
-
description: 'Configuration error - missing or invalid settings',
|
|
1121
|
-
suggestions: [
|
|
1122
|
-
'运行 kode config 检查配置设置',
|
|
1123
|
-
'删除损坏的配置文件重新初始化',
|
|
1124
|
-
'检查 JSON 配置文件语法是否正确',
|
|
1125
|
-
'验证环境变量设置',
|
|
1126
|
-
],
|
|
1127
|
-
debugSteps: [
|
|
1128
|
-
'查看 CONFIG_LOAD 和 CONFIG_SAVE 日志',
|
|
1129
|
-
'检查配置文件路径和权限',
|
|
1130
|
-
'验证 JSON 格式: cat ~/.kode/config.json | jq',
|
|
1131
|
-
'查看配置缓存相关的调试信息',
|
|
1132
|
-
],
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
// 通用错误兜底
|
|
1137
|
-
return {
|
|
1138
|
-
errorType: 'UNKNOWN',
|
|
1139
|
-
category: 'SYSTEM',
|
|
1140
|
-
severity: 'MEDIUM',
|
|
1141
|
-
description: `Unexpected error: ${errorMessage}`,
|
|
1142
|
-
suggestions: [
|
|
1143
|
-
'重新启动应用程序',
|
|
1144
|
-
'检查系统资源是否充足',
|
|
1145
|
-
'查看完整的错误日志获取更多信息',
|
|
1146
|
-
'如果问题持续,请报告此错误',
|
|
1147
|
-
],
|
|
1148
|
-
debugSteps: [
|
|
1149
|
-
'使用 --debug-verbose 获取详细日志',
|
|
1150
|
-
'检查 error.log 中的完整错误信息',
|
|
1151
|
-
'查看系统资源使用情况',
|
|
1152
|
-
'收集重现步骤和环境信息',
|
|
1153
|
-
],
|
|
1154
|
-
relatedLogs: errorStack ? [errorStack] : undefined,
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
export function logErrorWithDiagnosis(
|
|
1159
|
-
error: any,
|
|
1160
|
-
context?: any,
|
|
1161
|
-
requestId?: string,
|
|
1162
|
-
) {
|
|
1163
|
-
if (!isDebugMode()) return
|
|
1164
|
-
|
|
1165
|
-
const diagnosis = diagnoseError(error, context)
|
|
1166
|
-
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
1167
|
-
|
|
1168
|
-
// 记录标准错误日志
|
|
1169
|
-
debug.error(
|
|
1170
|
-
'ERROR_OCCURRED',
|
|
1171
|
-
{
|
|
1172
|
-
error: errorMessage,
|
|
1173
|
-
errorType: diagnosis.errorType,
|
|
1174
|
-
category: diagnosis.category,
|
|
1175
|
-
severity: diagnosis.severity,
|
|
1176
|
-
context,
|
|
1177
|
-
},
|
|
1178
|
-
requestId,
|
|
1179
|
-
)
|
|
1180
|
-
|
|
1181
|
-
// 在终端显示诊断信息
|
|
1182
|
-
console.log('\n' + chalk.red('🚨 ERROR DIAGNOSIS'))
|
|
1183
|
-
console.log(chalk.gray('━'.repeat(60)))
|
|
1184
|
-
|
|
1185
|
-
console.log(chalk.red(`❌ ${diagnosis.errorType}`))
|
|
1186
|
-
console.log(
|
|
1187
|
-
chalk.dim(
|
|
1188
|
-
`Category: ${diagnosis.category} | Severity: ${diagnosis.severity}`,
|
|
1189
|
-
),
|
|
1190
|
-
)
|
|
1191
|
-
console.log(`\n${diagnosis.description}`)
|
|
1192
|
-
|
|
1193
|
-
console.log(chalk.yellow('\n💡 Recovery Suggestions:'))
|
|
1194
|
-
diagnosis.suggestions.forEach((suggestion, index) => {
|
|
1195
|
-
console.log(` ${index + 1}. ${suggestion}`)
|
|
1196
|
-
})
|
|
1197
|
-
|
|
1198
|
-
console.log(chalk.cyan('\n🔍 Debug Steps:'))
|
|
1199
|
-
diagnosis.debugSteps.forEach((step, index) => {
|
|
1200
|
-
console.log(` ${index + 1}. ${step}`)
|
|
1201
|
-
})
|
|
1202
|
-
|
|
1203
|
-
if (diagnosis.relatedLogs && diagnosis.relatedLogs.length > 0) {
|
|
1204
|
-
console.log(chalk.magenta('\n📋 Related Information:'))
|
|
1205
|
-
diagnosis.relatedLogs.forEach((log, index) => {
|
|
1206
|
-
const truncatedLog =
|
|
1207
|
-
log.length > 200 ? log.substring(0, 200) + '...' : log
|
|
1208
|
-
console.log(chalk.dim(` ${truncatedLog}`))
|
|
1209
|
-
})
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
const debugPath = DEBUG_PATHS.base()
|
|
1213
|
-
console.log(chalk.gray(`\n📁 Complete logs: ${debugPath}`))
|
|
1214
|
-
console.log(chalk.gray('━'.repeat(60)))
|
|
1215
|
-
}
|
|
1216
|
-
export function getDebugInfo() {
|
|
1217
|
-
return {
|
|
1218
|
-
isDebugMode: isDebugMode(),
|
|
1219
|
-
isVerboseMode: isVerboseMode(),
|
|
1220
|
-
isDebugVerboseMode: isDebugVerboseMode(),
|
|
1221
|
-
startupTimestamp: STARTUP_TIMESTAMP,
|
|
1222
|
-
sessionId: SESSION_ID,
|
|
1223
|
-
currentRequest: currentRequest?.id,
|
|
1224
|
-
activeRequests: Array.from(activeRequests.keys()),
|
|
1225
|
-
terminalLogLevels: isDebugVerboseMode()
|
|
1226
|
-
? Array.from(DEBUG_VERBOSE_TERMINAL_LOG_LEVELS)
|
|
1227
|
-
: Array.from(TERMINAL_LOG_LEVELS),
|
|
1228
|
-
debugPaths: {
|
|
1229
|
-
detailed: DEBUG_PATHS.detailed(),
|
|
1230
|
-
flow: DEBUG_PATHS.flow(),
|
|
1231
|
-
api: DEBUG_PATHS.api(),
|
|
1232
|
-
state: DEBUG_PATHS.state(),
|
|
1233
|
-
},
|
|
1234
|
-
}
|
|
1235
|
-
}
|