@crownpeak/dqm-react-component-dev-mcp 1.2.0

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.
Files changed (444) hide show
  1. package/README.md +138 -0
  2. package/data/.env.example +22 -0
  3. package/data/.gitattributes +47 -0
  4. package/data/.glfrc.json +7 -0
  5. package/data/.husky/pre-commit +5 -0
  6. package/data/.nvmrc +1 -0
  7. package/data/CHANGELOG.md +75 -0
  8. package/data/CODE_OF_CONDUCT.md +129 -0
  9. package/data/CONTRIBUTING.md +203 -0
  10. package/data/DOCS-STRUCTURE.md +307 -0
  11. package/data/I18N.md +292 -0
  12. package/data/LICENSE +22 -0
  13. package/data/README.md +315 -0
  14. package/data/SECURITY.md +125 -0
  15. package/data/WIKI-DEPLOYMENT.md +348 -0
  16. package/data/docs/AI-FEATURES.md +610 -0
  17. package/data/docs/API-REFERENCE.md +1022 -0
  18. package/data/docs/AUTHENTICATION.md +301 -0
  19. package/data/docs/BACKEND-API.md +468 -0
  20. package/data/docs/DEVELOPMENT.md +375 -0
  21. package/data/docs/EXAMPLES.md +622 -0
  22. package/data/docs/MCP-SERVER.md +307 -0
  23. package/data/docs/MIGRATION-GUIDE.md +367 -0
  24. package/data/docs/NPM-PUBLISH.md +193 -0
  25. package/data/docs/QUICKSTART.md +206 -0
  26. package/data/docs/REDIS-SETUP.md +162 -0
  27. package/data/docs/SERVER.md +228 -0
  28. package/data/docs/TROUBLESHOOTING.md +657 -0
  29. package/data/docs/WIDGET-GUIDE.md +638 -0
  30. package/data/docs/WIKI-HOME.md +58 -0
  31. package/data/docs/WIKI-SIDEBAR.md +39 -0
  32. package/data/package.json +171 -0
  33. package/data/playwright.config.ts +64 -0
  34. package/data/probe/.cargo/config.toml +10 -0
  35. package/data/probe/.claude/commands/performance-review.md +15 -0
  36. package/data/probe/.clinerules +288 -0
  37. package/data/probe/.dockerignore +57 -0
  38. package/data/probe/.githooks/post-commit +11 -0
  39. package/data/probe/.githooks/pre-commit +99 -0
  40. package/data/probe/.githooks/pre-commit-vow +9 -0
  41. package/data/probe/.prompts/engineer.md +41 -0
  42. package/data/probe/.roomodes +28 -0
  43. package/data/probe/.windsurfrules +0 -0
  44. package/data/probe/BASH_TOOL_SUMMARY.md +148 -0
  45. package/data/probe/BENCHMARKING.md +256 -0
  46. package/data/probe/CLAUDE.md +226 -0
  47. package/data/probe/CODE_OF_CONDUCT.md +128 -0
  48. package/data/probe/CONTRIBUTING.md +193 -0
  49. package/data/probe/Cargo.toml +120 -0
  50. package/data/probe/Cross.toml +10 -0
  51. package/data/probe/DOCKER-README.md +224 -0
  52. package/data/probe/Dockerfile +32 -0
  53. package/data/probe/ENHANCED_DEBUG_TELEMETRY.md +188 -0
  54. package/data/probe/LICENSE +201 -0
  55. package/data/probe/Makefile +210 -0
  56. package/data/probe/README.md +824 -0
  57. package/data/probe/SECURITY.md +67 -0
  58. package/data/probe/WINDOWS-GUIDE.md +294 -0
  59. package/data/probe/benches/parsing_benchmarks.rs +370 -0
  60. package/data/probe/benches/search_benchmarks.rs +599 -0
  61. package/data/probe/benches/simd_benchmarks.rs +372 -0
  62. package/data/probe/benches/timing_benchmarks.rs +287 -0
  63. package/data/probe/build-windows.bat +229 -0
  64. package/data/probe/codex-config/config.toml +6 -0
  65. package/data/probe/docs/PERFORMANCE_OPTIMIZATION.md +161 -0
  66. package/data/probe/examples/cache_demo.rs +46 -0
  67. package/data/probe/examples/chat/.dockerignore +37 -0
  68. package/data/probe/examples/chat/ChatSessionManager.js +295 -0
  69. package/data/probe/examples/chat/Dockerfile +98 -0
  70. package/data/probe/examples/chat/LICENSE +201 -0
  71. package/data/probe/examples/chat/LOCAL_IMAGE_SUPPORT.md +195 -0
  72. package/data/probe/examples/chat/MCP_INTEGRATION.md +400 -0
  73. package/data/probe/examples/chat/README.md +338 -0
  74. package/data/probe/examples/chat/TRACING.md +226 -0
  75. package/data/probe/examples/chat/appTracer.js +968 -0
  76. package/data/probe/examples/chat/auth.js +76 -0
  77. package/data/probe/examples/chat/bin/probe-chat.js +13 -0
  78. package/data/probe/examples/chat/build.js +104 -0
  79. package/data/probe/examples/chat/cancelRequest.js +84 -0
  80. package/data/probe/examples/chat/demo-agentic-image-flow.js +88 -0
  81. package/data/probe/examples/chat/demo-local-images.js +128 -0
  82. package/data/probe/examples/chat/fileSpanExporter.js +181 -0
  83. package/data/probe/examples/chat/implement/README.md +228 -0
  84. package/data/probe/examples/chat/implement/backends/AiderBackend.js +750 -0
  85. package/data/probe/examples/chat/implement/backends/BaseBackend.js +276 -0
  86. package/data/probe/examples/chat/implement/backends/ClaudeCodeBackend.js +767 -0
  87. package/data/probe/examples/chat/implement/backends/MockBackend.js +237 -0
  88. package/data/probe/examples/chat/implement/backends/registry.js +85 -0
  89. package/data/probe/examples/chat/implement/core/BackendManager.js +567 -0
  90. package/data/probe/examples/chat/implement/core/ImplementTool.js +354 -0
  91. package/data/probe/examples/chat/implement/core/config.js +428 -0
  92. package/data/probe/examples/chat/implement/core/timeouts.js +58 -0
  93. package/data/probe/examples/chat/implement/core/utils.js +496 -0
  94. package/data/probe/examples/chat/implement/types/BackendTypes.js +126 -0
  95. package/data/probe/examples/chat/index.js +669 -0
  96. package/data/probe/examples/chat/mcpServer.js +341 -0
  97. package/data/probe/examples/chat/npm/LICENSE +15 -0
  98. package/data/probe/examples/chat/npm/README.md +168 -0
  99. package/data/probe/examples/chat/npm/bin/probe-chat.js +156 -0
  100. package/data/probe/examples/chat/npm/index.js +259 -0
  101. package/data/probe/examples/chat/npm/package.json +54 -0
  102. package/data/probe/examples/chat/package.json +102 -0
  103. package/data/probe/examples/chat/probeChat.js +456 -0
  104. package/data/probe/examples/chat/probeTool.js +491 -0
  105. package/data/probe/examples/chat/storage/JsonChatStorage.js +476 -0
  106. package/data/probe/examples/chat/telemetry.js +281 -0
  107. package/data/probe/examples/chat/test/integration/chatFlows.test.js +320 -0
  108. package/data/probe/examples/chat/test/integration/toolCalling.test.js +471 -0
  109. package/data/probe/examples/chat/test/mocks/mockLLMProvider.js +269 -0
  110. package/data/probe/examples/chat/test/test-backends.js +90 -0
  111. package/data/probe/examples/chat/test/testUtils.js +530 -0
  112. package/data/probe/examples/chat/test/unit/backendTimeout.test.js +161 -0
  113. package/data/probe/examples/chat/test/unit/packageFiles.test.js +120 -0
  114. package/data/probe/examples/chat/test/verify-tests.js +118 -0
  115. package/data/probe/examples/chat/test-agentic-image-loading.js +294 -0
  116. package/data/probe/examples/chat/test-ai-sdk-telemetry.js +204 -0
  117. package/data/probe/examples/chat/test-chat-tracing.js +38 -0
  118. package/data/probe/examples/chat/test-direct-function.js +49 -0
  119. package/data/probe/examples/chat/test-file-size-validation.js +103 -0
  120. package/data/probe/examples/chat/test-full-mcp-integration.js +258 -0
  121. package/data/probe/examples/chat/test-github-context.txt +12 -0
  122. package/data/probe/examples/chat/test-hierarchy.js +203 -0
  123. package/data/probe/examples/chat/test-image-spans.js +37 -0
  124. package/data/probe/examples/chat/test-local-image-reading.js +176 -0
  125. package/data/probe/examples/chat/test-mcp-integration.js +136 -0
  126. package/data/probe/examples/chat/test-mcp-probe-server.js +161 -0
  127. package/data/probe/examples/chat/test-mcp-with-ai.js +279 -0
  128. package/data/probe/examples/chat/test-multiple-allowed-dirs.js +111 -0
  129. package/data/probe/examples/chat/test-probe-mcp-server.js +110 -0
  130. package/data/probe/examples/chat/test-security-validation.js +145 -0
  131. package/data/probe/examples/chat/test-simple-tracing.js +32 -0
  132. package/data/probe/examples/chat/test-trace-verification.js +235 -0
  133. package/data/probe/examples/chat/test-tracing.js +114 -0
  134. package/data/probe/examples/chat/tokenCounter.js +419 -0
  135. package/data/probe/examples/chat/tokenUsageDisplay.js +134 -0
  136. package/data/probe/examples/chat/webServer.js +1103 -0
  137. package/data/probe/examples/reranker/Cargo.toml +33 -0
  138. package/data/probe/examples/reranker/DEBUG_OUTPUT_ANALYSIS.md +71 -0
  139. package/data/probe/examples/reranker/MODELS.md +66 -0
  140. package/data/probe/examples/reranker/MODEL_COMPARISON.md +60 -0
  141. package/data/probe/examples/reranker/MULTI_MODEL_ANALYSIS.md +176 -0
  142. package/data/probe/examples/reranker/PERFORMANCE_SUMMARY.md +156 -0
  143. package/data/probe/examples/reranker/README.md +347 -0
  144. package/data/probe/examples/reranker/RUST_BERT_COMPARISON.md +82 -0
  145. package/data/probe/examples/reranker/TOKENIZATION_GUIDE.md +120 -0
  146. package/data/probe/examples/reranker/check_rust_tokenizer.py +108 -0
  147. package/data/probe/examples/reranker/convert_to_torchscript.py +109 -0
  148. package/data/probe/examples/reranker/debug_scoring.py +189 -0
  149. package/data/probe/examples/reranker/debug_tokenization.py +154 -0
  150. package/data/probe/examples/reranker/download_models.sh +73 -0
  151. package/data/probe/examples/reranker/requirements.txt +13 -0
  152. package/data/probe/examples/reranker/run_comprehensive_benchmark.sh +83 -0
  153. package/data/probe/examples/reranker/rust_bert_test/Cargo.toml +12 -0
  154. package/data/probe/examples/reranker/rust_bert_test/README.md +54 -0
  155. package/data/probe/examples/reranker/simple_test.py +50 -0
  156. package/data/probe/examples/reranker/test_all_models.sh +63 -0
  157. package/data/probe/examples/reranker/test_bert_results.sh +44 -0
  158. package/data/probe/examples/reranker/test_cross_encoder.py +334 -0
  159. package/data/probe/examples/reranker/test_cross_encoder.sh +80 -0
  160. package/data/probe/examples/reranker/test_exact_comparison.py +151 -0
  161. package/data/probe/examples/reranker/test_parallel_performance.sh +56 -0
  162. package/data/probe/examples/reranker/test_scores.py +132 -0
  163. package/data/probe/install.ps1 +508 -0
  164. package/data/probe/install.sh +460 -0
  165. package/data/probe/npm/CLONE_METHOD_EXAMPLES.md +596 -0
  166. package/data/probe/npm/CONTEXT_COMPACTION.md +303 -0
  167. package/data/probe/npm/DELEGATE_TOOL_README.md +166 -0
  168. package/data/probe/npm/MAID_INTEGRATION.md +313 -0
  169. package/data/probe/npm/MCP_INTEGRATION_SUMMARY.md +241 -0
  170. package/data/probe/npm/README.md +824 -0
  171. package/data/probe/npm/bin/.gitignore +7 -0
  172. package/data/probe/npm/bin/.gitkeep +0 -0
  173. package/data/probe/npm/bin/README.md +12 -0
  174. package/data/probe/npm/bin/probe +167 -0
  175. package/data/probe/npm/docs/CLAUDE_CODE_INTEGRATION.md +414 -0
  176. package/data/probe/npm/docs/CODEX_INTEGRATION.md +502 -0
  177. package/data/probe/npm/docs/EDIT_CREATE_TOOLS.md +233 -0
  178. package/data/probe/npm/docs/RETRY_AND_FALLBACK.md +674 -0
  179. package/data/probe/npm/example-usage.js +335 -0
  180. package/data/probe/npm/examples/multi-engine-demo.js +117 -0
  181. package/data/probe/npm/examples/probe-agent-cli.js +113 -0
  182. package/data/probe/npm/examples/test-agent-edit.js +114 -0
  183. package/data/probe/npm/examples/test-edit-create.js +120 -0
  184. package/data/probe/npm/examples/test-edit-direct.js +114 -0
  185. package/data/probe/npm/index.d.ts +744 -0
  186. package/data/probe/npm/jest.config.js +52 -0
  187. package/data/probe/npm/package.json +117 -0
  188. package/data/probe/npm/scripts/build-agent.cjs +75 -0
  189. package/data/probe/npm/scripts/build-cjs.js +124 -0
  190. package/data/probe/npm/scripts/build-mcp.cjs +36 -0
  191. package/data/probe/npm/scripts/postinstall.js +216 -0
  192. package/data/probe/npm/test-codex-e2e.js +78 -0
  193. package/data/probe/npm/test-download-lock.js +109 -0
  194. package/data/probe/npm/test-grep-security.js +94 -0
  195. package/data/probe/npm/test-grep-simplified.js +63 -0
  196. package/data/probe/npm/test-grep.js +51 -0
  197. package/data/probe/npm/tests/README.md +96 -0
  198. package/data/probe/npm/tests/agent-compact-history.test.js +174 -0
  199. package/data/probe/npm/tests/allow-tests-default.test.js +151 -0
  200. package/data/probe/npm/tests/contextCompactor.test.js +498 -0
  201. package/data/probe/npm/tests/delegate-config.test.js +353 -0
  202. package/data/probe/npm/tests/delegate-integration.test.js +348 -0
  203. package/data/probe/npm/tests/extractor-integration.test.js +162 -0
  204. package/data/probe/npm/tests/extractor.test.js +317 -0
  205. package/data/probe/npm/tests/fixtures/sampleDiagrams.js +267 -0
  206. package/data/probe/npm/tests/integration/claude-code-auto-fallback.spec.js +148 -0
  207. package/data/probe/npm/tests/integration/claude-code-multi-step.spec.js +127 -0
  208. package/data/probe/npm/tests/integration/claude-code-tool-events.spec.js +163 -0
  209. package/data/probe/npm/tests/integration/codex-auto-fallback.spec.js +191 -0
  210. package/data/probe/npm/tests/integration/codex-tool-events.spec.js +147 -0
  211. package/data/probe/npm/tests/integration/examplesChatMcp.test.js +402 -0
  212. package/data/probe/npm/tests/integration/mcpDotenvSupport.test.js +174 -0
  213. package/data/probe/npm/tests/integration/mcpErrorHandling.test.js +566 -0
  214. package/data/probe/npm/tests/integration/mcpRobustness.test.js +564 -0
  215. package/data/probe/npm/tests/integration/mcpStdoutPurity.test.js +355 -0
  216. package/data/probe/npm/tests/integration/probeAgentMcp.test.js +398 -0
  217. package/data/probe/npm/tests/integration/retryFallback.test.js +368 -0
  218. package/data/probe/npm/tests/integration/schema-in-initial-message.test.js +318 -0
  219. package/data/probe/npm/tests/integration/schema-validation-loop-prevention.test.js +244 -0
  220. package/data/probe/npm/tests/integration/schemaRetryLogic.test.js +94 -0
  221. package/data/probe/npm/tests/integration/validationFlow.test.js +329 -0
  222. package/data/probe/npm/tests/manual/test-codex-basic.js +110 -0
  223. package/data/probe/npm/tests/mcp/mcpClientManager.test.js +614 -0
  224. package/data/probe/npm/tests/mcp/mcpConfig.test.js +359 -0
  225. package/data/probe/npm/tests/mcp/mcpXmlBridge.test.js +436 -0
  226. package/data/probe/npm/tests/mcp/mockMcpServer.js +510 -0
  227. package/data/probe/npm/tests/mcp-strict-syntax.test.js +319 -0
  228. package/data/probe/npm/tests/mermaidQuoteEscaping.test.js +214 -0
  229. package/data/probe/npm/tests/nestedQuoteFix.test.js +40 -0
  230. package/data/probe/npm/tests/setup.js +46 -0
  231. package/data/probe/npm/tests/unit/allowed-tools.test.js +513 -0
  232. package/data/probe/npm/tests/unit/attempt-completion-closing-tag-in-content.test.js +188 -0
  233. package/data/probe/npm/tests/unit/attemptCompletionJsonFix.test.js +238 -0
  234. package/data/probe/npm/tests/unit/attemptCompletionJsonIssue.test.js +128 -0
  235. package/data/probe/npm/tests/unit/backtickAutoFix.test.js +35 -0
  236. package/data/probe/npm/tests/unit/bash-probe-agent-integration.test.js +389 -0
  237. package/data/probe/npm/tests/unit/bash-simple-commands.test.js +324 -0
  238. package/data/probe/npm/tests/unit/bash-tool-comprehensive.test.js +371 -0
  239. package/data/probe/npm/tests/unit/bash-tool-integration.test.js +310 -0
  240. package/data/probe/npm/tests/unit/bash-tool.test.js +341 -0
  241. package/data/probe/npm/tests/unit/completion-prompt.test.js +379 -0
  242. package/data/probe/npm/tests/unit/cwd-path-options.test.js +287 -0
  243. package/data/probe/npm/tests/unit/delegate-limits.test.js +422 -0
  244. package/data/probe/npm/tests/unit/direct-content-attempt-completion.test.js +235 -0
  245. package/data/probe/npm/tests/unit/edit-create-tools.test.js +609 -0
  246. package/data/probe/npm/tests/unit/enhancedMermaidValidation.test.js +577 -0
  247. package/data/probe/npm/tests/unit/extract-content.test.js +83 -0
  248. package/data/probe/npm/tests/unit/extract-multiple-targets.test.js +89 -0
  249. package/data/probe/npm/tests/unit/fallbackManager.test.js +442 -0
  250. package/data/probe/npm/tests/unit/githubCompatibilityValidation.test.js +258 -0
  251. package/data/probe/npm/tests/unit/imageConfig.test.js +149 -0
  252. package/data/probe/npm/tests/unit/imagePathResolution.test.js +345 -0
  253. package/data/probe/npm/tests/unit/json-fixing-agent.test.js +238 -0
  254. package/data/probe/npm/tests/unit/json-validation-enhanced-errors.test.js +199 -0
  255. package/data/probe/npm/tests/unit/jsonValidationInfiniteLoopFix.test.js +228 -0
  256. package/data/probe/npm/tests/unit/maidIntegration.test.js +139 -0
  257. package/data/probe/npm/tests/unit/maxIterationsWarning.test.js +195 -0
  258. package/data/probe/npm/tests/unit/mermaidEdgeLabelFix.test.js +161 -0
  259. package/data/probe/npm/tests/unit/mermaidHtmlEntities.test.js +76 -0
  260. package/data/probe/npm/tests/unit/mermaidInfiniteLoopFix.test.js +64 -0
  261. package/data/probe/npm/tests/unit/mermaidValidation.test.js +723 -0
  262. package/data/probe/npm/tests/unit/mermaidValidationVisorExample.test.js +309 -0
  263. package/data/probe/npm/tests/unit/probe-agent-clone-realistic.test.js +643 -0
  264. package/data/probe/npm/tests/unit/probe-agent-clone.test.js +476 -0
  265. package/data/probe/npm/tests/unit/probe-agent-delegate.test.js +400 -0
  266. package/data/probe/npm/tests/unit/probe-agent-model-option.test.js +118 -0
  267. package/data/probe/npm/tests/unit/probeTool-security.test.js +283 -0
  268. package/data/probe/npm/tests/unit/readImageTool.test.js +418 -0
  269. package/data/probe/npm/tests/unit/retryManager.test.js +317 -0
  270. package/data/probe/npm/tests/unit/schema-aware-reminders.test.js +288 -0
  271. package/data/probe/npm/tests/unit/schemaDefinitionDetection.test.js +115 -0
  272. package/data/probe/npm/tests/unit/schemaUtils.test.js +1268 -0
  273. package/data/probe/npm/tests/unit/simpleTelemetry.test.js +282 -0
  274. package/data/probe/npm/tests/unit/simplified-attempt-completion.test.js +274 -0
  275. package/data/probe/npm/tests/unit/single-quote-json-bug.test.js +231 -0
  276. package/data/probe/npm/tests/unit/subgraphAutoFix.test.js +110 -0
  277. package/data/probe/npm/tests/unit/system-prompt.test.js +32 -0
  278. package/data/probe/npm/tests/unit/types-probe-agent-options.test.js +42 -0
  279. package/data/probe/npm/tests/unit/xmlParsing.test.js +720 -0
  280. package/data/probe/npm/tsconfig.json +21 -0
  281. package/data/probe/result1.txt +19 -0
  282. package/data/probe/result2.txt +26 -0
  283. package/data/probe/scripts/benchmark.sh +270 -0
  284. package/data/probe/scripts/cache_memory_analysis.rs +844 -0
  285. package/data/probe/scripts/claude-hook-wrapper.sh +56 -0
  286. package/data/probe/site/.env.example +10 -0
  287. package/data/probe/site/DEPLOYMENT.md +86 -0
  288. package/data/probe/site/README.md +183 -0
  289. package/data/probe/site/adding-languages.md +135 -0
  290. package/data/probe/site/ai-chat.md +427 -0
  291. package/data/probe/site/ai-integration.md +1488 -0
  292. package/data/probe/site/blog/agentic-flow-custom-xml-protocol.md +407 -0
  293. package/data/probe/site/blog/index.md +118 -0
  294. package/data/probe/site/blog/v0.6.0-release.md +426 -0
  295. package/data/probe/site/blog.md +8 -0
  296. package/data/probe/site/changelog.md +200 -0
  297. package/data/probe/site/cli-mode.md +437 -0
  298. package/data/probe/site/code-extraction.md +436 -0
  299. package/data/probe/site/contributing/README.md +9 -0
  300. package/data/probe/site/contributing/documentation-cross-references.md +215 -0
  301. package/data/probe/site/contributing/documentation-maintenance.md +275 -0
  302. package/data/probe/site/contributing/documentation-structure.md +75 -0
  303. package/data/probe/site/documentation-cross-references.md +215 -0
  304. package/data/probe/site/documentation-guide.md +132 -0
  305. package/data/probe/site/documentation-maintenance.md +275 -0
  306. package/data/probe/site/features.md +147 -0
  307. package/data/probe/site/how-it-works.md +118 -0
  308. package/data/probe/site/index.md +175 -0
  309. package/data/probe/site/index.md.bak +133 -0
  310. package/data/probe/site/installation.md +235 -0
  311. package/data/probe/site/integrations/docker.md +248 -0
  312. package/data/probe/site/integrations/github-actions.md +413 -0
  313. package/data/probe/site/language-support-overview.md +168 -0
  314. package/data/probe/site/mcp-integration.md +587 -0
  315. package/data/probe/site/mcp-server.md +304 -0
  316. package/data/probe/site/navigation-structure.md +76 -0
  317. package/data/probe/site/nodejs-sdk.md +798 -0
  318. package/data/probe/site/output-formats.md +625 -0
  319. package/data/probe/site/package.json +21 -0
  320. package/data/probe/site/public/_headers +28 -0
  321. package/data/probe/site/public/_redirects +11 -0
  322. package/data/probe/site/quick-start.md +289 -0
  323. package/data/probe/site/search-functionality.md +291 -0
  324. package/data/probe/site/search-reference.md +291 -0
  325. package/data/probe/site/supported-languages.md +215 -0
  326. package/data/probe/site/use-cases/README.md +8 -0
  327. package/data/probe/site/use-cases/advanced-cli.md +253 -0
  328. package/data/probe/site/use-cases/ai-code-editors.md +239 -0
  329. package/data/probe/site/use-cases/building-ai-tools.md +529 -0
  330. package/data/probe/site/use-cases/cli-ai-workflows.md +285 -0
  331. package/data/probe/site/use-cases/deploying-probe-web-interface.md +255 -0
  332. package/data/probe/site/use-cases/integrating-probe-into-ai-code-editors.md +161 -0
  333. package/data/probe/site/use-cases/nodejs-sdk.md +596 -0
  334. package/data/probe/site/use-cases/team-chat.md +350 -0
  335. package/data/probe/site/web-interface.md +434 -0
  336. package/data/probe/site/wrangler.toml +9 -0
  337. package/data/probe/test-api-key.sh +1 -0
  338. package/data/probe/test-probe-implementation/hello.js +7 -0
  339. package/data/probe/test_cases/demonstrate_early_termination_issues.sh +176 -0
  340. package/data/probe/test_cases/early_termination_issues.rs +533 -0
  341. package/data/probe/test_data/test_nested_struct.go +26 -0
  342. package/data/probe/tests/README.md +286 -0
  343. package/data/probe/tests/README_search_determinism_tests.md +116 -0
  344. package/data/probe/tests/adjacent_comment_test.rs +152 -0
  345. package/data/probe/tests/apostrophe_handling_tests.rs +132 -0
  346. package/data/probe/tests/block_filtering_with_ast_tests.rs +669 -0
  347. package/data/probe/tests/block_merging_tests.rs +396 -0
  348. package/data/probe/tests/c_outline_format_tests.rs +2179 -0
  349. package/data/probe/tests/cache_invalidation_issues.rs.disabled +682 -0
  350. package/data/probe/tests/cache_order_tests.rs +147 -0
  351. package/data/probe/tests/cache_query_scoping_tests.rs +221 -0
  352. package/data/probe/tests/cli_tests.rs +680 -0
  353. package/data/probe/tests/comment_context_integration_test.rs +240 -0
  354. package/data/probe/tests/common.rs +33 -0
  355. package/data/probe/tests/complex_block_merging_tests.rs +599 -0
  356. package/data/probe/tests/complex_query_block_filtering_tests.rs +422 -0
  357. package/data/probe/tests/control_flow_closing_braces_test.rs +91 -0
  358. package/data/probe/tests/cpp_outline_format_tests.rs +1507 -0
  359. package/data/probe/tests/csharp_outline_format_tests.rs +941 -0
  360. package/data/probe/tests/elastic_query_integration_tests.rs +922 -0
  361. package/data/probe/tests/extract_command_tests.rs +1848 -0
  362. package/data/probe/tests/extract_deduplication_tests.rs +146 -0
  363. package/data/probe/tests/extract_input_file_tests.rs +84 -0
  364. package/data/probe/tests/extract_prompt_tests.rs +102 -0
  365. package/data/probe/tests/filename_search_tests.rs +96 -0
  366. package/data/probe/tests/fixtures/user/AssemblyInfo.cs +3 -0
  367. package/data/probe/tests/github_extract_tests.rs +234 -0
  368. package/data/probe/tests/go_comment_test.rs +253 -0
  369. package/data/probe/tests/go_outline_format_tests.rs +2587 -0
  370. package/data/probe/tests/go_path_resolver_tests.rs +96 -0
  371. package/data/probe/tests/html_outline_format_tests.rs +637 -0
  372. package/data/probe/tests/integration_tests.rs +837 -0
  373. package/data/probe/tests/ip_whitelist_test.rs +148 -0
  374. package/data/probe/tests/java_outline_format_tests.rs +1611 -0
  375. package/data/probe/tests/javascript_extract_tests.rs +315 -0
  376. package/data/probe/tests/javascript_outline_format_tests.rs +1464 -0
  377. package/data/probe/tests/json_format_tests.rs +436 -0
  378. package/data/probe/tests/json_schema_validation_tests.rs +450 -0
  379. package/data/probe/tests/lib_usage.rs +60 -0
  380. package/data/probe/tests/line_comment_context_extension_test.rs +459 -0
  381. package/data/probe/tests/line_map_cache_tests.rs +114 -0
  382. package/data/probe/tests/markdown_integration_tests.rs +190 -0
  383. package/data/probe/tests/mocks/test_ip_whitelist.go +11 -0
  384. package/data/probe/tests/mocks/test_object.js +27 -0
  385. package/data/probe/tests/mocks/test_struct.go +50 -0
  386. package/data/probe/tests/multi_keyword_pattern_tests.rs +464 -0
  387. package/data/probe/tests/multi_language_syntax_integration_tests.rs +218 -0
  388. package/data/probe/tests/multiple_capture_groups_tests.rs +169 -0
  389. package/data/probe/tests/negative_compound_word_tests.rs +246 -0
  390. package/data/probe/tests/nested_symbol_extraction_tests.rs +99 -0
  391. package/data/probe/tests/outline_cross_file_interference_test.rs +335 -0
  392. package/data/probe/tests/outline_keyword_preservation_test.rs +67 -0
  393. package/data/probe/tests/output_format_edge_cases_tests.rs +693 -0
  394. package/data/probe/tests/parallel_extraction_tests.rs +178 -0
  395. package/data/probe/tests/parallel_search_tests.rs +355 -0
  396. package/data/probe/tests/path_resolver_tests.rs +698 -0
  397. package/data/probe/tests/php_outline_format_extended_tests.rs +928 -0
  398. package/data/probe/tests/php_outline_format_tests.rs +768 -0
  399. package/data/probe/tests/property_tests.proptest-regressions +9 -0
  400. package/data/probe/tests/property_tests.rs +118 -0
  401. package/data/probe/tests/python_outline_format_tests.rs +1538 -0
  402. package/data/probe/tests/query_command_json_tests.rs +438 -0
  403. package/data/probe/tests/query_command_tests.rs +232 -0
  404. package/data/probe/tests/query_command_xml_tests.rs +569 -0
  405. package/data/probe/tests/quoted_term_with_negative_keyword_tests.rs +216 -0
  406. package/data/probe/tests/required_terms_filename_tests.rs +116 -0
  407. package/data/probe/tests/ruby_outline_format_tests.rs +1011 -0
  408. package/data/probe/tests/rust_line_comment_context_test.rs +151 -0
  409. package/data/probe/tests/rust_outline_format_enhanced_tests.rs +725 -0
  410. package/data/probe/tests/rust_outline_format_tests.rs +843 -0
  411. package/data/probe/tests/schemas/xml_output_schema.xsd +38 -0
  412. package/data/probe/tests/search_determinism_tests.rs +451 -0
  413. package/data/probe/tests/search_hints_tests.rs +253 -0
  414. package/data/probe/tests/special_character_escaping_tests.rs +417 -0
  415. package/data/probe/tests/stemming_compound_word_filtering_tests.rs +535 -0
  416. package/data/probe/tests/strict_elastic_syntax_tests.rs +404 -0
  417. package/data/probe/tests/swift_outline_format_tests.rs +3319 -0
  418. package/data/probe/tests/symbols_tests.rs +166 -0
  419. package/data/probe/tests/test_file.rs +45 -0
  420. package/data/probe/tests/test_tokenize.rs +28 -0
  421. package/data/probe/tests/timeout_tests.rs +82 -0
  422. package/data/probe/tests/tokenization_tests.rs +195 -0
  423. package/data/probe/tests/tokenized_block_filtering_tests.rs +174 -0
  424. package/data/probe/tests/typescript_extract_tests.rs +214 -0
  425. package/data/probe/tests/typescript_outline_format_tests.rs +2188 -0
  426. package/data/probe/tests/xml_format_tests.rs +568 -0
  427. package/data/probe/tests/xml_schema_validation_tests.rs +497 -0
  428. package/data/scripts/postinstall.mjs +9 -0
  429. package/data/scripts/set-version.js +0 -0
  430. package/data/scripts/wiki-build.sh +111 -0
  431. package/data/scripts/wiki-deploy.sh +73 -0
  432. package/data/serve.json +12 -0
  433. package/data/test/demo-dynamic.html +134 -0
  434. package/data/test/demo-esm.html +105 -0
  435. package/data/test/demo-iife.html +78 -0
  436. package/data/tsconfig.json +7 -0
  437. package/data/vite.server.ts +483 -0
  438. package/data/vitest.config.ts +40 -0
  439. package/data/wiki/Home.md +58 -0
  440. package/data/wiki/_Sidebar.md +39 -0
  441. package/docs-mcp.config.json +20 -0
  442. package/package.json +56 -0
  443. package/src/config.js +111 -0
  444. package/src/index.js +395 -0
