Skip to content

Commit 539c826

Browse files
authored
fix(agent): allow system voice narration fallback
Generated-By: PostHog Code Task-Id: ac30fada-8c29-4973-a253-08d70be31be6
1 parent d58a256 commit 539c826

5 files changed

Lines changed: 25 additions & 16 deletions

File tree

packages/agent/src/adapters/local-tools/tools/speak.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ export const SPEAK_TOOL_DESCRIPTION =
5050
* it to the speech queue, exactly like completion/permission notifications are
5151
* pure side effects off the event stream. Gated on `spokenNarration`, which is
5252
* strictly opt-in (see `resolveSpokenNarration`): the desktop passes it true
53-
* only when the feature flag, the user's setting, and an ElevenLabs key are all
54-
* in place. Headless cloud runs (Slack threads, Signals scouts) never enable
55-
* it, so the tool and its instructions never load and never cost tokens there.
53+
* only when the feature flag and the user's setting are both enabled. Headless
54+
* cloud runs (Slack threads, Signals scouts) never enable it, so the tool and
55+
* its instructions never load and never cost tokens there.
5656
*/
5757
export const speakTool = defineLocalTool({
5858
name: SPEAK_TOOL_NAME,

packages/agent/src/adapters/session-meta.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ interface SpokenNarrationSource {
2323
/**
2424
* Spoken narration is strictly opt-in: it is on only when a caller explicitly
2525
* sets `spokenNarration` true at session start. The desktop is the only client
26-
* that can play audio and the only place that knows the feature flag, the
27-
* user's setting, and whether an ElevenLabs key is configured — so it computes
28-
* that boolean and passes it. Everything else (headless cloud runs like Slack
29-
* threads and Signals scouts, sandboxes, local runs without the setting) stays
30-
* silent, so the `speak` tool and its instructions never load and never cost
31-
* tokens where nothing is listening. Shared by the Claude and Codex adapters.
26+
* that can play audio and the only place that knows the feature flag and the
27+
* user's setting, so it computes that boolean and passes it. Everything else
28+
* (headless cloud runs like Slack threads and Signals scouts, sandboxes, local
29+
* runs without the setting) stays silent, so the `speak` tool and its
30+
* instructions never load and never cost tokens where nothing is listening.
31+
* Shared by the Claude and Codex adapters.
3232
*/
3333
export function resolveSpokenNarration(
3434
meta: SpokenNarrationSource | undefined,

packages/core/src/sessions/sessionService.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ export interface SessionServiceDeps {
336336
rtkEnabledLocal?: boolean;
337337
rtkEnabledCloud?: boolean;
338338
spokenNotifications?: boolean;
339-
elevenLabsKeyConfigured?: boolean;
339+
spokenNarrationEnabled?: boolean;
340340
};
341341
usageLimit: { show: (...args: any[]) => any };
342342
readonly addDirectoryDialog: { open: boolean };
@@ -1092,15 +1092,15 @@ export class SessionService {
10921092
customInstructions,
10931093
rtkEnabledLocal,
10941094
spokenNotifications,
1095-
elevenLabsKeyConfigured,
1095+
spokenNarrationEnabled,
10961096
} = this.d.settings;
10971097
const result = await this.d.trpc.agent.reconnect.mutate({
10981098
taskId,
10991099
taskRunId,
11001100
repoPath,
11011101
rtkEnabled: rtkEnabledLocal,
11021102
spokenNarration:
1103-
spokenNotifications === true && elevenLabsKeyConfigured === true,
1103+
spokenNotifications === true && spokenNarrationEnabled === true,
11041104
apiHost: auth.apiHost,
11051105
projectId: auth.projectId,
11061106
logUrl,
@@ -1424,7 +1424,7 @@ export class SessionService {
14241424
customInstructions: startCustomInstructions,
14251425
rtkEnabledLocal,
14261426
spokenNotifications,
1427-
elevenLabsKeyConfigured,
1427+
spokenNarrationEnabled,
14281428
} = this.d.settings;
14291429
const preferredModel = model ?? this.d.DEFAULT_GATEWAY_MODEL;
14301430
const result = await this.d.trpc.agent.start.mutate({
@@ -1438,7 +1438,7 @@ export class SessionService {
14381438
customInstructions: startCustomInstructions || undefined,
14391439
rtkEnabled: rtkEnabledLocal,
14401440
spokenNarration:
1441-
spokenNotifications === true && elevenLabsKeyConfigured === true,
1441+
spokenNotifications === true && spokenNarrationEnabled === true,
14421442
effort: effortLevelSchema.safeParse(reasoningLevel).success
14431443
? (reasoningLevel as EffortLevel)
14441444
: undefined,

packages/ui/src/features/sessions/sessionServiceHost.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@ import {
1515
HOST_TRPC_CLIENT,
1616
type HostTrpcClient,
1717
} from "@posthog/host-router/client";
18+
import { SPOKEN_NARRATION_FLAG } from "@posthog/shared";
1819
import {
1920
createAuthenticatedClient,
2021
getAuthenticatedClient,
2122
} from "@posthog/ui/features/auth/authClientImperative";
2223
import { fetchAuthState } from "@posthog/ui/features/auth/authQueries";
2324
import { useUsageLimitStore } from "@posthog/ui/features/billing/usageLimitStore";
25+
import {
26+
FEATURE_FLAGS,
27+
type FeatureFlags,
28+
} from "@posthog/ui/features/feature-flags/identifiers";
2429
import { useAddDirectoryDialogStore } from "@posthog/ui/features/folder-picker/addDirectoryDialogStore";
2530
import { NotificationBus } from "@posthog/ui/features/notifications/notifications";
2631
import { SpeechNotifier } from "@posthog/ui/features/notifications/speechNotifier";
@@ -117,6 +122,10 @@ function buildSessionServiceDeps(): SessionServiceDeps {
117122
return {
118123
...state,
119124
customInstructions: getEffectiveCustomInstructions(state),
125+
spokenNarrationEnabled:
126+
resolveService<FeatureFlags>(FEATURE_FLAGS).isEnabled(
127+
SPOKEN_NARRATION_FLAG,
128+
) || import.meta.env.DEV,
120129
};
121130
},
122131
usageLimit: {

packages/workspace-server/src/services/agent/schemas.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ export const startSessionInput = z.object({
9494
/**
9595
* The user's spoken-narration setting at session start. Gates the agent's
9696
* speak tool and its prompt instructions. Strictly opt-in: only the desktop
97-
* sets it true (feature flag + setting + ElevenLabs key); when absent the
98-
* adapter leaves narration off, so headless runs never load the tool.
97+
* sets it true (feature flag + setting); when absent the adapter leaves
98+
* narration off, so headless runs never load the tool.
9999
*/
100100
spokenNarration: z.boolean().optional(),
101101
});

0 commit comments

Comments
 (0)