@probelabs/probe-chat 0.6.0-rc224 → 0.6.0-rc225

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 (2) hide show
  1. package/appTracer.js +198 -0
  2. package/package.json +1 -1
package/appTracer.js CHANGED
@@ -895,6 +895,204 @@ class AppTracer {
895
895
  return span;
896
896
  }
897
897
 
898
+ /**
899
+ * Get the current iteration span for a session
900
+ * @private
901
+ */
902
+ _getCurrentIterationSpan(sessionId) {
903
+ // Try to find the most recent iteration span
904
+ for (let i = 100; i >= 0; i--) {
905
+ const span = this.activeSpans.get(`${sessionId}_iteration_${i}`);
906
+ if (span) return span;
907
+ }
908
+ // Fall back to session span
909
+ return this.sessionSpans.get(sessionId);
910
+ }
911
+
912
+ /**
913
+ * Record AI thinking/reasoning content
914
+ * @param {string} sessionId - Session ID
915
+ * @param {number} iterationNumber - Iteration number
916
+ * @param {string} thinkingContent - The thinking content from AI response
917
+ */
918
+ recordThinkingContent(sessionId, iterationNumber, thinkingContent) {
919
+ const span = this.activeSpans.get(`${sessionId}_iteration_${iterationNumber}`) || this._getCurrentIterationSpan(sessionId);
920
+ if (!span || !thinkingContent) return;
921
+
922
+ span.addEvent('ai.thinking', {
923
+ 'app.ai.thinking.content': thinkingContent.substring(0, 20000),
924
+ 'app.ai.thinking.length': thinkingContent.length,
925
+ 'app.ai.thinking.hash': this._hashString(thinkingContent),
926
+ 'app.iteration': iterationNumber,
927
+ 'app.timestamp': Date.now()
928
+ });
929
+ }
930
+
931
+ /**
932
+ * Record tool execution result
933
+ * @param {string} sessionId - Session ID
934
+ * @param {number} iterationNumber - Iteration number
935
+ * @param {string} toolName - Tool name
936
+ * @param {string|Object} result - Tool result
937
+ * @param {boolean} success - Whether succeeded
938
+ * @param {number} durationMs - Execution duration
939
+ */
940
+ recordToolResult(sessionId, iterationNumber, toolName, result, success, durationMs) {
941
+ const span = this.activeSpans.get(`${sessionId}_iteration_${iterationNumber}`) || this._getCurrentIterationSpan(sessionId);
942
+ if (!span) return;
943
+
944
+ const resultStr = typeof result === 'string' ? result : JSON.stringify(result || '');
945
+ span.addEvent('tool.result', {
946
+ 'app.tool.name': toolName,
947
+ 'app.tool.result': resultStr.substring(0, 20000),
948
+ 'app.tool.result.length': resultStr.length,
949
+ 'app.tool.result.hash': this._hashString(resultStr),
950
+ 'app.tool.success': success,
951
+ 'app.tool.duration_ms': durationMs,
952
+ 'app.iteration': iterationNumber,
953
+ 'app.timestamp': Date.now()
954
+ });
955
+ }
956
+
957
+ /**
958
+ * Record a conversation turn (assistant response or tool result)
959
+ * @param {string} sessionId - Session ID
960
+ * @param {number} iterationNumber - Iteration number
961
+ * @param {string} role - The role (assistant, tool_result)
962
+ * @param {string} content - The turn content
963
+ * @param {Object} metadata - Additional metadata
964
+ */
965
+ recordConversationTurn(sessionId, iterationNumber, role, content, metadata = {}) {
966
+ const span = this.activeSpans.get(`${sessionId}_iteration_${iterationNumber}`) || this._getCurrentIterationSpan(sessionId);
967
+ if (!span) return;
968
+
969
+ span.addEvent(`conversation.${role}`, {
970
+ 'app.conversation.role': role,
971
+ 'app.conversation.content': content.substring(0, 20000),
972
+ 'app.conversation.length': content.length,
973
+ 'app.conversation.hash': this._hashString(content),
974
+ 'app.iteration': iterationNumber,
975
+ 'app.timestamp': Date.now(),
976
+ ...Object.fromEntries(
977
+ Object.entries(metadata).map(([k, v]) => [`app.${k}`, v])
978
+ )
979
+ });
980
+ }
981
+
982
+ /**
983
+ * Record AI tool call decision
984
+ * @param {string} sessionId - Session ID
985
+ * @param {number} iterationNumber - Iteration number
986
+ * @param {string} toolName - Tool name AI decided to call
987
+ * @param {Object} params - Tool parameters
988
+ */
989
+ recordAIToolDecision(sessionId, iterationNumber, toolName, params) {
990
+ const span = this.activeSpans.get(`${sessionId}_iteration_${iterationNumber}`) || this._getCurrentIterationSpan(sessionId);
991
+ if (!span) return;
992
+
993
+ span.addEvent('ai.tool_decision', {
994
+ 'app.ai.tool_decision.name': toolName,
995
+ 'app.ai.tool_decision.params': JSON.stringify(params || {}).substring(0, 5000),
996
+ 'app.ai.tool_decision.params_hash': this._hashString(JSON.stringify(params || {})),
997
+ 'app.iteration': iterationNumber,
998
+ 'app.timestamp': Date.now()
999
+ });
1000
+ }
1001
+
1002
+ /**
1003
+ * Record MCP tool execution start
1004
+ * @param {string} sessionId - Session ID
1005
+ * @param {number} iterationNumber - Iteration number
1006
+ * @param {string} toolName - MCP tool name
1007
+ * @param {string} serverName - MCP server name
1008
+ * @param {Object} params - Tool parameters
1009
+ */
1010
+ recordMcpToolStart(sessionId, iterationNumber, toolName, serverName, params) {
1011
+ const span = this.activeSpans.get(`${sessionId}_iteration_${iterationNumber}`) || this._getCurrentIterationSpan(sessionId);
1012
+ if (!span) return;
1013
+
1014
+ span.addEvent('mcp.tool.start', {
1015
+ 'app.mcp.tool.name': toolName,
1016
+ 'app.mcp.tool.server': serverName || 'unknown',
1017
+ 'app.mcp.tool.params': JSON.stringify(params || {}).substring(0, 2000),
1018
+ 'app.iteration': iterationNumber,
1019
+ 'app.timestamp': Date.now()
1020
+ });
1021
+ }
1022
+
1023
+ /**
1024
+ * Record MCP tool execution end
1025
+ * @param {string} sessionId - Session ID
1026
+ * @param {number} iterationNumber - Iteration number
1027
+ * @param {string} toolName - MCP tool name
1028
+ * @param {string} serverName - MCP server name
1029
+ * @param {string|Object} result - Tool result
1030
+ * @param {boolean} success - Whether succeeded
1031
+ * @param {number} durationMs - Execution duration
1032
+ * @param {string} errorMessage - Error message if failed
1033
+ */
1034
+ recordMcpToolEnd(sessionId, iterationNumber, toolName, serverName, result, success, durationMs, errorMessage = null) {
1035
+ const span = this.activeSpans.get(`${sessionId}_iteration_${iterationNumber}`) || this._getCurrentIterationSpan(sessionId);
1036
+ if (!span) return;
1037
+
1038
+ const resultStr = typeof result === 'string' ? result : JSON.stringify(result || '');
1039
+ span.addEvent('mcp.tool.end', {
1040
+ 'app.mcp.tool.name': toolName,
1041
+ 'app.mcp.tool.server': serverName || 'unknown',
1042
+ 'app.mcp.tool.result': resultStr.substring(0, 10000),
1043
+ 'app.mcp.tool.result.length': resultStr.length,
1044
+ 'app.mcp.tool.duration_ms': durationMs,
1045
+ 'app.mcp.tool.success': success,
1046
+ 'app.mcp.tool.error': errorMessage,
1047
+ 'app.iteration': iterationNumber,
1048
+ 'app.timestamp': Date.now()
1049
+ });
1050
+ }
1051
+
1052
+ /**
1053
+ * Record error classification event
1054
+ * @param {string} sessionId - Session ID
1055
+ * @param {number} iterationNumber - Iteration number
1056
+ * @param {string} errorType - Error type (wrapped_tool, unrecognized_tool, no_tool_call, circuit_breaker, etc.)
1057
+ * @param {Object} errorDetails - Error details
1058
+ */
1059
+ recordErrorClassification(sessionId, iterationNumber, errorType, errorDetails = {}) {
1060
+ const span = this.activeSpans.get(`${sessionId}_iteration_${iterationNumber}`) || this._getCurrentIterationSpan(sessionId);
1061
+ if (!span) return;
1062
+
1063
+ span.addEvent(`error.${errorType}`, {
1064
+ 'app.error.type': errorType,
1065
+ 'app.error.message': errorDetails.message?.substring(0, 1000) || '',
1066
+ 'app.error.recoverable': errorDetails.recoverable ?? true,
1067
+ 'app.error.context': JSON.stringify(errorDetails.context || {}).substring(0, 1000),
1068
+ 'app.iteration': iterationNumber,
1069
+ 'app.timestamp': Date.now()
1070
+ });
1071
+ }
1072
+
1073
+ /**
1074
+ * Record per-turn token breakdown
1075
+ * @param {string} sessionId - Session ID
1076
+ * @param {number} iterationNumber - Iteration number
1077
+ * @param {Object} tokenData - Token metrics
1078
+ */
1079
+ recordTokenTurn(sessionId, iterationNumber, tokenData = {}) {
1080
+ const span = this.activeSpans.get(`${sessionId}_iteration_${iterationNumber}`) || this._getCurrentIterationSpan(sessionId);
1081
+ if (!span) return;
1082
+
1083
+ span.addEvent('tokens.turn', {
1084
+ 'app.iteration': iterationNumber,
1085
+ 'app.tokens.input': tokenData.inputTokens || 0,
1086
+ 'app.tokens.output': tokenData.outputTokens || 0,
1087
+ 'app.tokens.total': (tokenData.inputTokens || 0) + (tokenData.outputTokens || 0),
1088
+ 'app.tokens.cache_read': tokenData.cacheReadTokens || 0,
1089
+ 'app.tokens.cache_write': tokenData.cacheWriteTokens || 0,
1090
+ 'app.tokens.context_used': tokenData.contextTokens || 0,
1091
+ 'app.tokens.context_remaining': tokenData.maxContextTokens ? (tokenData.maxContextTokens - (tokenData.contextTokens || 0)) : null,
1092
+ 'app.timestamp': Date.now()
1093
+ });
1094
+ }
1095
+
898
1096
  /**
899
1097
  * Record a generic event (used by completionPrompt and other features)
900
1098
  * This provides compatibility with SimpleAppTracer interface
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probelabs/probe-chat",
3
- "version": "0.6.0-rc224",
3
+ "version": "0.6.0-rc225",
4
4
  "description": "CLI and web interface for Probe code search (formerly @probelabs/probe-web and @probelabs/probe-chat)",
5
5
  "main": "index.js",
6
6
  "type": "module",