@hyperspaceng/neural-coding-agent 0.63.0 → 0.64.1

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 (124) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/README.md +3 -3
  3. package/dist/core/agent-session.d.ts +14 -6
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +111 -54
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/auth-storage.d.ts +3 -1
  8. package/dist/core/auth-storage.d.ts.map +1 -1
  9. package/dist/core/auth-storage.js +5 -2
  10. package/dist/core/auth-storage.js.map +1 -1
  11. package/dist/core/compaction/branch-summarization.d.ts +2 -0
  12. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  13. package/dist/core/compaction/branch-summarization.js +2 -2
  14. package/dist/core/compaction/branch-summarization.js.map +1 -1
  15. package/dist/core/compaction/compaction.d.ts +3 -3
  16. package/dist/core/compaction/compaction.d.ts.map +1 -1
  17. package/dist/core/compaction/compaction.js +27 -26
  18. package/dist/core/compaction/compaction.js.map +1 -1
  19. package/dist/core/export-html/index.d.ts.map +1 -1
  20. package/dist/core/export-html/index.js +5 -4
  21. package/dist/core/export-html/index.js.map +1 -1
  22. package/dist/core/extensions/runner.d.ts +1 -0
  23. package/dist/core/extensions/runner.d.ts.map +1 -1
  24. package/dist/core/extensions/runner.js +4 -0
  25. package/dist/core/extensions/runner.js.map +1 -1
  26. package/dist/core/extensions/types.d.ts +14 -1
  27. package/dist/core/extensions/types.d.ts.map +1 -1
  28. package/dist/core/extensions/types.js.map +1 -1
  29. package/dist/core/model-registry.d.ts +21 -3
  30. package/dist/core/model-registry.d.ts.map +1 -1
  31. package/dist/core/model-registry.js +90 -70
  32. package/dist/core/model-registry.js.map +1 -1
  33. package/dist/core/model-resolver.d.ts.map +1 -1
  34. package/dist/core/model-resolver.js +4 -4
  35. package/dist/core/model-resolver.js.map +1 -1
  36. package/dist/core/package-manager.d.ts.map +1 -1
  37. package/dist/core/package-manager.js +88 -24
  38. package/dist/core/package-manager.js.map +1 -1
  39. package/dist/core/resolve-config-value.d.ts +6 -0
  40. package/dist/core/resolve-config-value.d.ts.map +1 -1
  41. package/dist/core/resolve-config-value.js +37 -5
  42. package/dist/core/resolve-config-value.js.map +1 -1
  43. package/dist/core/sdk.d.ts +2 -2
  44. package/dist/core/sdk.d.ts.map +1 -1
  45. package/dist/core/sdk.js +14 -23
  46. package/dist/core/sdk.js.map +1 -1
  47. package/dist/core/settings-manager.d.ts +2 -0
  48. package/dist/core/settings-manager.d.ts.map +1 -1
  49. package/dist/core/settings-manager.js +3 -0
  50. package/dist/core/settings-manager.js.map +1 -1
  51. package/dist/core/timings.d.ts +1 -0
  52. package/dist/core/timings.d.ts.map +1 -1
  53. package/dist/core/timings.js +6 -0
  54. package/dist/core/timings.js.map +1 -1
  55. package/dist/core/tools/edit-diff.d.ts +23 -1
  56. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  57. package/dist/core/tools/edit-diff.js +150 -57
  58. package/dist/core/tools/edit-diff.js.map +1 -1
  59. package/dist/core/tools/edit.d.ts +13 -11
  60. package/dist/core/tools/edit.d.ts.map +1 -1
  61. package/dist/core/tools/edit.js +55 -77
  62. package/dist/core/tools/edit.js.map +1 -1
  63. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  64. package/dist/core/tools/file-mutation-queue.js +4 -4
  65. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  66. package/dist/core/tools/index.d.ts +9 -6
  67. package/dist/core/tools/index.d.ts.map +1 -1
  68. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  69. package/dist/core/tools/tool-definition-wrapper.js +2 -0
  70. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  71. package/dist/main.d.ts.map +1 -1
  72. package/dist/main.js +29 -11
  73. package/dist/main.js.map +1 -1
  74. package/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  75. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  76. package/dist/modes/interactive/components/assistant-message.js +14 -3
  77. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  78. package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
  79. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  80. package/dist/modes/interactive/components/bash-execution.js +18 -5
  81. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  82. package/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  83. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  84. package/dist/modes/interactive/components/tool-execution.js +2 -7
  85. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  86. package/dist/modes/interactive/interactive-mode.d.ts +3 -1
  87. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  88. package/dist/modes/interactive/interactive-mode.js +51 -67
  89. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  90. package/dist/modes/print-mode.d.ts +1 -1
  91. package/dist/modes/print-mode.d.ts.map +1 -1
  92. package/dist/modes/print-mode.js +83 -71
  93. package/dist/modes/print-mode.js.map +1 -1
  94. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  95. package/dist/modes/rpc/rpc-mode.js +3 -0
  96. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  97. package/docs/compaction.md +4 -2
  98. package/docs/development.md +3 -1
  99. package/docs/extensions.md +107 -2
  100. package/docs/json.md +5 -2
  101. package/docs/models.md +6 -0
  102. package/docs/rpc.md +32 -9
  103. package/docs/sdk.md +12 -9
  104. package/docs/settings.md +12 -0
  105. package/docs/skills.md +3 -2
  106. package/examples/extensions/README.md +1 -0
  107. package/examples/extensions/custom-compaction.ts +17 -4
  108. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  109. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  110. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  111. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  112. package/examples/extensions/handoff.ts +5 -2
  113. package/examples/extensions/hidden-thinking-label.ts +57 -0
  114. package/examples/extensions/qna.ts +5 -2
  115. package/examples/extensions/sandbox/index.ts +4 -0
  116. package/examples/extensions/summarize.ts +15 -4
  117. package/examples/extensions/trigger-compact.ts +11 -1
  118. package/examples/extensions/with-deps/package-lock.json +2 -2
  119. package/examples/extensions/with-deps/package.json +1 -1
  120. package/examples/sdk/02-custom-model.ts +1 -1
  121. package/examples/sdk/09-api-keys-and-oauth.ts +3 -3
  122. package/examples/sdk/12-full-control.ts +1 -1
  123. package/examples/sdk/README.md +3 -3
  124. package/package.json +5 -4
