mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +00:00
feat: 添加对 langfuse 监控的支持 (#242)
* docs: 更新类型检查的 CLAUDE.md * feat: 添加模型 1M 上下文切换 * chore: remove prefetchOfficialMcpUrls call on startup * docs: 添加 git commit 规范 * feat: 第一次接入 langfuse * fix: 修复 generation 的计时的错误 * feat: 添加多 agent 的监控 * feat: 添加 /poor 省流模式,toggle 关闭 extract_memories 和 prompt_suggestion Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: 修复 lock 文件 * chore: 更新类型依赖 --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
70
src/services/langfuse/sanitize.ts
Normal file
70
src/services/langfuse/sanitize.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
const MAX_OUTPUT_LENGTH = 500
|
||||
const REDACTED_FILE_TOOLS = new Set(['FileReadTool', 'FileWriteTool', 'FileEditTool'])
|
||||
const REDACTED_SHELL_TOOLS = new Set(['BashTool', 'PowerShellTool'])
|
||||
const SENSITIVE_OUTPUT_TOOLS = new Set(['ConfigTool', 'MCPTool'])
|
||||
|
||||
const HOME_DIR_PATTERN = new RegExp(
|
||||
(process.env.HOME ?? '/Users/[^/]+').replace(/[.*+?^${}()|[\]\\]/g, '\\$&'),
|
||||
'g',
|
||||
)
|
||||
|
||||
const SENSITIVE_KEY_PATTERN = /(?:api_?key|token|secret|password|credential|auth_header)/i
|
||||
|
||||
export function sanitizeGlobal(data: unknown): unknown {
|
||||
if (typeof data === 'string') {
|
||||
return data.replace(HOME_DIR_PATTERN, '~')
|
||||
}
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
return sanitizeObject(data as Record<string, unknown>)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
function sanitizeObject(obj: Record<string, unknown>): Record<string, unknown> {
|
||||
const result: Record<string, unknown> = {}
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (SENSITIVE_KEY_PATTERN.test(key)) {
|
||||
result[key] = '[REDACTED]'
|
||||
} else if (typeof value === 'string') {
|
||||
result[key] = value.replace(HOME_DIR_PATTERN, '~')
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
result[key] = sanitizeObject(value as Record<string, unknown>)
|
||||
} else {
|
||||
result[key] = value
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export function sanitizeToolInput(toolName: string, input: unknown): unknown {
|
||||
if (typeof input !== 'object' || input === null) return input
|
||||
const obj = { ...(input as Record<string, unknown>) }
|
||||
|
||||
for (const key of Object.keys(obj)) {
|
||||
if (SENSITIVE_KEY_PATTERN.test(key)) {
|
||||
obj[key] = '[REDACTED]'
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of ['file_path', 'path', 'directory'] as const) {
|
||||
if (key in obj && typeof obj[key] === 'string') {
|
||||
obj[key] = (obj[key] as string).replace(HOME_DIR_PATTERN, '~')
|
||||
}
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
export function sanitizeToolOutput(toolName: string, output: string): string {
|
||||
if (REDACTED_FILE_TOOLS.has(toolName)) {
|
||||
return `[file content redacted, ${output.length} chars]`
|
||||
}
|
||||
if (REDACTED_SHELL_TOOLS.has(toolName)) {
|
||||
if (output.length > MAX_OUTPUT_LENGTH) {
|
||||
return output.slice(0, MAX_OUTPUT_LENGTH) + '\n[truncated]'
|
||||
}
|
||||
}
|
||||
if (SENSITIVE_OUTPUT_TOOLS.has(toolName)) {
|
||||
return `[${toolName} output redacted, ${output.length} chars]`
|
||||
}
|
||||
return output
|
||||
}
|
||||
Reference in New Issue
Block a user