@peopl-health/nexus 5.9.0-dev.921 → 6.0.0-dev.611

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 (126) hide show
  1. package/lib/clinical/AssistantProcessor.js +5 -34
  2. package/lib/clinical/config/divergenceConfig.js +1 -18
  3. package/lib/clinical/config/llmConfig.js +1 -9
  4. package/lib/clinical/context/ToolRuntimeContext.js +2 -1
  5. package/lib/clinical/helpers/divergenceHelper.js +0 -12
  6. package/lib/clinical/index.js +0 -2
  7. package/lib/clinical/memory/DefaultMemoryManager.js +9 -19
  8. package/lib/clinical/models/turnTraceModel.js +5 -18
  9. package/lib/clinical/providers/AnthropicProvider.js +29 -291
  10. package/lib/clinical/providers/BaseLLMProvider.js +24 -113
  11. package/lib/clinical/providers/GatewayProvider.js +3 -3
  12. package/lib/clinical/providers/OpenAIResponsesProvider.js +4 -46
  13. package/lib/clinical/services/divergenceService.js +5 -22
  14. package/lib/clinical/services/promptComposerService.js +15 -46
  15. package/lib/clinical/services/shadowMessageService.js +12 -28
  16. package/lib/clinical/services/shadowService.js +3 -12
  17. package/lib/clinical/stores/CtcaeCatalog.js +0 -20
  18. package/lib/config/airtableConfig.js +0 -3
  19. package/lib/core/BatchingManager.js +3 -10
  20. package/lib/core/NexusMessaging.js +13 -31
  21. package/lib/eval/EvalProvider.js +2 -3
  22. package/lib/fhir/config/fhirConfig.js +3 -34
  23. package/lib/fhir/constants/projectionSlugs.js +1 -41
  24. package/lib/fhir/helpers/elementHelper.js +0 -21
  25. package/lib/fhir/helpers/fhirHelper.js +2 -5
  26. package/lib/fhir/index.js +0 -24
  27. package/lib/fhir/models/envelopeModel.js +0 -5
  28. package/lib/fhir/projections/registerProjectors.js +0 -16
  29. package/lib/fhir/resources/Condition.js +2 -107
  30. package/lib/fhir/resources/Observation.js +1 -73
  31. package/lib/fhir/resources/Procedure.js +2 -34
  32. package/lib/fhir/resources/Provenance.js +2 -93
  33. package/lib/fhir/services/fhirService.js +2 -2
  34. package/lib/helpers/twilioHelper.js +1 -9
  35. package/lib/index.d.ts +0 -16
  36. package/lib/index.js +0 -9
  37. package/lib/models/messageModel.js +0 -6
  38. package/lib/routes/index.js +1 -21
  39. package/lib/services/airtableService.js +1 -2
  40. package/lib/shared/dtos/ContingencySafetyNet.js +3 -10
  41. package/lib/shared/dtos/DispatchedEscalation.js +8 -3
  42. package/lib/shared/dtos/Reminder.js +2 -2
  43. package/lib/storage/MongoStorage.js +0 -2
  44. package/package.json +1 -1
  45. package/lib/clinical/config/cohortConfig.js +0 -68
  46. package/lib/clinical/config/composerConfig.js +0 -42
  47. package/lib/clinical/config/subAgentsConfig.js +0 -44
  48. package/lib/clinical/flags/bridgeConfig.js +0 -14
  49. package/lib/clinical/flags/composerFlags.js +0 -14
  50. package/lib/clinical/helpers/clinicalFactsHelper.js +0 -108
  51. package/lib/clinical/helpers/clinicalMentionHelper.js +0 -68
  52. package/lib/clinical/helpers/cohortHelper.js +0 -22
  53. package/lib/clinical/helpers/gradeEstimateHelper.js +0 -29
  54. package/lib/clinical/helpers/resultsHelper.js +0 -34
  55. package/lib/clinical/helpers/safetyFlagsHelper.js +0 -10
  56. package/lib/clinical/services/bridgeService.js +0 -55
  57. package/lib/clinical/services/clinicalAirtableService.js +0 -162
  58. package/lib/clinical/services/clinicalExtractionService.js +0 -112
  59. package/lib/clinical/services/composerService.js +0 -59
  60. package/lib/clinical/services/dispatcherService.js +0 -137
  61. package/lib/clinical/services/reminderDispatchService.js +0 -36
  62. package/lib/clinical/services/skillService.js +0 -44
  63. package/lib/clinical/tools/analyzeSymptomPatternsTool.js +0 -279
  64. package/lib/clinical/tools/deliverPatientMessageTool.js +0 -202
  65. package/lib/clinical/tools/extractClinicalInfoTool.js +0 -167
  66. package/lib/clinical/tools/getActiveSymptomLandscapeTool.js +0 -141
  67. package/lib/clinical/tools/getPatientHistoryTool.js +0 -235
  68. package/lib/clinical/tools/getPatientRiskProfileTool.js +0 -71
  69. package/lib/clinical/tools/getRouterContextBundleTool.js +0 -93
  70. package/lib/clinical/tools/lookupCtcaeEntryTool.js +0 -35
  71. package/lib/clinical/tools/openClusterHypothesisTool.js +0 -160
  72. package/lib/clinical/tools/openConditionTool.js +0 -136
  73. package/lib/clinical/tools/recordClinicalImpressionTool.js +0 -251
  74. package/lib/clinical/tools/recordInterventionTool.js +0 -140
  75. package/lib/clinical/tools/registerClinicalTools.js +0 -39
  76. package/lib/clinical/tools/reportCrisisTool.js +0 -211
  77. package/lib/clinical/tools/reportMedicalEscalationTool.js +0 -187
  78. package/lib/clinical/tools/reportResultsReceivedTool.js +0 -153
  79. package/lib/clinical/tools/reportUnresolvedRequestv2Tool.js +0 -177
  80. package/lib/clinical/tools/schedulePatientReminderTool.js +0 -149
  81. package/lib/clinical/tools/setContingencyPlanTool.js +0 -176
  82. package/lib/clinical/tools/skillTool.js +0 -67
  83. package/lib/clinical/tools/submitRoutingDecisionTool.js +0 -291
  84. package/lib/clinical/tools/updateClusterHypothesisTool.js +0 -159
  85. package/lib/controllers/cohortController.js +0 -16
  86. package/lib/controllers/traceController.js +0 -26
  87. package/lib/core/workflowRunner.js +0 -35
  88. package/lib/fhir/config/fhirTablesConfig.js +0 -9
  89. package/lib/fhir/constants/severityPriority.js +0 -8
  90. package/lib/fhir/helpers/compositeHelper.js +0 -88
  91. package/lib/fhir/helpers/fhirReadHelper.js +0 -42
  92. package/lib/fhir/helpers/terminologyHelper.js +0 -260
  93. package/lib/fhir/projections/clusterProjection.js +0 -24
  94. package/lib/fhir/projections/contingencyProjection.js +0 -36
  95. package/lib/fhir/projections/dispatchedEscalationProjection.js +0 -25
  96. package/lib/fhir/projections/interventionProjection.js +0 -42
  97. package/lib/fhir/projections/proctcaeProjection.js +0 -179
  98. package/lib/fhir/projections/reminderProjection.js +0 -20
  99. package/lib/fhir/projections/riskProjection.js +0 -16
  100. package/lib/fhir/projections/routingProjection.js +0 -48
  101. package/lib/fhir/projections/symptomCaseProjection.js +0 -65
  102. package/lib/fhir/resources/CarePlan.js +0 -93
  103. package/lib/fhir/resources/ClinicalImpression.js +0 -118
  104. package/lib/fhir/resources/Communication.js +0 -65
  105. package/lib/fhir/resources/CommunicationRequest.js +0 -182
  106. package/lib/fhir/resources/Device.js +0 -24
  107. package/lib/fhir/resources/Patient.js +0 -18
  108. package/lib/fhir/resources/Questionnaire.js +0 -23
  109. package/lib/fhir/resources/QuestionnaireResponse.js +0 -29
  110. package/lib/fhir/resources/RequestOrchestration.js +0 -46
  111. package/lib/fhir/resources/RiskAssessment.js +0 -99
  112. package/lib/fhir/resources/Task.js +0 -106
  113. package/lib/fhir/resources/interventionExtensions.js +0 -28
  114. package/lib/fhir/services/clusterService.js +0 -77
  115. package/lib/fhir/services/contingencyService.js +0 -117
  116. package/lib/fhir/services/interventionService.js +0 -149
  117. package/lib/fhir/services/resultObservationService.js +0 -52
  118. package/lib/fhir/services/riskService.js +0 -101
  119. package/lib/fhir/services/routingService.js +0 -147
  120. package/lib/fhir/services/snapshotService.js +0 -28
  121. package/lib/fhir/services/symptomCaseService.js +0 -139
  122. package/lib/fhir/services/terminologyService.js +0 -58
  123. package/lib/fhir/services/triageService.js +0 -57
  124. package/lib/fhir/utils/normalizeUtils.js +0 -33
  125. package/lib/shared/dtos/GradedSymptom.js +0 -23
  126. package/lib/shared/dtos/TriageResponse.js +0 -35
