@gracker/smartperfetto 1.0.19 → 1.0.20

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 (115) hide show
  1. package/dist/agent/core/conclusionContract.d.ts +1 -0
  2. package/dist/agent/core/conclusionContract.d.ts.map +1 -1
  3. package/dist/agent/tools/frameAnalyzer.d.ts.map +1 -1
  4. package/dist/agent/tools/frameAnalyzer.js +1 -0
  5. package/dist/agent/tools/frameAnalyzer.js.map +1 -1
  6. package/dist/agentOpenAI/openAiRuntime.d.ts +24 -0
  7. package/dist/agentOpenAI/openAiRuntime.d.ts.map +1 -1
  8. package/dist/agentOpenAI/openAiRuntime.js +159 -191
  9. package/dist/agentOpenAI/openAiRuntime.js.map +1 -1
  10. package/dist/agentRuntime/index.d.ts +1 -0
  11. package/dist/agentRuntime/index.d.ts.map +1 -1
  12. package/dist/agentRuntime/index.js +16 -1
  13. package/dist/agentRuntime/index.js.map +1 -1
  14. package/dist/agentRuntime/runtimeCommon.d.ts +34 -0
  15. package/dist/agentRuntime/runtimeCommon.d.ts.map +1 -0
  16. package/dist/agentRuntime/runtimeCommon.js +231 -0
  17. package/dist/agentRuntime/runtimeCommon.js.map +1 -0
  18. package/dist/agentv3/claudeConfig.d.ts +6 -2
  19. package/dist/agentv3/claudeConfig.d.ts.map +1 -1
  20. package/dist/agentv3/claudeConfig.js +50 -48
  21. package/dist/agentv3/claudeConfig.js.map +1 -1
  22. package/dist/agentv3/claudeMcpServer.d.ts.map +1 -1
  23. package/dist/agentv3/claudeMcpServer.js +74 -66
  24. package/dist/agentv3/claudeMcpServer.js.map +1 -1
  25. package/dist/agentv3/claudeRuntime.d.ts +18 -2
  26. package/dist/agentv3/claudeRuntime.d.ts.map +1 -1
  27. package/dist/agentv3/claudeRuntime.js +198 -265
  28. package/dist/agentv3/claudeRuntime.js.map +1 -1
  29. package/dist/agentv3/claudeSseBridge.js +1 -1
  30. package/dist/agentv3/claudeSseBridge.js.map +1 -1
  31. package/dist/agentv3/claudeVerifier.d.ts.map +1 -1
  32. package/dist/agentv3/claudeVerifier.js +3 -6
  33. package/dist/agentv3/claudeVerifier.js.map +1 -1
  34. package/dist/cli-user/bin.js +83 -2
  35. package/dist/cli-user/bin.js.map +1 -1
  36. package/dist/cli-user/commands/analyze.d.ts +2 -0
  37. package/dist/cli-user/commands/analyze.d.ts.map +1 -1
  38. package/dist/cli-user/commands/analyze.js +1 -0
  39. package/dist/cli-user/commands/analyze.js.map +1 -1
  40. package/dist/cli-user/commands/capture.d.ts +37 -2
  41. package/dist/cli-user/commands/capture.d.ts.map +1 -1
  42. package/dist/cli-user/commands/capture.js +184 -95
  43. package/dist/cli-user/commands/capture.js.map +1 -1
  44. package/dist/cli-user/commands/compare.d.ts +2 -0
  45. package/dist/cli-user/commands/compare.d.ts.map +1 -1
  46. package/dist/cli-user/commands/compare.js +1 -0
  47. package/dist/cli-user/commands/compare.js.map +1 -1
  48. package/dist/cli-user/commands/doctor.js +4 -0
  49. package/dist/cli-user/commands/doctor.js.map +1 -1
  50. package/dist/cli-user/services/androidCapture.d.ts +59 -0
  51. package/dist/cli-user/services/androidCapture.d.ts.map +1 -0
  52. package/dist/cli-user/services/androidCapture.js +375 -0
  53. package/dist/cli-user/services/androidCapture.js.map +1 -0
  54. package/dist/cli-user/services/captureConfig.d.ts +38 -0
  55. package/dist/cli-user/services/captureConfig.d.ts.map +1 -0
  56. package/dist/cli-user/services/captureConfig.js +434 -0
  57. package/dist/cli-user/services/captureConfig.js.map +1 -0
  58. package/dist/cli-user/services/captureTools.d.ts +11 -0
  59. package/dist/cli-user/services/captureTools.d.ts.map +1 -0
  60. package/dist/cli-user/services/captureTools.js +247 -0
  61. package/dist/cli-user/services/captureTools.js.map +1 -0
  62. package/dist/cli-user/services/cliAnalyzeService.d.ts +2 -0
  63. package/dist/cli-user/services/cliAnalyzeService.d.ts.map +1 -1
  64. package/dist/cli-user/services/cliAnalyzeService.js +1 -0
  65. package/dist/cli-user/services/cliAnalyzeService.js.map +1 -1
  66. package/dist/cli-user/services/runtimeGuard.d.ts +10 -0
  67. package/dist/cli-user/services/runtimeGuard.d.ts.map +1 -1
  68. package/dist/cli-user/services/runtimeGuard.js +48 -0
  69. package/dist/cli-user/services/runtimeGuard.js.map +1 -1
  70. package/dist/cli-user/services/turnRunner.d.ts +3 -0
  71. package/dist/cli-user/services/turnRunner.d.ts.map +1 -1
  72. package/dist/cli-user/services/turnRunner.js +4 -0
  73. package/dist/cli-user/services/turnRunner.js.map +1 -1
  74. package/dist/cli-user/types.d.ts +57 -0
  75. package/dist/cli-user/types.d.ts.map +1 -1
  76. package/dist/perfetto-recording-tools-pin.env +24 -0
  77. package/dist/services/agentResultNormalizer.d.ts.map +1 -1
  78. package/dist/services/agentResultNormalizer.js +32 -4
  79. package/dist/services/agentResultNormalizer.js.map +1 -1
  80. package/dist/services/evidence/evidenceContractBuilder.d.ts.map +1 -1
  81. package/dist/services/evidence/evidenceContractBuilder.js +17 -3
  82. package/dist/services/evidence/evidenceContractBuilder.js.map +1 -1
  83. package/dist/services/perfettoSqlSkill.d.ts.map +1 -1
  84. package/dist/services/perfettoSqlSkill.js +1 -0
  85. package/dist/services/perfettoSqlSkill.js.map +1 -1
  86. package/dist/services/providerManager/connectionTester.d.ts.map +1 -1
  87. package/dist/services/providerManager/connectionTester.js +4 -68
  88. package/dist/services/providerManager/connectionTester.js.map +1 -1
  89. package/dist/services/providerManager/index.d.ts +1 -0
  90. package/dist/services/providerManager/index.d.ts.map +1 -1
  91. package/dist/services/providerManager/index.js +8 -1
  92. package/dist/services/providerManager/index.js.map +1 -1
  93. package/dist/services/providerManager/providerService.d.ts.map +1 -1
  94. package/dist/services/providerManager/providerService.js +37 -106
  95. package/dist/services/providerManager/providerService.js.map +1 -1
  96. package/dist/services/providerManager/providerSnapshot.d.ts.map +1 -1
  97. package/dist/services/providerManager/providerSnapshot.js +13 -12
  98. package/dist/services/providerManager/providerSnapshot.js.map +1 -1
  99. package/dist/services/providerManager/runtimeCapabilities.d.ts +9 -0
  100. package/dist/services/providerManager/runtimeCapabilities.d.ts.map +1 -0
  101. package/dist/services/providerManager/runtimeCapabilities.js +105 -0
  102. package/dist/services/providerManager/runtimeCapabilities.js.map +1 -0
  103. package/dist/services/skillEngine/skillExecutor.d.ts +1 -0
  104. package/dist/services/skillEngine/skillExecutor.d.ts.map +1 -1
  105. package/dist/services/skillEngine/skillExecutor.js +64 -12
  106. package/dist/services/skillEngine/skillExecutor.js.map +1 -1
  107. package/package.json +3 -3
  108. package/prebuilts/android-platform-tools/README.md +13 -0
  109. package/prebuilts/perfetto-recording-tools/README.md +17 -0
  110. package/skills/atomic/cpu_topology_detection.skill.yaml +105 -159
  111. package/skills/atomic/cpu_topology_view.skill.yaml +2 -0
  112. package/strategies/prompt-openai-final-report-continuation-en.template.md +3 -1
  113. package/strategies/prompt-openai-final-report-continuation-zh.template.md +3 -1
  114. package/strategies/prompt-output-format.template.md +1 -1
  115. package/strategies/startup.strategy.md +4 -4
