Skip to content

perf: 遥测关闭时跳过完整响应/请求的 JSON 序列化 (#31)#37

Open
appergb wants to merge 24 commits into
OrionStarAI:opensourcefrom
appergb:perf/issue-31-lazy-telemetry-serialization
Open

perf: 遥测关闭时跳过完整响应/请求的 JSON 序列化 (#31)#37
appergb wants to merge 24 commits into
OrionStarAI:opensourcefrom
appergb:perf/issue-31-lazy-telemetry-serialization

Conversation

@appergb

@appergb appergb commented May 31, 2026

Copy link
Copy Markdown

关联 issue

Closes #31

问题

GeminiChat 在每轮响应结束后,都会对完整响应(非流式)/ 全部累积 chunk(流式)以及完整 curated 请求历史执行 JSON.stringify,仅仅为了传给 logApiRequest / logApiResponse

但这些文本只在 OpenTelemetry SDK 初始化后才会作为日志属性使用(telemetry/loggers.tsif (!isTelemetrySdkInitialized()) return; 之后才 attributes.response_text = ...);ClearcutLogger.logApiRequestEvent/logApiResponseEvent 完全不读取 request_text / response_text(仅用 model / token 数 / 状态码 / auth_type 等)。

因此在**默认路径(遥测关闭)**下,这是发生在「响应结束 → 记录历史」热路径上的纯 O(响应大小) 开销;流式大响应(上百个 chunk)尤其明显。

改动

  • 新增私有助手 _serializeForTelemetry(value):仅当 isTelemetrySdkInitialized() 为真时才 JSON.stringify,否则返回 undefined
  • _getRequestTextFromContents 与两处 _logApiResponse 调用(非流式 geminiChat.ts:~380 / 流式 :~991)改用该助手。
  • 遥测开启时行为完全不变(仍记录同样的文本),仅消除遥测关闭时的无谓序列化。

测试

  • 新增 3 个单测(geminiChat.test.ts):
    • 非流式 + SDK 未初始化 → request_text / response_text 均为 undefined
    • 非流式 + SDK 已初始化 → 两者均为字符串(行为保持);
    • 流式 + SDK 未初始化 → 不序列化整个 chunk 数组(response_textundefined)。
  • npx vitest run packages/core/src/core/geminiChat.test.ts25 passed
  • npm run typecheck --workspace=packages/core → 通过。
  • 仅改动 geminiChat.ts / geminiChat.test.ts;新增行均符合 Prettier,未触碰文件中既有的历史 lint 负债。

jiangmuran and others added 24 commits February 11, 2026 14:28
- 新增 MermaidBlock 组件,支持流式感知的异步渲染
  - 流式阶段防抖 300ms,代码块闭合后立即渲染
  - 渲染失败时回退到上次成功的 SVG,避免图表消失
  - 通过 MutationObserver 监听 VSCode 主题切换并重新渲染
- 将 markdownComponents 重构为 MarkdownRenderer(React.memo + useMemo)
  稳定流式输出期间的组件引用,避免每次 token 更新导致
  MermaidBlock 卸载重建和 SVG 闪烁
- 修复自动滚动逻辑,通过 ResizeObserver 捕获异步内容高度变化,
  并用 scrollHeight 守卫排除内容缩小导致的误判
- webview 新增 mermaid@11.13.0 依赖
- 新增 .mermaid-block 和 .mermaid-error-badge 样式

Signed-off-by: huangdengdui <huangdengdui@cmcm.com>
Signed-off-by: huangdengdui <huangdengdui@cmcm.com>
统一要求 AI 在响应中使用相对路径+行号格式引用文件
(如 src/routes/index.ts:42),便于 VSCode 等 IDE
插件场景将文件引用渲染为可点击的跳转链接。

涉及:cursor、claude-code、gemini3、vscode、default 风格

Signed-off-by: huangdengdui <huangdengdui@cmcm.com>
工具通过提示词告知大模型 new_string 是"精确字面文本",没有特殊符号限制。

但实现使用 JS 的 String.prototype.replaceAll(string, string),
该方法会将替换字符串中的 $'、$`、$& 等特殊模式展开:
例如 $' 展开为匹配位置之后的所有内容,导致文件内容静默损坏,
工具却仍返回"Successfully modified",大模型无法感知错误。
这与给大模型的使用描述提示词不符。

将替换参数改为函数形式 replaceAll(oldString, () => newString),
函数返回值不触发任何特殊模式解析,使实现与使用描述保持一致。

Signed-off-by: huangdengdui <huangdengdui@cmcm.com>
    根本原因:
    config.initialize() 通过 setImmediate 异步触发 discoverMcpToolsAsync(),
    工具发现完成后结果存入全局缓存 globalDiscoveredTools。但 waitForMcpDiscovery()
    仅等待发现状态变为 COMPLETED,从未将缓存中的工具同步到当前 toolRegistry
    实例,导致非交互模式下 toolRegistry.getFunctionDeclarations() 始终只返回
    内置工具,AI 无法感知和调用任何 MCP 工具。

    修复方案:
    - waitForMcpDiscovery 新增 config 参数
    - 三种状态(COMPLETED/NOT_STARTED/IN_PROGRESS)均在等待后调用
      toolRegistry.discoverMcpTools(),触发从全局缓存的同步
    - 新增 waitForMCPDiscoveryComplete 导入

Signed-off-by: huangdengdui <huangdengdui@cmcm.com>
Signed-off-by: huangdengdui <huangdengdui@cmcm.com>
…I#31)

GeminiChat serialized the full response (and the entire accumulated
stream-chunk array) with JSON.stringify on every turn, plus the full
curated request history, only to hand them to logApiRequest /
logApiResponse. Those payloads are attached solely as OpenTelemetry log
attributes and only when the telemetry SDK is initialized; the
ClearcutLogger path never reads request_text/response_text. So on the
default path (telemetry off) this was pure O(response size) work on the
hot "response end -> record history" path — heaviest for long streaming
responses with many chunks.

Gate the serialization behind isTelemetrySdkInitialized() via a small
_serializeForTelemetry() helper. Behavior is unchanged when telemetry
is active. Adds tests covering streaming and non-streaming paths with
the SDK both on and off.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[性能/CRITICAL] 遥测每轮 JSON.stringify 完整响应 / 全部 chunk

3 participants