@@ -134,6 +134,23 @@ export class AgentSession {
134
134
  get modelRegistry() {
135
135
  return this._modelRegistry;
136
136
  }
137
+ async _getRequiredRequestAuth(model) {
138
+ const result = await this._modelRegistry.getApiKeyAndHeaders(model);
139
+ if (!result.ok) {
140
+ throw new Error(result.error);
141
+ }
142
+ if (result.apiKey) {
143
+ return { apiKey: result.apiKey, headers: result.headers };
144
+ }
145
+ const isOAuth = this._modelRegistry.isUsingOAuth(model);
146
+ if (isOAuth) {
147
+ throw new Error(`Authentication failed for "${model.provider}". ` +
148
+ `Credentials may have expired or network is unavailable. ` +
149
+ `Run '/login ${model.provider}' to re-authenticate.`);
150
+ }
151
+ throw new Error(`No API key found for ${model.provider}.\n\n` +
152
+ `Use /login or set an API key environment variable. See ${join(getDocsPath(), "providers.md")}`);
153
+ }
137
154
  /**
138
155
  * Install tool hooks once on the Agent instance.
139
156
  *
@@ -196,6 +213,13 @@ export class AgentSession {
196
213
  l(event);
197
214
  }
198
215
  }
216
+ _emitQueueUpdate() {
217
+ this._emit({
218
+ type: "queue_update",
219
+ steering: [...this._steeringMessages],
220
+ followUp: [...this._followUpMessages],
221
+ });
222
+ }
199
223
  // Track last assistant message for auto-compaction check
200
224
  _lastAssistantMessage = undefined;
201
225
  /** Internal handler for agent events - shared by subscribe and reconnect */
@@ -246,12 +270,14 @@ export class AgentSession {
246
270
  const steeringIndex = this._steeringMessages.indexOf(messageText);
247
271
  if (steeringIndex !== -1) {
248
272
  this._steeringMessages.splice(steeringIndex, 1);
273
+ this._emitQueueUpdate();
249
274
  }
250
275
  else {
251
276
  // Check follow-up queue
252
277
  const followUpIndex = this._followUpMessages.indexOf(messageText);
253
278
  if (followUpIndex !== -1) {
254
279
  this._followUpMessages.splice(followUpIndex, 1);
280
+ this._emitQueueUpdate();
255
281
  }
256
282
  }
257
283
  }
@@ -686,9 +712,7 @@ export class AgentSession {
686
712
  `Use /login or set an API key environment variable. See ${join(getDocsPath(), "providers.md")}\n\n` +
687
713
  "Then use /model to select a model.");
688
714
  }
