@hyperspaceng/neural-coding-agent 0.63.0 → 0.63.2
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.
- package/CHANGELOG.md +71 -0
- package/README.md +2 -2
- package/dist/core/agent-session.d.ts +9 -6
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +98 -54
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +3 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +5 -2
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +2 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +2 -2
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +3 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +27 -26
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +5 -4
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/extensions/types.d.ts +7 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-registry.d.ts +18 -2
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +83 -69
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +4 -4
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +88 -24
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts +6 -0
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +37 -5
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +13 -22
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +3 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/timings.d.ts +1 -0
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +6 -0
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +23 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +150 -57
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts +18 -6
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +108 -59
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +4 -4
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/index.d.ts +12 -4
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +28 -10
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +18 -5
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +0 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +2 -7
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +0 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +28 -65
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +83 -71
- package/dist/modes/print-mode.js.map +1 -1
- package/docs/development.md +3 -1
- package/docs/extensions.md +13 -2
- package/docs/models.md +6 -0
- package/docs/rpc.md +11 -2
- package/docs/settings.md +12 -0
- package/docs/skills.md +3 -2
- package/examples/extensions/custom-compaction.ts +17 -4
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/handoff.ts +5 -2
- package/examples/extensions/qna.ts +5 -2
- package/examples/extensions/summarize.ts +15 -4
- package/examples/extensions/trigger-compact.ts +11 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- 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
|
*
|
|
@@ -686,9 +703,7 @@ export class AgentSession {
|
|
|
686
703
|
`Use /login or set an API key environment variable. See ${join(getDocsPath(), "providers.md")}\n\n` +
|
|
687
704
|
"Then use /model to select a model.");
|
|
688
705
|
}
|
|
689
|
-
|
|
690
|
-
const apiKey = await this._modelRegistry.getApiKey(this.model);
|
|
691
|
-
if (!apiKey) {
|
|
706
|
+
if (!this._modelRegistry.hasConfiguredAuth(this.model)) {
|
|
692
707
|
const isOAuth = this._modelRegistry.isUsingOAuth(this.model);
|
|
693
708
|
if (isOAuth) {
|
|
694
709
|
throw new Error(`Authentication failed for "${this.model.provider}". ` +
|
|
@@ -1065,12 +1080,11 @@ export class AgentSession {
|
|
|
1065
1080
|
}
|
|
1066
1081
|
/**
|
|
1067
1082
|
* Set model directly.
|
|
1068
|
-
* Validates
|
|
1069
|
-
* @throws Error if no
|
|
1083
|
+
* Validates that auth is configured, saves to session and settings.
|
|
1084
|
+
* @throws Error if no auth is configured for the model
|
|
1070
1085
|
*/
|
|
1071
1086
|
async setModel(model) {
|
|
1072
|
-
|
|
1073
|
-
if (!apiKey) {
|
|
1087
|
+
if (!this._modelRegistry.hasConfiguredAuth(model)) {
|
|
1074
1088
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
1075
1089
|
}
|
|
1076
1090
|
const previousModel = this.model;
|
|
@@ -1094,27 +1108,11 @@ export class AgentSession {
|
|
|
1094
1108
|
}
|
|
1095
1109
|
return this._cycleAvailableModel(direction);
|
|
1096
1110
|
}
|
|
1097
|
-
|
|
1098
|
-
|
|
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;
|
|
1111
|
+
_getScopedModelsWithAuth() {
|
|
1112
|
+
return this._scopedModels.filter((scoped) => this._modelRegistry.hasConfiguredAuth(scoped.model));
|
|
1115
1113
|
}
|
|
1116
1114
|
async _cycleScopedModel(direction) {
|
|
1117
|
-
const scopedModels =
|
|
1115
|
+
const scopedModels = this._getScopedModelsWithAuth();
|
|
1118
1116
|
if (scopedModels.length <= 1)
|
|
1119
1117
|
return undefined;
|
|
1120
1118
|
const currentModel = this.model;
|
|
@@ -1148,10 +1146,6 @@ export class AgentSession {
|
|
|
1148
1146
|
const len = availableModels.length;
|
|
1149
1147
|
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
1150
1148
|
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
1149
|
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
1156
1150
|
this.agent.setModel(nextModel);
|
|
1157
1151
|
this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
|
|
@@ -1276,14 +1270,12 @@ export class AgentSession {
|
|
|
1276
1270
|
this._disconnectFromAgent();
|
|
1277
1271
|
await this.abort();
|
|
1278
1272
|
this._compactionAbortController = new AbortController();
|
|
1273
|
+
this._emit({ type: "compaction_start", reason: "manual" });
|
|
1279
1274
|
try {
|
|
1280
1275
|
if (!this.model) {
|
|
1281
1276
|
throw new Error("No model selected");
|
|
1282
1277
|
}
|
|
1283
|
-
const apiKey = await this.
|
|
1284
|
-
if (!apiKey) {
|
|
1285
|
-
throw new Error(`No API key for ${this.model.provider}`);
|
|
1286
|
-
}
|
|
1278
|
+
const { apiKey, headers } = await this._getRequiredRequestAuth(this.model);
|
|
1287
1279
|
const pathEntries = this.sessionManager.getBranch();
|
|
1288
1280
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1289
1281
|
const preparation = prepareCompaction(pathEntries, settings);
|
|
@@ -1326,7 +1318,7 @@ export class AgentSession {
|
|
|
1326
1318
|
}
|
|
1327
1319
|
else {
|
|
1328
1320
|
// Generate compaction result
|
|
1329
|
-
const result = await compact(preparation, this.model, apiKey, customInstructions, this._compactionAbortController.signal);
|
|
1321
|
+
const result = await compact(preparation, this.model, apiKey, headers, customInstructions, this._compactionAbortController.signal);
|
|
1330
1322
|
summary = result.summary;
|
|
1331
1323
|
firstKeptEntryId = result.firstKeptEntryId;
|
|
1332
1324
|
tokensBefore = result.tokensBefore;
|
|
@@ -1348,12 +1340,33 @@ export class AgentSession {
|
|
|
1348
1340
|
fromExtension,
|
|
1349
1341
|
});
|
|
1350
1342
|
}
|
|
1351
|
-
|
|
1343
|
+
const compactionResult = {
|
|
1352
1344
|
summary,
|
|
1353
1345
|
firstKeptEntryId,
|
|
1354
1346
|
tokensBefore,
|
|
1355
1347
|
details,
|
|
1356
1348
|
};
|
|
1349
|
+
this._emit({
|
|
1350
|
+
type: "compaction_end",
|
|
1351
|
+
reason: "manual",
|
|
1352
|
+
result: compactionResult,
|
|
1353
|
+
aborted: false,
|
|
1354
|
+
willRetry: false,
|
|
1355
|
+
});
|
|
1356
|
+
return compactionResult;
|
|
1357
|
+
}
|
|
1358
|
+
catch (error) {
|
|
1359
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1360
|
+
const aborted = message === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError");
|
|
1361
|
+
this._emit({
|
|
1362
|
+
type: "compaction_end",
|
|
1363
|
+
reason: "manual",
|
|
1364
|
+
result: undefined,
|
|
1365
|
+
aborted,
|
|
1366
|
+
willRetry: false,
|
|
1367
|
+
errorMessage: aborted ? undefined : `Compaction failed: ${message}`,
|
|
1368
|
+
});
|
|
1369
|
+
throw error;
|
|
1357
1370
|
}
|
|
1358
1371
|
finally {
|
|
1359
1372
|
this._compactionAbortController = undefined;
|
|
@@ -1409,7 +1422,8 @@ export class AgentSession {
|
|
|
1409
1422
|
if (sameModel && isContextOverflow(assistantMessage, contextWindow)) {
|
|
1410
1423
|
if (this._overflowRecoveryAttempted) {
|
|
1411
1424
|
this._emit({
|
|
1412
|
-
type: "
|
|
1425
|
+
type: "compaction_end",
|
|
1426
|
+
reason: "overflow",
|
|
1413
1427
|
result: undefined,
|
|
1414
1428
|
aborted: false,
|
|
1415
1429
|
willRetry: false,
|
|
@@ -1459,22 +1473,41 @@ export class AgentSession {
|
|
|
1459
1473
|
*/
|
|
1460
1474
|
async _runAutoCompaction(reason, willRetry) {
|
|
1461
1475
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1462
|
-
this._emit({ type: "
|
|
1476
|
+
this._emit({ type: "compaction_start", reason });
|
|
1463
1477
|
this._autoCompactionAbortController = new AbortController();
|
|
1464
1478
|
try {
|
|
1465
1479
|
if (!this.model) {
|
|
1466
|
-
this._emit({
|
|
1480
|
+
this._emit({
|
|
1481
|
+
type: "compaction_end",
|
|
1482
|
+
reason,
|
|
1483
|
+
result: undefined,
|
|
1484
|
+
aborted: false,
|
|
1485
|
+
willRetry: false,
|
|
1486
|
+
});
|
|
1467
1487
|
return;
|
|
1468
1488
|
}
|
|
1469
|
-
const
|
|
1470
|
-
if (!apiKey) {
|
|
1471
|
-
this._emit({
|
|
1489
|
+
const authResult = await this._modelRegistry.getApiKeyAndHeaders(this.model);
|
|
1490
|
+
if (!authResult.ok || !authResult.apiKey) {
|
|
1491
|
+
this._emit({
|
|
1492
|
+
type: "compaction_end",
|
|
1493
|
+
reason,
|
|
1494
|
+
result: undefined,
|
|
1495
|
+
aborted: false,
|
|
1496
|
+
willRetry: false,
|
|
1497
|
+
});
|
|
1472
1498
|
return;
|
|
1473
1499
|
}
|
|
1500
|
+
const { apiKey, headers } = authResult;
|
|
1474
1501
|
const pathEntries = this.sessionManager.getBranch();
|
|
1475
1502
|
const preparation = prepareCompaction(pathEntries, settings);
|
|
1476
1503
|
if (!preparation) {
|
|
1477
|
-
this._emit({
|
|
1504
|
+
this._emit({
|
|
1505
|
+
type: "compaction_end",
|
|
1506
|
+
reason,
|
|
1507
|
+
result: undefined,
|
|
1508
|
+
aborted: false,
|
|
1509
|
+
willRetry: false,
|
|
1510
|
+
});
|
|
1478
1511
|
return;
|
|
1479
1512
|
}
|
|
1480
1513
|
let extensionCompaction;
|
|
@@ -1488,7 +1521,13 @@ export class AgentSession {
|
|
|
1488
1521
|
signal: this._autoCompactionAbortController.signal,
|
|
1489
1522
|
}));
|
|
1490
1523
|
if (extensionResult?.cancel) {
|
|
1491
|
-
this._emit({
|
|
1524
|
+
this._emit({
|
|
1525
|
+
type: "compaction_end",
|
|
1526
|
+
reason,
|
|
1527
|
+
result: undefined,
|
|
1528
|
+
aborted: true,
|
|
1529
|
+
willRetry: false,
|
|
1530
|
+
});
|
|
1492
1531
|
return;
|
|
1493
1532
|
}
|
|
1494
1533
|
if (extensionResult?.compaction) {
|
|
@@ -1509,14 +1548,20 @@ export class AgentSession {
|
|
|
1509
1548
|
}
|
|
1510
1549
|
else {
|
|
1511
1550
|
// Generate compaction result
|
|
1512
|
-
const compactResult = await compact(preparation, this.model, apiKey, undefined, this._autoCompactionAbortController.signal);
|
|
1551
|
+
const compactResult = await compact(preparation, this.model, apiKey, headers, undefined, this._autoCompactionAbortController.signal);
|
|
1513
1552
|
summary = compactResult.summary;
|
|
1514
1553
|
firstKeptEntryId = compactResult.firstKeptEntryId;
|
|
1515
1554
|
tokensBefore = compactResult.tokensBefore;
|
|
1516
1555
|
details = compactResult.details;
|
|
1517
1556
|
}
|
|
1518
1557
|
if (this._autoCompactionAbortController.signal.aborted) {
|
|
1519
|
-
this._emit({
|
|
1558
|
+
this._emit({
|
|
1559
|
+
type: "compaction_end",
|
|
1560
|
+
reason,
|
|
1561
|
+
result: undefined,
|
|
1562
|
+
aborted: true,
|
|
1563
|
+
willRetry: false,
|
|
1564
|
+
});
|
|
1520
1565
|
return;
|
|
1521
1566
|
}
|
|
1522
1567
|
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension);
|
|
@@ -1538,7 +1583,7 @@ export class AgentSession {
|
|
|
1538
1583
|
tokensBefore,
|
|
1539
1584
|
details,
|
|
1540
1585
|
};
|
|
1541
|
-
this._emit({ type: "
|
|
1586
|
+
this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry });
|
|
1542
1587
|
if (willRetry) {
|
|
1543
1588
|
const messages = this.agent.state.messages;
|
|
1544
1589
|
const lastMsg = messages[messages.length - 1];
|
|
@@ -1560,7 +1605,8 @@ export class AgentSession {
|
|
|
1560
1605
|
catch (error) {
|
|
1561
1606
|
const errorMessage = error instanceof Error ? error.message : "compaction failed";
|
|
1562
1607
|
this._emit({
|
|
1563
|
-
type: "
|
|
1608
|
+
type: "compaction_end",
|
|
1609
|
+
reason,
|
|
1564
1610
|
result: undefined,
|
|
1565
1611
|
aborted: false,
|
|
1566
1612
|
willRetry: false,
|
|
@@ -1720,8 +1766,7 @@ export class AgentSession {
|
|
|
1720
1766
|
refreshTools: () => this._refreshToolRegistry(),
|
|
1721
1767
|
getCommands,
|
|
1722
1768
|
setModel: async (model) => {
|
|
1723
|
-
|
|
1724
|
-
if (!key)
|
|
1769
|
+
if (!this.modelRegistry.hasConfiguredAuth(model))
|
|
1725
1770
|
return false;
|
|
1726
1771
|
await this.setModel(model);
|
|
1727
1772
|
return true;
|
|
@@ -2302,14 +2347,12 @@ export class AgentSession {
|
|
|
2302
2347
|
let summaryDetails;
|
|
2303
2348
|
if (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {
|
|
2304
2349
|
const model = this.model;
|
|
2305
|
-
const apiKey = await this.
|
|
2306
|
-
if (!apiKey) {
|
|
2307
|
-
throw new Error(`No API key for ${model.provider}`);
|
|
2308
|
-
}
|
|
2350
|
+
const { apiKey, headers } = await this._getRequiredRequestAuth(model);
|
|
2309
2351
|
const branchSummarySettings = this.settingsManager.getBranchSummarySettings();
|
|
2310
2352
|
const result = await generateBranchSummary(entriesToSummarize, {
|
|
2311
2353
|
model,
|
|
2312
2354
|
apiKey,
|
|
2355
|
+
headers,
|
|
2313
2356
|
signal: this._branchSummaryAbortController.signal,
|
|
2314
2357
|
customInstructions,
|
|
2315
2358
|
replaceInstructions,
|
|
@@ -2466,6 +2509,7 @@ export class AgentSession {
|
|
|
2466
2509
|
total: totalInput + totalOutput + totalCacheRead + totalCacheWrite,
|
|
2467
2510
|
},
|
|
2468
2511
|
cost: totalCost,
|
|
2512
|
+
contextUsage: this.getContextUsage(),
|
|
2469
2513
|
};
|
|
2470
2514
|
}
|
|
2471
2515
|
getContextUsage() {
|