fix(coding-agent): persist custom working message across loader recreation
Replace transient pendingWorkingMessage with a persistent workingMessage field on InteractiveMode, matching the workingIndicatorOptions pattern. New loaders now use this.workingMessage || this.defaultWorkingMessage instead of always falling back to the default. Also add working-message-test.ts extension example. closes #3566
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed `ctx.ui.setWorkingMessage()` to persist across loader recreation, matching the behavior of `ctx.ui.setWorkingIndicator()` ([#3566](https://github.com/badlogic/pi-mono/issues/3566))
|
||||||
|
|
||||||
## [0.69.0] - 2026-04-22
|
## [0.69.0] - 2026-04-22
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Working Message Persistence Test
|
||||||
|
*
|
||||||
|
* Sets a custom working message and indicator on session start so you can
|
||||||
|
* verify they survive across loader recreations (e.g. between agent turns).
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* pi --extension examples/extensions/working-message-test.ts
|
||||||
|
*
|
||||||
|
* Then send a few messages in interactive mode. The working message should
|
||||||
|
* stay "Working... (custom)" with a brown dot indicator every time the
|
||||||
|
* loader appears, not revert to the default gray "Working...".
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
||||||
|
|
||||||
|
const CUSTOM_MESSAGE = "\x1b[38;2;155;86;63mWorking... (custom)\x1b[39m";
|
||||||
|
const CUSTOM_INDICATOR = { frames: ["\x1b[38;2;155;86;63m●\x1b[39m"] };
|
||||||
|
|
||||||
|
export default function (pi: ExtensionAPI) {
|
||||||
|
pi.on("session_start", async (_event, ctx) => {
|
||||||
|
ctx.ui.setWorkingMessage(CUSTOM_MESSAGE);
|
||||||
|
ctx.ui.setWorkingIndicator(CUSTOM_INDICATOR);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -205,7 +205,7 @@ export class InteractiveMode {
|
|||||||
private isInitialized = false;
|
private isInitialized = false;
|
||||||
private onInputCallback?: (text: string) => void;
|
private onInputCallback?: (text: string) => void;
|
||||||
private loadingAnimation: Loader | undefined = undefined;
|
private loadingAnimation: Loader | undefined = undefined;
|
||||||
private pendingWorkingMessage: string | undefined = undefined;
|
private workingMessage: string | undefined = undefined;
|
||||||
private workingIndicatorOptions: LoaderIndicatorOptions | undefined = undefined;
|
private workingIndicatorOptions: LoaderIndicatorOptions | undefined = undefined;
|
||||||
private readonly defaultWorkingMessage = "Working...";
|
private readonly defaultWorkingMessage = "Working...";
|
||||||
private readonly defaultHiddenThinkingLabel = "Thinking...";
|
private readonly defaultHiddenThinkingLabel = "Thinking...";
|
||||||
@@ -1724,7 +1724,7 @@ export class InteractiveMode {
|
|||||||
this.setupAutocompleteProvider();
|
this.setupAutocompleteProvider();
|
||||||
this.defaultEditor.onExtensionShortcut = undefined;
|
this.defaultEditor.onExtensionShortcut = undefined;
|
||||||
this.updateTerminalTitle();
|
this.updateTerminalTitle();
|
||||||
this.pendingWorkingMessage = undefined;
|
this.workingMessage = undefined;
|
||||||
this.setWorkingIndicator();
|
this.setWorkingIndicator();
|
||||||
if (this.loadingAnimation) {
|
if (this.loadingAnimation) {
|
||||||
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
|
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
|
||||||
@@ -1875,6 +1875,7 @@ export class InteractiveMode {
|
|||||||
onTerminalInput: (handler) => this.addExtensionTerminalInputListener(handler),
|
onTerminalInput: (handler) => this.addExtensionTerminalInputListener(handler),
|
||||||
setStatus: (key, text) => this.setExtensionStatus(key, text),
|
setStatus: (key, text) => this.setExtensionStatus(key, text),
|
||||||
setWorkingMessage: (message) => {
|
setWorkingMessage: (message) => {
|
||||||
|
this.workingMessage = message;
|
||||||
if (this.loadingAnimation) {
|
if (this.loadingAnimation) {
|
||||||
if (message) {
|
if (message) {
|
||||||
this.loadingAnimation.setMessage(message);
|
this.loadingAnimation.setMessage(message);
|
||||||
@@ -1883,9 +1884,6 @@ export class InteractiveMode {
|
|||||||
`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`,
|
`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Queue message for when loadingAnimation is created (handles agent_start race)
|
|
||||||
this.pendingWorkingMessage = message;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setWorkingIndicator: (options) => this.setWorkingIndicator(options),
|
setWorkingIndicator: (options) => this.setWorkingIndicator(options),
|
||||||
@@ -2591,17 +2589,10 @@ export class InteractiveMode {
|
|||||||
this.ui,
|
this.ui,
|
||||||
(spinner) => theme.fg("accent", spinner),
|
(spinner) => theme.fg("accent", spinner),
|
||||||
(text) => theme.fg("muted", text),
|
(text) => theme.fg("muted", text),
|
||||||
this.defaultWorkingMessage,
|
this.workingMessage || this.defaultWorkingMessage,
|
||||||
this.workingIndicatorOptions,
|
this.workingIndicatorOptions,
|
||||||
);
|
);
|
||||||
this.statusContainer.addChild(this.loadingAnimation);
|
this.statusContainer.addChild(this.loadingAnimation);
|
||||||
// Apply any pending working message queued before loader existed
|
|
||||||
if (this.pendingWorkingMessage !== undefined) {
|
|
||||||
if (this.pendingWorkingMessage) {
|
|
||||||
this.loadingAnimation.setMessage(this.pendingWorkingMessage);
|
|
||||||
}
|
|
||||||
this.pendingWorkingMessage = undefined;
|
|
||||||
}
|
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user