fix(coding-agent): emit session name changes to extensions
This commit is contained in:
@@ -322,6 +322,9 @@ user sends another prompt ◄─────────────────
|
|||||||
├─► session_start { reason: "fork", previousSessionFile }
|
├─► session_start { reason: "fork", previousSessionFile }
|
||||||
└─► resources_discover { reason: "startup" }
|
└─► resources_discover { reason: "startup" }
|
||||||
|
|
||||||
|
/name or pi.setSessionName()
|
||||||
|
└─► session_info_changed
|
||||||
|
|
||||||
/compact or auto-compaction
|
/compact or auto-compaction
|
||||||
├─► session_before_compact (can cancel or customize)
|
├─► session_before_compact (can cancel or customize)
|
||||||
└─► session_compact
|
└─► session_compact
|
||||||
@@ -395,6 +398,17 @@ pi.on("session_start", async (event, ctx) => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### session_info_changed
|
||||||
|
|
||||||
|
Fired when the current session display name is set via `/name`, RPC, or `pi.setSessionName()`.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
pi.on("session_info_changed", async (event, ctx) => {
|
||||||
|
// event.name - current normalized name, or undefined if cleared
|
||||||
|
ctx.ui.notify(`Session renamed: ${event.name ?? "(none)"}`, "info");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
#### session_before_switch
|
#### session_before_switch
|
||||||
|
|
||||||
Fired before starting a new session (`/new`) or switching sessions (`/resume`).
|
Fired before starting a new session (`/new`) or switching sessions (`/resume`).
|
||||||
|
|||||||
@@ -2683,7 +2683,9 @@ export class AgentSession {
|
|||||||
*/
|
*/
|
||||||
setSessionName(name: string): void {
|
setSessionName(name: string): void {
|
||||||
this.sessionManager.appendSessionInfo(name);
|
this.sessionManager.appendSessionInfo(name);
|
||||||
this._emit({ type: "session_info_changed", name: this.sessionManager.getSessionName() });
|
const event = { type: "session_info_changed", name: this.sessionManager.getSessionName() } as const;
|
||||||
|
this._emit(event);
|
||||||
|
void this._extensionRunner.emit(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ export type {
|
|||||||
SessionBeforeTreeResult,
|
SessionBeforeTreeResult,
|
||||||
SessionCompactEvent,
|
SessionCompactEvent,
|
||||||
SessionEvent,
|
SessionEvent,
|
||||||
|
SessionInfoChangedEvent,
|
||||||
SessionShutdownEvent,
|
SessionShutdownEvent,
|
||||||
// Events - Session
|
// Events - Session
|
||||||
SessionStartEvent,
|
SessionStartEvent,
|
||||||
|
|||||||
@@ -551,6 +551,13 @@ export interface SessionStartEvent {
|
|||||||
previousSessionFile?: string;
|
previousSessionFile?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Fired when the current session metadata changes. */
|
||||||
|
export interface SessionInfoChangedEvent {
|
||||||
|
type: "session_info_changed";
|
||||||
|
/** Current normalized session name. Undefined when the name is cleared. */
|
||||||
|
name: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/** Fired before switching to another session (can be cancelled) */
|
/** Fired before switching to another session (can be cancelled) */
|
||||||
export interface SessionBeforeSwitchEvent {
|
export interface SessionBeforeSwitchEvent {
|
||||||
type: "session_before_switch";
|
type: "session_before_switch";
|
||||||
@@ -630,6 +637,7 @@ export interface SessionTreeEvent {
|
|||||||
|
|
||||||
export type SessionEvent =
|
export type SessionEvent =
|
||||||
| SessionStartEvent
|
| SessionStartEvent
|
||||||
|
| SessionInfoChangedEvent
|
||||||
| SessionBeforeSwitchEvent
|
| SessionBeforeSwitchEvent
|
||||||
| SessionBeforeForkEvent
|
| SessionBeforeForkEvent
|
||||||
| SessionBeforeCompactEvent
|
| SessionBeforeCompactEvent
|
||||||
@@ -1133,6 +1141,7 @@ export interface ExtensionAPI {
|
|||||||
on(event: "project_trust", handler: ProjectTrustHandler): void;
|
on(event: "project_trust", handler: ProjectTrustHandler): void;
|
||||||
on(event: "resources_discover", handler: ExtensionHandler<ResourcesDiscoverEvent, ResourcesDiscoverResult>): void;
|
on(event: "resources_discover", handler: ExtensionHandler<ResourcesDiscoverEvent, ResourcesDiscoverResult>): void;
|
||||||
on(event: "session_start", handler: ExtensionHandler<SessionStartEvent>): void;
|
on(event: "session_start", handler: ExtensionHandler<SessionStartEvent>): void;
|
||||||
|
on(event: "session_info_changed", handler: ExtensionHandler<SessionInfoChangedEvent>): void;
|
||||||
on(
|
on(
|
||||||
event: "session_before_switch",
|
event: "session_before_switch",
|
||||||
handler: ExtensionHandler<SessionBeforeSwitchEvent, SessionBeforeSwitchResult>,
|
handler: ExtensionHandler<SessionBeforeSwitchEvent, SessionBeforeSwitchResult>,
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ export type {
|
|||||||
SessionBeforeSwitchEvent,
|
SessionBeforeSwitchEvent,
|
||||||
SessionBeforeTreeEvent,
|
SessionBeforeTreeEvent,
|
||||||
SessionCompactEvent,
|
SessionCompactEvent,
|
||||||
|
SessionInfoChangedEvent,
|
||||||
SessionShutdownEvent,
|
SessionShutdownEvent,
|
||||||
SessionStartEvent,
|
SessionStartEvent,
|
||||||
SessionTreeEvent,
|
SessionTreeEvent,
|
||||||
|
|||||||
@@ -37,4 +37,25 @@ describe("regression #3686: session name changes emit an event", () => {
|
|||||||
expect(harness.sessionManager.getSessionName()).toBe("from extension");
|
expect(harness.sessionManager.getSessionName()).toBe("from extension");
|
||||||
expect(harness.eventsOfType("session_info_changed").map((event) => event.name)).toEqual(["from extension"]);
|
expect(harness.eventsOfType("session_info_changed").map((event) => event.name)).toEqual(["from extension"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("emits session_info_changed to extensions", async () => {
|
||||||
|
let api: ExtensionAPI | undefined;
|
||||||
|
const events: Array<{ name: string | undefined }> = [];
|
||||||
|
const harness = await createHarness({
|
||||||
|
extensionFactories: [
|
||||||
|
(pi) => {
|
||||||
|
api = pi;
|
||||||
|
pi.on("session_info_changed", (event) => {
|
||||||
|
events.push({ name: event.name });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
harnesses.push(harness);
|
||||||
|
|
||||||
|
api?.setSessionName("first");
|
||||||
|
harness.session.setSessionName("second");
|
||||||
|
|
||||||
|
expect(events).toEqual([{ name: "first" }, { name: "second" }]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user