diff --git a/src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.test.tsx b/src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.test.tsx index d07ae3ae745..1d985c70118 100644 --- a/src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.test.tsx +++ b/src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.test.tsx @@ -127,7 +127,7 @@ describe('NativeChatPickerMenu', () => { /> ) - expect(screen.getAllByText("Skills aren't available in SSH chats")).toHaveLength(2) + expect(screen.getAllByText("Skills can't be listed in SSH chats")).toHaveLength(2) expect(screen.queryByText("Couldn't load skills")).toBeNull() expect(screen.queryByRole('button', { name: 'Retry' })).toBeNull() }) diff --git a/src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.tsx b/src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.tsx index a88157523a6..0ae77cafa9a 100644 --- a/src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.tsx +++ b/src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.tsx @@ -44,7 +44,7 @@ export const NativeChatPickerMenu = memo(function NativeChatPickerMenu({ autocomplete.skillErrorKind === 'unavailable' ? translate( 'components.native-chat.composer.skillsUnavailableHost', - "Skills aren't available in SSH chats" + "Skills can't be listed in SSH chats" ) : translate('components.native-chat.composer.skillsLoadFailed', "Couldn't load skills") diff --git a/src/renderer/src/components/native-chat/NativeChatBackgroundTaskRun.test.tsx b/src/renderer/src/components/native-chat/NativeChatBackgroundTaskRun.test.tsx index cf1da100b4e..dc9e79c39bb 100644 --- a/src/renderer/src/components/native-chat/NativeChatBackgroundTaskRun.test.tsx +++ b/src/renderer/src/components/native-chat/NativeChatBackgroundTaskRun.test.tsx @@ -62,10 +62,10 @@ describe('NativeChatBackgroundTaskRun', () => { expect(screen.getAllByText('Background task')).toHaveLength(1) }) - it('reads a state this build has no word for as no recent update, never as live', () => { + it('reads a state this build has no word for as status unavailable, never as live', () => { // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: models a row a newer build wrote, which the wire admits as an open string. render() - expect(screen.getByText(/no recent update/)).toBeInTheDocument() + expect(screen.getByText(/status unavailable/)).toBeInTheDocument() }) }) diff --git a/src/renderer/src/components/native-chat/NativeChatBackgroundTasksStatus.test.tsx b/src/renderer/src/components/native-chat/NativeChatBackgroundTasksStatus.test.tsx index 8e829556fc0..b7c2947dc76 100644 --- a/src/renderer/src/components/native-chat/NativeChatBackgroundTasksStatus.test.tsx +++ b/src/renderer/src/components/native-chat/NativeChatBackgroundTasksStatus.test.tsx @@ -291,7 +291,7 @@ describe('background-task row reasons', () => { { id: 'a4', kind: 'agent', description: 'busy child', state: 'working' } ]) expect(rows).toHaveLength(4) - expect(rows[0].textContent).toContain('ssh child · no recent update') + expect(rows[0].textContent).toContain('ssh child · status unavailable') expect(rows[1].textContent).toContain('flaky child · failed') expect(rows[2].textContent).toContain('approval child · needs approval') // A running row has nothing to explain. diff --git a/src/renderer/src/components/native-chat/NativeChatStructuredSession.read-error.test.tsx b/src/renderer/src/components/native-chat/NativeChatStructuredSession.read-error.test.tsx index dd1f1846ec4..3715910cbc3 100644 --- a/src/renderer/src/components/native-chat/NativeChatStructuredSession.read-error.test.tsx +++ b/src/renderer/src/components/native-chat/NativeChatStructuredSession.read-error.test.tsx @@ -104,7 +104,7 @@ it("says a code's own words that the history didn't load, and nothing under them }) // "This isn't available in this chat." would name nothing the reader asked for. -it('says only that the history did not load for a chat its host cannot run', () => { +it('says why the history did not load for a chat its host cannot run', () => { mocks.status = 'error' mocks.readRefusal = { code: 'structured_agent_session_unsupported', @@ -114,7 +114,11 @@ it('says only that the history did not load for a chat its host cannot run', () renderPane() - expect(screen.getAllByText("This chat's history couldn't be loaded.")).toHaveLength(1) + expect( + screen.getAllByText( + "Orca can't run this agent in a chat here. This chat's history couldn't be loaded." + ) + ).toHaveLength(1) expect(screen.queryByText(/isn't available|newer Orca/)).toBeNull() }) diff --git a/src/renderer/src/components/native-chat/NativeChatSubagentRun.test.tsx b/src/renderer/src/components/native-chat/NativeChatSubagentRun.test.tsx index e66130b9c93..ddbb96347e3 100644 --- a/src/renderer/src/components/native-chat/NativeChatSubagentRun.test.tsx +++ b/src/renderer/src/components/native-chat/NativeChatSubagentRun.test.tsx @@ -168,7 +168,7 @@ describe('NativeChatSubagentRun', () => { ) const row = screen.getByRole('button') - expect(row).toHaveTextContent('no recent update') + expect(row).toHaveTextContent('status unavailable') // `unverifiable` with no terminal timestamp has no known run length, so the // clock would measure to `now` and report the time since we lost sight of // the child as how long it ran — on a row that is not even counting. @@ -189,7 +189,7 @@ describe('NativeChatSubagentRun', () => { ) const row = screen.getByRole('button') - expect(row).toHaveTextContent('1 with no recent update') + expect(row).toHaveTextContent('1 with status unavailable') expect(row.textContent).not.toContain('·') }) diff --git a/src/renderer/src/components/native-chat/NativeChatSubagentRun.tsx b/src/renderer/src/components/native-chat/NativeChatSubagentRun.tsx index d6fdf3b5e76..a5d9b2a2837 100644 --- a/src/renderer/src/components/native-chat/NativeChatSubagentRun.tsx +++ b/src/renderer/src/components/native-chat/NativeChatSubagentRun.tsx @@ -48,7 +48,10 @@ function subagentStateLabel( case 'stopped': return translate('components.native-chat.subagents.state.stopped', 'stopped') case 'unverifiable': - return translate('components.native-chat.subagents.state.unverifiable', 'no recent update') + return translate( + 'components.native-chat.subagents.state.unverifiable', + 'status unavailable' + ) } } switch (state) { @@ -79,7 +82,7 @@ function subagentStateLabel( case 'unverifiable': return translate( 'components.native-chat.subagents.state.unverifiableCount', - '{{value0}} with no recent update', + '{{value0}} with status unavailable', { value0: count } ) } diff --git a/src/renderer/src/components/native-chat/NativeChatToolRun.sentences.test.tsx b/src/renderer/src/components/native-chat/NativeChatToolRun.sentences.test.tsx index 7f6a25d965d..086aca9b749 100644 --- a/src/renderer/src/components/native-chat/NativeChatToolRun.sentences.test.tsx +++ b/src/renderer/src/components/native-chat/NativeChatToolRun.sentences.test.tsx @@ -101,6 +101,6 @@ describe('tool run sentences', () => { expect(screen.getByText('Subagente')).toBeInTheDocument() expect(screen.getByText('Flujo de trabajo en segundo plano')).toBeInTheDocument() expect(screen.getByText('Salida: /tmp/result.txt')).toBeInTheDocument() - expect(screen.getByText('bloqueado · falló')).toBeInTheDocument() + expect(screen.getByText('bloqueado · con error')).toBeInTheDocument() }) }) diff --git a/src/renderer/src/components/native-chat/agent-session-write-notice-text.ts b/src/renderer/src/components/native-chat/agent-session-write-notice-text.ts index 706777fe645..44f5e737f2a 100644 --- a/src/renderer/src/components/native-chat/agent-session-write-notice-text.ts +++ b/src/renderer/src/components/native-chat/agent-session-write-notice-text.ts @@ -65,6 +65,8 @@ const SENTENCES: Record string> = { unsupported: () => translate('components.native-chat.writeNotice.unsupported', COPY.unsupported), notAvailable: () => translate('components.native-chat.writeNotice.notAvailable', COPY.notAvailable), + cannotRunHere: () => + translate('components.native-chat.writeNotice.cannotRunHere', COPY.cannotRunHere), unreachable: () => translate('components.native-chat.writeNotice.unreachable', COPY.unreachable), recordFailed: () => translate('components.native-chat.writeNotice.recordFailed', COPY.recordFailed), diff --git a/src/renderer/src/components/native-chat/background-task-roster.test.ts b/src/renderer/src/components/native-chat/background-task-roster.test.ts index d4d6167533f..804bd68bcb5 100644 --- a/src/renderer/src/components/native-chat/background-task-roster.test.ts +++ b/src/renderer/src/components/native-chat/background-task-roster.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest' import type { AgentSessionBackgroundTask } from '../../../../shared/agent-session-wire' import { backgroundTasksHeaderContent } from './background-task-header-content' import { + backgroundTaskCountedState, buildBackgroundTaskGroups, formatBackgroundTaskTokens, resolveBackgroundTaskName @@ -77,7 +78,7 @@ describe('backgroundTasksHeaderContent', () => { expect( header([agent('a', { state: 'unverifiable' }), agent('b', { state: 'unverifiable' })]) ).toEqual({ - segments: [{ text: '2 agents with no recent update', kind: 'agent' }], + segments: [{ text: '2 agents with status unavailable', kind: 'agent' }], detail: null }) }) @@ -184,6 +185,18 @@ describe('buildBackgroundTaskGroups', () => { }) }) +describe('backgroundTaskCountedState', () => { + it('words a count with each state as one sentence', () => { + expect(backgroundTaskCountedState('2 agents', 'working')).toBe('2 agents working') + expect(backgroundTaskCountedState('2 agents', 'monitoring')).toBe('2 agents monitoring') + expect(backgroundTaskCountedState('2 agents', 'waiting')).toBe('2 agents waiting') + expect(backgroundTaskCountedState('2 agents', 'blocked')).toBe('2 agents blocked') + expect(backgroundTaskCountedState('2 agents', 'done')).toBe('2 agents done') + expect(backgroundTaskCountedState(3, 'idle')).toBe('3 stopped') + expect(backgroundTaskCountedState(3, 'unverifiable')).toBe('3 with status unavailable') + }) +}) + describe('formatBackgroundTaskTokens', () => { it('renders compact token counts like the mock', () => { expect(formatBackgroundTaskTokens(950)).toBe('950') diff --git a/src/renderer/src/components/native-chat/background-task-roster.ts b/src/renderer/src/components/native-chat/background-task-roster.ts index a54e729c845..71ec84106e5 100644 --- a/src/renderer/src/components/native-chat/background-task-roster.ts +++ b/src/renderer/src/components/native-chat/background-task-roster.ts @@ -122,9 +122,10 @@ export function backgroundTaskStateWord(state: RunState): string { case 'idle': return translate('components.native-chat.backgroundTasks.stateIdle', 'stopped') case 'unverifiable': + // Settled unknown or out of contact: claims neither an exit nor a coming update. return translate( 'components.native-chat.backgroundTasks.stateUnverifiable', - 'no recent update' + 'status unavailable' ) } } @@ -146,15 +147,52 @@ export function backgroundTaskStateReason(state: RunState): string | null { } } -/** A count and its state ("2 agents waiting"); after a count, "no recent update" needs a "with". */ +/** A count and its state ("2 agents waiting"), one whole sentence per state so a language can + * agree the state with the count. */ export function backgroundTaskCountedState(counted: string | number, state: RunState): string { - return state === 'unverifiable' - ? translate( - 'components.native-chat.backgroundTasks.stateUnverifiableCount', - '{{value0}} with no recent update', + switch (state) { + case 'working': + return translate( + 'components.native-chat.backgroundTasks.stateWorkingCount', + '{{value0}} working', { value0: counted } ) - : `${counted} ${backgroundTaskStateWord(state)}` + case 'monitoring': + return translate( + 'components.native-chat.backgroundTasks.stateMonitoringCount', + '{{value0}} monitoring', + { value0: counted } + ) + case 'waiting': + return translate( + 'components.native-chat.backgroundTasks.stateWaitingCount', + '{{value0}} waiting', + { value0: counted } + ) + case 'blocked': + return translate( + 'components.native-chat.backgroundTasks.stateBlockedCount', + '{{value0}} blocked', + { value0: counted } + ) + case 'done': + return translate('components.native-chat.backgroundTasks.stateDoneCount', '{{value0}} done', { + value0: counted + }) + case 'idle': + return translate( + 'components.native-chat.backgroundTasks.stateIdleCount', + '{{value0}} stopped', + { value0: counted } + ) + case 'unverifiable': + // After a count, "status unavailable" needs a "with". + return translate( + 'components.native-chat.backgroundTasks.stateUnverifiableCount', + '{{value0}} with status unavailable', + { value0: counted } + ) + } } function tokenScaleText(value: number): string { diff --git a/src/renderer/src/components/sidebar/__snapshots__/subagent-child-row-fallback-pixels.test.tsx.snap b/src/renderer/src/components/sidebar/__snapshots__/subagent-child-row-fallback-pixels.test.tsx.snap index bb64a6a3f59..342897ca5a4 100644 --- a/src/renderer/src/components/sidebar/__snapshots__/subagent-child-row-fallback-pixels.test.tsx.snap +++ b/src/renderer/src/components/sidebar/__snapshots__/subagent-child-row-fallback-pixels.test.tsx.snap @@ -1,8 +1,8 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`chat strip rows from a legacy background-task roster > render exactly as before 1`] = `"

Agents

  • Failed child · failed
  • Background agent · no recent update
  • Cancelled child
  • Approve edits · needs approval
  • Summarize logs900
  • Review the parser18.2k · 10m 0s
  • Explore · failed8m 20s
  • Old host child6m 40s

Shell

  • npm run dev11m 40s

Monitors

  • tail -f server.log
"`; +exports[`chat strip rows from a legacy background-task roster > render exactly as before 1`] = `"

Agents

  • Failed child · failed
  • Background agent · status unavailable
  • Cancelled child
  • Approve edits · needs approval
  • Summarize logs900
  • Review the parser18.2k · 10m 0s
  • Explore · failed8m 20s
  • Old host child6m 40s

Shell

  • npm run dev11m 40s

Monitors

  • tail -f server.log
"`; -exports[`chat strip rows from a legacy background-task roster > render exactly as before 2`] = `"

Agents

  • Failed child · failed
  • Background agent · no recent update
  • Cancelled child
  • Approve edits · needs approval
  • Summarize logs900
  • Review the parser18.2k · 10m 0s
  • Explore · failed8m 20s
  • Old host child6m 40s

Shell

  • npm run dev11m 40s

Monitors

  • tail -f server.log
"`; +exports[`chat strip rows from a legacy background-task roster > render exactly as before 2`] = `"

Agents

  • Failed child · failed
  • Background agent · status unavailable
  • Cancelled child
  • Approve edits · needs approval
  • Summarize logs900
  • Review the parser18.2k · 10m 0s
  • Explore · failed8m 20s
  • Old host child6m 40s

Shell

  • npm run dev11m 40s

Monitors

  • tail -f server.log
"`; exports[`sidebar child rows from a legacy subagents snapshot > render a stale parent and a lost transport exactly as before 1`] = ` [ diff --git a/src/renderer/src/components/sidebar/subagent-child-row-fallback-pixels.test.tsx b/src/renderer/src/components/sidebar/subagent-child-row-fallback-pixels.test.tsx index 3307d2f9dce..68463bc5ec8 100644 --- a/src/renderer/src/components/sidebar/subagent-child-row-fallback-pixels.test.tsx +++ b/src/renderer/src/components/sidebar/subagent-child-row-fallback-pixels.test.tsx @@ -221,7 +221,7 @@ describe('chat strip rows from a legacy background-task roster', () => { container.innerHTML = markup expect([...container.querySelectorAll('li')].map((row) => row.textContent)).toEqual([ 'Failed child · failed', - 'Background agent · no recent updateStop', + 'Background agent · status unavailableStop', 'Cancelled child', 'Approve edits · needs approvalStop', 'Summarize logs900', diff --git a/src/renderer/src/i18n/en-runtime-required.json b/src/renderer/src/i18n/en-runtime-required.json index d262c825b45..9abb0410a1d 100644 --- a/src/renderer/src/i18n/en-runtime-required.json +++ b/src/renderer/src/i18n/en-runtime-required.json @@ -2892,6 +2892,7 @@ "messageNotSaved": "Couldn't save your message.", "messagesUnsettled": "A message you sent earlier isn't confirmed yet.", "notAvailable": "This isn't available in this chat.", + "cannotRunHere": "Orca can't run this agent in a chat here.", "notDoneAnswer": "Your answer was not sent.", "notDoneCommand": "The command didn't run.", "notDoneGoal": "The goal wasn't changed.", diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index d0a08821b98..e8d79b4e4fa 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -17845,6 +17845,7 @@ "updateOrcaToOpenChat": "Update Orca to open it.", "unsupported": "This needs a newer Orca on the computer running this chat. Update Orca there, then try again.", "notAvailable": "This isn't available in this chat.", + "cannotRunHere": "Orca can't run this agent in a chat here.", "unreachable": "Orca couldn't reach the agent.", "recordFailed": "Orca couldn't save this to the chat's history.", "conversationCleared": "This conversation has been cleared.", @@ -17929,7 +17930,7 @@ "skills": "Skills", "loadingSkills": "Loading skills...", "skillsLoaded": "Skills loaded", - "skillsUnavailableHost": "Skills aren't available in SSH chats", + "skillsUnavailableHost": "Skills can't be listed in SSH chats", "skillsLoadFailed": "Couldn't load skills", "retrySkills": "Retry", "skillCommandCollision": "Also a skill name - agent decides", @@ -18116,13 +18117,19 @@ "countTasksMany": "{{value0}} tasks", "headerTotal": "{{value0}} background tasks", "stateWorking": "working", + "stateWorkingCount": "{{value0}} working", "stateMonitoring": "monitoring", + "stateMonitoringCount": "{{value0}} monitoring", "stateWaiting": "waiting", + "stateWaitingCount": "{{value0}} waiting", "stateBlocked": "blocked", + "stateBlockedCount": "{{value0}} blocked", "stateDone": "done", + "stateDoneCount": "{{value0}} done", "stateIdle": "stopped", - "stateUnverifiable": "no recent update", - "stateUnverifiableCount": "{{value0}} with no recent update", + "stateIdleCount": "{{value0}} stopped", + "stateUnverifiable": "status unavailable", + "stateUnverifiableCount": "{{value0}} with status unavailable", "reasonWaiting": "needs approval", "reasonBlocked": "failed", "groupAgents": "Agents", @@ -18210,12 +18217,12 @@ "idle": "idle", "failed": "failed", "stopped": "stopped", - "unverifiable": "no recent update", + "unverifiable": "status unavailable", "workingCount": "{{value0}} working", "idleCount": "{{value0}} idle", "failedCount": "{{value0}} failed", "stoppedCount": "{{value0}} stopped", - "unverifiableCount": "{{value0}} with no recent update" + "unverifiableCount": "{{value0}} with status unavailable" }, "startedOne": "Kicked off 1 subagent", "startedN": "Kicked off {{value0}} subagents", diff --git a/src/renderer/src/i18n/locales/es.json b/src/renderer/src/i18n/locales/es.json index c670fbc079d..d769e6f3dcd 100644 --- a/src/renderer/src/i18n/locales/es.json +++ b/src/renderer/src/i18n/locales/es.json @@ -17621,6 +17621,7 @@ "updateOrcaToOpenChat": "Actualice Orca para abrirlo.", "unsupported": "Esto requiere una versión más reciente de Orca en el equipo que ejecuta este chat. Actualice Orca allí y vuelva a intentarlo.", "notAvailable": "Esto no está disponible en este chat.", + "cannotRunHere": "Orca no puede ejecutar este agente en un chat aquí.", "unreachable": "Orca no pudo comunicarse con el agente.", "recordFailed": "Orca no pudo guardar esto en el historial del chat.", "conversationCleared": "Esta conversación se borró.", @@ -17704,7 +17705,7 @@ "commands": "Comandos", "skills": "Habilidades", "loadingSkills": "Cargando habilidades…", - "skillsUnavailableHost": "Las habilidades no están disponibles en los chats SSH", + "skillsUnavailableHost": "Las habilidades no se pueden listar en los chats SSH", "skillsLoadFailed": "No se pudieron cargar las habilidades", "retrySkills": "Reintentar", "skillCommandCollision": "También es un nombre de habilidad - el agente decide", @@ -17908,17 +17909,17 @@ "subagents": { "unnamed": "Subagente", "state": { - "failedCount": "{{value0}} fallidas", + "failedCount": "{{value0}} con error", "working": "trabajando", "failed": "falló", "stopped": "detenido", - "unverifiable": "sin actualización reciente", - "unverifiableCount": "{{value0}} sin actualización reciente", + "unverifiable": "estado no disponible", + "unverifiableCount": "{{value0}} con estado no disponible", "completed": "completado", - "idle": "idle", + "idle": "inactivo", "workingCount": "{{value0}} trabajando", - "idleCount": "{{value0}} inactivo", - "stoppedCount": "{{value0}} detenido" + "idleCount": "{{value0}} inactivo(s)", + "stoppedCount": "{{value0}} detenido(s)" }, "startedOne": "Inició 1 subagente", "startedN": "Inició {{value0}} subagentes", @@ -17986,15 +17987,21 @@ "countTasksMany": "{{value0}} tareas", "headerTotal": "{{value0}} tareas en segundo plano", "stateWorking": "trabajando", + "stateWorkingCount": "{{value0}} trabajando", "stateMonitoring": "supervisando", + "stateMonitoringCount": "{{value0}} supervisando", "stateWaiting": "esperando", + "stateWaitingCount": "{{value0}} esperando", "stateBlocked": "bloqueado", - "stateDone": "listo", + "stateBlockedCount": "{{value0}} en estado bloqueado", + "stateDone": "terminado", + "stateDoneCount": "{{value0}} en estado terminado", "stateIdle": "detenido", - "stateUnverifiable": "sin actualización reciente", - "stateUnverifiableCount": "{{value0}} sin actualización reciente", - "reasonWaiting": "necesita aprobación", - "reasonBlocked": "falló", + "stateIdleCount": "{{value0}} en estado detenido", + "stateUnverifiable": "estado no disponible", + "stateUnverifiableCount": "{{value0}} con estado no disponible", + "reasonWaiting": "aprobación pendiente", + "reasonBlocked": "con error", "groupShell": "Shell", "groupMonitors": "Monitores", "groupWorkflows": "Flujos de trabajo" diff --git a/src/renderer/src/i18n/locales/fr.json b/src/renderer/src/i18n/locales/fr.json index 7dde6febdcc..fec8d16043d 100644 --- a/src/renderer/src/i18n/locales/fr.json +++ b/src/renderer/src/i18n/locales/fr.json @@ -17720,6 +17720,7 @@ "updateOrcaToOpenChat": "Mettez à jour Orca pour l'ouvrir.", "unsupported": "Cela nécessite une version plus récente d'Orca sur l'ordinateur qui exécute ce chat. Mettez Orca à jour sur cet ordinateur, puis réessayez.", "notAvailable": "Ceci n'est pas disponible dans ce chat.", + "cannotRunHere": "Orca ne peut pas exécuter cet agent dans un chat ici.", "unreachable": "Orca n'a pas pu joindre l'agent.", "recordFailed": "Orca n'a pas pu enregistrer ceci dans l'historique du chat.", "conversationCleared": "Cette conversation a été effacée.", @@ -17768,7 +17769,7 @@ "skills": "Skills", "loadingSkills": "Chargement des skills...", "skillsLoaded": "Skills chargées", - "skillsUnavailableHost": "Les skills ne sont pas disponibles dans les chats SSH", + "skillsUnavailableHost": "Les skills ne peuvent pas être listées dans les chats SSH", "skillsLoadFailed": "Impossible de charger les skills", "retrySkills": "Réessayer", "skillCommandCollision": "Aussi un nom de skill - l'agent décide", @@ -18054,13 +18055,19 @@ "countTasksMany": "{{value0}} tâches", "headerTotal": "{{value0}} tâches en arrière-plan", "stateWorking": "fonctionnement", + "stateWorkingCount": "{{value0}} en cours", "stateMonitoring": "surveillance", + "stateMonitoringCount": "{{value0}} en surveillance", "stateWaiting": "en attendant", + "stateWaitingCount": "{{value0}} en attente", "stateBlocked": "bloqué", + "stateBlockedCount": "{{value0}} à l'état bloqué", "stateDone": "fait", + "stateDoneCount": "{{value0}} à l'état terminé", "stateIdle": "arrêté", - "stateUnverifiable": "aucune mise à jour récente", - "stateUnverifiableCount": "{{value0}} sans mise à jour récente", + "stateIdleCount": "{{value0}} à l'état arrêté", + "stateUnverifiable": "statut indisponible", + "stateUnverifiableCount": "{{value0}} au statut indisponible", "reasonWaiting": "a besoin d'approbation", "reasonBlocked": "échoué", "groupAgents": "Agents", @@ -18085,12 +18092,12 @@ "idle": "idle", "failed": "échoué", "stopped": "arrêté", - "unverifiable": "aucune mise à jour récente", + "unverifiable": "statut indisponible", "workingCount": "{{value0}} fonctionne", "idleCount": "{{value0}} inactif", "failedCount": "{{value0}} a échoué", "stoppedCount": "{{value0}} arrêté", - "unverifiableCount": "{{value0}} sans mise à jour récente" + "unverifiableCount": "{{value0}} au statut indisponible" }, "startedOne": "A lancé 1 sous-agent", "startedN": "Lancement des sous-agents {{value0}}", diff --git a/src/renderer/src/i18n/locales/ja.json b/src/renderer/src/i18n/locales/ja.json index becf91c95e5..88379cfe2ab 100644 --- a/src/renderer/src/i18n/locales/ja.json +++ b/src/renderer/src/i18n/locales/ja.json @@ -17656,6 +17656,7 @@ "updateOrcaToOpenChat": "開くには Orca を更新してください。", "unsupported": "このチャットを実行しているコンピューターに新しいバージョンの Orca が必要です。そのコンピューターで Orca を更新してから、もう一度お試しください。", "notAvailable": "このチャットでは利用できません。", + "cannotRunHere": "Orca はここでこの Agent をチャットで実行できません。", "unreachable": "Orca は Agent に接続できませんでした。", "recordFailed": "Orca はこれをチャットの履歴に保存できませんでした。", "conversationCleared": "この会話はクリアされました。", @@ -17739,7 +17740,7 @@ "commands": "コマンド", "skills": "スキル", "loadingSkills": "スキルを読み込み中…", - "skillsUnavailableHost": "SSH チャットではスキルを利用できません", + "skillsUnavailableHost": "SSH チャットではスキルを一覧表示できません", "skillsLoadFailed": "スキルを読み込めませんでした", "retrySkills": "再試行", "skillCommandCollision": "スキル名でもあります - Agent が判断します", @@ -17990,13 +17991,19 @@ "countTasksMany": "{{value0}} タスク", "headerTotal": "{{value0}} バックグラウンドタスク", "stateWorking": "実行中", + "stateWorkingCount": "{{value0}} 実行中", "stateMonitoring": "監視", + "stateMonitoringCount": "{{value0}} 監視", "stateWaiting": "待機中", + "stateWaitingCount": "{{value0}} 待機中", "stateBlocked": "ブロックされました", + "stateBlockedCount": "{{value0}} ブロックされました", "stateDone": "終わり", + "stateDoneCount": "{{value0}} 終わり", "stateIdle": "止まった", - "stateUnverifiable": "最近の更新なし", - "stateUnverifiableCount": "{{value0}} は最近の更新なし", + "stateIdleCount": "{{value0}} 止まった", + "stateUnverifiable": "状態を取得できません", + "stateUnverifiableCount": "{{value0}} は状態を取得できません", "reasonWaiting": "承認が必要です", "reasonBlocked": "失敗した", "groupAgents": "Agent", @@ -18021,12 +18028,12 @@ "idle": "idle", "failed": "失敗した", "stopped": "止まった", - "unverifiable": "最近の更新なし", + "unverifiable": "状態を取得できません", "workingCount": "{{value0}} は動作しています", "idleCount": "{{value0}} アイドル状態", "failedCount": "{{value0}} 件失敗", "stoppedCount": "{{value0}} が停止しました", - "unverifiableCount": "{{value0}} は最近の更新なし" + "unverifiableCount": "{{value0}} 件は状態を取得できません" }, "startedOne": "1 人のサブ Agent を解雇しました", "startedN": "{{value0}} サブ Agent をキックオフしました", diff --git a/src/renderer/src/i18n/locales/ko.json b/src/renderer/src/i18n/locales/ko.json index f81a9442788..5adf75f1fff 100644 --- a/src/renderer/src/i18n/locales/ko.json +++ b/src/renderer/src/i18n/locales/ko.json @@ -17656,6 +17656,7 @@ "updateOrcaToOpenChat": "열려면 Orca를 업데이트하세요.", "unsupported": "이 채팅을 실행 중인 컴퓨터에 최신 버전의 Orca가 필요합니다. 해당 컴퓨터에서 Orca를 업데이트한 후 다시 시도하세요.", "notAvailable": "이 채팅에서는 사용할 수 없습니다.", + "cannotRunHere": "Orca는 여기에서 이 에이전트를 채팅으로 실행할 수 없습니다.", "unreachable": "Orca가 에이전트에 연결하지 못했습니다.", "recordFailed": "Orca가 이 내용을 채팅 기록에 저장하지 못했습니다.", "conversationCleared": "이 대화는 지워졌습니다.", @@ -17739,7 +17740,7 @@ "commands": "명령어", "skills": "스킬", "loadingSkills": "스킬 로딩 중…", - "skillsUnavailableHost": "SSH 채팅에서는 스킬을 사용할 수 없습니다", + "skillsUnavailableHost": "SSH 채팅에서는 스킬 목록을 표시할 수 없습니다", "skillsLoadFailed": "스킬을 불러올 수 없습니다", "retrySkills": "재시도", "skillCommandCollision": "스킬 이름이기도 합니다 - 에이전트가 결정합니다", @@ -17990,13 +17991,19 @@ "countTasksMany": "{{value0}} 작업", "headerTotal": "{{value0}} 백그라운드 작업", "stateWorking": "작업 중", + "stateWorkingCount": "{{value0}} 작업 중", "stateMonitoring": "모니터링", + "stateMonitoringCount": "{{value0}} 모니터링", "stateWaiting": "대기 중", + "stateWaitingCount": "{{value0}} 대기 중", "stateBlocked": "막힌", + "stateBlockedCount": "{{value0}} 막힌", "stateDone": "완료", + "stateDoneCount": "{{value0}} 완료", "stateIdle": "중지됨", - "stateUnverifiable": "최근 업데이트 없음", - "stateUnverifiableCount": "{{value0}} 최근 업데이트 없음", + "stateIdleCount": "{{value0}} 중지됨", + "stateUnverifiable": "상태를 확인할 수 없음", + "stateUnverifiableCount": "{{value0}} 상태를 확인할 수 없음", "reasonWaiting": "승인이 필요합니다", "reasonBlocked": "실패한", "groupAgents": "에이전트", @@ -18021,12 +18028,12 @@ "idle": "idle", "failed": "실패한", "stopped": "중지됨", - "unverifiable": "최근 업데이트 없음", + "unverifiable": "상태를 확인할 수 없음", "workingCount": "{{value0}} 작업 중", "idleCount": "{{value0}} 유휴", "failedCount": "{{value0}} 실패", "stoppedCount": "{{value0}} 중지됨", - "unverifiableCount": "{{value0}} 최근 업데이트 없음" + "unverifiableCount": "{{value0}} 상태를 확인할 수 없음" }, "startedOne": "서브에이전트 1명 추방", "startedN": "{{value0}} 하위 에이전트가 시작되었습니다.", diff --git a/src/renderer/src/i18n/locales/zh.json b/src/renderer/src/i18n/locales/zh.json index 9707c04c143..5a0fbe1c6d6 100644 --- a/src/renderer/src/i18n/locales/zh.json +++ b/src/renderer/src/i18n/locales/zh.json @@ -17621,6 +17621,7 @@ "updateOrcaToOpenChat": "请更新 Orca 以打开它。", "unsupported": "运行此聊天的计算机需要更新版本的 Orca。请在该计算机上更新 Orca 后重试。", "notAvailable": "此聊天中无法使用此功能。", + "cannotRunHere": "Orca 无法在此处以聊天方式运行此智能体。", "unreachable": "Orca 无法连接到智能体。", "recordFailed": "Orca 无法将此内容保存到聊天历史记录中。", "conversationCleared": "此对话已被清除。", @@ -17704,7 +17705,7 @@ "commands": "命令", "skills": "技能", "loadingSkills": "正在加载技能…", - "skillsUnavailableHost": "SSH 聊天中无法使用技能", + "skillsUnavailableHost": "SSH 聊天中无法列出技能", "skillsLoadFailed": "无法加载技能", "retrySkills": "重试", "skillCommandCollision": "也是技能名称 — 由智能体决定", @@ -17955,13 +17956,19 @@ "countTasksMany": "{{value0}} 任务", "headerTotal": "{{value0}} 后台任务", "stateWorking": "处理中", + "stateWorkingCount": "{{value0}} 处理中", "stateMonitoring": "监控", + "stateMonitoringCount": "{{value0}} 监控", "stateWaiting": "等待", + "stateWaitingCount": "{{value0}} 等待", "stateBlocked": "被阻止", + "stateBlockedCount": "{{value0}} 被阻止", "stateDone": "完毕", + "stateDoneCount": "{{value0}} 完毕", "stateIdle": "停止了", - "stateUnverifiable": "暂无近期更新", - "stateUnverifiableCount": "{{value0}} 暂无近期更新", + "stateIdleCount": "{{value0}} 停止了", + "stateUnverifiable": "状态不可用", + "stateUnverifiableCount": "{{value0}} 状态不可用", "reasonWaiting": "需要批准", "reasonBlocked": "失败的", "groupAgents": "智能体", @@ -17986,12 +17993,12 @@ "idle": "idle", "failed": "失败的", "stopped": "停止了", - "unverifiable": "暂无近期更新", + "unverifiable": "状态不可用", "workingCount": "{{value0}} 工作", "idleCount": "{{value0}} 空闲", "failedCount": "{{value0}} 失败", "stoppedCount": "{{value0}} 已停止", - "unverifiableCount": "{{value0}} 暂无近期更新" + "unverifiableCount": "{{value0}} 状态不可用" }, "startedOne": "踢掉 1 个子智能体", "startedN": "启动 {{value0}} 子智能体", diff --git a/src/shared/agent-session-refusal-notice.test.ts b/src/shared/agent-session-refusal-notice.test.ts index 41a9606deca..2d53a1330e2 100644 --- a/src/shared/agent-session-refusal-notice.test.ts +++ b/src/shared/agent-session-refusal-notice.test.ts @@ -341,15 +341,21 @@ describe('the notice for every reason a host names', () => { })) ) - // An unsupported location or agent, or no chat host, is not fixed by updating Orca. A read asked - // for nothing "this" could name, so it says only that the history didn't load. - it('says an unsupported write only is not available when the host names why', () => { + // An unsupported location or agent, or no chat host, is not fixed by updating Orca. Only an + // agent or location the host can't run names its cause; a read otherwise asked for nothing + // "this" could name, so it says only that the history didn't load. + it('says an unsupported write never asks for an update when the host names why', () => { for (const { failure, write, parts, cell } of cells) { - if (failure.code === 'structured_agent_session_unsupported') { - expect(parts, cell).toEqual( - write === 'read-history' ? ['notDoneReadHistory'] : ['notAvailable'] - ) + if (failure.code !== 'structured_agent_session_unsupported') { + continue } + if (failure.details?.reason === 'hostUnsupported') { + expect(parts, cell).toEqual(['cannotRunHere', NOT_DONE[write]]) + continue + } + expect(parts, cell).toEqual( + write === 'read-history' ? ['notDoneReadHistory'] : ['notAvailable'] + ) } }) @@ -441,7 +447,9 @@ describe('the notice for every reason a host names', () => { const notDone = parts.filter((part) => typeof part === 'string' && part.startsWith('notDone')) const answeredAway = write === 'answer' && parts.includes('questionChanged') const unsupported = - failure.code === 'structured_agent_session_unsupported' && write !== 'read-history' + failure.code === 'structured_agent_session_unsupported' && + failure.details?.reason !== 'hostUnsupported' && + write !== 'read-history' const saysNotDone = write === 'read-history' && failure.code === 'agent_session_journal_unreadable' expect(notDone, cell).toEqual( diff --git a/src/shared/agent-session-refusal-reason-words.ts b/src/shared/agent-session-refusal-reason-words.ts index 43893f67b47..d8756a3c9ec 100644 --- a/src/shared/agent-session-refusal-reason-words.ts +++ b/src/shared/agent-session-refusal-reason-words.ts @@ -165,14 +165,15 @@ const REASON_WORDS = { history: { cause: 'chatSavedByNewerOrca', step: 'updateOrcaToOpenChat' } } }, - // Thrown, so a client meets these only as an RPC error. The code's own words ask for an update, - // which only a method the host doesn't know proves; no reason here means an older Orca. An - // unsupported location or agent, or no chat host, is not fixed by updating, and a client missing - // the capability words this with its own older copy. + // Mostly thrown as an RPC error; `hostUnsupported` is also returned and recorded. The code's own + // words ask for an update, which only a method the host doesn't know proves; no reason here means + // an older Orca. An unsupported location or agent, or no chat host, is not fixed by updating, and + // a client missing the capability words this with its own older copy. Only `hostUnsupported` + // names its cause: this agent or location can't run as a chat. structured_agent_session_unsupported: { clientCapabilityMissing: causeWords('notAvailable', 'hostFinding'), hostDisabled: causeWords('notAvailable', 'hostFinding'), - hostUnsupported: causeWords('notAvailable', 'hostFinding') + hostUnsupported: causeWords('cannotRunHere', 'hostFinding') }, agent_session_owner_restart_failed: {} } satisfies { diff --git a/src/shared/agent-session-write-notice-copy.ts b/src/shared/agent-session-write-notice-copy.ts index 0904ecf8551..3796de6eaf0 100644 --- a/src/shared/agent-session-write-notice-copy.ts +++ b/src/shared/agent-session-write-notice-copy.ts @@ -41,6 +41,7 @@ export const AGENT_SESSION_WRITE_NOTICE_COPY = { unsupported: 'This needs a newer Orca on the computer running this chat. Update Orca there, then try again.', notAvailable: "This isn't available in this chat.", + cannotRunHere: "Orca can't run this agent in a chat here.", unreachable: "Orca couldn't reach the agent.", recordFailed: "Orca couldn't save this to the chat's history.", conversationCleared: 'This conversation has been cleared.',