@@ -27,9 +27,7 @@ const queryComplexityClassifier_1 = require("../agentv3/queryComplexityClassifie
27
27
  const openAiComplexityClassifier_1 = require("./openAiComplexityClassifier");
28
28
  const artifactStore_1 = require("../agentv3/artifactStore");
29
29
  const analysisPatternMemory_1 = require("../agentv3/analysisPatternMemory");
30
- const skillNotesInjector_1 = require("../agentv3/selfImprove/skillNotesInjector");
31
30
  const traceCompletenessProber_1 = require("../agentv3/traceCompletenessProber");
32
- const entityCapture_1 = require("../agent/core/entityCapture");
33
31
  const outputLanguage_1 = require("../agentv3/outputLanguage");
34
32
  const codeAwareOutputRegistry_1 = require("../services/security/codeAwareOutputRegistry");
35
33
  const toolNarration_1 = require("../agentv3/toolNarration");
@@ -38,29 +36,16 @@ const mimoReasoningCompat_1 = require("./mimoReasoningCompat");
38
36
  const openAiToolAdapter_1 = require("./openAiToolAdapter");
39
37
  const finalResultQualityGate_1 = require("../services/finalResultQualityGate");
40
38
  const finalReportContractGate_1 = require("../services/finalReportContractGate");
41
- const OPENAI_SESSION_FRESHNESS_MS = 4 * 60 * 60 * 1000;
39
+ const runtimeCommon_1 = require("../agentRuntime/runtimeCommon");
40
+ const OPENAI_SESSION_FRESHNESS_MS = runtimeCommon_1.SDK_SESSION_FRESHNESS_MS;
42
41
  const OPENAI_MAX_PLAN_CONTINUATIONS = 3;
43
- const OPENAI_MAX_FINAL_REPORT_CONTINUATIONS = 2;
42
+ const OPENAI_MAX_FINAL_REPORT_CONTINUATIONS = 4;
44
43
  const OPENAI_PLAN_COMPLETE_IDLE_ABORT_MS = 8000;
45
44
  function hasAdequateClosedPhaseSummary(phase) {
46
45
  if (phase.status !== 'completed' && phase.status !== 'skipped')
47
46
  return false;
48
47
  return typeof phase.summary === 'string' && phase.summary.trim().length >= claudeMcpServer_1.MIN_PHASE_SUMMARY_CHARS;
49
48
  }
50
- function formatTraceContext(datasets, outputLanguage) {
51
- if (!datasets || datasets.length === 0)
52
- return '';
53
- const parts = datasets.map((d) => {
54
- const header = `| ${d.columns.join(' | ')} |`;
55
- const sep = `| ${d.columns.map(() => '---').join(' | ')} |`;
56
- const rows = d.rows.slice(0, 100).map((r) => `| ${r.map((v) => String(v ?? '-')).join(' | ')} |`);
57
- const truncNote = d.rows.length > 100
58
- ? (0, outputLanguage_1.localize)(outputLanguage, `\n*(前 100 行,共 ${d.rows.length} 行)*`, `\n*(first 100 rows out of ${d.rows.length})*`)
59
- : '';
60
- return `### ${d.label}\n${header}\n${sep}\n${rows.join('\n')}${truncNote}`;
61
- });
62
- return (0, outputLanguage_1.localize)(outputLanguage, `## 前端预查询 Trace 数据\n\n以下数据已由前端查询完毕,直接使用,无需重复 SQL 查询:\n\n${parts.join('\n\n')}`, `## Frontend Pre-queried Trace Data\n\nThe frontend has already queried the following data. Use it directly; do not repeat the same SQL query.\n\n${parts.join('\n\n')}`);
63
- }
64
49
  function parseJsonObject(value) {
65
50
  if (typeof value !== 'string')
66
51
  return undefined;
@@ -72,25 +57,6 @@ function parseJsonObject(value) {
72
57
  return undefined;
73
58
  }
74
59
  }
75
- function providerScopeFromOptions(options) {
76
- if (!options.tenantId || !options.workspaceId)
77
- return undefined;
78
- return {
79
- tenantId: options.tenantId,
80
- workspaceId: options.workspaceId,
81
- userId: options.userId,
82
- };
83
- }
84
- function knowledgeScopeFromOptions(options) {
85
- if (!options.tenantId || !options.workspaceId)
86
- return undefined;
87
- return {
88
- tenantId: options.tenantId,
89
- workspaceId: options.workspaceId,
90
- userId: options.userId,
91
- sourceRunId: options.runId,
92
- };
93
- }
94
60
  function summarizeToolOutput(value) {
95
61
  const text = typeof value === 'string' ? value : JSON.stringify(value);
96
62
  if (!text)
@@ -301,12 +267,54 @@ function chooseOpenAiConclusionText(input) {
301
267
  }
302
268
  return selected;
303
269
  }
270
+ function resolveOpenAIRunInput(params) {
271
+ let effectivePrompt = params.effectivePrompt;
272
+ if (params.quickMode) {
273
+ const quickConversationContext = (0, runtimeCommon_1.buildQuickConversationContext)(params.previousTurns, params.config.outputLanguage);
274
+ if (quickConversationContext) {
275
+ effectivePrompt = `${quickConversationContext}\n\n${effectivePrompt}`;
276
+ }
277
+ return {
278
+ input: effectivePrompt,
279
+ effectivePrompt,
280
+ shouldPersistRemoteSession: false,
281
+ };
282
+ }
283
+ const hasFreshSessionEntry = (0, runtimeCommon_1.isFreshRuntimeEntry)(params.sessionEntry, OPENAI_SESSION_FRESHNESS_MS, params.now ?? Date.now());
284
+ const freshSessionEntry = hasFreshSessionEntry ? params.sessionEntry : undefined;
285
+ const usePreviousResponse = params.config.protocol === 'responses'
286
+ && !!freshSessionEntry?.lastResponseId;
287
+ if (usePreviousResponse) {
288
+ return {
289
+ input: effectivePrompt,
290
+ effectivePrompt,
291
+ previousResponseId: freshSessionEntry.lastResponseId,
292
+ shouldPersistRemoteSession: true,
293
+ };
294
+ }
295
+ if (freshSessionEntry?.history) {
296
+ return {
297
+ input: [
298
+ ...freshSessionEntry.history,
299
+ { role: 'user', content: effectivePrompt },
300
+ ],
301
+ effectivePrompt,
302
+ shouldPersistRemoteSession: true,
303
+ };
304
+ }
305
+ return {
306
+ input: effectivePrompt,
307
+ effectivePrompt,
308
+ shouldPersistRemoteSession: true,
309
+ };
310
+ }
304
311
  exports.__testing = {
305
312
  isMissingOpenAIPreviousResponseError,
306
313
  readCompletedStreamFinalOutput,
307
314
  sanitizeOpenAiConclusionText,
308
315
  chooseOpenAiConclusionText,
309
316
  selectOpenAiRecoveryAnswer,
317
+ resolveOpenAIRunInput,
310
318
  isRecoverableOpenAIStreamTermination,
311
319
  compactProviderErrorMessage,
312
320
  };
@@ -327,11 +335,11 @@ class OpenAIRuntime extends events_1.EventEmitter {
327
335
  this.traceProcessorService = traceProcessorService;
328
336
  }
329
337
  buildSessionMapKey(sessionId, referenceTraceId) {
330
- return referenceTraceId ? `${sessionId}:ref:${referenceTraceId}` : sessionId;
338
+ return (0, runtimeCommon_1.buildRuntimeSessionMapKey)(sessionId, referenceTraceId);
331
339
  }
332
340
  getSdkSessionId(sessionId, referenceTraceId) {
333
341
  const entry = this.sessionMap.get(this.buildSessionMapKey(sessionId, referenceTraceId));
334
- return entry && Date.now() - (entry.updatedAt || 0) < OPENAI_SESSION_FRESHNESS_MS
342
+ return (0, runtimeCommon_1.isFreshRuntimeEntry)(entry, OPENAI_SESSION_FRESHNESS_MS)
335
343
  ? entry.lastResponseId
336
344
  : undefined;
337
345
  }
@@ -344,7 +352,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
344
352
  });