@@ -0,0 +1,968 @@
1
+ /**
2
+ * Custom Application Tracing Layer for Probe Chat
3
+ *
4
+ * This module provides granular tracing that follows application logic closely,
5
+ * replacing the generic Vercel AI SDK tracing with application-specific spans.
6
+ */
7
+
8
+ import { trace, SpanStatusCode, SpanKind, context, TraceFlags } from '@opentelemetry/api';
9
+ import { randomUUID, createHash } from 'crypto';
10
+
11
+ /**
12
+ * Convert a session ID to a valid OpenTelemetry trace ID (32-char hex)
13
+ */
14
+ function sessionIdToTraceId(sessionId) {
15
+ // Create a hash of the session ID and take first 32 chars
16
+ const hash = createHash('sha256').update(sessionId).digest('hex');
17
+ return hash.substring(0, 32);
18
+ }
19
+
20
+ // OpenTelemetry semantic conventions and custom attributes
21
+ const OTEL_ATTRS = {
22
+ // Standard semantic conventions
23
+ SERVICE_NAME: 'service.name',
24
+ SERVICE_VERSION: 'service.version',
25
+ HTTP_METHOD: 'http.method',
26
+ HTTP_STATUS_CODE: 'http.status_code',
27
+ ERROR_TYPE: 'error.type',
28
+ ERROR_MESSAGE: 'error.message',
29
+
30
+ // Custom application attributes following OpenTelemetry naming conventions
31
+ APP_SESSION_ID: 'app.session.id',
32
+ APP_MESSAGE_TYPE: 'app.message.type',
33
+ APP_MESSAGE_CONTENT: 'app.message.content',
34
+ APP_MESSAGE_LENGTH: 'app.message.length',
35
+ APP_MESSAGE_HASH: 'app.message.hash',
36
+ APP_AI_PROVIDER: 'app.ai.provider',
37
+ APP_AI_MODEL: 'app.ai.model',
38
+ APP_AI_TEMPERATURE: 'app.ai.temperature',
39
+ APP_AI_MAX_TOKENS: 'app.ai.max_tokens',
40
+ APP_AI_RESPONSE_CONTENT: 'app.ai.response.content',
41
+ APP_AI_RESPONSE_LENGTH: 'app.ai.response.length',
42
+ APP_AI_RESPONSE_HASH: 'app.ai.response.hash',
43
+ APP_AI_COMPLETION_TOKENS: 'app.ai.completion_tokens',
44
+ APP_AI_PROMPT_TOKENS: 'app.ai.prompt_tokens',
45
+ APP_AI_FINISH_REASON: 'app.ai.finish_reason',
46
+ APP_TOOL_NAME: 'app.tool.name',
47
+ APP_TOOL_PARAMS: 'app.tool.params',
48
+ APP_TOOL_RESULT: 'app.tool.result',
49
+ APP_TOOL_SUCCESS: 'app.tool.success',
50
+ APP_ITERATION_NUMBER: 'app.iteration.number'
51
+ };
52
+
53
+ class AppTracer {
54
+ constructor() {
55
+ // Use consistent tracer name across the application
56
+ this.tracer = trace.getTracer('probe-chat', '1.0.0');
57
+ this.activeSpans = new Map();
58
+ this.sessionSpans = new Map();
59
+ this.sessionContexts = new Map(); // Store active context for each session
60
+ }
61
+
62
+ /**
63
+ * Get the shared tracer instance
64
+ */
65
+ getTracer() {
66
+ return this.tracer;
67
+ }
68
+
69
+ /**
70
+ * Hash a string for deduplication purposes
71
+ */
72
+ _hashString(str) {
73
+ let hash = 0;
74
+ if (str.length === 0) return hash;
75
+ for (let i = 0; i < str.length; i++) {
76
+ const char = str.charCodeAt(i);
77
+ hash = ((hash << 5) - hash) + char;
78
+ hash = hash & hash; // Convert to 32bit integer
79
+ }
80
+ return hash.toString();
81
+ }
82
+
83
+ /**
84
+ * Get the active context for a session, creating spans within the session trace
85
+ */
86
+ _getSessionContext(sessionId) {
87
+ return this.sessionContexts.get(sessionId) || context.active();
88
+ }
89
+
90
+ /**
91
+ * Start a chat session span with custom trace ID based on session ID
92
+ */
93
+ startChatSession(sessionId, userMessage, provider, model) {
94
+ if (process.env.DEBUG_CHAT === '1') {
95
+ console.log(`[DEBUG] AppTracer: Starting chat session span for ${sessionId}`);
96
+ }
97
+
98
+ // Create a custom trace ID from the session ID
99
+ const traceId = sessionIdToTraceId(sessionId);
100
+
101
+ // Generate a span ID for the root span
102
+ const spanId = randomUUID().replace(/-/g, '').substring(0, 16);
103
+
104
+ // Create trace context with custom trace ID
105
+ const spanContext = {
106
+ traceId: traceId,
107
+ spanId: spanId,
108
+ traceFlags: TraceFlags.SAMPLED,
109
+ isRemote: false
110
+ };
111
+
112
+ // Create a new context with our custom trace context
113
+ const activeContext = trace.setSpanContext(context.active(), spanContext);
114
+
115
+ // Start the span within this custom context
116
+ const span = context.with(activeContext, () => {
117
+ return this.tracer.startSpan('messaging.process', {
118
+ kind: SpanKind.SERVER,
119
+ attributes: {
120
+ [OTEL_ATTRS.APP_SESSION_ID]: sessionId,
121
+ [OTEL_ATTRS.APP_MESSAGE_CONTENT]: userMessage.substring(0, 500), // Capture more message content
122
+ [OTEL_ATTRS.APP_MESSAGE_LENGTH]: userMessage.length,
123
+ [OTEL_ATTRS.APP_MESSAGE_HASH]: this._hashString(userMessage), // Add hash for deduplication
124
+ [OTEL_ATTRS.APP_AI_PROVIDER]: provider,
125
+ [OTEL_ATTRS.APP_AI_MODEL]: model,
126
+ 'app.session.start_time': Date.now(),
127
+ 'app.trace.custom_id': true // Mark that we're using custom trace ID
128
+ }
129
+ });
130
+ });
131
+
132
+ if (process.env.DEBUG_CHAT === '1') {
133
+ console.log(`[DEBUG] AppTracer: Created chat session span ${span.spanContext().spanId} in trace ${span.spanContext().traceId}`);
134
+ }
135
+
136
+ // Create session context with the span as the active span
137
+ const sessionContext = trace.setSpan(context.active(), span);
138
+ this.sessionContexts.set(sessionId, sessionContext);
139
+ this.sessionSpans.set(sessionId, span);
140
+
141
+ if (process.env.DEBUG_CHAT === '1') {
142
+ console.log(`[DEBUG] AppTracer: Session context established for ${sessionId}`);
143
+ }
144
+
145
+ return span;
146
+ }
147
+
148
+ /**
149
+ * Execute a function within the session context to ensure proper trace correlation
150
+ */
151
+ withSessionContext(sessionId, fn) {
152
+ const sessionContext = this._getSessionContext(sessionId);
153
+ return context.with(sessionContext, fn);
154
+ }
155
+
156
+ /**
157
+ * Get the trace ID for a session (derived from session ID)
158
+ */
159
+ getTraceIdForSession(sessionId) {
160
+ return sessionIdToTraceId(sessionId);
161
+ }
162
+
163
+ /**
164
+ * Start processing a user message
165
+ */
166
+ startUserMessageProcessing(sessionId, messageId, message, imageUrlsFound = 0) {
167
+ if (process.env.DEBUG_CHAT === '1') {
168
+ console.log(`[DEBUG] AppTracer: Starting user message processing span for ${sessionId}`);
169
+ }
170
+
171
+ const sessionContext = this._getSessionContext(sessionId);
172
+
173
+ return context.with(sessionContext, () => {
174
+ // Get the parent span (should be the session span) from the context
175
+ const parentSpan = trace.getActiveSpan();
176
+ const spanOptions = {
177
+ kind: SpanKind.INTERNAL,
178
+ attributes: {
179
+ [OTEL_ATTRS.APP_SESSION_ID]: sessionId,
180
+ 'app.message.id': messageId,
181
+ [OTEL_ATTRS.APP_MESSAGE_TYPE]: 'user',
182
+ [OTEL_ATTRS.APP_MESSAGE_CONTENT]: message.substring(0, 1000), // Include actual message content
183
+ [OTEL_ATTRS.APP_MESSAGE_LENGTH]: message.length,
184
+ [OTEL_ATTRS.APP_MESSAGE_HASH]: this._hashString(message),
185
+ 'app.message.image_urls_found': imageUrlsFound,
186
+ 'app.processing.start_time': Date.now()
187
+ }
188
+ };
189
+
190
+ // Explicitly set the parent if available
191
+ if (parentSpan) {
192
+ spanOptions.parent = parentSpan.spanContext();
193
+ }
194
+
195
+ const span = this.tracer.startSpan('messaging.message.process', spanOptions);
196
+
197
+ if (process.env.DEBUG_CHAT === '1') {
198
+ console.log(`[DEBUG] AppTracer: Created user message processing span ${span.spanContext().spanId} with parent ${parentSpan?.spanContext().spanId}`);
199
+ }
200
+
201
+ this.activeSpans.set(`${sessionId}_user_processing`, span);
202
+ // DO NOT overwrite the session context - this breaks parent-child relationships
203
+ // Instead, create a temporary context for this message processing without storing it
204
+ const messageContext = trace.setSpan(sessionContext, span);
205
+ // Store the message context temporarily for child operations, but keep session context intact
206
+ this.sessionContexts.set(`${sessionId}_message_processing`, messageContext);
207
+ return span;
208
+ });
209
+ }
210
+
211
+ /**
212
+ * Execute a function within the context of user message processing span
213
+ */
214
+ withUserProcessingContext(sessionId, fn) {
215
+ const span = this.activeSpans.get(`${sessionId}_user_processing`);
216
+ if (span) {
217
+ return context.with(trace.setSpan(context.active(), span), fn);
218
+ }
219
+ return fn();
220
+ }
221
+
222
+ /**
223
+ * Start the agent loop
224
+ */
225
+ startAgentLoop(sessionId, maxIterations) {
226
+ const sessionContext = this._getSessionContext(sessionId);
227
+
228
+ return context.with(sessionContext, () => {
229
+ // Get the parent span from the context
230
+ const parentSpan = trace.getActiveSpan();
231
+ const spanOptions = {
232
+ kind: SpanKind.INTERNAL,
233
+ attributes: {
234
+ 'app.session.id': sessionId,
235
+ 'app.loop.max_iterations': maxIterations,
236
+ 'app.loop.start_time': Date.now()
237
+ }
238
+ };
239
+
240
+ // Explicitly set the parent if available
241
+ if (parentSpan) {
242
+ spanOptions.parent = parentSpan.spanContext();
243
+ }
244
+
245
+ const span = this.tracer.startSpan('agent.loop.start', spanOptions);
246
+
247
+ this.activeSpans.set(`${sessionId}_agent_loop`, span);
248
+ // DO NOT overwrite the session context - store agent loop context separately
249
+ const agentLoopContext = trace.setSpan(sessionContext, span);
250
+ this.sessionContexts.set(`${sessionId}_agent_loop`, agentLoopContext);
251
+ return span;
252
+ });
253
+ }
254
+
255
+ /**
256
+ * Execute a function within the context of agent loop span
257
+ */
258
+ withAgentLoopContext(sessionId, fn) {
259
+ const span = this.activeSpans.get(`${sessionId}_agent_loop`);
260
+ if (span) {
261
+ return context.with(trace.setSpan(context.active(), span), fn);
262
+ }
263
+ return fn();
264
+ }
265
+
266
+ /**
267
+ * Start a single iteration of the agent loop
268
+ */
269
+ startAgentIteration(sessionId, iterationNumber, messagesCount, contextTokens) {
270
+ const sessionContext = this._getSessionContext(sessionId);
271
+
272
+ return context.with(sessionContext, () => {
273
+ const span = this.tracer.startSpan('agent.loop.iteration', {
274
+ kind: SpanKind.INTERNAL,
275
+ attributes: {
276
+ 'app.session.id': sessionId,
277
+ 'app.iteration.number': iterationNumber,
278
+ 'app.iteration.messages_count': messagesCount,
279
+ 'app.iteration.context_tokens': contextTokens,
280
+ 'app.iteration.start_time': Date.now()
281
+ }
282
+ });
283
+
284
+ this.activeSpans.set(`${sessionId}_iteration_${iterationNumber}`, span);
285
+ // DO NOT overwrite the session context - store iteration context separately
286
+ const iterationContext = trace.setSpan(sessionContext, span);
287
+ this.sessionContexts.set(`${sessionId}_iteration_${iterationNumber}`, iterationContext);
288
+ return span;
289
+ });
290
+ }
291
+
292
+ /**
293
+ * Execute a function within the context of agent iteration span
294
+ */
295
+ withIterationContext(sessionId, iterationNumber, fn) {
296
+ const span = this.activeSpans.get(`${sessionId}_iteration_${iterationNumber}`);
297
+ if (span) {
298
+ return context.with(trace.setSpan(context.active(), span), fn);
299
+ }
300
+ return fn();
301
+ }
302
+
303
+ /**
304
+ * Start an AI generation request
305
+ */
306
+ startAiGenerationRequest(sessionId, iterationNumber, model, provider, settings = {}, messagesContext = []) {
307
+ if (process.env.DEBUG_CHAT === '1') {
308
+ console.log(`[DEBUG] AppTracer: Starting AI generation request span for session ${sessionId}, iteration ${iterationNumber}`);
309
+ }
310
+
311
+ // Get the most appropriate context - prefer iteration context over session context
312
+ const iterationContext = this.sessionContexts.get(`${sessionId}_iteration_${iterationNumber}`);
313
+ const sessionContext = iterationContext || this._getSessionContext(sessionId);
314
+
315
+ return context.with(sessionContext, () => {
316
+ const span = this.tracer.startSpan('ai.generation.request', {
317
+ kind: SpanKind.CLIENT,
318
+ attributes: {
319
+ [OTEL_ATTRS.APP_SESSION_ID]: sessionId,
320
+ [OTEL_ATTRS.APP_ITERATION_NUMBER]: iterationNumber,
321
+ [OTEL_ATTRS.APP_AI_MODEL]: model,
322
+ [OTEL_ATTRS.APP_AI_PROVIDER]: provider,
323
+ [OTEL_ATTRS.APP_AI_TEMPERATURE]: settings.temperature || 0,
324
+ [OTEL_ATTRS.APP_AI_MAX_TOKENS]: settings.maxTokens || 0,
325
+ 'app.ai.max_retries': settings.maxRetries || 0,
326
+ 'app.ai.messages_count': messagesContext.length,
327
+ 'app.ai.request_start_time': Date.now()
328
+ }
329
+ });
330
+
331
+ if (process.env.DEBUG_CHAT === '1') {
332
+ console.log(`[DEBUG] AppTracer: Created AI generation span ${span.spanContext().spanId}`);
333
+ }
334
+
335
+ this.activeSpans.set(`${sessionId}_ai_request_${iterationNumber}`, span);
336
+ // Store AI request context separately, don't overwrite session context
337
+ const aiRequestContext = trace.setSpan(sessionContext, span);
338
+ this.sessionContexts.set(`${sessionId}_ai_request_${iterationNumber}`, aiRequestContext);
339
+ return span;
340
+ });
341
+ }
342
+
343
+ /**
344
+ * Record AI response received
345
+ */
346
+ recordAiResponse(sessionId, iterationNumber, responseData) {
347
+ const sessionContext = this._getSessionContext(sessionId);
348
+
349
+ return context.with(sessionContext, () => {
350
+ const span = this.tracer.startSpan('ai.generation.response', {
351
+ kind: SpanKind.INTERNAL,
352
+ attributes: {
353
+ [OTEL_ATTRS.APP_SESSION_ID]: sessionId,
354
+ [OTEL_ATTRS.APP_ITERATION_NUMBER]: iterationNumber,
355
+ [OTEL_ATTRS.APP_AI_RESPONSE_CONTENT]: responseData.response ? responseData.response.substring(0, 2000) : '', // Include actual response content
356
+ [OTEL_ATTRS.APP_AI_RESPONSE_LENGTH]: responseData.responseLength || (responseData.response ? responseData.response.length : 0),
357
+ [OTEL_ATTRS.APP_AI_RESPONSE_HASH]: responseData.response ? this._hashString(responseData.response) : '',
358
+ [OTEL_ATTRS.APP_AI_COMPLETION_TOKENS]: responseData.completionTokens || 0,
359
+ [OTEL_ATTRS.APP_AI_PROMPT_TOKENS]: responseData.promptTokens || 0,
360
+ [OTEL_ATTRS.APP_AI_FINISH_REASON]: responseData.finishReason || 'unknown',
361
+ 'app.ai.response.time_to_first_chunk_ms': responseData.timeToFirstChunk || 0,
362
+ 'app.ai.response.time_to_finish_ms': responseData.timeToFinish || 0,
363
+ 'app.ai.response.received_time': Date.now()
364
+ }
365
+ });
366
+
367
+ // End the span immediately since this is just recording the response
368
+ span.setStatus({ code: SpanStatusCode.OK });
369
+ span.end();
370
+ return span;
371
+ });
372
+ }
373
+
374
+ /**
375
+ * Record a parsed tool call
376
+ */
377
+ recordToolCallParsed(sessionId, iterationNumber, toolName, toolParams) {
378
+ const aiRequestSpan = this.activeSpans.get(`${sessionId}_ai_request_${iterationNumber}`);
379
+ const spanOptions = {
380
+ kind: SpanKind.INTERNAL,
381
+ attributes: {
382
+ 'app.session.id': sessionId,
383
+ 'app.tool.name': toolName,
384
+ 'app.tool.params': JSON.stringify(toolParams).substring(0, 500), // Truncate large params
385
+ 'app.tool.parsed_time': Date.now()
386
+ }
387
+ };
388
+
389
+ if (aiRequestSpan) {
390
+ spanOptions.parent = aiRequestSpan.spanContext();
391
+ }
392
+
393
+ const span = this.tracer.startSpan('tool.call.parse', spanOptions);
394
+
395
+ // End immediately since this is just recording the parsing
396
+ span.setStatus({ code: SpanStatusCode.OK });
397
+ span.end();
398
+
399
+ return span;
400
+ }
401
+
402
+ /**
403
+ * Start tool execution
404
+ */
405
+ startToolExecution(sessionId, iterationNumber, toolName, toolParams) {
406
+ // Get the most appropriate context - prefer AI request context over session context
407
+ const aiRequestContext = this.sessionContexts.get(`${sessionId}_ai_request_${iterationNumber}`);
408
+ const sessionContext = aiRequestContext || this._getSessionContext(sessionId);
409
+
410
+ return context.with(sessionContext, () => {
411
+ const span = this.tracer.startSpan('tool.call', {
412
+ kind: SpanKind.INTERNAL,
413
+ attributes: {
414
+ [OTEL_ATTRS.APP_SESSION_ID]: sessionId,
415
+ [OTEL_ATTRS.APP_ITERATION_NUMBER]: iterationNumber,
416
+ [OTEL_ATTRS.APP_TOOL_NAME]: toolName,
417
+ [OTEL_ATTRS.APP_TOOL_PARAMS]: JSON.stringify(toolParams).substring(0, 1000), // Include actual tool parameters
418
+ 'app.tool.params.hash': this._hashString(JSON.stringify(toolParams)),
419
+ 'app.tool.execution_start_time': Date.now(),
420
+ // Add specific attributes based on tool type
421
+ ...(toolName === 'search' && toolParams.query ? { 'app.tool.search.query': toolParams.query } : {}),
422
+ ...(toolName === 'extract' && toolParams.file_path ? { 'app.tool.extract.file_path': toolParams.file_path } : {}),
423
+ ...(toolName === 'query' && toolParams.pattern ? { 'app.tool.query.pattern': toolParams.pattern } : {}),
424
+ }
425
+ });
426
+
427
+ this.activeSpans.set(`${sessionId}_tool_execution_${iterationNumber}`, span);
428
+ // Store tool execution context separately, don't overwrite session context
429
+ const toolExecutionContext = trace.setSpan(sessionContext, span);
430
+ this.sessionContexts.set(`${sessionId}_tool_execution_${iterationNumber}`, toolExecutionContext);
431
+ return span;
432
+ });
433
+ }
434
+
435
+ /**
436
+ * End tool execution with results
437
+ */
438
+ endToolExecution(sessionId, iterationNumber, success, resultLength = 0, errorMessage = null, result = null) {
439
+ const span = this.activeSpans.get(`${sessionId}_tool_execution_${iterationNumber}`);
440
+ if (!span) return;
441
+
442
+ const attributes = {
443
+ [OTEL_ATTRS.APP_TOOL_SUCCESS]: success,
444
+ 'app.tool.result_length': resultLength,
445
+ 'app.tool.execution_end_time': Date.now(),
446
+ ...(errorMessage ? { [OTEL_ATTRS.ERROR_MESSAGE]: errorMessage } : {}),
447
+ ...(result ? {
448
+ [OTEL_ATTRS.APP_TOOL_RESULT]: typeof result === 'string' ? result.substring(0, 2000) : JSON.stringify(result).substring(0, 2000),
449
+ 'app.tool.result.hash': this._hashString(typeof result === 'string' ? result : JSON.stringify(result))
450
+ } : {})
451
+ };
452
+
453
+ span.setAttributes(attributes);
454
+
455
+ span.setStatus({
456
+ code: success ? SpanStatusCode.OK : SpanStatusCode.ERROR,
457
+ message: errorMessage
458
+ });
459
+
460
+ span.end();
461
+ this.activeSpans.delete(`${sessionId}_tool_execution_${iterationNumber}`);
462
+ }
463
+
464
+ /**
465
+ * End an iteration
466
+ */
467
+ endIteration(sessionId, iterationNumber, success = true, completedAction = null) {
468
+ const span = this.activeSpans.get(`${sessionId}_iteration_${iterationNumber}`);
469
+ if (!span) return;
470
+
471
+ span.setAttributes({
472
+ 'app.iteration.success': success,
473
+ 'app.iteration.end_time': Date.now(),
474
+ ...(completedAction ? { 'app.iteration.completed_action': completedAction } : {})
475
+ });
476
+
477
+ span.setStatus({ code: success ? SpanStatusCode.OK : SpanStatusCode.ERROR });
478
+ span.end();
479
+ this.activeSpans.delete(`${sessionId}_iteration_${iterationNumber}`);
480
+ }
481
+
482
+ /**
483
+ * End the agent loop
484
+ */
485
+ endAgentLoop(sessionId, totalIterations, success = true, completionReason = null) {
486
+ const span = this.activeSpans.get(`${sessionId}_agent_loop`);
487
+ if (!span) return;
488
+
489
+ span.setAttributes({
490
+ 'app.loop.total_iterations': totalIterations,
491
+ 'app.loop.success': success,
492
+ 'app.loop.end_time': Date.now(),
493
+ ...(completionReason ? { 'app.loop.completion_reason': completionReason } : {})
494
+ });
495
+
496
+ span.setStatus({ code: success ? SpanStatusCode.OK : SpanStatusCode.ERROR });
497
+ span.end();
498
+ this.activeSpans.delete(`${sessionId}_agent_loop`);
499
+ }
500
+
501
+ /**
502
+ * End user message processing
503
+ */
504
+ endUserMessageProcessing(sessionId, success = true) {
505
+ const span = this.activeSpans.get(`${sessionId}_user_processing`);
506
+ if (!span) {
507
+ if (process.env.DEBUG_CHAT === '1') {
508
+ console.log(`[DEBUG] AppTracer: No user message processing span found for ${sessionId}`);
509
+ }
510
+ return;
511
+ }
512
+
513
+ if (process.env.DEBUG_CHAT === '1') {
514
+ console.log(`[DEBUG] AppTracer: Ending user message processing span ${span.spanContext().spanId} for ${sessionId}`);
515
+ }
516
+
517
+ span.setAttributes({
518
+ 'app.processing.success': success,
519
+ 'app.processing.end_time': Date.now()
520
+ });
521
+
522
+ span.setStatus({ code: success ? SpanStatusCode.OK : SpanStatusCode.ERROR });
523
+ span.end();
524
+
525
+ this.activeSpans.delete(`${sessionId}_user_processing`);
526
+ // Clean up the message processing context
527
+ this.sessionContexts.delete(`${sessionId}_message_processing`);
528
+ }
529
+
530
+ /**
531
+ * End the chat session
532
+ */
533
+ endChatSession(sessionId, success = true, totalTokensUsed = 0) {
534
+ const span = this.sessionSpans.get(sessionId);
535
+ if (!span) {
536
+ if (process.env.DEBUG_CHAT === '1') {
537
+ console.log(`[DEBUG] AppTracer: No chat session span found for ${sessionId}`);
538
+ }
539
+ return;
540
+ }
541
+
542
+ if (process.env.DEBUG_CHAT === '1') {
543
+ console.log(`[DEBUG] AppTracer: Ending chat session span ${span.spanContext().spanId} for ${sessionId}`);
544
+ }
545
+
546
+ span.setAttributes({
547
+ 'app.session.success': success,
548
+ 'app.session.total_tokens_used': totalTokensUsed,
549
+ 'app.session.end_time': Date.now()
550
+ });
551
+
552
+ span.setStatus({ code: success ? SpanStatusCode.OK : SpanStatusCode.ERROR });
553
+ span.end();
554
+
555
+ this.sessionSpans.delete(sessionId);
556
+ // Clean up the session context after ending the span
557
+ this.sessionContexts.delete(sessionId);
558
+ }
559
+
560
+ /**
561
+ * End AI request span
562
+ */
563
+ endAiRequest(sessionId, iterationNumber, success = true) {
564
+ const span = this.activeSpans.get(`${sessionId}_ai_request_${iterationNumber}`);
565
+ if (!span) {
566
+ if (process.env.DEBUG_CHAT === '1') {
567
+ console.log(`[DEBUG] AppTracer: No AI request span found for ${sessionId}_ai_request_${iterationNumber}`);
568
+ }
569
+ return;
570
+ }
571
+
572
+ if (process.env.DEBUG_CHAT === '1') {
573
+ console.log(`[DEBUG] AppTracer: Ending AI request span ${span.spanContext().spanId} for ${sessionId}, iteration ${iterationNumber}`);
574
+ }
575
+
576
+ span.setAttributes({
577
+ 'app.ai.request_success': success,
578
+ 'app.ai.request_end_time': Date.now()
579
+ });
580
+
581
+ span.setStatus({ code: success ? SpanStatusCode.OK : SpanStatusCode.ERROR });
582
+ span.end();
583
+ this.activeSpans.delete(`${sessionId}_ai_request_${iterationNumber}`);
584
+ }
585
+
586
+ /**
587
+ * Record a completion attempt
588
+ */
589
+ recordCompletionAttempt(sessionId, success = true, finalResult = null) {
590
+ const sessionSpan = this.sessionSpans.get(sessionId);
591
+ const spanOptions = {
592
+ kind: SpanKind.INTERNAL,
593
+ attributes: {
594
+ 'app.session.id': sessionId,
595
+ 'app.completion.success': success,
596
+ 'app.completion.result_length': finalResult ? finalResult.length : 0,
597
+ 'app.completion.attempt_time': Date.now()
598
+ }
599
+ };
600
+
601
+ if (sessionSpan) {
602
+ spanOptions.parent = sessionSpan.spanContext();
603
+ }
604
+
605
+ const span = this.tracer.startSpan('agent.completion.attempt', spanOptions);
606
+
607
+ span.setStatus({ code: success ? SpanStatusCode.OK : SpanStatusCode.ERROR });
608
+ span.end();
609
+
610
+ return span;
611
+ }
612
+
613
+ /**
614
+ * Start image URL processing
615
+ */
616
+ startImageProcessing(sessionId, messageId, imageUrls = [], cleanedMessageLength = 0) {
617
+ const userProcessingSpan = this.activeSpans.get(`${sessionId}_user_processing`);
618
+ const spanOptions = {
619
+ kind: SpanKind.INTERNAL,
620
+ attributes: {
621
+ 'app.session.id': sessionId,
622
+ 'app.message.id': messageId,
623
+ 'app.image.urls_found': imageUrls.length,
624
+ 'app.image.message_cleaned_length': cleanedMessageLength,
625
+ 'app.image.processing_start_time': Date.now(),
626
+ 'app.image.urls_list': JSON.stringify(imageUrls).substring(0, 500)
627
+ }
628
+ };
629
+
630
+ if (userProcessingSpan) {
631
+ spanOptions.parent = userProcessingSpan.spanContext();
632
+ }
633
+
634
+ const span = this.tracer.startSpan('content.image.processing', spanOptions);
635
+ this.activeSpans.set(`${sessionId}_image_processing`, span);
636
+ return span;
637
+ }
638
+
639
+ /**
640
+ * Record image URL validation results
641
+ */
642
+ recordImageValidation(sessionId, validationResults) {
643
+ const imageProcessingSpan = this.activeSpans.get(`${sessionId}_image_processing`);
644
+ const spanOptions = {
645
+ kind: SpanKind.INTERNAL,
646
+ attributes: {
647
+ 'app.session.id': sessionId,
648
+ 'app.image.validation.total_urls': validationResults.totalUrls || 0,
649
+ 'app.image.validation.valid_urls': validationResults.validUrls || 0,
650
+ 'app.image.validation.invalid_urls': validationResults.invalidUrls || 0,
651
+ 'app.image.validation.redirected_urls': validationResults.redirectedUrls || 0,
652
+ 'app.image.validation.timeout_urls': validationResults.timeoutUrls || 0,
653
+ 'app.image.validation.network_errors': validationResults.networkErrors || 0,
654
+ 'app.image.validation.duration_ms': validationResults.durationMs || 0,
655
+ 'app.image.validation_time': Date.now()
656
+ }
657
+ };
658
+
659
+ if (imageProcessingSpan) {
660
+ spanOptions.parent = imageProcessingSpan.spanContext();
661
+ }
662
+
663
+ const span = this.tracer.startSpan('content.image.validation', spanOptions);
664
+ span.setStatus({
665
+ code: validationResults.validUrls > 0 ? SpanStatusCode.OK : SpanStatusCode.ERROR,
666
+ message: `${validationResults.validUrls}/${validationResults.totalUrls} URLs validated successfully`
667
+ });
668
+ span.end();
669
+ return span;
670
+ }
671
+
672
+ /**
673
+ * End image processing
674
+ */
675
+ endImageProcessing(sessionId, success = true, finalValidUrls = 0) {
676
+ const span = this.activeSpans.get(`${sessionId}_image_processing`);
677
+ if (!span) return;
678
+
679
+ span.setAttributes({
680
+ 'app.image.processing_success': success,
681
+ 'app.image.final_valid_urls': finalValidUrls,
682
+ 'app.image.processing_end_time': Date.now()
683
+ });
684
+
685
+ span.setStatus({ code: success ? SpanStatusCode.OK : SpanStatusCode.ERROR });
686
+ span.end();
687
+ this.activeSpans.delete(`${sessionId}_image_processing`);
688
+ }
689
+
690
+ /**
691
+ * Record AI model errors
692
+ */
693
+ recordAiModelError(sessionId, iterationNumber, errorDetails) {
694
+ const aiRequestSpan = this.activeSpans.get(`${sessionId}_ai_request_${iterationNumber}`);
695
+ const spanOptions = {
696
+ kind: SpanKind.INTERNAL,
697
+ attributes: {
698
+ 'app.session.id': sessionId,
699
+ 'app.error.type': 'ai_model_error',
700
+ 'app.error.category': errorDetails.category || 'unknown', // timeout, api_limit, network, etc.
701
+ 'app.error.message': errorDetails.message?.substring(0, 500) || '',
702
+ 'app.error.model': errorDetails.model || '',
703
+ 'app.error.provider': errorDetails.provider || '',
704
+ 'app.error.status_code': errorDetails.statusCode || 0,
705
+ 'app.error.retry_attempt': errorDetails.retryAttempt || 0,
706
+ 'app.error.timestamp': Date.now()
707
+ }
708
+ };
709
+
710
+ if (aiRequestSpan) {
711
+ spanOptions.parent = aiRequestSpan.spanContext();
712
+ }
713
+
714
+ const span = this.tracer.startSpan('ai.generation.error', spanOptions);
715
+ span.setStatus({ code: SpanStatusCode.ERROR, message: errorDetails.message });
716
+ span.end();
717
+ return span;
718
+ }
719
+
720
+ /**
721
+ * Record tool execution errors
722
+ */
723
+ recordToolError(sessionId, iterationNumber, toolName, errorDetails) {
724
+ const toolExecutionSpan = this.activeSpans.get(`${sessionId}_tool_execution_${iterationNumber}`);
725
+ const spanOptions = {
726
+ kind: SpanKind.INTERNAL,
727
+ attributes: {
728
+ 'app.session.id': sessionId,
729
+ 'app.error.type': 'tool_execution_error',
730
+ 'app.error.tool_name': toolName,
731
+ 'app.error.category': errorDetails.category || 'unknown', // validation, execution, network, filesystem
732
+ 'app.error.message': errorDetails.message?.substring(0, 500) || '',
733
+ 'app.error.exit_code': errorDetails.exitCode || 0,
734
+ 'app.error.signal': errorDetails.signal || '',
735
+ 'app.error.params': JSON.stringify(errorDetails.params || {}).substring(0, 300),
736
+ 'app.error.timestamp': Date.now()
737
+ }
738
+ };
739
+
740
+ if (toolExecutionSpan) {
741
+ spanOptions.parent = toolExecutionSpan.spanContext();
742
+ }
743
+
744
+ const span = this.tracer.startSpan('tool.call.error', spanOptions);
745
+ span.setStatus({ code: SpanStatusCode.ERROR, message: errorDetails.message });
746
+ span.end();
747
+ return span;
748
+ }
749
+
750
+ /**
751
+ * Record session cancellation
752
+ */
753
+ recordSessionCancellation(sessionId, reason = 'user_request', context = {}) {
754
+ const sessionSpan = this.sessionSpans.get(sessionId);
755
+ const spanOptions = {
756
+ kind: SpanKind.INTERNAL,
757
+ attributes: {
758
+ 'app.session.id': sessionId,
759
+ 'app.cancellation.reason': reason, // user_request, timeout, error, signal
760
+ 'app.cancellation.context': JSON.stringify(context).substring(0, 300),
761
+ 'app.cancellation.current_iteration': context.currentIteration || 0,
762
+ 'app.cancellation.active_tool': context.activeTool || '',
763
+ 'app.cancellation.timestamp': Date.now()
764
+ }
765
+ };
766
+
767
+ if (sessionSpan) {
768
+ spanOptions.parent = sessionSpan.spanContext();
769
+ }
770
+
771
+ const span = this.tracer.startSpan('messaging.session.cancel', spanOptions);
772
+ span.setStatus({ code: SpanStatusCode.ERROR, message: `Session cancelled: ${reason}` });
773
+ span.end();
774
+ return span;
775
+ }
776
+
777
+ /**
778
+ * Record token management metrics
779
+ */
780
+ recordTokenMetrics(sessionId, tokenData) {
781
+ const sessionSpan = this.sessionSpans.get(sessionId);
782
+ const spanOptions = {
783
+ kind: SpanKind.INTERNAL,
784
+ attributes: {
785
+ 'app.session.id': sessionId,
786
+ 'app.tokens.context_window': tokenData.contextWindow || 0,
787
+ 'app.tokens.current_total': tokenData.currentTotal || 0,
788
+ 'app.tokens.request_tokens': tokenData.requestTokens || 0,
789
+ 'app.tokens.response_tokens': tokenData.responseTokens || 0,
790
+ 'app.tokens.cache_read': tokenData.cacheRead || 0,
791
+ 'app.tokens.cache_write': tokenData.cacheWrite || 0,
792
+ 'app.tokens.utilization_percent': tokenData.contextWindow ?
793
+ Math.round((tokenData.currentTotal / tokenData.contextWindow) * 100) : 0,
794
+ 'app.tokens.measurement_time': Date.now()
795
+ }
796
+ };
797
+
798
+ if (sessionSpan) {
799
+ spanOptions.parent = sessionSpan.spanContext();
800
+ }
801
+
802
+ const span = this.tracer.startSpan('ai.token.metrics', spanOptions);
803
+ span.setStatus({ code: SpanStatusCode.OK });
804
+ span.end();
805
+ return span;
806
+ }
807
+
808
+ /**
809
+ * Record history management operations
810
+ */
811
+ recordHistoryOperation(sessionId, operation, details = {}) {
812
+ const sessionSpan = this.sessionSpans.get(sessionId);
813
+ const spanOptions = {
814
+ kind: SpanKind.INTERNAL,
815
+ attributes: {
816
+ 'app.session.id': sessionId,
817
+ 'app.history.operation': operation, // trim, update, clear, save
818
+ 'app.history.messages_before': details.messagesBefore || 0,
819
+ 'app.history.messages_after': details.messagesAfter || 0,
820
+ 'app.history.messages_removed': details.messagesRemoved || 0,
821
+ 'app.history.reason': details.reason || '', // max_length, memory_limit, session_reset
822
+ 'app.history.operation_time': Date.now()
823
+ }
824
+ };
825
+
826
+ if (sessionSpan) {
827
+ spanOptions.parent = sessionSpan.spanContext();
828
+ }
829
+
830
+ const span = this.tracer.startSpan('messaging.history.manage', spanOptions);
831
+ span.setStatus({ code: SpanStatusCode.OK });
832
+ span.end();
833
+ return span;
834
+ }
835
+
836
+ /**
837
+ * Record system prompt generation metrics
838
+ */
839
+ recordSystemPromptGeneration(sessionId, promptData) {
840
+ const sessionSpan = this.sessionSpans.get(sessionId);
841
+ const spanOptions = {
842
+ kind: SpanKind.INTERNAL,
843
+ attributes: {
844
+ 'app.session.id': sessionId,
845
+ 'app.prompt.base_length': promptData.baseLength || 0,
846
+ 'app.prompt.final_length': promptData.finalLength || 0,
847
+ 'app.prompt.files_added': promptData.filesAdded || 0,
848
+ 'app.prompt.generation_duration_ms': promptData.generationDurationMs || 0,
849
+ 'app.prompt.type': promptData.promptType || 'default',
850
+ 'app.prompt.estimated_tokens': promptData.estimatedTokens || 0,
851
+ 'app.prompt.generation_time': Date.now()
852
+ }
853
+ };
854
+
855
+ if (sessionSpan) {
856
+ spanOptions.parent = sessionSpan.spanContext();
857
+ }
858
+
859
+ const span = this.tracer.startSpan('ai.prompt.generate', spanOptions);
860
+ span.setStatus({ code: SpanStatusCode.OK });
861
+ span.end();
862
+ return span;
863
+ }
864
+
865
+ /**
866
+ * Record file system operations
867
+ */
868
+ recordFileSystemOperation(sessionId, operation, details = {}) {
869
+ const activeSpan = this.activeSpans.get(`${sessionId}_tool_execution_${details.iterationNumber}`) ||
870
+ this.sessionSpans.get(sessionId);
871
+ const spanOptions = {
872
+ kind: SpanKind.INTERNAL,
873
+ attributes: {
874
+ 'app.session.id': sessionId,
875
+ 'app.fs.operation': operation, // read, write, create_temp, delete, mkdir
876
+ 'app.fs.path': details.path?.substring(0, 200) || '',
877
+ 'app.fs.size_bytes': details.sizeBytes || 0,
878
+ 'app.fs.duration_ms': details.durationMs || 0,
879
+ 'app.fs.success': details.success !== false,
880
+ 'app.fs.error_code': details.errorCode || '',
881
+ 'app.fs.operation_time': Date.now()
882
+ }
883
+ };
884
+
885
+ if (activeSpan) {
886
+ spanOptions.parent = activeSpan.spanContext();
887
+ }
888
+
889
+ const span = this.tracer.startSpan('fs.operation', spanOptions);
890
+ span.setStatus({
891
+ code: details.success !== false ? SpanStatusCode.OK : SpanStatusCode.ERROR,
892
+ message: details.errorMessage
893
+ });
894
+ span.end();
895
+ return span;
896
+ }
897
+
898
+ /**
899
+ * Record a generic event (used by completionPrompt and other features)
900
+ * This provides compatibility with SimpleAppTracer interface
901
+ * Adds an event to the existing session span rather than creating a new span
902
+ */
903
+ // visor-disable: Events are added to existing spans per OpenTelemetry convention - recordEvent semantically means adding an event, not creating a span. Both SimpleAppTracer and AppTracer now consistently add events.
904
+ recordEvent(name, attributes = {}) {
905
+ const sessionId = attributes['session.id'] || 'unknown';
906
+ const sessionSpan = this.sessionSpans.get(sessionId);
907
+
908
+ if (sessionSpan) {
909
+ // Add event to the existing session span
910
+ sessionSpan.addEvent(name, {
911
+ 'app.event.timestamp': Date.now(),
912
+ ...attributes
913
+ });
914
+ } else if (process.env.DEBUG_CHAT === '1') {
915
+ console.log(`[DEBUG] AppTracer: recordEvent called but no session span for ${sessionId}`);
916
+ }
917
+ }
918
+
919
+ /**
920
+ * Clean up any remaining active spans for a session
921
+ */
922
+ cleanup(sessionId) {
923
+ if (process.env.DEBUG_CHAT === '1') {
924
+ console.log(`[DEBUG] AppTracer: Cleaning up session ${sessionId}`);
925
+ }
926
+
927
+ // End any remaining active spans
928
+ const keysToDelete = [];
929
+ for (const [key, span] of this.activeSpans.entries()) {
930
+ if (key.includes(sessionId)) {
931
+ if (process.env.DEBUG_CHAT === '1') {
932
+ console.log(`[DEBUG] AppTracer: Cleaning up active span ${key}`);
933
+ }
934
+ span.setStatus({ code: SpanStatusCode.ERROR, message: 'Session cleanup' });
935
+ span.end();
936
+ keysToDelete.push(key);
937
+ }
938
+ }
939
+ keysToDelete.forEach(key => this.activeSpans.delete(key));
940
+
941
+ // Only clean up session span if it still exists (wasn't properly ended by endChatSession)
942
+ const sessionSpan = this.sessionSpans.get(sessionId);
943
+ if (sessionSpan) {
944
+ if (process.env.DEBUG_CHAT === '1') {
945
+ console.log(`[DEBUG] AppTracer: Cleaning up orphaned session span for ${sessionId}`);
946
+ }
947
+ sessionSpan.setStatus({ code: SpanStatusCode.ERROR, message: 'Session cleanup - orphaned span' });
948
+ sessionSpan.end();
949
+ this.sessionSpans.delete(sessionId);
950
+ }
951
+
952
+ // Clean up all session-related contexts (session, message processing, iterations, AI requests, tool executions)
953
+ const contextKeysToDelete = [];
954
+ for (const [key] of this.sessionContexts.entries()) {
955
+ if (key.includes(sessionId)) {
956
+ contextKeysToDelete.push(key);
957
+ }
958
+ }
959
+ contextKeysToDelete.forEach(key => this.sessionContexts.delete(key));
960
+
961
+ if (process.env.DEBUG_CHAT === '1') {
962
+ console.log(`[DEBUG] AppTracer: Session cleanup completed for ${sessionId}, cleaned ${contextKeysToDelete.length} contexts`);
963
+ }
964
+ }
965
+ }
966
+
967
+ // Export a singleton instance
968
+ export const appTracer = new AppTracer();