@averyyy/pi-coding-agent 0.84.3-piclient.1 → 0.84.4-piclient.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 +124 -0
- package/README.md +5 -4
- package/dist/bundle/chunks/{chunk-GPPBJGBU.js → chunk-2KVJKXS2.js} +1 -1
- package/dist/bundle/chunks/{chunk-QI42RBZ4.js → chunk-WJEX5SB4.js} +74 -74
- package/dist/bundle/chunks/{google-generative-ai-XDKMGBCJ.js → google-generative-ai-YMUPJBKR.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-D5FGEO3Y.js → google-vertex-MPWMV4OF.js} +1 -1
- package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +13 -0
- package/dist/bundle/chunks/{mistral-conversations-YK73UAOZ.js → mistral-conversations-Q3AWZJAZ.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-JD4WAC3R.js → openai-completions-ERMU2SS7.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +2 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/core/agent-session.d.ts +15 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +122 -21
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +8 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +9 -4
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +42 -22
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +5 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +45 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +18 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/pi-server-client.d.ts.map +1 -1
- package/dist/core/pi-server-client.js +26 -9
- package/dist/core/pi-server-client.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +4 -2
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +8 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +17 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +5 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +65 -28
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +7 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +7 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +3 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +12 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +6 -4
- package/dist/utils/shell.js.map +1 -1
- package/docs/compaction.md +2 -0
- package/docs/custom-provider.md +7 -7
- package/docs/environment-variables.md +3 -0
- package/docs/extensions.md +18 -0
- package/docs/keybindings.md +1 -1
- package/docs/quickstart.md +1 -1
- package/docs/rpc.md +23 -0
- package/docs/settings.md +12 -4
- package/docs/terminal-setup.md +12 -0
- package/docs/usage.md +4 -3
- 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/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +6 -6
- package/dist/bundle/chunks/dist-RDWOYWHR.js +0 -13
|
@@ -102,6 +102,16 @@ function getPiServerFailurePhase(message) {
|
|
|
102
102
|
}
|
|
103
103
|
return undefined;
|
|
104
104
|
}
|
|
105
|
+
function getPiServerFailureRetryable(message) {
|
|
106
|
+
for (const diagnostic of message.diagnostics ?? []) {
|
|
107
|
+
if (diagnostic.type !== "pi_server_failure")
|
|
108
|
+
continue;
|
|
109
|
+
const retryable = diagnostic.details?.retryable;
|
|
110
|
+
if (typeof retryable === "boolean")
|
|
111
|
+
return retryable;
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
105
115
|
function toolTextContent(content) {
|
|
106
116
|
return content
|
|
107
117
|
.filter((part) => part.type === "text")
|
|
@@ -170,6 +180,8 @@ export class AgentSession {
|
|
|
170
180
|
_followUpMessages = [];
|
|
171
181
|
/** Messages queued to be included with the next user prompt as context ("asides"). */
|
|
172
182
|
_pendingNextTurnMessages = [];
|
|
183
|
+
/** Context-only custom messages queued during a run, flushed once the current turn's tool results are in. */
|
|
184
|
+
_pendingCustomMessages = [];
|
|
173
185
|
// Compaction state
|
|
174
186
|
_compactionAbortController = undefined;
|
|
175
187
|
_autoCompactionAbortController = undefined;
|
|
@@ -472,6 +484,11 @@ export class AgentSession {
|
|
|
472
484
|
followUp: [...this._followUpMessages],
|
|
473
485
|
});
|
|
474
486
|
}
|
|
487
|
+
async _emitSessionCompactFailed(event) {
|
|
488
|
+
if (this._extensionRunner.hasHandlers("session_compact_failed")) {
|
|
489
|
+
await this._extensionRunner.emit({ type: "session_compact_failed", ...event });
|
|
490
|
+
}
|
|
491
|
+
}
|
|
475
492
|
_getIdleWaitPromise() {
|
|
476
493
|
if (!this._idleWaitPromise) {
|
|
477
494
|
this._idleWaitPromise = new Promise((resolve) => {
|
|
@@ -562,6 +579,14 @@ export class AgentSession {
|
|
|
562
579
|
}
|
|
563
580
|
}
|
|
564
581
|
}
|
|
582
|
+
// A turn ends after its assistant message and every tool result has been appended,
|
|
583
|
+
// so this is the first point in the run where a context-only custom message can be
|
|
584
|
+
// inserted without landing between a tool call and its result. Flushing after the
|
|
585
|
+
// extension and listener dispatch above also picks up messages that turn_end
|
|
586
|
+
// handlers queued.
|
|
587
|
+
if (event.type === "turn_end") {
|
|
588
|
+
this._flushPendingCustomMessages();
|
|
589
|
+
}
|
|
565
590
|
};
|
|
566
591
|
_willRetryAfterAgentEnd(event) {
|
|
567
592
|
const settings = this.settingsManager.getRetrySettings();
|
|
@@ -990,6 +1015,7 @@ export class AgentSession {
|
|
|
990
1015
|
finally {
|
|
991
1016
|
this._systemPromptOverride = undefined;
|
|
992
1017
|
this._flushPendingBashMessages();
|
|
1018
|
+
this._flushPendingCustomMessages();
|
|
993
1019
|
await this._emitAgentSettled();
|
|
994
1020
|
}
|
|
995
1021
|
}
|
|
@@ -1148,8 +1174,9 @@ export class AgentSession {
|
|
|
1148
1174
|
preflightResult?.(true);
|
|
1149
1175
|
return;
|
|
1150
1176
|
}
|
|
1151
|
-
// Flush any pending bash messages before the new prompt
|
|
1177
|
+
// Flush any pending bash and custom messages before the new prompt
|
|
1152
1178
|
this._flushPendingBashMessages();
|
|
1179
|
+
this._flushPendingCustomMessages();
|
|
1153
1180
|
// Validate model
|
|
1154
1181
|
if (!this.model) {
|
|
1155
1182
|
throw new Error(formatNoModelSelectedMessage());
|
|
@@ -1366,8 +1393,9 @@ export class AgentSession {
|
|
|
1366
1393
|
/**
|
|
1367
1394
|
* Send a custom message to the session. Creates a CustomMessageEntry.
|
|
1368
1395
|
*
|
|
1369
|
-
* Handles
|
|
1396
|
+
* Handles four cases:
|
|
1370
1397
|
* - Streaming: queues message, processed when loop pulls from queue
|
|
1398
|
+
* - Streaming + triggerTurn false: appended to state/session once the current turn ends
|
|
1371
1399
|
* - Not streaming + triggerTurn: appends to state/session, starts new turn
|
|
1372
1400
|
* - Not streaming + no trigger: appends to state/session, no turn
|
|
1373
1401
|
*
|
|
@@ -1399,11 +1427,34 @@ export class AgentSession {
|
|
|
1399
1427
|
else if (options?.triggerTurn) {
|
|
1400
1428
|
await this._runAgentPrompt(appMessage);
|
|
1401
1429
|
}
|
|
1430
|
+
else if (this.isStreaming) {
|
|
1431
|
+
// Appending now would put the message between an assistant tool call and its
|
|
1432
|
+
// result, which providers that validate message order reject on replay. Defer
|
|
1433
|
+
// to the end of the turn. Nothing is emitted yet: message events must not
|
|
1434
|
+
// describe messages the session tree does not contain.
|
|
1435
|
+
this._pendingCustomMessages.push(appMessage);
|
|
1436
|
+
}
|
|
1402
1437
|
else {
|
|
1403
|
-
this.
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1438
|
+
this._appendCustomMessage(appMessage);
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
_appendCustomMessage(appMessage) {
|
|
1442
|
+
this.agent.state.messages.push(appMessage);
|
|
1443
|
+
this.sessionManager.appendCustomMessageEntry(appMessage.customType, appMessage.content, appMessage.display, appMessage.details);
|
|
1444
|
+
this._emit({ type: "message_start", message: appMessage });
|
|
1445
|
+
this._emit({ type: "message_end", message: appMessage });
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* Append custom messages queued while the agent was running.
|
|
1449
|
+
* Called once the current turn's tool results are in agent state and session history.
|
|
1450
|
+
*/
|
|
1451
|
+
_flushPendingCustomMessages() {
|
|
1452
|
+
if (this._pendingCustomMessages.length === 0)
|
|
1453
|
+
return;
|
|
1454
|
+
const pending = this._pendingCustomMessages;
|
|
1455
|
+
this._pendingCustomMessages = [];
|
|
1456
|
+
for (const appMessage of pending) {
|
|
1457
|
+
this._appendCustomMessage(appMessage);
|
|
1407
1458
|
}
|
|
1408
1459
|
}
|
|
1409
1460
|
/**
|
|
@@ -1518,6 +1569,7 @@ export class AgentSession {
|
|
|
1518
1569
|
this.sessionManager.appendModelChange(model.provider, model.id);
|
|
1519
1570
|
if (options.persist) {
|
|
1520
1571
|
this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
|
|
1572
|
+
this._addPersistedDefaultToNonEmptyScope(model);
|
|
1521
1573
|
}
|
|
1522
1574
|
// Apply thinking level for the new model.
|
|
1523
1575
|
// Per-model thinking level overrides take priority over the global default.
|
|
@@ -1525,6 +1577,20 @@ export class AgentSession {
|
|
|
1525
1577
|
this.setThinkingLevel(thinkingLevel);
|
|
1526
1578
|
await this._emitModelSelect(model, previousModel, "set");
|
|
1527
1579
|
}
|
|
1580
|
+
_addPersistedDefaultToNonEmptyScope(model) {
|
|
1581
|
+
if (this._scopedModels.length === 0)
|
|
1582
|
+
return;
|
|
1583
|
+
if (this._scopedModels.some((scoped) => modelsAreEqual(scoped.model, model)))
|
|
1584
|
+
return;
|
|
1585
|
+
this._scopedModels = [...this._scopedModels, { model }];
|
|
1586
|
+
const enabledModels = this.settingsManager.getEnabledModels();
|
|
1587
|
+
if (!enabledModels?.length)
|
|
1588
|
+
return;
|
|
1589
|
+
const modelReference = `${model.provider}/${model.id}`;
|
|
1590
|
+
if (enabledModels.some((pattern) => pattern.toLowerCase() === modelReference.toLowerCase()))
|
|
1591
|
+
return;
|
|
1592
|
+
this.settingsManager.setEnabledModels([...enabledModels, modelReference]);
|
|
1593
|
+
}
|
|
1528
1594
|
/**
|
|
1529
1595
|
* Cycle to next/previous model.
|
|
1530
1596
|
* Uses scoped models (from --models flag) if available, otherwise all available models.
|
|
@@ -1555,6 +1621,7 @@ export class AgentSession {
|
|
|
1555
1621
|
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
|
|
1556
1622
|
if (options.persist) {
|
|
1557
1623
|
this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
|
|
1624
|
+
this._addPersistedDefaultToNonEmptyScope(next.model);
|
|
1558
1625
|
}
|
|
1559
1626
|
// Apply thinking level for the new model.
|
|
1560
1627
|
// - Explicit scoped model thinking level overrides defaults
|
|
@@ -1581,6 +1648,7 @@ export class AgentSession {
|
|
|
1581
1648
|
this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
|
|
1582
1649
|
if (options.persist) {
|
|
1583
1650
|
this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
|
|
1651
|
+
this._addPersistedDefaultToNonEmptyScope(nextModel);
|
|
1584
1652
|
}
|
|
1585
1653
|
// Apply thinking level for the new model.
|
|
1586
1654
|
// Model persistence does not implicitly rewrite the global thinking default.
|
|
@@ -1920,20 +1988,24 @@ export class AgentSession {
|
|
|
1920
1988
|
// independent of the configured context size or any context-clamped provider request limit.
|
|
1921
1989
|
// A successful response over the configured window should compact but must not retry: the
|
|
1922
1990
|
// assistant answer already completed and agent.continue() cannot continue from an assistant.
|
|
1991
|
+
const contextOverflow = sameModel && isContextOverflow(assistantMessage, contextWindow);
|
|
1923
1992
|
const recoverableLength = sameModel && isRecoverableLength(assistantMessage, this.model?.maxTokens ?? 0);
|
|
1924
|
-
if (
|
|
1993
|
+
if (contextOverflow || recoverableLength) {
|
|
1925
1994
|
const willRetry = assistantMessage.stopReason !== "stop";
|
|
1926
1995
|
if (!willRetry) {
|
|
1927
1996
|
return await this._runAutoCompaction("overflow", false);
|
|
1928
1997
|
}
|
|
1929
1998
|
if (this._overflowRecoveryAttempted) {
|
|
1999
|
+
const errorMessage = contextOverflow
|
|
2000
|
+
? "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model."
|
|
2001
|
+
: "Truncated response recovery failed after one compact-and-retry attempt.";
|
|
1930
2002
|
this._emit({
|
|
1931
2003
|
type: "compaction_end",
|
|
1932
2004
|
reason: "overflow",
|
|
1933
2005
|
result: undefined,
|
|
1934
2006
|
aborted: false,
|
|
1935
2007
|
willRetry: false,
|
|
1936
|
-
errorMessage
|
|
2008
|
+
errorMessage,
|
|
1937
2009
|
});
|
|
1938
2010
|
return false;
|
|
1939
2011
|
}
|
|
@@ -1963,16 +2035,16 @@ export class AgentSession {
|
|
|
1963
2035
|
if (assistantMessage.stopReason === "error" || directContextTokens === 0) {
|
|
1964
2036
|
const messages = this.agent.state.messages;
|
|
1965
2037
|
const estimate = estimateContextTokens(messages);
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
//
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
2038
|
+
// When a valid usage entry exists, verify it is post-compaction. Kept
|
|
2039
|
+
// pre-compaction messages have stale usage reflecting the old (larger)
|
|
2040
|
+
// context and would falsely trigger compaction right after one finished.
|
|
2041
|
+
if (estimate.lastUsageIndex !== null) {
|
|
2042
|
+
const usageMsg = messages[estimate.lastUsageIndex];
|
|
2043
|
+
if (compactionTimestamp > 0 &&
|
|
2044
|
+
usageMsg.role === "assistant" &&
|
|
2045
|
+
usageMsg.timestamp <= compactionTimestamp) {
|
|
2046
|
+
return false;
|
|
2047
|
+
}
|
|
1976
2048
|
}
|
|
1977
2049
|
contextTokens = estimate.tokens;
|
|
1978
2050
|
}
|
|
@@ -1990,6 +2062,7 @@ export class AgentSession {
|
|
|
1990
2062
|
async _runAutoCompaction(reason, willRetry, preparationOverride, preparationOptions) {
|
|
1991
2063
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1992
2064
|
let started = false;
|
|
2065
|
+
let fromExtension = false;
|
|
1993
2066
|
try {
|
|
1994
2067
|
if (!this.model) {
|
|
1995
2068
|
return false;
|
|
@@ -2029,7 +2102,6 @@ export class AgentSession {
|
|
|
2029
2102
|
this._autoCompactionAbortController = new AbortController();
|
|
2030
2103
|
started = true;
|
|
2031
2104
|
let extensionCompaction;
|
|
2032
|
-
let fromExtension = false;
|
|
2033
2105
|
if (this._extensionRunner.hasHandlers("session_before_compact")) {
|
|
2034
2106
|
const extensionResult = (await this._extensionRunner.emit({
|
|
2035
2107
|
type: "session_before_compact",
|
|
@@ -2048,6 +2120,12 @@ export class AgentSession {
|
|
|
2048
2120
|
aborted: true,
|
|
2049
2121
|
willRetry: false,
|
|
2050
2122
|
});
|
|
2123
|
+
await this._emitSessionCompactFailed({
|
|
2124
|
+
reason,
|
|
2125
|
+
aborted: true,
|
|
2126
|
+
willRetry: false,
|
|
2127
|
+
fromExtension: false,
|
|
2128
|
+
});
|
|
2051
2129
|
return false;
|
|
2052
2130
|
}
|
|
2053
2131
|
if (extensionResult?.compaction) {
|
|
@@ -2085,6 +2163,12 @@ export class AgentSession {
|
|
|
2085
2163
|
aborted: true,
|
|
2086
2164
|
willRetry: false,
|
|
2087
2165
|
});
|
|
2166
|
+
await this._emitSessionCompactFailed({
|
|
2167
|
+
reason,
|
|
2168
|
+
aborted: true,
|
|
2169
|
+
willRetry: false,
|
|
2170
|
+
fromExtension,
|
|
2171
|
+
});
|
|
2088
2172
|
return false;
|
|
2089
2173
|
}
|
|
2090
2174
|
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);
|
|
@@ -2141,6 +2225,15 @@ export class AgentSession {
|
|
|
2141
2225
|
? `Context overflow recovery failed: ${errorMessage}`
|
|
2142
2226
|
: `Auto-compaction failed: ${errorMessage}`,
|
|
2143
2227
|
});
|
|
2228
|
+
await this._emitSessionCompactFailed({
|
|
2229
|
+
reason,
|
|
2230
|
+
errorMessage: reason === "overflow"
|
|
2231
|
+
? `Context overflow recovery failed: ${errorMessage}`
|
|
2232
|
+
: `Auto-compaction failed: ${errorMessage}`,
|
|
2233
|
+
aborted: false,
|
|
2234
|
+
willRetry: false,
|
|
2235
|
+
fromExtension,
|
|
2236
|
+
});
|
|
2144
2237
|
}
|
|
2145
2238
|
return false;
|
|
2146
2239
|
}
|
|
@@ -2554,6 +2647,9 @@ export class AgentSession {
|
|
|
2554
2647
|
* Check if an error is retryable. Provider error text is retryable by default,
|
|
2555
2648
|
* except usage/quota/balance limits and session or context failures.
|
|
2556
2649
|
* Context overflow errors are NOT retryable (handled by compaction instead).
|
|
2650
|
+
* Pi-server diagnostics may mark recovery/history failures as non-retryable;
|
|
2651
|
+
* transient session_init/tree_sync outages stay retryable so the next attempt
|
|
2652
|
+
* re-runs the whole stream path.
|
|
2557
2653
|
*/
|
|
2558
2654
|
_isRetryableError(message) {
|
|
2559
2655
|
// Context overflow is handled by compaction, not retry.
|
|
@@ -2561,9 +2657,14 @@ export class AgentSession {
|
|
|
2561
2657
|
return false;
|
|
2562
2658
|
if (this._isPostAssistantPiServerSyncFailure(message))
|
|
2563
2659
|
return false;
|
|
2564
|
-
const
|
|
2565
|
-
if (
|
|
2660
|
+
const piServerRetryable = getPiServerFailureRetryable(message);
|
|
2661
|
+
if (piServerRetryable === false)
|
|
2566
2662
|
return false;
|
|
2663
|
+
if (piServerRetryable !== true) {
|
|
2664
|
+
const piServerPhase = getPiServerFailurePhase(message);
|
|
2665
|
+
if (piServerPhase && piServerPhase !== "provider_stream")
|
|
2666
|
+
return false;
|
|
2667
|
+
}
|
|
2567
2668
|
return isRetryableAssistantError(message);
|
|
2568
2669
|
}
|
|
2569
2670
|
/**
|