@@ -2,14 +2,10 @@ const { sanitizeOutput } = require('../utils/formatUtils');
2
2
 
3
3
  const { getThread } = require('../helpers/threadHelper');
4
4
  const { runAssistantWithRetries } = require('./helpers/assistantHelper');
5
- const { overlayCohortPreset } = require('./helpers/cohortHelper');
6
5
 
7
6
  const { forkShadowTurn } = require('./services/shadowService');
8
7
  const { diverge } = require('./services/divergenceService');
9
8
  const { getAssistantById } = require('./services/assistantResolver');
10
- const { maybeSendBridge } = require('./services/bridgeService');
11
- const { getBridgePresetId } = require('./flags/bridgeConfig');
12
- const { ToolRuntimeContext } = require('./context/ToolRuntimeContext');
13
9
 
14
10
  class AssistantProcessor {
15
11
  constructor({ mode = 'local', queueAdapter = null, sendMessage = null, phiProcessor = null, storeRunMetrics = null }) {
@@ -22,15 +18,14 @@ class AssistantProcessor {
22
18
  setSendMessage(fn) { this.sendMessage = fn; }
23
19
 
24
20
  async resolveThread(code) {
25
- const stored = await getThread(code);
26
- if (!stored) return null;
27
- const thread = await overlayCohortPreset(stored);
21
+ const thread = await getThread(code);
22
+ if (!thread) return null;
28
23
  const assistant = getAssistantById(thread.getAssistantId(), thread);
29
24
  return { thread, assistant };
30
25
  }
31
26
 
32
27
  async executeLLM(thread, assistant, runOptions = {}, message = null) {
33
- if (!runOptions.shadow && !thread.isInCohort) {
28
+ if (!runOptions.shadow) {
34
29
  forkShadowTurn({
35
30
  thread,
36
31
  message,
@@ -42,33 +37,11 @@ class AssistantProcessor {
42
37
  });
43
38
  }
44
39
 
45
- if (thread.isInCohort && !runOptions.toolRuntimeContext && runOptions.runId && thread.code) {
46
- runOptions.toolRuntimeContext = new ToolRuntimeContext({ patientCode: thread.code, turnId: runOptions.runId });
47
- }
48
-
49
40
  const ctx = runOptions.toolRuntimeContext || null;
50
41
  assistant.toolRuntimeContext = ctx;
51
- if (ctx && thread) thread.toolRuntimeContext = ctx;
52
-
53
- const runConfig = { ...runOptions, phiProcessor: this.phiProcessor };
54
- const isClinicalAgentTurn = thread.preset_id === getBridgePresetId();
55
- if (!runOptions.shadow && isClinicalAgentTurn && message?.body && this.sendMessage) {
56
- let decision = null;
57
- runConfig.onFirstIteration = (args) => {
58
- decision = decision || maybeSendBridge({
59
- ...args,
60
- code: thread.code,
61
- turnId: runOptions.runId || null,
62
- traceId: ctx?.trace?._id ? String(ctx.trace._id) : null,
63
- shouldContinue: runOptions.shouldContinue,
64
- sendMessage: this.sendMessage,
65
- });
66
- return decision;
67
- };
68
- }
69
42
 
70
43
  const startTime = Date.now();
71
- const runResult = await runAssistantWithRetries(thread, assistant, runConfig, message);
44
+ const runResult = await runAssistantWithRetries(thread, assistant, { ...runOptions, phiProcessor: this.phiProcessor }, message);
72
45
  const predictionTimeMs = Date.now() - startTime;
73
46
 
74
47
  const output = sanitizeOutput(runResult?.output);
@@ -88,8 +61,6 @@ class AssistantProcessor {
88
61
  prompt: run?.prompt || null,
89
62
  preset: run?.preset || null,
90
63
  response_id: run?.id || null,
91
- turnId: runOptions.runId || null,
92
- traceId: ctx?.trace?._id ? String(ctx.trace._id) : null,
93
64
  run,
94
65
  predictionTimeMs,
95
66
  retries: runResult?.retries || 0,
@@ -124,7 +95,7 @@ class AssistantProcessor {
124
95
  async sendResponse(code, result) {
125
96
  if (!this.sendMessage) throw new Error('sendMessage function not configured');
126
97
  if (!result?.output) return null;
127
- await this.sendMessage({ code, body: result.output, processed: true, origin: 'assistant', tools_executed: result.tools_executed, prompt: result.prompt, preset: result.preset, response_id: result.response_id, turnId: result.turnId, traceId: result.traceId });
98
+ await this.sendMessage({ code, body: result.output, processed: true, origin: 'assistant', tools_executed: result.tools_executed, prompt: result.prompt, preset: result.preset, response_id: result.response_id });
128
99
  return result.output;
129
100
  }
130
101
  }
@@ -46,23 +46,7 @@ async function load() {
46
46
  const stochastic = { ...STOCHASTIC_DEFAULTS, ...(parsedStochastic || {}) };
47
47
  if (stochastic.enabled && !stochastic.presetId) throw new Error('divergence config STOCHASTIC.presetId is required when enabled');
48
48
 
49
- let safetyFlagPatterns = [];
50
- if (byKey.SAFETY_FLAG_PATTERNS) {
51
- const parsedPatterns = safeParseArray(byKey.SAFETY_FLAG_PATTERNS);
52
- if (!parsedPatterns) throw new Error('divergence config SAFETY_FLAG_PATTERNS is not a JSON array');
53
- safetyFlagPatterns = parsedPatterns.map((row) => {
54
- if (!isPlainObject(row)) throw new Error('divergence config SAFETY_FLAG_PATTERNS row is not an object');
55
- const { flag, pattern } = row;
56
- if (!flag || !pattern) throw new Error('divergence config SAFETY_FLAG_PATTERNS row missing flag or pattern');
57
- try {
58
- return { flag, re: new RegExp(pattern, 'i') };
59
- } catch (err) {
60
- throw new Error(`divergence config SAFETY_FLAG_PATTERNS pattern for ${flag} is not a valid regex: ${err.message}`);
61
- }
62
- });
63
- }
64
-
65
- const config = { FIELDS: fields, ORACLE_CONNECTION: oracleConnection, STOCHASTIC: stochastic, SAFETY_FLAG_PATTERNS: safetyFlagPatterns };
49
+ const config = { FIELDS: fields, ORACLE_CONNECTION: oracleConnection, STOCHASTIC: stochastic };
66
50
  cache.set(CACHE_KEY, config);
67
51
  return config;
68
52
  }
@@ -76,5 +60,4 @@ module.exports = {
76
60
  getFields: () => get('FIELDS'),
77
61
  getOracleConnection: () => get('ORACLE_CONNECTION'),
78
62
  getStochastic: () => get('STOCHASTIC'),
79
- getSafetyFlagPatterns: () => get('SAFETY_FLAG_PATTERNS'),
80
63
  };
@@ -7,8 +7,7 @@ const state = {
7
7
  anthropicClient: null,
8
8
  openaiClient: null,
9
9
  provider: null,
10
- variant: null,
11
- gatewayProvider: null
10
+ variant: null
12
11
  };
13
12
 
14
13
  const setOpenAIProvider = (provider) => {
@@ -39,11 +38,6 @@ const configureOpenAIProvider = (config = {}) => {
39
38
  return provider;
40
39
  };
41
40
 
42
- const requireGatewayProvider = () => {
43
- if (!state.gatewayProvider) state.gatewayProvider = createLLMProvider({ variant: 'gateway' });
44
- return state.gatewayProvider;
45
- };
46
-
47
41
  const getAnthropicClient = () => {
48
42
  if (state.anthropicClient) return state.anthropicClient;
49
43
  const apiKey = runtimeConfig.get('ANTHROPIC_API_KEY');
@@ -63,7 +57,6 @@ const _resetState = () => {
63
57
  state.openaiClient = null;
64
58
  state.provider = null;
65
59
  state.variant = null;
66
- state.gatewayProvider = null;
67
60
  };
68
61
 
69
62
  module.exports = {
@@ -74,7 +67,6 @@ module.exports = {
74
67
  setOpenAIProvider,
75
68
  getOpenAIProvider,
76
69
  requireOpenAIProvider,
77
- requireGatewayProvider,
78
70
  configureOpenAIProvider,
79
71
  _resetState
80
72
  };
@@ -7,6 +7,7 @@ class ToolRuntimeContext {
7
7
  sessionId = null,
8
8
  repos = {},
9
9
  contextSource = null,
10
+ thread = null,
10
11
  } = {}) {
11
12
  if (typeof patientCode !== 'string' || !patientCode) {
12
13
  throw new Error('ToolRuntimeContext requires a non-empty patientCode');
@@ -23,7 +24,7 @@ class ToolRuntimeContext {
23
24
  this.sessionId = sessionId;
24
25
  this.repos = repos;
25
26
  this.contextSource = contextSource;
26
- this.enabledSkills = [];
27
+ this.thread = thread;
27
28
  this.toolHistory = [];
28
29
  this.safetyArtifact = null;
29
30
  this.palliativeAssessment = null;
@@ -29,17 +29,6 @@ const COMPARATORS = {
29
29
  set: (expected, actual) => isDeepStrictEqual(new Set(expected || []), new Set(actual || [])),
30
30
  };
31
31
 
32
- function oracleToolsInvoked(turn = {}, enabledTools = null) {
33
- const summary = Array.isArray(turn.state_mutations_summary) ? turn.state_mutations_summary : [];
34
- const allow = Array.isArray(enabledTools) ? new Set(enabledTools) : null;
35
- const names = summary
36
- .filter((entry) => typeof entry === 'string')
37
- .map((entry) => entry.split('(')[0].trim())
38
- .filter(Boolean)
39
- .filter((name) => !allow || allow.has(name));
40
- return [...new Set(names)];
41
- }
42
-
43
32
  const OUTCOME_RULES = [
44
33
  [({ deterministic }) => deterministic.divergences.some((d) => d.isEmergencyFlip), 'review'],
45
34
  [({ stochastic }) => stochastic.verdict === 'fail', 'fail'],
@@ -107,6 +96,5 @@ async function classify({ expected, actual, expectedMessage, actualMessage }) {
107
96
 
108
97
  module.exports = {
109
98
  deterministicDivergence,
110
- oracleToolsInvoked,
111
99
  classify,
112
100
  };
@@ -24,7 +24,6 @@ const llmConfigModule = require('./config/llmConfig');
24
24
  const { ToolRuntimeContext } = require('./context/ToolRuntimeContext');
25
25
 
26
26
  const { getCtcaeCatalog } = require('./stores/CtcaeCatalog');
27
- const { registerClinicalTools } = require('./tools/registerClinicalTools');
28
27
 
29
28
  async function initialize() {
30
29
  await getCtcaeCatalog().initialize();
@@ -32,7 +31,6 @@ async function initialize() {
32
31
 
33
32
  module.exports = {
34
33
  initialize,
35
- registerClinicalTools,
36
34
  createLLMProvider,
37
35
  PROVIDER_VARIANTS,
38
36
  OpenAIResponsesProvider,
@@ -1,7 +1,5 @@
1
1
  const { handlePendingFunctionCalls: handlePendingFunctionCallsUtil } = require('../providers/OpenAIResponsesProviderTools');
2
-
3
2
  const { Follow_Up_ID } = require('../../config/airtableConfig');
4
- const runtimeConfig = require('../../config/runtimeConfig');
5
3
 
6
4
  const { logger } = require('../../utils/logger');
7
5
 
@@ -9,11 +7,11 @@ const { getMessageTools, formatMessage } = require('../../helpers/messageHelper'
9
7
 
10
8
  const { getRecordByFilter } = require('../../services/airtableService');
11
9
  const { getMessages } = require('../../services/messageService');
12
-
10
+ const runtimeConfig = require('../../config/runtimeConfig');
13
11
  const { MemoryManager } = require('./MemoryManager');
14
12
 
15
13
  const DEFAULT_MAX_HISTORICAL_MESSAGES = 50;
16
- const OPERATOR_TURN_PREFIX = '[SYSTEM]';
14
+ const ALLOWED_SYSTEM_ROLES = new Set(['system', 'developer']);
17
15
 
18
16
  class DefaultMemoryManager extends MemoryManager {
19
17
  constructor(options = {}) {
@@ -38,15 +36,13 @@ class DefaultMemoryManager extends MemoryManager {
38
36
 
39
37
  const context = allMessages.reverse().flatMap(msg => {
40
38
  const toolItems = getMessageTools(msg);
41
- const role = this._resolveContextRole(msg);
42
- const prefix = this._isInlineOperatorTurn(msg, role) ? `${OPERATOR_TURN_PREFIX} ` : '';
43
39
  const contentItems = formatMessage(msg)
44
- .filter(Boolean)
45
40
  .map(content => ({
46
- role,
47
- content: `${prefix}${content}`,
41
+ role: this._resolveContextRole(msg),
42
+ content: content,
48
43
  type: 'message'
49
- }));
44
+ }))
45
+ .filter(item => item.content);
50
46
  return [...toolItems, ...contentItems];
51
47
  });
52
48
 
@@ -61,19 +57,13 @@ class DefaultMemoryManager extends MemoryManager {
61
57
  if (msg.origin === 'patient') return 'user';
62
58
  if (msg.origin === 'system' && msg.raw?.role) {
63
59
  const role = String(msg.raw.role).trim().toLowerCase();
64
- if (role === 'developer') return 'developer';
65
- if (role !== 'system') {
66
- logger.warn('[DefaultMemoryManager] Unrecognized operator role, treating as an inline turn', { role: msg.raw.role });
67
- }
68
- return 'user';
60
+ if (ALLOWED_SYSTEM_ROLES.has(role)) return role;
61
+ logger.warn('[DefaultMemoryManager] Unexpected system message role, using fallback', { role: msg.raw.role });
62
+ return 'system';
69
63
  }
70
64
  return 'assistant';
71
65
  }
72
66
 
73
- _isInlineOperatorTurn(msg, role) {
74
- return msg.origin === 'system' && role === 'user';
75
- }
76
-
77
67
  async processResponse(response, thread) {
78
68
  this._logActivity('Processing response', { threadCode: thread.code, responseId: response.id });
79
69
  try {
@@ -14,7 +14,6 @@ const iterationSchema = new mongoose.Schema({
14
14
  reasoning: { type: mongoose.Schema.Types.Mixed, default: null },
15
15
  responseId: { type: String, default: null },
16
16
  toolCallIds: { type: [String], default: [] },
17
- toolNames: { type: [String], default: [] },
18
17
  durationMs: { type: Number, default: null },
19
18
  }, { _id: false });
20
19
 
@@ -53,9 +52,6 @@ turnTraceSchema.methods.toDecision = function toDecision() {
53
52
  outbound_purpose: signals.outboundPurpose || null,
54
53
  branch_taken: signals.branchTaken || null,
55
54
  red_flags_matched: decision.redFlagsMatched || [],
56
- tools_invoked: [...new Set(this.iterations.flatMap((it) => it.toolNames || []))],
57
- escalation_justification: signals.medicalEscalation?.urgencyJustification || null,
58
- model_identifier: this.iterations.at(-1)?.model || null,
59
55
  };
60
56
  };
61
57
 
@@ -70,26 +66,17 @@ function buildIterationRecord(response, durationMs, apiCallConfig = {}) {
70
66
  const usage = response?.usage || {};
71
67
  const inputDetails = usage.input_tokens_details || {};
72
68
  const output = response?.output || [];
73
- const content = Array.isArray(response?.content) ? response.content : [];
74
69
  return {
75
70
  model: apiCallConfig?.model || null,
76
71
  temperature: apiCallConfig?.temperature ?? null,
77
- maxOutputTokens: apiCallConfig?.max_output_tokens || apiCallConfig?.max_tokens || null,
72
+ maxOutputTokens: apiCallConfig?.max_output_tokens || null,
78
73
  stopReason: response?.stop_reason || response?.status || null,
79
74
  inputTokens: usage.input_tokens || 0,
80
75
  outputTokens: usage.output_tokens || 0,
81
- cacheCreationTokens: usage.cache_creation_tokens || usage.cache_creation_input_tokens || inputDetails.cache_creation_tokens || 0,
82
- cacheReadTokens: usage.cache_read_tokens || usage.cache_read_input_tokens || inputDetails.cached_tokens || 0,
83
- reasoning: output.find((item) => item.type === 'reasoning')?.summary
84
- || content.find((block) => block.type === 'thinking')?.thinking || null,
85
- toolCallIds: [
86
- ...output.filter((item) => item.type === 'function_call').map((item) => item.call_id),
87
- ...content.filter((block) => block.type === 'tool_use').map((block) => block.id),
88
- ].filter((id) => typeof id === 'string' && id.length > 0),
89
- toolNames: [
90
- ...output.filter((item) => item.type === 'function_call' && typeof item.call_id === 'string' && item.call_id.length > 0).map((item) => item.name),
91
- ...content.filter((block) => block.type === 'tool_use' && typeof block.id === 'string' && block.id.length > 0).map((block) => block.name),
92
- ].filter((name) => typeof name === 'string' && name.length > 0),
76
+ cacheCreationTokens: usage.cache_creation_tokens || inputDetails.cache_creation_tokens || 0,
77
+ cacheReadTokens: usage.cache_read_tokens || inputDetails.cached_tokens || 0,
78
+ reasoning: output.find((item) => item.type === 'reasoning')?.summary || null,
79
+ toolCallIds: output.filter((item) => item.type === 'function_call').map((item) => item.call_id),
93
80
  responseId: response?.id || null,
94
81
  durationMs,
95
82
  };