345
353
  }
346
354
  restoreArchitectureCache(traceId, architecture) {
347
- this.architectureCache.set(traceId, architecture);
355
+ (0, runtimeCommon_1.setLruCacheEntry)(this.architectureCache, traceId, architecture);
348
356
  }
349
357
  forgetOpenAILastResponseId(sessionMapKey, reason) {
350
358
  const existing = this.sessionMap.get(sessionMapKey);
@@ -394,7 +402,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
394
402
  const startTime = Date.now();
395
403
  let accumulatedAnswer = '';
396
404
  let rounds = 0;
397
- const config = (0, openAiConfig_1.loadOpenAIConfig)(options.providerId, providerScopeFromOptions(options));
405
+ const config = (0, openAiConfig_1.loadOpenAIConfig)(options.providerId, (0, runtimeCommon_1.providerScopeFromAnalysisOptions)(options));
398
406
  const sceneType = (0, sceneClassifier_1.classifyScene)(query);
399
407
  const quickMode = await this.classifyModeForRequest(query, sessionId, traceId, options, sceneType, config);
400
408
  try {
@@ -403,22 +411,17 @@ class OpenAIRuntime extends events_1.EventEmitter {
403
411
  sceneType,
404
412
  lightweight: quickMode,
405
413
  });
406
- const promptPrefix = formatTraceContext(options.traceContext, config.outputLanguage);
414
+ const promptPrefix = (0, runtimeCommon_1.formatTraceContext)(options.traceContext, config.outputLanguage);
407
415
  const effectivePrompt = promptPrefix ? `${promptPrefix}\n\n${query}` : query;
408
416
  const sessionEntry = this.sessionMap.get(context.sessionMapKey);
409
- const hasFreshHistory = !!sessionEntry?.history
410
- && Date.now() - sessionEntry.updatedAt < OPENAI_SESSION_FRESHNESS_MS;
411
- const usePreviousResponse = config.protocol === 'responses'
412
- && !!sessionEntry?.lastResponseId
413
- && Date.now() - sessionEntry.updatedAt < OPENAI_SESSION_FRESHNESS_MS;
414
- const input = usePreviousResponse
415
- ? effectivePrompt
416
- : hasFreshHistory
417
- ? [
418
- ...sessionEntry.history,
419
- { role: 'user', content: effectivePrompt },
420
- ]
421
- : effectivePrompt;
417
+ const runInput = resolveOpenAIRunInput({
418
+ quickMode,
419
+ config,
420
+ sessionEntry,
421
+ effectivePrompt,
422
+ previousTurns: context.previousTurns,
423
+ });
424
+ const input = runInput.input;
422
425
  (0, agents_1.setTracingDisabled)(true);
423
426
  const provider = (0, mimoReasoningCompat_1.shouldUseMimoReasoningContentCompat)(config)
424
427
  ? new agents_1.OpenAIProvider({
@@ -465,13 +468,13 @@ class OpenAIRuntime extends events_1.EventEmitter {
465
468
  type: 'progress',
466
469
  content: {
467
470
  phase: 'answering',
468
- message: (0, outputLanguage_1.localize)(config.outputLanguage, `OpenAI Agents SDK 分析中 (${agent.model})...`, `Analyzing with OpenAI Agents SDK (${agent.model})...`),
471
+ message: (0, outputLanguage_1.localize)(config.outputLanguage, `AI 分析引擎分析中 (${agent.model})...`, `AI analysis engine is running (${agent.model})...`),
469
472
  runtime: 'openai-agents-sdk',
470
473
  model: agent.model,
471
474
  },
472
475
  timestamp: Date.now(),
473
476
  });
474
- let currentPreviousResponseId = usePreviousResponse ? sessionEntry.lastResponseId : undefined;
477
+ let currentPreviousResponseId = runInput.previousResponseId;
475
478
  try {
476
479
  let currentInput = input;
477
480
  let conclusion = '';
@@ -528,7 +531,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
528
531
  type: 'progress',
529
532
  content: {
530
533
  phase: 'concluding',
531
- message: (0, outputLanguage_1.localize)(config.outputLanguage, 'OpenAI plan 已完成,provider 未主动结束 stream,按已完成计划收尾。', 'The OpenAI plan is complete; the provider did not close the stream, so finalizing from the completed plan.'),
534
+ message: (0, outputLanguage_1.localize)(config.outputLanguage, '分析阶段已完成,正在整理最终报告。', 'Analysis phases are complete; preparing the final report.'),
532
535
  },
533
536
  timestamp: Date.now(),
534
537
  });
@@ -685,7 +688,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
685
688
  (0, finalResultQualityGate_1.looksLikePhaseSummaryFallback)(conclusion)) &&
