Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

Commit d4ace51

Browse files
authored
feat(sessions): default messaging mode to steer (#3983)
1 parent 112dc5b commit d4ace51

4 files changed

Lines changed: 131 additions & 3 deletions

File tree

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { useSettingsStore } from "@posthog/ui/features/settings/settingsStore";
2+
import { renderHook } from "@testing-library/react";
3+
import { beforeEach, describe, expect, it } from "vitest";
4+
import { useMessagingModeStore } from "../messagingModeStore";
5+
import {
6+
type AgentSession,
7+
sessionStoreSetters,
8+
useSessionStore,
9+
} from "../sessionStore";
10+
import { useMessagingMode } from "./useMessagingMode";
11+
12+
function seedSession(overrides: Partial<AgentSession>): void {
13+
sessionStoreSetters.setSession({
14+
taskRunId: "run-1",
15+
taskId: "task-1",
16+
taskTitle: "Test",
17+
channel: "agent-event:run-1",
18+
events: [],
19+
startedAt: 0,
20+
status: "connected",
21+
isPromptPending: false,
22+
isCompacting: false,
23+
promptStartedAt: null,
24+
pendingPermissions: new Map(),
25+
pausedDurationMs: 0,
26+
messageQueue: [],
27+
optimisticItems: [],
28+
...overrides,
29+
});
30+
}
31+
32+
describe("useMessagingMode", () => {
33+
beforeEach(() => {
34+
useMessagingModeStore.setState({ modesByTaskId: {} });
35+
useSettingsStore.setState({
36+
defaultMessagingMode: "queue",
37+
defaultCloudMessagingMode: "steer",
38+
});
39+
useSessionStore.setState((state) => {
40+
state.sessions = {};
41+
state.taskIdIndex = {};
42+
});
43+
});
44+
45+
it("per-task override wins over any default", () => {
46+
seedSession({ isCloud: true });
47+
useMessagingModeStore.getState().setMode("task-1", "queue");
48+
const { result } = renderHook(() => useMessagingMode("task-1"));
49+
expect(result.current).toBe("queue");
50+
});
51+
52+
it("returns global cloud default for cloud sessions", () => {
53+
seedSession({ isCloud: true });
54+
const { result } = renderHook(() => useMessagingMode("task-1"));
55+
expect(result.current).toBe("steer");
56+
});
57+
58+
it("returns global local default for local sessions", () => {
59+
seedSession({ isCloud: false });
60+
const { result } = renderHook(() => useMessagingMode("task-1"));
61+
expect(result.current).toBe("queue");
62+
});
63+
64+
it("returns global local default when no session exists for the task", () => {
65+
const { result } = renderHook(() => useMessagingMode("task-1"));
66+
expect(result.current).toBe("queue");
67+
});
68+
69+
it("returns global local default when taskId is undefined", () => {
70+
seedSession({ isCloud: true });
71+
const { result } = renderHook(() => useMessagingMode(undefined));
72+
expect(result.current).toBe("queue");
73+
});
74+
75+
it("respects a changed cloud messaging mode default", () => {
76+
seedSession({ isCloud: true });
77+
useSettingsStore.getState().setDefaultCloudMessagingMode("queue");
78+
const { result } = renderHook(() => useMessagingMode("task-1"));
79+
expect(result.current).toBe("queue");
80+
});
81+
});

packages/ui/src/features/sessions/hooks/useMessagingMode.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,22 @@ import {
44
useMessagingModeStore,
55
} from "@posthog/ui/features/sessions/messagingModeStore";
66
import { useSessionStore } from "@posthog/ui/features/sessions/sessionStore";
7+
import { useSessionIsCloud } from "@posthog/ui/features/sessions/useSession";
78
import { useSettingsStore } from "@posthog/ui/features/settings/settingsStore";
89

9-
/** Effective messaging mode for a task: per-task override, else global default. */
10+
/**
11+
* Effective messaging mode for a task: per-task override, else the global
12+
* default for the session's run target — cloud sessions have their own
13+
* default (steer ships enabled for cloud), local sessions use the local one.
14+
*/
1015
export function useMessagingMode(taskId: string | undefined): MessagingMode {
1116
const override = useMessagingModeStore((s) =>
1217
taskId ? s.modesByTaskId[taskId] : undefined,
1318
);
14-
const globalDefault = useSettingsStore((s) => s.defaultMessagingMode);
19+
const isCloud = useSessionIsCloud(taskId);
20+
const globalDefault = useSettingsStore((s) =>
21+
isCloud ? s.defaultCloudMessagingMode : s.defaultMessagingMode,
22+
);
1523
return override ?? globalDefault;
1624
}
1725

packages/ui/src/features/settings/sections/GeneralSettings.tsx

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export function GeneralSettings() {
9595
autoConvertLongText,
9696
defaultInitialTaskMode,
9797
defaultMessagingMode,
98+
defaultCloudMessagingMode,
9899
defaultReasoningEffort,
99100
diffOpenMode,
100101
sendMessagesWith,
@@ -105,6 +106,7 @@ export function GeneralSettings() {
105106
setAutoConvertLongText,
106107
setDefaultInitialTaskMode,
107108
setDefaultMessagingMode,
109+
setDefaultCloudMessagingMode,
108110
setDefaultReasoningEffort,
109111
setDiffOpenMode,
110112
setSendMessagesWith,
@@ -176,6 +178,18 @@ export function GeneralSettings() {
176178
[defaultMessagingMode, setDefaultMessagingMode],
177179
);
178180

181+
const handleDefaultCloudMessagingModeChange = useCallback(
182+
(value: DefaultMessagingMode) => {
183+
track(ANALYTICS_EVENTS.SETTING_CHANGED, {
184+
setting_name: "default_cloud_messaging_mode",
185+
new_value: value,
186+
old_value: defaultCloudMessagingMode,
187+
});
188+
setDefaultCloudMessagingMode(value);
189+
},
190+
[defaultCloudMessagingMode, setDefaultCloudMessagingMode],
191+
);
192+
179193
const handleDefaultReasoningEffortChange = useCallback(
180194
(value: DefaultReasoningEffort) => {
181195
track(ANALYTICS_EVENTS.SETTING_CHANGED, {
@@ -318,7 +332,7 @@ export function GeneralSettings() {
318332

319333
<SettingRow
320334
label="Default messaging mode"
321-
description="Mode new sessions start in. Steer applies messages mid-turn. Queue holds them until the turn ends."
335+
description="Mode new local sessions start in. Steer applies messages mid-turn. Queue holds them until the turn ends."
322336
>
323337
<Select.Root
324338
value={defaultMessagingMode}
@@ -335,6 +349,25 @@ export function GeneralSettings() {
335349
</Select.Root>
336350
</SettingRow>
337351

352+
<SettingRow
353+
label="Default cloud messaging mode"
354+
description="Mode new cloud sessions start in. Steer applies messages mid-turn. Queue holds them until the turn ends."
355+
>
356+
<Select.Root
357+
value={defaultCloudMessagingMode}
358+
onValueChange={(value) =>
359+
handleDefaultCloudMessagingModeChange(value as DefaultMessagingMode)
360+
}
361+
size="1"
362+
>
363+
<Select.Trigger className="min-w-[100px]" />
364+
<Select.Content>
365+
<Select.Item value="queue">Queue</Select.Item>
366+
<Select.Item value="steer">Steer</Select.Item>
367+
</Select.Content>
368+
</Select.Root>
369+
</SettingRow>
370+
338371
<SettingRow
339372
label="Default effort level"
340373
description="Choose the default reasoning effort for new tasks, or remember your last-used level"

packages/ui/src/features/settings/settingsStore.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ interface SettingsStore {
123123
lastPlanApprovalMode: ExecutionMode | null;
124124
defaultReasoningEffort: DefaultReasoningEffort;
125125
defaultMessagingMode: DefaultMessagingMode;
126+
defaultCloudMessagingMode: DefaultMessagingMode;
126127
setDefaultMessagingMode: (mode: DefaultMessagingMode) => void;
128+
setDefaultCloudMessagingMode: (mode: DefaultMessagingMode) => void;
127129
setDefaultRunMode: (mode: DefaultRunMode) => void;
128130
setLastUsedRunMode: (mode: "local" | "cloud") => void;
129131
setLastUsedLocalWorkspaceMode: (mode: LocalWorkspaceMode) => void;
@@ -320,6 +322,7 @@ export const useSettingsStore = create<SettingsStore>()(
320322
lastPlanApprovalMode: null,
321323
defaultReasoningEffort: "last_used",
322324
defaultMessagingMode: "queue",
325+
defaultCloudMessagingMode: "steer",
323326
setDefaultRunMode: (mode) => set({ defaultRunMode: mode }),
324327
setLastUsedRunMode: (mode) => set({ lastUsedRunMode: mode }),
325328
setLastUsedLocalWorkspaceMode: (mode) =>
@@ -369,6 +372,8 @@ export const useSettingsStore = create<SettingsStore>()(
369372
setDefaultReasoningEffort: (effort) =>
370373
set({ defaultReasoningEffort: effort }),
371374
setDefaultMessagingMode: (mode) => set({ defaultMessagingMode: mode }),
375+
setDefaultCloudMessagingMode: (mode) =>
376+
set({ defaultCloudMessagingMode: mode }),
372377

373378
// Notifications
374379
...NOTIFICATION_DEFAULTS,
@@ -568,6 +573,7 @@ export const useSettingsStore = create<SettingsStore>()(
568573
lastPlanApprovalMode: state.lastPlanApprovalMode,
569574
defaultReasoningEffort: state.defaultReasoningEffort,
570575
defaultMessagingMode: state.defaultMessagingMode,
576+
defaultCloudMessagingMode: state.defaultCloudMessagingMode,
571577

572578
// Notifications
573579
desktopNotifications: state.desktopNotifications,

0 commit comments

Comments
 (0)