@codex-infinity/pi-infinity 0.62.3 → 0.63.3

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 (94) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +2 -2
  3. package/dist/core/agent-session.d.ts +8 -6
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +98 -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/extensions/runner.d.ts +1 -0
  20. package/dist/core/extensions/runner.d.ts.map +1 -1
  21. package/dist/core/extensions/runner.js +3 -0
  22. package/dist/core/extensions/runner.js.map +1 -1
  23. package/dist/core/extensions/types.d.ts +10 -1
  24. package/dist/core/extensions/types.d.ts.map +1 -1
  25. package/dist/core/extensions/types.js.map +1 -1
  26. package/dist/core/model-registry.d.ts +18 -2
  27. package/dist/core/model-registry.d.ts.map +1 -1
  28. package/dist/core/model-registry.js +83 -69
  29. package/dist/core/model-registry.js.map +1 -1
  30. package/dist/core/model-resolver.d.ts.map +1 -1
  31. package/dist/core/model-resolver.js +4 -4
  32. package/dist/core/model-resolver.js.map +1 -1
  33. package/dist/core/package-manager.d.ts.map +1 -1
  34. package/dist/core/package-manager.js +34 -18
  35. package/dist/core/package-manager.js.map +1 -1
  36. package/dist/core/resolve-config-value.d.ts +6 -0
  37. package/dist/core/resolve-config-value.d.ts.map +1 -1
  38. package/dist/core/resolve-config-value.js +37 -5
  39. package/dist/core/resolve-config-value.js.map +1 -1
  40. package/dist/core/sdk.d.ts +1 -1
  41. package/dist/core/sdk.d.ts.map +1 -1
  42. package/dist/core/sdk.js +13 -22
  43. package/dist/core/sdk.js.map +1 -1
  44. package/dist/core/settings-manager.d.ts +2 -0
  45. package/dist/core/settings-manager.d.ts.map +1 -1
  46. package/dist/core/settings-manager.js +3 -0
  47. package/dist/core/settings-manager.js.map +1 -1
  48. package/dist/core/timings.d.ts +1 -0
  49. package/dist/core/timings.d.ts.map +1 -1
  50. package/dist/core/timings.js +6 -0
  51. package/dist/core/timings.js.map +1 -1
  52. package/dist/core/tools/edit-diff.d.ts +23 -1
  53. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  54. package/dist/core/tools/edit-diff.js +150 -57
  55. package/dist/core/tools/edit-diff.js.map +1 -1
  56. package/dist/core/tools/edit.d.ts +13 -11
  57. package/dist/core/tools/edit.d.ts.map +1 -1
  58. package/dist/core/tools/edit.js +44 -77
  59. package/dist/core/tools/edit.js.map +1 -1
  60. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  61. package/dist/core/tools/file-mutation-queue.js +4 -4
  62. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  63. package/dist/core/tools/index.d.ts +9 -6
  64. package/dist/core/tools/index.d.ts.map +1 -1
  65. package/dist/main.d.ts.map +1 -1
  66. package/dist/main.js +24 -9
  67. package/dist/main.js.map +1 -1
  68. package/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  69. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  70. package/dist/modes/interactive/components/tool-execution.js +2 -7
  71. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  72. package/dist/modes/interactive/interactive-mode.d.ts +0 -1
  73. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  74. package/dist/modes/interactive/interactive-mode.js +29 -65
  75. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  76. package/docs/compaction.md +4 -2
  77. package/docs/development.md +3 -1
  78. package/docs/extensions.md +46 -2
  79. package/docs/models.md +6 -0
  80. package/docs/settings.md +12 -0
  81. package/docs/skills.md +3 -2
  82. package/examples/extensions/custom-compaction.ts +17 -4
  83. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  84. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  85. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  86. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  87. package/examples/extensions/handoff.ts +5 -2
  88. package/examples/extensions/qna.ts +5 -2
  89. package/examples/extensions/sandbox/index.ts +4 -0
  90. package/examples/extensions/summarize.ts +15 -4
  91. package/examples/extensions/trigger-compact.ts +11 -1
  92. package/examples/extensions/with-deps/package-lock.json +2 -2
  93. package/examples/extensions/with-deps/package.json +1 -1
  94. 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
  *
