Skip to content

Commit e4ce08f

Browse files
Fixture/langfuse record auto mode data error (#308)
* fix: 修复状态栏 context 计数器在 loading 时闪现为 0 的问题 第三方 API(如智谱)在 message_start 中可能不返回完整 usage 数据, 导致 getCurrentUsage 返回全零 usage 对象,使 ctx 显示为 0%。 双重保护: - getCurrentUsage: 跳过全零 usage,继续往前找有真实数据的 message - calculateContextPercentages: totalInputTokens 为 0 时返回 null Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 外部化 ESM 包使用 createRequire 替代裸 require color-diff-napi、image-processor-napi、audio-capture-napi 声明 "type": "module" 但使用裸 require(),Node.js ESM 中 require 不可用。改用 createRequire(import.meta.url) 或顶层 import。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: getDefaultSonnetModel 优先使用用户配置的模型,修复第三方 provider 模型不存在错误 当用户通过 ANTHROPIC_MODEL 或 settings 配置了自定义 provider 支持的模型时, getDefaultSonnetModel/Haiku/Opus 现在会优先使用该配置,而非硬编码 Anthropic 官方模型 ID。 同时改进 Langfuse 可观测性:sideQuery 失败时记录错误信息到 span, optional 模式下标记 WARNING 而非 ERROR。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 将 auto_mode classifier 的 side-query span 绑定到父 trace classifyYoloAction 及 classifyYoloActionXml 接收 parentSpan 参数, 透传给 sideQuery 调用,使 auto_mode 的 side-query span 嵌套在主 agent trace 下。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 穷鬼模式下跳过 memdir_relevance side-query Poor mode 启用时不执行 findRelevantMemories 的预取调用, 避免额外的 API token 消耗。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: 添加 test:all 脚本用于完成任务后的全量检查 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: Vite 构建补齐缺失的 feature flags,修复 auto mode 不可见 Vite 构建插件的 DEFAULT_BUILD_FEATURES 缺少 BUDDY、TRANSCRIPT_CLASSIFIER、 BRIDGE_MODE、ACP、BG_SESSIONS、TEMPLATES,导致 feature('TRANSCRIPT_CLASSIFIER') 被替换为 false,auto mode 从 Shift+Tab 循环中消失。与 build.ts 对齐。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 统一 feature flags 到 defines.ts,修复 Vite 构建缺失 auto mode 将 DEFAULT_BUILD_FEATURES 列表从 build.ts、dev.ts、vite-plugin-feature-flags.ts 三处内联定义统一到 scripts/defines.ts 单一导出。之前的 Vite 插件缺少 TRANSCRIPT_CLASSIFIER 等 feature flag,导致 auto mode 在 Vite 构建中不可见。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 92f8a92 commit e4ce08f

19 files changed

Lines changed: 231 additions & 137 deletions

File tree

CLAUDE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ bun run health
5858
# Check unused exports
5959
bun run check:unused
6060

61+
# Full check (typecheck + lint + test) — run after completing any task
62+
bun run test:all
63+
6164
bun run typecheck
6265

6366
# Remote Control Server

build.ts

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,14 @@
11
import { readdir, readFile, writeFile, cp } from 'fs/promises'
22
import { join } from 'path'
33
import { getMacroDefines } from './scripts/defines.ts'
4+
import { DEFAULT_BUILD_FEATURES } from './scripts/defines.ts'
45

56
const outdir = 'dist'
67

78
// Step 1: Clean output directory
89
const { rmSync } = await import('fs')
910
rmSync(outdir, { recursive: true, force: true })
1011

11-
// Default features that match the official CLI build.
12-
// Additional features can be enabled via FEATURE_<NAME>=1 env vars.
13-
const DEFAULT_BUILD_FEATURES = [
14-
'BUDDY', 'TRANSCRIPT_CLASSIFIER', 'BRIDGE_MODE',
15-
'AGENT_TRIGGERS_REMOTE',
16-
'CHICAGO_MCP',
17-
'VOICE_MODE',
18-
'SHOT_STATS',
19-
'PROMPT_CACHE_BREAK_DETECTION',
20-
'TOKEN_BUDGET',
21-
// P0: local features
22-
'AGENT_TRIGGERS',
23-
'ULTRATHINK',
24-
'BUILTIN_EXPLORE_PLAN_AGENTS',
25-
'LODESTONE',
26-
// P1: API-dependent features
27-
'EXTRACT_MEMORIES',
28-
'VERIFICATION_AGENT',
29-
'KAIROS_BRIEF',
30-
'AWAY_SUMMARY',
31-
'ULTRAPLAN',
32-
// P2: daemon + remote control server
33-
'DAEMON',
34-
// ACP (Agent Client Protocol) agent mode
35-
'ACP',
36-
// PR-package restored features
37-
'WORKFLOW_SCRIPTS',
38-
'HISTORY_SNIP',
39-
'CONTEXT_COLLAPSE',
40-
'MONITOR_TOOL',
41-
'FORK_SUBAGENT',
42-
// 'UDS_INBOX',
43-
'KAIROS',
44-
'COORDINATOR_MODE',
45-
'LAN_PIPES',
46-
'BG_SESSIONS',
47-
'TEMPLATES',
48-
// 'REVIEW_ARTIFACT', // API 请求无响应,需进一步排查 schema 兼容性
49-
// P3: poor mode (disable extract_memories + prompt_suggestion)
50-
'POOR',
51-
]
52-
5312
// Collect FEATURE_* env vars → Bun.build features
5413
const envFeatures = Object.keys(process.env)
5514
.filter(k => k.startsWith('FEATURE_'))

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"postinstall": "node scripts/run-parallel.mjs scripts/postinstall.cjs scripts/setup-chrome-mcp.mjs",
5959
"docs:dev": "npx mintlify dev",
6060
"typecheck": "tsc --noEmit",
61+
"test:all": "bun run typecheck && bun test",
6162
"rcs": "bun run scripts/rcs.ts"
6263
},
6364
"dependencies": {

packages/audio-capture-napi/src/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
import { createRequire } from 'node:module'
2+
3+
// createRequire works in both Bun and Node.js ESM contexts.
4+
// Needed because this package is "type": "module" but uses require() for
5+
// loading native .node addons — bare require is not available in Node.js ESM.
6+
const nodeRequire = createRequire(import.meta.url)
17

28
type AudioCaptureNapi = {
39
startRecording(
@@ -41,7 +47,7 @@ function loadModule(): AudioCaptureNapi | null {
4147
if (process.env.AUDIO_CAPTURE_NODE_PATH) {
4248
try {
4349
// eslint-disable-next-line @typescript-eslint/no-require-imports
44-
cachedModule = require(
50+
cachedModule = nodeRequire(
4551
process.env.AUDIO_CAPTURE_NODE_PATH,
4652
) as AudioCaptureNapi
4753
return cachedModule
@@ -63,7 +69,7 @@ function loadModule(): AudioCaptureNapi | null {
6369
for (const p of fallbacks) {
6470
try {
6571
// eslint-disable-next-line @typescript-eslint/no-require-imports
66-
cachedModule = require(p) as AudioCaptureNapi
72+
cachedModule = nodeRequire(p) as AudioCaptureNapi
6773
return cachedModule
6874
} catch {
6975
// try next

packages/color-diff-napi/src/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@
1717
* getSyntaxTheme always returns the default for the given Claude theme.
1818
*/
1919

20+
import { createRequire } from 'node:module'
2021
import { diffArrays } from 'diff'
2122
import type * as hljsNamespace from 'highlight.js'
2223
import { basename, extname } from 'path'
2324

25+
// createRequire works in both Bun and Node.js ESM contexts.
26+
// Needed because this package is "type": "module" but uses require() for
27+
// lazy loading — bare require is not available in Node.js ESM.
28+
const nodeRequire = createRequire(import.meta.url)
29+
2430
// Lazy: defers loading highlight.js until first render. The full bundle
2531
// registers 190+ language grammars at require time (~50MB, 100-200ms on
2632
// macOS, several× that on Windows). With a top-level import, any caller
@@ -34,8 +40,7 @@ type HLJSApi = typeof hljsNamespace.default
3440
let cachedHljs: HLJSApi | null = null
3541
function hljs(): HLJSApi {
3642
if (cachedHljs) return cachedHljs
37-
// eslint-disable-next-line @typescript-eslint/no-require-imports
38-
const mod = require('highlight.js')
43+
const mod = nodeRequire('highlight.js')
3944
// highlight.js uses `export =` (CJS). Under bun/ESM the interop wraps it
4045
// in .default; under node CJS the module IS the API. Check at runtime.
4146
cachedHljs = 'default' in mod && mod.default ? mod.default : mod

packages/image-processor-napi/src/index.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { readFileSync, unlinkSync } from 'node:fs'
12
import sharpModule from 'sharp'
23

34
export const sharp = sharpModule
@@ -62,13 +63,11 @@ return "${tmpPath}"
6263
}
6364

6465
const file = Bun.file(tmpPath)
65-
// Use synchronous read via Node compat
66-
const fs = require('fs')
67-
const buffer: Buffer = fs.readFileSync(tmpPath)
66+
const buffer: Buffer = readFileSync(tmpPath)
6867

6968
// Clean up temp file
7069
try {
71-
fs.unlinkSync(tmpPath)
70+
unlinkSync(tmpPath)
7271
} catch {
7372
// ignore cleanup errors
7473
}

scripts/defines.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,52 @@ export function getMacroDefines(): Record<string, string> {
1616
"MACRO.VERSION_CHANGELOG": JSON.stringify(""),
1717
};
1818
}
19+
20+
/**
21+
* Default feature flags enabled in both Bun.build and Vite builds.
22+
* Additional features can be enabled via FEATURE_<NAME>=1 env vars.
23+
*
24+
* Used by:
25+
* - build.ts (Bun.build)
26+
* - scripts/vite-plugin-feature-flags.ts (Vite/Rollup)
27+
* - scripts/dev.ts (bun run dev)
28+
*/
29+
export const DEFAULT_BUILD_FEATURES = [
30+
'BUDDY', 'TRANSCRIPT_CLASSIFIER', 'BRIDGE_MODE',
31+
'AGENT_TRIGGERS_REMOTE',
32+
'CHICAGO_MCP',
33+
'VOICE_MODE',
34+
'SHOT_STATS',
35+
'PROMPT_CACHE_BREAK_DETECTION',
36+
'TOKEN_BUDGET',
37+
// P0: local features
38+
'AGENT_TRIGGERS',
39+
'ULTRATHINK',
40+
'BUILTIN_EXPLORE_PLAN_AGENTS',
41+
'LODESTONE',
42+
// P1: API-dependent features
43+
'EXTRACT_MEMORIES',
44+
'VERIFICATION_AGENT',
45+
'KAIROS_BRIEF',
46+
'AWAY_SUMMARY',
47+
'ULTRAPLAN',
48+
// P2: daemon + remote control server
49+
'DAEMON',
50+
// ACP (Agent Client Protocol) agent mode
51+
'ACP',
52+
// PR-package restored features
53+
'WORKFLOW_SCRIPTS',
54+
'HISTORY_SNIP',
55+
'CONTEXT_COLLAPSE',
56+
'MONITOR_TOOL',
57+
'FORK_SUBAGENT',
58+
// 'UDS_INBOX',
59+
'KAIROS',
60+
'COORDINATOR_MODE',
61+
'LAN_PIPES',
62+
'BG_SESSIONS',
63+
'TEMPLATES',
64+
// 'REVIEW_ARTIFACT', // API 请求无响应,需进一步排查 schema 兼容性
65+
// P3: poor mode (disable extract_memories + prompt_suggestion)
66+
'POOR',
67+
] as const;

scripts/dev.ts

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77
import { join, dirname } from "node:path";
88
import { fileURLToPath } from "node:url";
9-
import { getMacroDefines } from "./defines.ts";
9+
import { getMacroDefines, DEFAULT_BUILD_FEATURES } from "./defines.ts";
1010

1111
// Resolve project root from this script's location
1212
const __filename = fileURLToPath(import.meta.url);
@@ -22,47 +22,15 @@ const defineArgs = Object.entries(defines).flatMap(([k, v]) => [
2222
]);
2323

2424
// Bun --feature flags: enable feature() gates at runtime.
25-
// Default features enabled in dev mode.
26-
const DEFAULT_FEATURES = [
27-
"BUDDY", "TRANSCRIPT_CLASSIFIER", "BRIDGE_MODE",
28-
"AGENT_TRIGGERS_REMOTE", "CHICAGO_MCP", "VOICE_MODE",
29-
"SHOT_STATS", "PROMPT_CACHE_BREAK_DETECTION", "TOKEN_BUDGET",
30-
// P0: local features
31-
"AGENT_TRIGGERS",
32-
"ULTRATHINK",
33-
"BUILTIN_EXPLORE_PLAN_AGENTS",
34-
"LODESTONE",
35-
// P1: API-dependent features
36-
"EXTRACT_MEMORIES", "VERIFICATION_AGENT",
37-
"KAIROS_BRIEF", "AWAY_SUMMARY", "ULTRAPLAN",
38-
// P2: daemon + remote control server
39-
"DAEMON",
40-
// ACP (Agent Client Protocol) agent mode
41-
"ACP",
42-
// PR-package restored features
43-
"WORKFLOW_SCRIPTS",
44-
"HISTORY_SNIP",
45-
"CONTEXT_COLLAPSE",
46-
"MONITOR_TOOL",
47-
"FORK_SUBAGENT",
48-
"UDS_INBOX",
49-
"KAIROS",
50-
"COORDINATOR_MODE",
51-
"LAN_PIPES",
52-
"BG_SESSIONS",
53-
"TEMPLATES",
54-
// "REVIEW_ARTIFACT", // API 请求无响应,需进一步排查 schema 兼容性
55-
// P3: poor mode (disable extract_memories + prompt_suggestion)
56-
"POOR",
57-
];
25+
// Uses the shared DEFAULT_BUILD_FEATURES list from defines.ts.
5826

5927
// Any env var matching FEATURE_<NAME>=1 will also enable that feature.
6028
// e.g. FEATURE_PROACTIVE=1 bun run dev
6129
const envFeatures = Object.entries(process.env)
6230
.filter(([k]) => k.startsWith("FEATURE_"))
6331
.map(([k]) => k.replace("FEATURE_", ""));
6432

65-
const allFeatures = [...new Set([...DEFAULT_FEATURES, ...envFeatures])];
33+
const allFeatures = [...new Set([...DEFAULT_BUILD_FEATURES, ...envFeatures])];
6634
const featureArgs = allFeatures.flatMap((name) => ["--feature", name]);
6735

6836
// If BUN_INSPECT is set, pass --inspect-wait to the child process

scripts/vite-plugin-feature-flags.ts

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,5 @@
11
import type { Plugin } from "rollup";
2-
3-
/**
4-
* Default features that match the official CLI build.
5-
* Additional features can be enabled via FEATURE_<NAME>=1 env vars.
6-
*/
7-
const DEFAULT_BUILD_FEATURES = [
8-
"AGENT_TRIGGERS_REMOTE",
9-
"CHICAGO_MCP",
10-
"VOICE_MODE",
11-
"SHOT_STATS",
12-
"PROMPT_CACHE_BREAK_DETECTION",
13-
"TOKEN_BUDGET",
14-
// P0: local features
15-
"AGENT_TRIGGERS",
16-
"ULTRATHINK",
17-
"BUILTIN_EXPLORE_PLAN_AGENTS",
18-
"LODESTONE",
19-
// P1: API-dependent features
20-
"EXTRACT_MEMORIES",
21-
"VERIFICATION_AGENT",
22-
"KAIROS_BRIEF",
23-
"AWAY_SUMMARY",
24-
"ULTRAPLAN",
25-
// P2: daemon + remote control server
26-
"DAEMON",
27-
// PR-package restored features
28-
"WORKFLOW_SCRIPTS",
29-
"HISTORY_SNIP",
30-
"CONTEXT_COLLAPSE",
31-
"MONITOR_TOOL",
32-
"FORK_SUBAGENT",
33-
"KAIROS",
34-
"COORDINATOR_MODE",
35-
"LAN_PIPES",
36-
// P3: poor mode
37-
"POOR",
38-
];
2+
import { DEFAULT_BUILD_FEATURES } from "./defines.ts";
393

404
/**
415
* Collect enabled feature flags from defaults + env vars.

src/memdir/findRelevantMemories.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { logForDebugging } from '../utils/debug.js'
33
import { errorMessage } from '../utils/errors.js'
44
import { getDefaultSonnetModel } from '../utils/model/model.js'
55
import { sideQuery } from '../utils/sideQuery.js'
6+
import type { LangfuseSpan } from '../services/langfuse/index.js'
67
import { jsonParse } from '../utils/slowOperations.js'
78
import {
89
formatMemoryManifest,
@@ -42,6 +43,7 @@ export async function findRelevantMemories(
4243
signal: AbortSignal,
4344
recentTools: readonly string[] = [],
4445
alreadySurfaced: ReadonlySet<string> = new Set(),
46+
parentSpan?: LangfuseSpan | null,
4547
): Promise<RelevantMemory[]> {
4648
const memories = (await scanMemoryFiles(memoryDir, signal)).filter(
4749
m => !alreadySurfaced.has(m.filePath),
@@ -55,6 +57,7 @@ export async function findRelevantMemories(
5557
memories,
5658
signal,
5759
recentTools,
60+
parentSpan,
5861
)
5962
const byFilename = new Map(memories.map(m => [m.filename, m]))
6063
const selected = selectedFilenames
@@ -79,6 +82,7 @@ async function selectRelevantMemories(
7982
memories: MemoryHeader[],
8083
signal: AbortSignal,
8184
recentTools: readonly string[],
85+
parentSpan?: LangfuseSpan | null,
8286
): Promise<string[]> {
8387
const validFilenames = new Set(memories.map(m => m.filename))
8488

@@ -119,6 +123,8 @@ async function selectRelevantMemories(
119123
},
120124
signal,
121125
querySource: 'memdir_relevance',
126+
optional: true,
127+
parentSpan,
122128
})
123129

124130
const textBlock = result.content.find(block => block.type === 'text')

0 commit comments

Comments
 (0)