@mariozechner/pi-coding-agent 0.56.2 → 0.56.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.
- package/CHANGELOG.md +26 -0
- package/README.md +1 -1
- package/dist/core/agent-session.d.ts +1 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +50 -17
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +1 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +25 -1
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/utils.d.ts +3 -0
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +16 -1
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +26 -2
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +13 -4
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/compaction.md +2 -0
- package/docs/extensions.md +13 -1
- package/docs/tmux.md +39 -0
- 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/with-deps/index.ts +1 -5
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
|
@@ -1013,11 +1013,12 @@ export class AgentSession {
|
|
|
1013
1013
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
1014
1014
|
}
|
|
1015
1015
|
const previousModel = this.model;
|
|
1016
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
1016
1017
|
this.agent.setModel(model);
|
|
1017
1018
|
this.sessionManager.appendModelChange(model.provider, model.id);
|
|
1018
1019
|
this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
|
|
1019
1020
|
// Re-clamp thinking level for new model's capabilities
|
|
1020
|
-
this.setThinkingLevel(
|
|
1021
|
+
this.setThinkingLevel(thinkingLevel);
|
|
1021
1022
|
await this._emitModelSelect(model, previousModel, "set");
|
|
1022
1023
|
}
|
|
1023
1024
|
/**
|
|
@@ -1062,15 +1063,16 @@ export class AgentSession {
|
|
|
1062
1063
|
const len = scopedModels.length;
|
|
1063
1064
|
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
1064
1065
|
const next = scopedModels[nextIndex];
|
|
1066
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);
|
|
1065
1067
|
// Apply model
|
|
1066
1068
|
this.agent.setModel(next.model);
|
|
1067
1069
|
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
|
|
1068
1070
|
this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
|
|
1069
1071
|
// Apply thinking level.
|
|
1070
1072
|
// - Explicit scoped model thinking level overrides current session level
|
|
1071
|
-
// - Undefined scoped model thinking level inherits current session
|
|
1073
|
+
// - Undefined scoped model thinking level inherits the current session preference
|
|
1072
1074
|
// setThinkingLevel clamps to model capabilities.
|
|
1073
|
-
this.setThinkingLevel(
|
|
1075
|
+
this.setThinkingLevel(thinkingLevel);
|
|
1074
1076
|
await this._emitModelSelect(next.model, currentModel, "cycle");
|
|
1075
1077
|
return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };
|
|
1076
1078
|
}
|
|
@@ -1089,11 +1091,12 @@ export class AgentSession {
|
|
|
1089
1091
|
if (!apiKey) {
|
|
1090
1092
|
throw new Error(`No API key for ${nextModel.provider}/${nextModel.id}`);
|
|
1091
1093
|
}
|
|
1094
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
1092
1095
|
this.agent.setModel(nextModel);
|
|
1093
1096
|
this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
|
|
1094
1097
|
this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
|
|
1095
1098
|
// Re-clamp thinking level for new model's capabilities
|
|
1096
|
-
this.setThinkingLevel(
|
|
1099
|
+
this.setThinkingLevel(thinkingLevel);
|
|
1097
1100
|
await this._emitModelSelect(nextModel, currentModel, "cycle");
|
|
1098
1101
|
return { model: nextModel, thinkingLevel: this.thinkingLevel, isScoped: false };
|
|
1099
1102
|
}
|
|
@@ -1113,7 +1116,9 @@ export class AgentSession {
|
|
|
1113
1116
|
this.agent.setThinkingLevel(effectiveLevel);
|
|
1114
1117
|
if (isChanging) {
|
|
1115
1118
|
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
|
1116
|
-
this.
|
|
1119
|
+
if (this.supportsThinking() || effectiveLevel !== "off") {
|
|
1120
|
+
this.settingsManager.setDefaultThinkingLevel(effectiveLevel);
|
|
1121
|
+
}
|
|
1117
1122
|
}
|
|
1118
1123
|
}
|
|
1119
1124
|
/**
|
|
@@ -1151,6 +1156,15 @@ export class AgentSession {
|
|
|
1151
1156
|
supportsThinking() {
|
|
1152
1157
|
return !!this.model?.reasoning;
|
|
1153
1158
|
}
|
|
1159
|
+
_getThinkingLevelForModelSwitch(explicitLevel) {
|
|
1160
|
+
if (explicitLevel !== undefined) {
|
|
1161
|
+
return explicitLevel;
|
|
1162
|
+
}
|
|
1163
|
+
if (!this.supportsThinking()) {
|
|
1164
|
+
return this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
|
|
1165
|
+
}
|
|
1166
|
+
return this.thinkingLevel;
|
|
1167
|
+
}
|
|
1154
1168
|
_clampThinkingLevel(level, availableLevels) {
|
|
1155
1169
|
const ordered = THINKING_LEVELS_WITH_XHIGH;
|
|
1156
1170
|
const available = new Set(availableLevels);
|
|
@@ -1322,15 +1336,16 @@ export class AgentSession {
|
|
|
1322
1336
|
// to a larger-context model (e.g. codex) - the overflow error from the old model
|
|
1323
1337
|
// shouldn't trigger compaction for the new model.
|
|
1324
1338
|
const sameModel = this.model && assistantMessage.provider === this.model.provider && assistantMessage.model === this.model.id;
|
|
1325
|
-
// Skip
|
|
1326
|
-
//
|
|
1327
|
-
//
|
|
1328
|
-
// Example: opus fails → switch to codex → compact → switch back to opus → opus error
|
|
1329
|
-
// is still in context but shouldn't trigger compaction again.
|
|
1339
|
+
// Skip compaction checks if this assistant message is older than the latest
|
|
1340
|
+
// compaction boundary. This prevents a stale pre-compaction usage/error
|
|
1341
|
+
// from retriggering compaction on the first prompt after compaction.
|
|
1330
1342
|
const compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());
|
|
1331
|
-
const
|
|
1343
|
+
const assistantIsFromBeforeCompaction = compactionEntry !== null && assistantMessage.timestamp <= new Date(compactionEntry.timestamp).getTime();
|
|
1344
|
+
if (assistantIsFromBeforeCompaction) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1332
1347
|
// Case 1: Overflow - LLM returned context overflow error
|
|
1333
|
-
if (sameModel &&
|
|
1348
|
+
if (sameModel && isContextOverflow(assistantMessage, contextWindow)) {
|
|
1334
1349
|
if (this._overflowRecoveryAttempted) {
|
|
1335
1350
|
this._emit({
|
|
1336
1351
|
type: "auto_compaction_end",
|
|
@@ -1351,11 +1366,29 @@ export class AgentSession {
|
|
|
1351
1366
|
await this._runAutoCompaction("overflow", true);
|
|
1352
1367
|
return;
|
|
1353
1368
|
}
|
|
1354
|
-
// Case 2: Threshold -
|
|
1355
|
-
//
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1369
|
+
// Case 2: Threshold - context is getting large
|
|
1370
|
+
// For error messages (no usage data), estimate from last successful response.
|
|
1371
|
+
// This ensures sessions that hit persistent API errors (e.g. 529) can still compact.
|
|
1372
|
+
let contextTokens;
|
|
1373
|
+
if (assistantMessage.stopReason === "error") {
|
|
1374
|
+
const messages = this.agent.state.messages;
|
|
1375
|
+
const estimate = estimateContextTokens(messages);
|
|
1376
|
+
if (estimate.lastUsageIndex === null)
|
|
1377
|
+
return; // No usage data at all
|
|
1378
|
+
// Verify the usage source is post-compaction. Kept pre-compaction messages
|
|
1379
|
+
// have stale usage reflecting the old (larger) context and would falsely
|
|
1380
|
+
// trigger compaction right after one just finished.
|
|
1381
|
+
const usageMsg = messages[estimate.lastUsageIndex];
|
|
1382
|
+
if (compactionEntry &&
|
|
1383
|
+
usageMsg.role === "assistant" &&
|
|
1384
|
+
usageMsg.timestamp <= new Date(compactionEntry.timestamp).getTime()) {
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
contextTokens = estimate.tokens;
|
|
1388
|
+
}
|
|
1389
|
+
else {
|
|
1390
|
+
contextTokens = calculateContextTokens(assistantMessage.usage);
|
|
1391
|
+
}
|
|
1359
1392
|
if (shouldCompact(contextTokens, contextWindow, settings)) {
|
|
1360
1393
|
await this._runAutoCompaction("threshold", false);
|
|
1361
1394
|
}
|