689
- // Validate API key
690
- const apiKey = await this._modelRegistry.getApiKey(this.model);
691
- if (!apiKey) {
715
+ if (!this._modelRegistry.hasConfiguredAuth(this.model)) {
692
716
  const isOAuth = this._modelRegistry.isUsingOAuth(this.model);
693
717
  if (isOAuth) {
694
718
  throw new Error(`Authentication failed for "${this.model.provider}". ` +
@@ -847,6 +871,7 @@ export class AgentSession {
847
871
  */
848
872
  async _queueSteer(text, images) {
849
873
  this._steeringMessages.push(text);
874
+ this._emitQueueUpdate();
850
875
  const content = [{ type: "text", text }];
851
876
  if (images) {
852
877
  content.push(...images);
@@ -862,6 +887,7 @@ export class AgentSession {
862
887
  */
863
888
  async _queueFollowUp(text, images) {
864
889
  this._followUpMessages.push(text);
890
+ this._emitQueueUpdate();
865
891
  const content = [{ type: "text", text }];
866
892
  if (images) {
867
893
  content.push(...images);
@@ -975,6 +1001,7 @@ export class AgentSession {
975
1001
  this._steeringMessages = [];
976
1002
  this._followUpMessages = [];
977
1003
  this.agent.clearAllQueues();
1004
+ this._emitQueueUpdate();
978
1005
  return { steering, followUp };
979
1006
  }
980
1007
  /** Number of pending messages (includes both steering and follow-up) */
@@ -1065,12 +1092,11 @@ export class AgentSession {
1065
1092
  }
1066
1093
  /**
1067
1094
  * Set model directly.
1068
- * Validates API key, saves to session and settings.
1069
- * @throws Error if no API key available for the model
1095
+ * Validates that auth is configured, saves to session and settings.
1096
+ * @throws Error if no auth is configured for the model
1070
1097
  */
1071
1098
  async setModel(model) {
1072
- const apiKey = await this._modelRegistry.getApiKey(model);
1073
- if (!apiKey) {
1099
+ if (!this._modelRegistry.hasConfiguredAuth(model)) {
1074
1100
  throw new Error(`No API key for ${model.provider}/${model.id}`);
1075
1101
  }
1076
1102
  const previousModel = this.model;
@@ -1094,27 +1120,11 @@ export class AgentSession {
1094
1120
  }
1095
1121
  return this._cycleAvailableModel(direction);
1096
1122
  }
1097
- async _getScopedModelsWithApiKey() {
1098
- const apiKeysByProvider = new Map();
1099
- const result = [];
1100
- for (const scoped of this._scopedModels) {
1101
- const provider = scoped.model.provider;
1102
- let apiKey;
1103
- if (apiKeysByProvider.has(provider)) {
1104
- apiKey = apiKeysByProvider.get(provider);
1105
- }
1106
- else {
1107
- apiKey = await this._modelRegistry.getApiKeyForProvider(provider);
1108
- apiKeysByProvider.set(provider, apiKey);
1109
- }
1110
- if (apiKey) {
1111
- result.push(scoped);
1112
- }
1113
- }
1114
- return result;
1123
+ _getScopedModelsWithAuth() {
1124
+ return this._scopedModels.filter((scoped) => this._modelRegistry.hasConfiguredAuth(scoped.model));
1115
1125
  }
1116
1126
  async _cycleScopedModel(direction) {
1117
- const scopedModels = await this._getScopedModelsWithApiKey();
1127
+ const scopedModels = this._getScopedModelsWithAuth();
1118
1128
  if (scopedModels.length <= 1)
1119
1129
  return undefined;
1120
1130
  const currentModel = this.model;
@@ -1148,10 +1158,6 @@ export class AgentSession {
1148
1158
  const len = availableModels.length;
1149
1159
  const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
1150
1160
  const nextModel = availableModels[nextIndex];
1151
- const apiKey = await this._modelRegistry.getApiKey(nextModel);
1152
- if (!apiKey) {
1153
- throw new Error(`No API key for ${nextModel.provider}/${nextModel.id}`);
1154
- }
1155
1161
  const thinkingLevel = this._getThinkingLevelForModelSwitch();
1156
1162
  this.agent.setModel(nextModel);
1157
1163
  this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
@@ -1276,14 +1282,12 @@ export class AgentSession {
1276
1282
  this._disconnectFromAgent();
1277
1283
  await this.abort();
1278
1284
  this._compactionAbortController = new AbortController();
1285
+ this._emit({ type: "compaction_start", reason: "manual" });
1279
1286
  try {
1280
1287
  if (!this.model) {
1281
1288
  throw new Error("No model selected");
1282
1289
  }
1283
- const apiKey = await this._modelRegistry.getApiKey(this.model);
1284
- if (!apiKey) {
1285
- throw new Error(`No API key for ${this.model.provider}`);
1286
- }
1290
+ const { apiKey, headers } = await this._getRequiredRequestAuth(this.model);
1287
1291
  const pathEntries = this.sessionManager.getBranch();
1288
1292
  const settings = this.settingsManager.getCompactionSettings();
1289
1293
  const preparation = prepareCompaction(pathEntries, settings);
@@ -1326,7 +1330,7 @@ export class AgentSession {
1326
1330
  }
1327
1331
  else {
1328
1332
  // Generate compaction result
1329
- const result = await compact(preparation, this.model, apiKey, customInstructions, this._compactionAbortController.signal);
1333
+ const result = await compact(preparation, this.model, apiKey, headers, customInstructions, this._compactionAbortController.signal);
1330
1334
  summary = result.summary;
1331
1335
  firstKeptEntryId = result.firstKeptEntryId;
1332
1336
  tokensBefore = result.tokensBefore;
@@ -1348,12 +1352,33 @@ export class AgentSession {
1348
1352
  fromExtension,
1349
1353
  });
1350
1354
  }
1351
- return {
1355
+ const compactionResult = {
1352
1356
  summary,
1353
1357
  firstKeptEntryId,
1354
1358
  tokensBefore,
1355
1359
  details,
1356
1360
  };
1361
+ this._emit({
1362
+ type: "compaction_end",
1363
+ reason: "manual",
1364
+ result: compactionResult,
1365
+ aborted: false,
1366
+ willRetry: false,
1367
+ });
1368
+ return compactionResult;
1369
+ }
1370
+ catch (error) {
1371
+ const message = error instanceof Error ? error.message : String(error);
1372
+ const aborted = message === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError");
1373
+ this._emit({
1374
+ type: "compaction_end",
1375
+ reason: "manual",
1376
+ result: undefined,
1377
+ aborted,
1378
+ willRetry: false,
1379
+ errorMessage: aborted ? undefined : `Compaction failed: ${message}`,
1380
+ });
1381
+ throw error;
1357
1382
  }
1358
1383
  finally {
1359
1384
  this._compactionAbortController = undefined;
@@ -1409,7 +1434,8 @@ export class AgentSession {
1409
1434
  if (sameModel && isContextOverflow(assistantMessage, contextWindow)) {
1410
1435
  if (this._overflowRecoveryAttempted) {
1411
1436
  this._emit({
1412
- type: "auto_compaction_end",
1437
+ type: "compaction_end",
1438
+ reason: "overflow",
1413
1439
  result: undefined,
1414
1440
  aborted: false,
1415
1441
  willRetry: false,
@@ -1459,22 +1485,41 @@ export class AgentSession {
1459
1485
  */
1460
1486
  async _runAutoCompaction(reason, willRetry) {
1461
1487
  const settings = this.settingsManager.getCompactionSettings();
1462
- this._emit({ type: "auto_compaction_start", reason });
1488
+ this._emit({ type: "compaction_start", reason });
1463
1489
  this._autoCompactionAbortController = new AbortController();
1464
1490
  try {
1465
1491
  if (!this.model) {
1466
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: false, willRetry: false });
1492
+ this._emit({
1493
+ type: "compaction_end",
1494
+ reason,
1495
+ result: undefined,
1496
+ aborted: false,
1497
+ willRetry: false,
1498
+ });
1467
1499
  return;
1468
1500
  }
1469
- const apiKey = await this._modelRegistry.getApiKey(this.model);
1470
- if (!apiKey) {
1471
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: false, willRetry: false });
1501
+ const authResult = await this._modelRegistry.getApiKeyAndHeaders(this.model);
1502
+ if (!authResult.ok || !authResult.apiKey) {
1503
+ this._emit({
1504
+ type: "compaction_end",
1505
+ reason,
1506
+ result: undefined,
1507
+ aborted: false,
1508
+ willRetry: false,
1509
+ });
1472
1510
  return;
1473
1511
  }
1512
+ const { apiKey, headers } = authResult;
1474
1513
  const pathEntries = this.sessionManager.getBranch();
1475
1514
  const preparation = prepareCompaction(pathEntries, settings);
1476
1515
  if (!preparation) {
1477
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: false, willRetry: false });
1516
+ this._emit({
1517
+ type: "compaction_end",
1518
+ reason,
1519
+ result: undefined,
1520
+ aborted: false,
1521
+ willRetry: false,
1522
+ });
1478
1523
  return;
1479
1524
  }
1480
1525
  let extensionCompaction;
@@ -1488,7 +1533,13 @@ export class AgentSession {
1488
1533
  signal: this._autoCompactionAbortController.signal,
1489
1534
  }));
1490
1535
  if (extensionResult?.cancel) {
1491
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: true, willRetry: false });
1536
+ this._emit({
1537
+ type: "compaction_end",
1538
+ reason,
1539
+ result: undefined,
1540
+ aborted: true,
1541
+ willRetry: false,
1542
+ });
1492
1543
  return;
1493
1544
  }
1494
1545
  if (extensionResult?.compaction) {
@@ -1509,14 +1560,20 @@ export class AgentSession {
1509
1560
  }
1510
1561
  else {
1511
1562
  // Generate compaction result
1512
- const compactResult = await compact(preparation, this.model, apiKey, undefined, this._autoCompactionAbortController.signal);
1563
+ const compactResult = await compact(preparation, this.model, apiKey, headers, undefined, this._autoCompactionAbortController.signal);
1513
1564
  summary = compactResult.summary;
1514
1565
  firstKeptEntryId = compactResult.firstKeptEntryId;
1515
1566
  tokensBefore = compactResult.tokensBefore;
1516
1567
  details = compactResult.details;
1517
1568
  }
1518
1569
  if (this._autoCompactionAbortController.signal.aborted) {
1519
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: true, willRetry: false });
1570
+ this._emit({
1571
+ type: "compaction_end",
1572
+ reason,
1573
+ result: undefined,
1574
+ aborted: true,
1575
+ willRetry: false,
1576
+ });
1520
1577
  return;
1521
1578
  }
1522
1579
  this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension);
@@ -1538,7 +1595,7 @@ export class AgentSession {
1538
1595
  tokensBefore,
1539
1596
  details,
1540
1597
  };
1541
- this._emit({ type: "auto_compaction_end", result, aborted: false, willRetry });
1598
+ this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry });
1542
1599
  if (willRetry) {
1543
1600
  const messages = this.agent.state.messages;
1544
1601
  const lastMsg = messages[messages.length - 1];
@@ -1560,7 +1617,8 @@ export class AgentSession {
1560
1617
  catch (error) {
1561
1618
  const errorMessage = error instanceof Error ? error.message : "compaction failed";
1562
1619
  this._emit({
1563
- type: "auto_compaction_end",
1620
+ type: "compaction_end",
1621
+ reason,
1564
1622
  result: undefined,
1565
1623
  aborted: false,
1566
1624
  willRetry: false,
@@ -1720,8 +1778,7 @@ export class AgentSession {
1720
1778
  refreshTools: () => this._refreshToolRegistry(),
1721
1779
  getCommands,
1722
1780
  setModel: async (model) => {
1723
- const key = await this.modelRegistry.getApiKey(model);
1724
- if (!key)
1781
+ if (!this.modelRegistry.hasConfiguredAuth(model))
1725
1782
  return false;
1726
1783
  await this.setModel(model);
1727
1784
  return true;
@@ -1731,6 +1788,7 @@ export class AgentSession {
1731
1788
  }, {
1732
1789
  getModel: () => this.model,
1733
1790
  isIdle: () => !this.isStreaming,
1791
+ getSignal: () => this.agent.signal,
1734
1792
  abort: () => this.abort(),
1735
1793
  hasPendingMessages: () => this.pendingMessageCount > 0,
1736
1794
  shutdown: () => {
@@ -2302,14 +2360,12 @@ export class AgentSession {
2302
2360
  let summaryDetails;
2303
2361
  if (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {
2304
2362
  const model = this.model;
2305
- const apiKey = await this._modelRegistry.getApiKey(model);
2306
- if (!apiKey) {
2307
- throw new Error(`No API key for ${model.provider}`);
2308
- }
2363
+ const { apiKey, headers } = await this._getRequiredRequestAuth(model);
2309
2364
  const branchSummarySettings = this.settingsManager.getBranchSummarySettings();
2310
2365
  const result = await generateBranchSummary(entriesToSummarize, {
2311
2366
  model,
2312
2367
  apiKey,
2368
+ headers,
2313
2369
  signal: this._branchSummaryAbortController.signal,
2314
2370
  customInstructions,
2315
2371
  replaceInstructions,
@@ -2466,6 +2522,7 @@ export class AgentSession {
2466
2522
  total: totalInput + totalOutput + totalCacheRead + totalCacheWrite,
2467
2523
  },
2468
2524
  cost: totalCost,
2525
+ contextUsage: this.getContextUsage(),
2469
2526
  };
2470
2527
  }
2471
2528
  getContextUsage() {