diff --git a/src/servers/api/command-hq/directory.ts b/src/servers/api/command-hq/directory.ts index d59b6648..8df9067a 100644 --- a/src/servers/api/command-hq/directory.ts +++ b/src/servers/api/command-hq/directory.ts @@ -335,10 +335,9 @@ export function commanderClaudeMd(params: CommanderClaudeMdParams): string { '', '## Talking to the owner', '', - "**In the owner's language.** `GET /api/user/settings` returns `languages.default` — that is the", - 'language they chose for this platform, and everything you say to them goes in it: your messages, your', - 'questions, the options on them, and what you write in `JOB.md`. Read it on your first turn and do not', - 'assume it is English.', + "**In the owner's language**, which the first message of your first turn names. Everything you say to", + 'them goes in it: your messages, your questions, the options on them, and what you write in `JOB.md`.', + 'If you ever need to check it, `GET /api/user/settings` has it as `languages.default`.' '', 'Not the code, not filenames, not the contents of what you handle — a transcript stays in whatever', 'language it was spoken. Only the words you address to them.', diff --git a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx index 7ac23bfb..555675ac 100644 --- a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx +++ b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx @@ -93,7 +93,24 @@ const NewCommanderGuide = () => { * before asking anything at all, all live in the Commanders skill — which is re-read from disk every run, so * it can be reworded without a deploy. Duplicating any of it here would create a second copy to drift. */ -const startBrief = (name: string, referencePath: string): string => +/** + * The locale as a name the model will act on. + * + * Told, not fetched. The first version pointed the commander at `GET /api/user/settings` and it never + * called it — its brief says the first message is what it found plus one question and nothing else, so an + * errand before speaking is exactly what it skips. The platform already knows the answer; making the agent + * go and get it is a request it is right to weigh against everything else it was told. + */ +const LANGUAGE_NAMES: Record = { + 'en-GB': 'English', + 'pt-PT': 'European Portuguese', + 'es-ES': 'Spanish', + 'de-DE': 'German', + 'fr-FR': 'French', + 'sv-SE': 'Swedish', +}; + +const startBrief = (name: string, referencePath: string, locale: string): string => [ // i18n-exempt: agent brief — the MODEL reads this; the transcript shows displayText to the person `You have been named "${name}". Look in \`${referencePath}\` and see whether there is anything there`, @@ -104,7 +121,8 @@ const startBrief = (name: string, referencePath: string): string => '', 'Ask it with AskUserQuestion, so I can answer by picking rather than by typing.', '', - 'And talk to me in MY language — `GET /api/user/settings`, `languages.default`. Do not assume English.', + `Talk to me in ${LANGUAGE_NAMES[locale] ?? locale} — every message, every question, every option on`, + 'one. Not the code, not filenames.', '', 'That is the whole of your first message: what you found, and that question. Nothing else.', ].join('\n'); @@ -285,7 +303,7 @@ function ActiveNewCommander({ category: number | 'none' | undefined; onStarted: (id: string) => void; }) { - const { t, tUi } = useTranslation(); + const { t, tUi, locale } = useTranslation(); const navigate = useNavigate(); // Sonnet, not the account's default. A commander is long-running and mostly repeats one settled job, so @@ -312,7 +330,7 @@ function ActiveNewCommander({ if (sentRef.current) return; sentRef.current = true; chat.sendPrompt( - startBrief(commander.name ?? '', commander.referencePaths[0] ?? ''), + startBrief(commander.name ?? '', commander.referencePaths[0] ?? '', locale), undefined, undefined, { path: commander.cwd },