686
689
  !partial) {
687
690
  partial = true;
688
- terminationMessage = (0, outputLanguage_1.localize)(config.outputLanguage, 'OpenAI plan 已完成,但 provider 没有输出独立最终报告;已退回到阶段摘要,结果信息密度可能不足。', 'The OpenAI plan completed, but the provider did not produce an independent final report; falling back to phase summaries, which may be less informative.');
691
+ terminationMessage = (0, outputLanguage_1.localize)(config.outputLanguage, '分析阶段已完成,但模型没有输出独立最终报告;已使用阶段摘要兜底,结果信息密度可能不足。', 'Analysis phases completed, but the model did not produce an independent final report; falling back to phase summaries, which may be less informative.');
689
692
  this.emitUpdate({
690
693
  type: 'degraded',
691
694
  content: {
@@ -727,12 +730,14 @@ class OpenAIRuntime extends events_1.EventEmitter {
727
730
  timestamp: Date.now(),
728
731
  });
729
732
  }
730
- this.sessionMap.set(context.sessionMapKey, {
731
- history: finalHistory,
732
- lastResponseId: finalLastResponseId,
733
- runState: finalRunState,
734
- updatedAt: Date.now(),
735
- });
733
+ if (runInput.shouldPersistRemoteSession) {
734
+ this.sessionMap.set(context.sessionMapKey, {
735
+ history: finalHistory,
736
+ lastResponseId: finalLastResponseId,
737
+ runState: finalRunState,
738
+ updatedAt: Date.now(),
739
+ });
740
+ }
736
741
  this.recordTurn({
737
742
  query,
738
743
  sessionId,
@@ -769,33 +774,18 @@ class OpenAIRuntime extends events_1.EventEmitter {
769
774
  });
770
775
  }
771
776
  else if (error instanceof agents_1.MaxTurnsExceededError) {
772
- const partialConclusion = accumulatedAnswer || (0, outputLanguage_1.localize)(config.outputLanguage, '分析达到 OpenAI Agents SDK 轮次上限,尚未形成完整结论。', 'The OpenAI Agents SDK run reached the turn limit before a complete conclusion was produced.');
773
- const findings = (0, claudeFindingExtractor_1.extractFindingsFromText)(partialConclusion);
774
- const confidence = Math.min(0.55, this.estimateConfidence(findings, partialConclusion));
775
- this.emitUpdate({
776
- type: 'degraded',
777
- content: {
778
- module: 'openAiRuntime',
779
- fallback: 'partial_result_after_max_turns',
780
- partial: true,
781
- terminationReason: 'max_turns',
782
- message: (0, outputLanguage_1.localize)(config.outputLanguage, 'OpenAI 分析达到轮次上限,结果可能不完整', 'OpenAI analysis reached the turn limit; result may be incomplete'),
783
- },
784
- timestamp: Date.now(),
785
- });
786
- return {
777
+ return this.recordMaxTurnsPartialResult({
778
+ error,
779
+ query,
787
780
  sessionId,
788
- success: true,
789
- findings,
790
- hypotheses: context.hypotheses.map(h => this.toProtocolHypothesis(h)),
791
- conclusion: partialConclusion,
792
- confidence,
781
+ outputLanguage: config.outputLanguage,
782
+ accumulatedAnswer,
783
+ context,
784
+ startTime,
793
785
  rounds,
794
- totalDurationMs: Date.now() - startTime,
795
- partial: true,
796
- terminationReason: 'max_turns',
797
- terminationMessage: error.message,
798
- };
786
+ quickMode,
787
+ codeAwareMode: options.codeAwareMode,
788
+ });
799
789
  }
800
790
  const recoverablePartial = this.recoverPartialResultAfterStreamTermination({
801
791
  error,
@@ -807,6 +797,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
807
797
  query,
808
798
  startTime,
809
799
  rounds,
800
+ codeAwareMode: options.codeAwareMode,
810
801
  });
811
802
  if (recoverablePartial) {
812
803
  return recoverablePartial;
@@ -818,7 +809,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
818
809
  const message = compactProviderErrorMessage(error);
819
810
  this.emitUpdate({
820
811
  type: 'error',
821
- content: { message: `OpenAI Agents SDK analysis failed: ${message}` },
812
+ content: { message: `AI analysis failed: ${message}` },
822
813
  timestamp: Date.now(),
823
814
  });
824
815
  return {
@@ -826,7 +817,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
826
817
  success: false,
827
818
  findings: [],
828
819
  hypotheses: [],
829
- conclusion: (0, outputLanguage_1.localize)(config.outputLanguage, `OpenAI Agents SDK 分析失败:${message}`, `OpenAI Agents SDK analysis failed: ${message}`),
820
+ conclusion: (0, outputLanguage_1.localize)(config.outputLanguage, `AI 分析失败:${message}`, `AI analysis failed: ${message}`),
830
821
  confidence: 0,
831
822
  rounds,
832
823
  totalDurationMs: Date.now() - startTime,
@@ -869,7 +860,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
869
860
  const planState = this.sessionPlans.get(sessionId);
870
861
  const artifactStore = this.artifactStores.get(sessionId);
871
862
  const sessionEntry = this.sessionMap.get(this.buildSessionMapKey(sessionId, sessionFields.referenceTraceId));
872
- const freshSessionEntry = sessionEntry && Date.now() - (sessionEntry.updatedAt || 0) < OPENAI_SESSION_FRESHNESS_MS
863
+ const freshSessionEntry = (0, runtimeCommon_1.isFreshRuntimeEntry)(sessionEntry, OPENAI_SESSION_FRESHNESS_MS)
873
864
  ? sessionEntry
874
865
  : undefined;
875
866
  return {
@@ -990,12 +981,10 @@ class OpenAIRuntime extends events_1.EventEmitter {
990
981
  uncertaintyFlags.splice(0);
991
982
  let sqlErrors = this.sessionSqlErrors.get(sessionId);
992
983
  if (!sqlErrors) {
993
- sqlErrors = (0, claudeMcpServer_1.loadLearnedSqlFixPairs)(5, knowledgeScopeFromOptions(options));
984
+ sqlErrors = (0, claudeMcpServer_1.loadLearnedSqlFixPairs)(5, (0, runtimeCommon_1.knowledgeScopeFromAnalysisOptions)(options));
994
985
  this.sessionSqlErrors.set(sessionId, sqlErrors);
995
986
  }
996
- const skillNotesBudget = !lightweight && process.env.SELF_IMPROVE_NOTES_INJECT_ENABLED === '1'
997
- ? new skillNotesInjector_1.SkillNotesBudget({ mode: 'full' })
998
- : undefined;
987
+ const skillNotesBudget = (0, runtimeCommon_1.createRuntimeSkillNotesBudget)(lightweight);
999
988
  const { allowedTools, toolDefinitions } = (0, claudeMcpServer_1.createClaudeMcpServer)({
1000
989
  sessionId,
1001
990
  traceId,
@@ -1023,7 +1012,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
1023
1012
  lightweight,
1024
1013
  skillNotesBudget,
1025
1014
  outputLanguage: config.outputLanguage,
1026
- knowledgeScope: knowledgeScopeFromOptions(options),
1015
+ knowledgeScope: (0, runtimeCommon_1.knowledgeScopeFromAnalysisOptions)(options),
1027
1016
  codeAwareMode: options.codeAwareMode,
1028
1017
  codebaseIds: options.codebaseIds,
1029
1018
  });
@@ -1045,6 +1034,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
1045
1034
  .filter((e) => e.fixedSql)
1046
1035
  .slice(-3)
1047
1036
  .map((e) => ({ errorSql: e.errorSql, errorMessage: e.errorMessage, fixedSql: e.fixedSql }));
1037
+ const traceInfo = this.traceProcessorService.getTrace(traceId);
1048
1038
  const systemPrompt = lightweight
1049
1039
  ? (0, claudeSystemPrompt_1.buildQuickSystemPrompt)({
1050
1040
  architecture,
@@ -1075,6 +1065,8 @@ class OpenAIRuntime extends events_1.EventEmitter {
1075
1065
  selectionContext: options.selectionContext,
1076
1066
  comparison: comparisonContext,
1077
1067
  traceCompleteness,
1068
+ traceOs: traceInfo?.traceOs,
1069
+ traceFormat: traceInfo?.traceFormat,
1078
1070
  outputLanguage: config.outputLanguage,
1079
1071
  codeAwareMode: options.codeAwareMode,
1080
1072
  codebaseIds: options.codebaseIds,
@@ -1092,7 +1084,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
1092
1084
  };
1093
1085
  }
1094
1086
  async detectArchitecture(traceId, packageName) {
1095
- const cached = this.architectureCache.get(traceId);
1087
+ const cached = (0, runtimeCommon_1.getLruCacheEntry)(this.architectureCache, traceId);
1096
1088
  if (cached)
1097
1089
  return cached;
1098
1090
  try {
@@ -1103,7 +1095,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
1103
1095
  packageName,
1104
1096
  });
1105
1097
  if (architecture) {
1106
- this.architectureCache.set(traceId, architecture);
1098
+ (0, runtimeCommon_1.setLruCacheEntry)(this.architectureCache, traceId, architecture);
1107
1099
  this.emitUpdate({ type: 'architecture_detected', content: { architecture }, timestamp: Date.now() });
1108
1100
  }
1109
1101
  return architecture;
@@ -1161,15 +1153,16 @@ class OpenAIRuntime extends events_1.EventEmitter {
1161
1153
  };
1162
1154
  }
1163
1155
  async detectVendor(traceId) {
1164
- const cached = this.vendorCache.get(traceId);
1156
+ const cached = (0, runtimeCommon_1.getLruCacheEntry)(this.vendorCache, traceId);
1165
1157
  if (cached)
1166
1158
  return cached;
1167
1159
  try {
1168
1160
  const adapter = (0, skillAnalysisAdapter_1.getSkillAnalysisAdapter)(this.traceProcessorService);
1169
1161
  await adapter.ensureInitialized();
1170
1162
  const result = await adapter.detectVendor(traceId);
1171
- if (result.vendor && result.vendor !== 'aosp')
1172
- this.vendorCache.set(traceId, result.vendor);
1163
+ if (result.vendor && result.vendor !== 'aosp') {
1164
+ (0, runtimeCommon_1.setLruCacheEntry)(this.vendorCache, traceId, result.vendor);
1165
+ }
1173
1166
  return result.vendor;
1174
1167
  }
1175
1168
  catch (error) {
@@ -1178,12 +1171,12 @@ class OpenAIRuntime extends events_1.EventEmitter {
1178
1171
  }
1179
1172
  }
1180
1173
  async detectCompleteness(traceId, architecture) {
1181
- const cached = this.completenessCache.get(traceId);
1174
+ const cached = (0, runtimeCommon_1.getLruCacheEntry)(this.completenessCache, traceId);
1182
1175
  if (cached)
1183
1176
  return cached;
1184
1177
  try {
1185
1178
  const completeness = await (0, traceCompletenessProber_1.probeTraceCompleteness)(this.traceProcessorService, traceId, architecture?.type);
1186
- this.completenessCache.set(traceId, completeness);
1179
+ (0, runtimeCommon_1.setLruCacheEntry)(this.completenessCache, traceId, completeness);
1187
1180
  return completeness;
1188
1181
  }
1189
1182
  catch (error) {
@@ -1289,7 +1282,7 @@ class OpenAIRuntime extends events_1.EventEmitter {
1289
1282
  return template;
1290
1283
  }
1291
1284
  formatPlanCompleteReportContinuationMessage(outputLanguage) {
1292
- return (0, outputLanguage_1.localize)(outputLanguage, 'OpenAI plan 已完成,但最终正文仍是阶段摘要,继续请求完整最终报告。', 'The OpenAI plan is complete, but the final body is still a phase summary; requesting the complete final report.');
1285
+ return (0, outputLanguage_1.localize)(outputLanguage, '最终报告仍需补齐,继续整理完整结论。', 'The final report still needs completion; continuing to assemble the full conclusion.');
1293
1286
  }
1294
1287
  buildCompletedPlanFallbackConclusion(sessionId, quickMode, outputLanguage) {
1295
1288
  if (quickMode)
@@ -1404,7 +1397,9 @@ class OpenAIRuntime extends events_1.EventEmitter {
1404
1397
  let conclusion = planStatus.complete
1405
1398
  ? conclusionBase
1406
1399
  : this.withIncompletePlanWarning(conclusionBase, planStatus, params.outputLanguage);
1407
- conclusion = (0, codeAwareOutputRegistry_1.sanitizeCodeAwareText)(params.sessionId, conclusion);
1400
+ if (params.codeAwareMode && params.codeAwareMode !== 'off') {
1401
+ conclusion = (0, codeAwareOutputRegistry_1.sanitizeCodeAwareText)(params.sessionId, conclusion);
1402
+ }
1408
1403
  const findings = (0, claudeFindingExtractor_1.extractFindingsFromText)(conclusion);
1409
1404
  const confidence = Math.min(0.55, this.estimateConfidence(findings, conclusion));
1410
1405
  const terminationReason = planStatus.complete ? 'timeout' : 'plan_incomplete';
@@ -1464,12 +1459,63 @@ class OpenAIRuntime extends events_1.EventEmitter {
1464
1459
  terminationMessage,
1465
1460
  };
1466
1461
  }
1462
+ recordMaxTurnsPartialResult(params) {
1463
+ let partialConclusion = params.accumulatedAnswer || (0, outputLanguage_1.localize)(params.outputLanguage, '分析达到轮次上限,尚未形成完整结论。', 'The analysis reached the turn limit before a complete conclusion was produced.');
1464
+ if (params.codeAwareMode && params.codeAwareMode !== 'off') {
1465
+ partialConclusion = (0, codeAwareOutputRegistry_1.sanitizeCodeAwareText)(params.sessionId, partialConclusion);
1466
+ }
1467
+ const findings = (0, claudeFindingExtractor_1.extractFindingsFromText)(partialConclusion);
1468
+ const confidence = Math.min(0.55, this.estimateConfidence(findings, partialConclusion));
1469
+ const result = {
1470
+ sessionId: params.sessionId,
1471
+ success: true,
1472
+ findings,
1473
+ hypotheses: params.context.hypotheses.map(h => this.toProtocolHypothesis(h)),
1474
+ conclusion: partialConclusion,
1475
+ confidence,
1476
+ rounds: params.rounds,
1477
+ totalDurationMs: Date.now() - params.startTime,
1478
+ partial: true,
1479
+ terminationReason: 'max_turns',
1480
+ terminationMessage: params.error.message,
1481
+ };
1482
+ this.emitUpdate({
1483
+ type: 'degraded',
1484
+ content: {
1485
+ module: 'openAiRuntime',
1486
+ fallback: 'partial_result_after_max_turns',
1487
+ partial: true,
1488
+ terminationReason: 'max_turns',
1489
+ message: (0, outputLanguage_1.localize)(params.outputLanguage, 'OpenAI 分析达到轮次上限,结果可能不完整', 'OpenAI analysis reached the turn limit; result may be incomplete'),
1490
+ },
1491
+ timestamp: Date.now(),
1492
+ });
1493
+ this.recordTurn({
1494
+ query: params.query,
1495
+ sessionId: params.sessionId,
1496
+ result,
1497
+ sessionContext: params.context.sessionContext,
1498
+ previousTurnCount: params.context.previousTurns.length,
1499
+ quickMode: params.quickMode,
1500
+ });
1501
+ this.emitUpdate({
1502
+ type: 'conclusion',
1503
+ content: { conclusion: result.conclusion, durationMs: Date.now() - params.startTime, turns: params.rounds },
1504
+ timestamp: Date.now(),
1505
+ });
1506
+ this.emitUpdate({
1507
+ type: 'answer_token',
1508
+ content: { done: true, totalChars: result.conclusion.length },
1509
+ timestamp: Date.now(),
1510
+ });
1511
+ return result;
1512
+ }
1467
1513
  formatPlanContinuationMessage(status, outputLanguage) {
1468
1514
  if (!status.hasPlan) {
1469
- return (0, outputLanguage_1.localize)(outputLanguage, 'OpenAI 模型提前结束但尚未提交分析计划,继续执行...', 'The OpenAI model stopped before submitting an analysis plan; continuing...');
1515
+ return (0, outputLanguage_1.localize)(outputLanguage, '继续建立分析计划并补齐必要证据...', 'Continuing by creating the analysis plan and collecting required evidence...');
1470
1516
  }
1471
1517
  const phaseNames = status.pendingPhases.map(p => p.name || p.id).slice(0, 3).join('、');
1472
- return (0, outputLanguage_1.localize)(outputLanguage, `OpenAI 模型提前结束但 plan 未完成,继续执行剩余阶段:${phaseNames}`, `The OpenAI model stopped before the plan completed; continuing remaining phases: ${phaseNames}`);
1518
+ return (0, outputLanguage_1.localize)(outputLanguage, `继续补齐剩余分析阶段:${phaseNames}`, `Continuing the remaining analysis phases: ${phaseNames}`);
1473
1519
  }
1474
1520
  formatIncompletePlanMessage(status, outputLanguage) {
1475
1521
  if (!status.hasPlan) {
@@ -1593,94 +1639,16 @@ class OpenAIRuntime extends events_1.EventEmitter {
1593
1639
  });
1594
1640
  }
1595
1641
  captureEntitiesFromSkillDisplayResults(displayResults, entityStore) {
1596
- try {
1597
- const data = {};
1598
- for (const dr of displayResults) {
1599
- if (dr.stepId && dr.data)
1600
- data[dr.stepId] = dr.data;
1601
- }
1602
- const captured = (0, entityCapture_1.captureEntitiesFromResponses)([{
1603
- agentId: 'openai-agent',
1604
- success: true,
1605
- toolResults: [{ toolName: 'invoke_skill', data }],
1606
- }]);
1607
- (0, entityCapture_1.applyCapturedEntities)(entityStore, captured);
1608
- }
1609
- catch (error) {
1610
- console.warn('[OpenAIRuntime] Entity capture failed:', error.message);
1611
- }
1642
+ (0, runtimeCommon_1.captureSkillDisplayEntities)(displayResults, entityStore, 'openai-agent');
1612
1643
  }
1613
1644
  collectPreviousFindings(sessionContext, maxTurns = 3) {
1614
- try {
1615
- const turns = sessionContext.getAllTurns?.() || [];
1616
- return turns.slice(-maxTurns).flatMap((turn) => turn.findings || []).slice(0, 5);
1617
- }
1618
- catch {
1619
- return [];
1620
- }
1645
+ return (0, runtimeCommon_1.collectRecentFindings)(sessionContext, { maxTurns, maxFindings: 5 });
1621
1646
  }
1622
1647
  buildEntityContext(entityStore) {
1623
- try {
1624
- const lines = [];
1625
- const frames = entityStore.getAllFrames?.() || [];
1626
- if (frames.length > 0) {
1627
- lines.push(`**帧 (${frames.length})**:`);
1628
- for (const f of frames.slice(0, 15)) {
1629
- const parts = [`frame_id=${f.frame_id}`];
1630
- if (f.start_ts)
1631
- parts.push(`ts=${f.start_ts}`);
1632
- if (f.jank_type)
1633
- parts.push(`jank=${f.jank_type}`);
1634
- if (f.dur_ms)
1635
- parts.push(`dur=${f.dur_ms}ms`);
1636
- if (f.process_name)
1637
- parts.push(`proc=${f.process_name}`);
1638
- lines.push(`- ${parts.join(', ')}`);
1639
- }
1640
- }
1641
- const sessions = entityStore.getAllSessions?.() || [];
1642
- if (sessions.length > 0) {
1643
- lines.push(`**滑动会话 (${sessions.length})**:`);
1644
- for (const s of sessions.slice(0, 8)) {
1645
- const parts = [`session_id=${s.session_id}`];
1646
- if (s.start_ts)
1647
- parts.push(`ts=${s.start_ts}`);
1648
- if (s.jank_count)
1649
- parts.push(`janks=${s.jank_count}`);
1650
- if (s.process_name)
1651
- parts.push(`proc=${s.process_name}`);
1652
- lines.push(`- ${parts.join(', ')}`);
1653
- }
1654
- }
1655
- return lines.length > 0 ? lines.join('\n') : undefined;
1656
- }
1657
- catch {
1658
- return undefined;
1659
- }
1648
+ return (0, runtimeCommon_1.buildEntityContext)(entityStore);
1660
1649
  }
1661
1650
  toProtocolHypothesis(h) {
1662
- const statusMap = {
1663
- formed: 'proposed',
1664
- confirmed: 'confirmed',
1665
- rejected: 'rejected',
1666
- };
1667
- const confidenceMap = { formed: 0.5, confirmed: 0.85, rejected: 0.1 };
1668
- return {
1669
- id: h.id,
1670
- description: h.statement,
1671
- status: statusMap[h.status] || 'proposed',
1672
- confidence: confidenceMap[h.status] ?? 0.5,
1673
- supportingEvidence: h.evidence && h.status === 'confirmed'
1674
- ? [{ id: `${h.id}-ev`, type: 'observation', description: h.evidence, source: 'openai', strength: 0.8 }]
1675
- : [],
1676
- contradictingEvidence: h.evidence && h.status === 'rejected'
1677
- ? [{ id: `${h.id}-ev`, type: 'observation', description: h.evidence, source: 'openai', strength: 0.8 }]
1678
- : [],
1679
- proposedBy: 'openai',
1680
- relevantAgents: ['openai'],
1681
- createdAt: h.formedAt,
1682
- updatedAt: h.resolvedAt || h.formedAt,
1683
- };
1651
+ return (0, runtimeCommon_1.toProtocolHypothesis)(h, 'openai');
1684
1652
  }
1685
1653
  emitUpdate(update) {
1686
1654
  this.emit('update', update);