Files
oh-my-pi/packages/coding-agent/src/session/agent-session-events.ts
T
Márton Danóczy bce1ff55a7 feat(session): emit model_changed event on every internal model switch
AgentSession#setModelWithProviderSessionReset is the single choke point
every model mutation runs through (explicit /model, prewalk hand-offs,
retry-fallback, model cycling). It previously changed agent.state.model
silently — no session event told subscribers (ACP, RPC, TUI) that the
active model moved.

Emit a new model_changed AgentSessionEvent from that choke point
whenever the model actually changes, and wire it into every consumer
that must exhaustively handle AgentSessionEvent: the TUI event
controller (invalidates the status line, same as thinking_level_changed)
and the RPC client's forwarded-event allowlist.

(cherry picked from commit f76325de2c7821dd7046ddb67546577c3575a263)
2026-07-29 23:08:25 +02:00

68 lines
2.5 KiB
TypeScript

import type { AgentEvent, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
import type { CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
import type { Effort } from "@oh-my-pi/pi-ai";
import type { Rule } from "../capability/rule";
import type { RecoveredRetryError } from "../extensibility/shared-events";
import type { Goal, GoalModeState } from "../goals/state";
import type { ConfiguredThinkingLevel } from "../thinking";
import type { TodoItem } from "../tools/todo";
import type { CustomMessage } from "./messages";
/** Session-specific events that extend the core AgentEvent. */
export type AgentSessionEvent =
| Exclude<AgentEvent, { type: "agent_end" }>
| (Extract<AgentEvent, { type: "agent_end" }> & {
/** False when an async delivery will resume the session before its true final settle. */
isTerminal?: boolean;
})
| {
type: "auto_compaction_start";
reason: "threshold" | "overflow" | "idle" | "incomplete";
action: "context-full" | "handoff" | "shake" | "snapcompact";
}
| {
type: "auto_compaction_end";
action: "context-full" | "handoff" | "shake" | "snapcompact";
result: CompactionResult | undefined;
aborted: boolean;
willRetry: boolean;
errorMessage?: string;
/** True when compaction was skipped for a benign reason. */
skipped?: boolean;
}
| {
type: "auto_retry_start";
attempt: number;
maxAttempts: number;
delayMs: number;
errorMessage: string;
errorId?: number;
}
| {
type: "auto_retry_end";
success: boolean;
attempt: number;
finalError?: string;
recoveredErrors?: RecoveredRetryError[];
}
| { type: "retry_fallback_applied"; from: string; to: string; role: string }
| { type: "retry_fallback_succeeded"; model: string; role: string }
| { type: "model_changed" }
| { type: "ttsr_triggered"; rules: Rule[] }
| { type: "todo_reminder"; todos: TodoItem[]; attempt: number; maxAttempts: number }
| { type: "todo_auto_clear" }
| { type: "irc_message"; message: CustomMessage }
| { type: "notice"; level: "info" | "warning" | "error"; message: string; source?: string }
| {
type: "thinking_level_changed";
thinkingLevel: ThinkingLevel | undefined;
/** The user-configured selector when it differs from the effective level. */
configured?: ConfiguredThinkingLevel;
/** The level `auto` resolved to this turn, once classified. */
resolved?: Effort;
}
| { type: "goal_updated"; goal: Goal | null; state?: GoalModeState };
/** Listener function for agent session events. */
export type AgentSessionEventListener = (event: AgentSessionEvent) => void;