@@ -674,9 +691,7 @@ export class AgentSession {
674
691
  `Use /login or set an API key environment variable. See ${join(getDocsPath(), "providers.md")}\n\n` +
675
692
  "Then use /model to select a model.");
676
693
  }
677
- // Validate API key
678
- const apiKey = await this._modelRegistry.getApiKey(this.model);
679
- if (!apiKey) {
694
+ if (!this._modelRegistry.hasConfiguredAuth(this.model)) {
680
695
  const isOAuth = this._modelRegistry.isUsingOAuth(this.model);
681
696
  if (isOAuth) {
682
697
  throw new Error(`Authentication failed for "${this.model.provider}". ` +
@@ -1053,12 +1068,11 @@ export class AgentSession {
1053
1068
  }
1054
1069
  /**
1055
1070
  * Set model directly.
1056
- * Validates API key, saves to session and settings.
1057
- * @throws Error if no API key available for the model
1071
+ * Validates that auth is configured, saves to session and settings.
1072
+ * @throws Error if no auth is configured for the model
1058
1073
  */
1059
1074
  async setModel(model) {
1060
- const apiKey = await this._modelRegistry.getApiKey(model);
1061
- if (!apiKey) {
1075
+ if (!this._modelRegistry.hasConfiguredAuth(model)) {
1062
1076
  throw new Error(`No API key for ${model.provider}/${model.id}`);
1063
1077
  }
1064
1078
  const previousModel = this.model;
@@ -1082,27 +1096,11 @@ export class AgentSession {
1082
1096
  }
1083
1097
  return this._cycleAvailableModel(direction);
1084
1098
  }
1085
- async _getScopedModelsWithApiKey() {
1086
- const apiKeysByProvider = new Map();
1087
- const result = [];
1088
- for (const scoped of this._scopedModels) {
1089
- const provider = scoped.model.provider;
1090
- let apiKey;
1091
- if (apiKeysByProvider.has(provider)) {
1092
- apiKey = apiKeysByProvider.get(provider);
1093
- }
1094
- else {
1095
- apiKey = await this._modelRegistry.getApiKeyForProvider(provider);
1096
- apiKeysByProvider.set(provider, apiKey);
1097
- }
1098
- if (apiKey) {
1099
- result.push(scoped);
1100
- }
1101
- }
1102
- return result;
1099
+ _getScopedModelsWithAuth() {
1100
+ return this._scopedModels.filter((scoped) => this._modelRegistry.hasConfiguredAuth(scoped.model));
1103
1101
  }
1104
1102
  async _cycleScopedModel(direction) {
1105
- const scopedModels = await this._getScopedModelsWithApiKey();
1103
+ const scopedModels = this._getScopedModelsWithAuth();
1106
1104
  if (scopedModels.length <= 1)
1107
1105
  return undefined;
1108
1106
  const currentModel = this.model;
@@ -1136,10 +1134,6 @@ export class AgentSession {
1136
1134
  const len = availableModels.length;
1137
1135
  const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
1138
1136
  const nextModel = availableModels[nextIndex];
1139
- const apiKey = await this._modelRegistry.getApiKey(nextModel);
1140
- if (!apiKey) {
1141
- throw new Error(`No API key for ${nextModel.provider}/${nextModel.id}`);
1142
- }
1143
1137
  const thinkingLevel = this._getThinkingLevelForModelSwitch();
1144
1138
  this.agent.setModel(nextModel);
1145
1139
  this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
@@ -1264,14 +1258,12 @@ export class AgentSession {
1264
1258
  this._disconnectFromAgent();
1265
1259
  await this.abort();
1266
1260
  this._compactionAbortController = new AbortController();
1261
+ this._emit({ type: "compaction_start", reason: "manual" });
1267
1262
  try {
1268
1263
  if (!this.model) {
1269
1264
  throw new Error("No model selected");
1270
1265
  }
1271
- const apiKey = await this._modelRegistry.getApiKey(this.model);
1272
- if (!apiKey) {
1273
- throw new Error(`No API key for ${this.model.provider}`);
1274
- }
1266
+ const { apiKey, headers } = await this._getRequiredRequestAuth(this.model);
1275
1267
  const pathEntries = this.sessionManager.getBranch();
1276
1268
  const settings = this.settingsManager.getCompactionSettings();
1277
1269
  const preparation = prepareCompaction(pathEntries, settings);
@@ -1314,7 +1306,7 @@ export class AgentSession {
1314
1306
  }
1315
1307
  else {
1316
1308
  // Generate compaction result
1317
- const result = await compact(preparation, this.model, apiKey, customInstructions, this._compactionAbortController.signal);
1309
+ const result = await compact(preparation, this.model, apiKey, headers, customInstructions, this._compactionAbortController.signal);
1318
1310
  summary = result.summary;
1319
1311
  firstKeptEntryId = result.firstKeptEntryId;
1320
1312
  tokensBefore = result.tokensBefore;
@@ -1336,12 +1328,33 @@ export class AgentSession {
1336
1328
  fromExtension,
1337
1329
  });
1338
1330
  }
1339
- return {
1331
+ const compactionResult = {
1340
1332
  summary,
1341
1333
  firstKeptEntryId,
1342
1334
  tokensBefore,
1343
1335
  details,
1344
1336
  };
1337
+ this._emit({
1338
+ type: "compaction_end",
1339
+ reason: "manual",
1340
+ result: compactionResult,
1341
+ aborted: false,
1342
+ willRetry: false,
1343
+ });
1344
+ return compactionResult;
1345
+ }
1346
+ catch (error) {
1347
+ const message = error instanceof Error ? error.message : String(error);
1348
+ const aborted = message === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError");
1349
+ this._emit({
1350
+ type: "compaction_end",
1351
+ reason: "manual",
1352
+ result: undefined,
1353
+ aborted,
1354
+ willRetry: false,
1355
+ errorMessage: aborted ? undefined : `Compaction failed: ${message}`,
1356
+ });
1357
+ throw error;
1345
1358
  }
1346
1359
  finally {
1347
1360
  this._compactionAbortController = undefined;
@@ -1397,7 +1410,8 @@ export class AgentSession {
1397
1410
  if (sameModel && isContextOverflow(assistantMessage, contextWindow)) {
1398
1411
  if (this._overflowRecoveryAttempted) {
1399
1412
  this._emit({
1400
- type: "auto_compaction_end",
1413
+ type: "compaction_end",
1414
+ reason: "overflow",
1401
1415
  result: undefined,
1402
1416
  aborted: false,
1403
1417
  willRetry: false,
@@ -1447,22 +1461,41 @@ export class AgentSession {
1447
1461
  */
1448
1462
  async _runAutoCompaction(reason, willRetry) {
1449
1463
  const settings = this.settingsManager.getCompactionSettings();
1450
- this._emit({ type: "auto_compaction_start", reason });
1464
+ this._emit({ type: "compaction_start", reason });
1451
1465
  this._autoCompactionAbortController = new AbortController();
1452
1466
  try {
1453
1467
  if (!this.model) {
1454
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: false, willRetry: false });
1468
+ this._emit({
1469
+ type: "compaction_end",
1470
+ reason,
1471
+ result: undefined,
1472
+ aborted: false,
1473
+ willRetry: false,
1474
+ });
1455
1475
  return;
1456
1476
  }
1457
- const apiKey = await this._modelRegistry.getApiKey(this.model);
1458
- if (!apiKey) {
1459
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: false, willRetry: false });
1477
+ const authResult = await this._modelRegistry.getApiKeyAndHeaders(this.model);
1478
+ if (!authResult.ok || !authResult.apiKey) {
1479
+ this._emit({
1480
+ type: "compaction_end",
1481
+ reason,
1482
+ result: undefined,
1483
+ aborted: false,
1484
+ willRetry: false,
1485
+ });
1460
1486
  return;
1461
1487
  }
1488
+ const { apiKey, headers } = authResult;
1462
1489
  const pathEntries = this.sessionManager.getBranch();
1463
1490
  const preparation = prepareCompaction(pathEntries, settings);
1464
1491
  if (!preparation) {
1465
- 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
+ });
1466
1499
  return;
1467
1500
  }
1468
1501
  let extensionCompaction;
@@ -1476,7 +1509,13 @@ export class AgentSession {
1476
1509
  signal: this._autoCompactionAbortController.signal,
1477
1510
  }));
1478
1511
  if (extensionResult?.cancel) {
1479
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: true, willRetry: false });
1512
+ this._emit({
1513
+ type: "compaction_end",
1514
+ reason,
1515
+ result: undefined,
1516
+ aborted: true,
1517
+ willRetry: false,
1518
+ });
1480
1519
  return;
1481
1520
  }
1482
1521
  if (extensionResult?.compaction) {
@@ -1497,14 +1536,20 @@ export class AgentSession {
1497
1536
  }
1498
1537
  else {
1499
1538
  // Generate compaction result
1500
- const compactResult = await compact(preparation, this.model, apiKey, undefined, this._autoCompactionAbortController.signal);
1539
+ const compactResult = await compact(preparation, this.model, apiKey, headers, undefined, this._autoCompactionAbortController.signal);
1501
1540
  summary = compactResult.summary;
1502
1541
  firstKeptEntryId = compactResult.firstKeptEntryId;
1503
1542
  tokensBefore = compactResult.tokensBefore;
1504
1543
  details = compactResult.details;
1505
1544
  }
1506
1545
  if (this._autoCompactionAbortController.signal.aborted) {
1507
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: true, willRetry: false });
1546
+ this._emit({
1547
+ type: "compaction_end",
1548
+ reason,
1549
+ result: undefined,
1550
+ aborted: true,
1551
+ willRetry: false,
1552
+ });
1508
1553
  return;
1509
1554
  }
1510
1555
  this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension);
@@ -1526,7 +1571,7 @@ export class AgentSession {
1526
1571
  tokensBefore,
1527
1572
  details,
1528
1573
  };
1529
- this._emit({ type: "auto_compaction_end", result, aborted: false, willRetry });
1574
+ this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry });
1530
1575
  if (willRetry) {
1531
1576
  const messages = this.agent.state.messages;
1532
1577
  const lastMsg = messages[messages.length - 1];
@@ -1548,7 +1593,8 @@ export class AgentSession {
1548
1593
  catch (error) {
1549
1594
  const errorMessage = error instanceof Error ? error.message : "compaction failed";
1550
1595
  this._emit({
1551
- type: "auto_compaction_end",
1596
+ type: "compaction_end",
1597
+ reason,
1552
1598
  result: undefined,
1553
1599
  aborted: false,
1554
1600
  willRetry: false,
@@ -1708,8 +1754,7 @@ export class AgentSession {
1708
1754
  refreshTools: () => this._refreshToolRegistry(),
1709
1755
  getCommands,
1710
1756
  setModel: async (model) => {
1711
- const key = await this.modelRegistry.getApiKey(model);
1712
- if (!key)
1757
+ if (!this.modelRegistry.hasConfiguredAuth(model))
1713
1758
  return false;
1714
1759
  await this.setModel(model);
1715
1760
  return true;
@@ -1719,6 +1764,7 @@ export class AgentSession {
1719
1764
  }, {
1720
1765
  getModel: () => this.model,
1721
1766
  isIdle: () => !this.isStreaming,
1767
+ getSignal: () => this.agent.signal,
1722
1768
  abort: () => this.abort(),
1723
1769
  hasPendingMessages: () => this.pendingMessageCount > 0,
1724
1770
  shutdown: () => {
@@ -2328,14 +2374,12 @@ export class AgentSession {
2328
2374
  let summaryDetails;
2329
2375
  if (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {
2330
2376
  const model = this.model;
2331
- const apiKey = await this._modelRegistry.getApiKey(model);
2332
- if (!apiKey) {
2333
- throw new Error(`No API key for ${model.provider}`);
2334
- }
2377
+ const { apiKey, headers } = await this._getRequiredRequestAuth(model);
2335
2378
  const branchSummarySettings = this.settingsManager.getBranchSummarySettings();
2336
2379
  const result = await generateBranchSummary(entriesToSummarize, {
2337
2380
  model,
2338
2381
  apiKey,
2382
+ headers,
2339
2383
  signal: this._branchSummaryAbortController.signal,
2340
2384
  customInstructions,
2341
2385
  replaceInstructions,