diff --git a/mobile/src/session/MobileNativeChatQueuedMessages.test.tsx b/mobile/src/session/MobileNativeChatQueuedMessages.test.tsx index b01a0fa66c18..5454450ed397 100644 --- a/mobile/src/session/MobileNativeChatQueuedMessages.test.tsx +++ b/mobile/src/session/MobileNativeChatQueuedMessages.test.tsx @@ -168,7 +168,7 @@ describe('MobileNativeChatQueuedMessages', () => { it("lets a returned card's reason wrap whole, in the destructive color, beside an alert", async () => { const reason = - 'The provider did not accept this message: Claude does not support the image type .bmp in a steering message.' + "Claude didn't accept this message: Claude does not support the image type .bmp in a steering message." const mounted = await mount({ cards: [ card({ messageId: 'r', state: 'returned', needsAttention: true, caption: reason }), diff --git a/src/main/codex/codex-structured-compaction-refusal.test.ts b/src/main/codex/codex-structured-compaction-refusal.test.ts index fa8800f9605f..c1c8e262e3c3 100644 --- a/src/main/codex/codex-structured-compaction-refusal.test.ts +++ b/src/main/codex/codex-structured-compaction-refusal.test.ts @@ -32,7 +32,7 @@ describe('Codex compaction refused at the request', () => { }) ).resolves.toEqual({ state: 'rejected', - reason: 'The provider did not accept this message: thread has nothing to compact.', + reason: "Codex didn't accept this message: thread has nothing to compact.", rejection: { kind: 'providerRejected', detail: { text: 'thread has nothing to compact', audience: 'person' } diff --git a/src/main/codex/codex-structured-dispatch-admission.test.ts b/src/main/codex/codex-structured-dispatch-admission.test.ts index 80bf0cee097d..dc0bf170af79 100644 --- a/src/main/codex/codex-structured-dispatch-admission.test.ts +++ b/src/main/codex/codex-structured-dispatch-admission.test.ts @@ -155,7 +155,7 @@ describe('codex dispatch admission', () => { // Codex's own words reach the sentence and the fact; Orca's prefix reaches neither. expect(await send(adapter, 'client-1')).toEqual({ state: 'rejected', - reason: 'The provider did not accept this message: thread not found.', + reason: "Codex didn't accept this message: thread not found.", rejection: { kind: 'providerRejected', detail: { text: 'thread not found', audience: 'person' } diff --git a/src/main/codex/codex-structured-session-adapter.test.ts b/src/main/codex/codex-structured-session-adapter.test.ts index 2fcd0a41f6be..f02826c780f7 100644 --- a/src/main/codex/codex-structured-session-adapter.test.ts +++ b/src/main/codex/codex-structured-session-adapter.test.ts @@ -583,7 +583,7 @@ describe('CodexStructuredSessionAdapter.dispatch', () => { ).toEqual({ // Built without Codex's own words, so nothing is quoted and no detail is invented. state: 'rejected', - reason: 'The provider did not accept this message.', + reason: "Codex didn't accept this message.", rejection: { kind: 'providerRejected' } }) }) diff --git a/src/main/codex/codex-structured-turn-steer.test.ts b/src/main/codex/codex-structured-turn-steer.test.ts index dfde08edafd1..e6c654c00775 100644 --- a/src/main/codex/codex-structured-turn-steer.test.ts +++ b/src/main/codex/codex-structured-turn-steer.test.ts @@ -168,7 +168,7 @@ describe('a Codex send while a turn runs', () => { expect(await send('client-1')).toEqual({ state: 'rejected', - reason: 'The provider did not accept this message: thread not found.', + reason: "Codex didn't accept this message: thread not found.", rejection: { kind: 'providerRejected', detail: { text: 'thread not found', audience: 'person' } diff --git a/src/main/native-chat/agent-session-journal/journal-reducer-rejection-fact.test.ts b/src/main/native-chat/agent-session-journal/journal-reducer-rejection-fact.test.ts index 3332e53b0b3e..542c704bc785 100644 --- a/src/main/native-chat/agent-session-journal/journal-reducer-rejection-fact.test.ts +++ b/src/main/native-chat/agent-session-journal/journal-reducer-rejection-fact.test.ts @@ -45,14 +45,14 @@ describe('a rejected dispatch', () => { clientMessageId: 'cm_1', state: 'rejected', providerItemId: null, - reason: 'The provider did not accept this message.', + reason: "The agent didn't accept this message.", rejection: { kind: 'providerRejected', detail: { text: 'Too long', audience: 'person' } }, ...base(2) } ]) expect(state.submissions.get('cm_1')).toMatchObject({ dispatchState: 'rejected', - reason: 'The provider did not accept this message.', + reason: "The agent didn't accept this message.", rejection }) diff --git a/src/main/native-chat/agent-session-wire/structured-conversation-compaction.test.ts b/src/main/native-chat/agent-session-wire/structured-conversation-compaction.test.ts index 35e5b4fda216..e671fc96d9f4 100644 --- a/src/main/native-chat/agent-session-wire/structured-conversation-compaction.test.ts +++ b/src/main/native-chat/agent-session-wire/structured-conversation-compaction.test.ts @@ -298,7 +298,7 @@ it('settles a command the provider refused as a failure with its reason, and mov // The message was not sent, in the provider's words; the command's row says the compaction failed. expect(snapshot.submissions.find((entry) => entry.clientMessageId === cmid)).toMatchObject({ dispatchState: 'rejected', - reason: 'The provider did not accept this message: Not enough messages to compact.', + reason: "The agent didn't accept this message: Not enough messages to compact.", rejection: { kind: 'providerRejected', detail: NOT_ENOUGH } }) expect( diff --git a/src/renderer/src/components/native-chat/NativeChatStructuredSession.approval-and-start-failure.test.tsx b/src/renderer/src/components/native-chat/NativeChatStructuredSession.approval-and-start-failure.test.tsx index 8b0d39764b22..3dc83d883e84 100644 --- a/src/renderer/src/components/native-chat/NativeChatStructuredSession.approval-and-start-failure.test.tsx +++ b/src/renderer/src/components/native-chat/NativeChatStructuredSession.approval-and-start-failure.test.tsx @@ -254,18 +254,12 @@ afterEach(() => { renderPane([ rejected('stated', START_FAILED_REASON, START_FAILED), - rejected( - 'other', - 'The provider did not accept this message: Image type .bmp.', - providerRejected - ) + rejected('other', "Claude didn't accept this message: Image type .bmp.", providerRejected) ]) expect(within(await notice('stated')).getByText('Your message was not sent.')).toBeTruthy() expect( - within(await notice('other')).getByText( - 'The provider did not accept this message: Image type .bmp.' - ) + within(await notice('other')).getByText("Claude didn't accept this message: Image type .bmp.") ).toBeTruthy() }) diff --git a/src/renderer/src/components/native-chat/agent-session-failure-words-text.test.ts b/src/renderer/src/components/native-chat/agent-session-failure-words-text.test.ts index 9e4c7ddbcafb..de6163b883c8 100644 --- a/src/renderer/src/components/native-chat/agent-session-failure-words-text.test.ts +++ b/src/renderer/src/components/native-chat/agent-session-failure-words-text.test.ts @@ -173,14 +173,14 @@ describe('desktop words for a failure fact', () => { ) const detail = 'Uses {{agent}} $t(components.native-chat.failureWords.theAgent) &' const rejected = structuredAgentSessionRejectionParts( - `The provider did not accept this message: ${detail}.`, + `Codex didn't accept this message: ${detail}.`, 'send', { kind: 'providerRejected', detail: { text: detail, audience: 'person' } }, { agentName: 'Codex' } ) // The provider's own words stay as written: placeholders, nesting and markup are not read. expect(agentSessionWriteNoticeText(rejected)).toBe( - `Le fournisseur n'a pas accepté ce message : ${detail}.` + `Codex n'a pas accepté ce message : ${detail}.` ) expect( agentSessionWriteNoticeText( diff --git a/src/renderer/src/components/native-chat/agent-session-failure-words-text.ts b/src/renderer/src/components/native-chat/agent-session-failure-words-text.ts index 4739ecabb433..1fa3268378c5 100644 --- a/src/renderer/src/components/native-chat/agent-session-failure-words-text.ts +++ b/src/renderer/src/components/native-chat/agent-session-failure-words-text.ts @@ -10,6 +10,7 @@ import { } from '../../../../shared/agent-session-failure-copy' import { AVAILABILITY_PIECES } from './agent-session-availability-words-text' import { ATTACHMENT_FAILURE_PIECES } from './agent-session-failure-attachment-words-text' +import { PROVIDER_RETRY_PIECES } from './agent-session-provider-retry-words-text' // The pieces a refusal notice says too keep the notice's keys, so each has one translation. const PIECES: Record string> = @@ -160,8 +161,12 @@ const PIECES: Record - translate('components.native-chat.failureWords.providerRejected', COPY.providerRejected), + providerRejected: (values) => + translate( + 'components.native-chat.failureWords.providerRejected', + COPY.providerRejected, + values + ), providerRejectedQuoted: (values) => translate( 'components.native-chat.failureWords.providerRejectedQuoted', @@ -252,42 +257,7 @@ const PIECES: Record translate('components.native-chat.failureWords.hostStopped', COPY.hostStopped, values), - providerRateLimited: (values) => - translate( - 'components.native-chat.failureWords.providerRateLimited', - COPY.providerRateLimited, - values - ), - providerRetrying: (values) => - translate( - 'components.native-chat.failureWords.providerRetrying', - COPY.providerRetrying, - values - ), - providerRetryingQuoted: (values) => - translate( - 'components.native-chat.failureWords.providerRetryingQuoted', - COPY.providerRetryingQuoted, - values - ), - providerRetryNumber: (values) => - translate( - 'components.native-chat.failureWords.providerRetryNumber', - COPY.providerRetryNumber, - values - ), - providerRetryNumberOf: (values) => - translate( - 'components.native-chat.failureWords.providerRetryNumberOf', - COPY.providerRetryNumberOf, - values - ), - providerRetryLastError: (values) => - translate( - 'components.native-chat.failureWords.providerRetryLastError', - COPY.providerRetryLastError, - values - ), + ...PROVIDER_RETRY_PIECES, previousExitUnverifiable: (values) => translate( 'components.native-chat.failureWords.previousExitUnverifiable', diff --git a/src/renderer/src/components/native-chat/agent-session-provider-retry-words-text.ts b/src/renderer/src/components/native-chat/agent-session-provider-retry-words-text.ts new file mode 100644 index 000000000000..6faea6a28ef6 --- /dev/null +++ b/src/renderer/src/components/native-chat/agent-session-provider-retry-words-text.ts @@ -0,0 +1,49 @@ +// Desktop words for a provider's retries, kept beside the other failure pieces' translations. + +import { translate } from '@/i18n/i18n' +import { + AGENT_SESSION_FAILURE_COPY as COPY, + type AgentSessionFailureCopyId, + type AgentSessionFailureCopyValues +} from '../../../../shared/agent-session-failure-copy' + +export const PROVIDER_RETRY_PIECES = { + providerRateLimited: (values) => + translate( + 'components.native-chat.failureWords.providerRateLimited', + COPY.providerRateLimited, + values + ), + providerRetrying: (values) => + translate( + 'components.native-chat.failureWords.providerRetrying', + COPY.providerRetrying, + values + ), + providerRetryingQuoted: (values) => + translate( + 'components.native-chat.failureWords.providerRetryingQuoted', + COPY.providerRetryingQuoted, + values + ), + providerRetryNumber: (values) => + translate( + 'components.native-chat.failureWords.providerRetryNumber', + COPY.providerRetryNumber, + values + ), + providerRetryNumberOf: (values) => + translate( + 'components.native-chat.failureWords.providerRetryNumberOf', + COPY.providerRetryNumberOf, + values + ), + providerRetryLastError: (values) => + translate( + 'components.native-chat.failureWords.providerRetryLastError', + COPY.providerRetryLastError, + values + ) +} satisfies Partial< + Record string> +> diff --git a/src/renderer/src/i18n/en-runtime-required.json b/src/renderer/src/i18n/en-runtime-required.json index 55263d5ee7fc..059834079b14 100644 --- a/src/renderer/src/i18n/en-runtime-required.json +++ b/src/renderer/src/i18n/en-runtime-required.json @@ -2894,8 +2894,8 @@ "providerExitedRejection": "{{agent}} stopped before this message was sent.", "providerExitedRow": "{{agent}} stopped while this response was in progress. You can continue in this conversation.", "providerRateLimited": "{{agent}} is rate-limited and retrying.", - "providerRejected": "The provider did not accept this message.", - "providerRejectedQuoted": "The provider did not accept this message: {{detail}}.", + "providerRejected": "{{agent}} didn't accept this message.", + "providerRejectedQuoted": "{{agent}} didn't accept this message: {{detail}}.", "providerRetryLastError": "Last error: {{detail}}.", "providerRetryNumber": "Retry {{attempt}}.", "providerRetryNumberOf": "Retry {{attempt}} of {{maxRetries}}.", diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index 4d51de70365b..336d8f5aeac2 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -18072,8 +18072,8 @@ "chooseClaudeAccountThenSend": "Choose or add one in Claude Accounts settings, then send your message again.", "providerExitedRow": "{{agent}} stopped while this response was in progress. You can continue in this conversation.", "providerExitedRejection": "{{agent}} stopped before this message was sent.", - "providerRejected": "The provider did not accept this message.", - "providerRejectedQuoted": "The provider did not accept this message: {{detail}}.", + "providerRejected": "{{agent}} didn't accept this message.", + "providerRejectedQuoted": "{{agent}} didn't accept this message: {{detail}}.", "attachmentEmpty": "An image on this message is empty, so the message was not sent.", "attachmentTooLarge": "An image on this message is too large, so the message was not sent.", "attachmentLargerThan": "An image on this message is larger than {{size}} MB, so the message was not sent.", diff --git a/src/renderer/src/i18n/locales/es.json b/src/renderer/src/i18n/locales/es.json index 4b92605e734a..aaf33ef8d5e2 100644 --- a/src/renderer/src/i18n/locales/es.json +++ b/src/renderer/src/i18n/locales/es.json @@ -17772,8 +17772,8 @@ "chooseClaudeAccountThenSend": "Elija o agregue una en la configuración de Cuentas de Claude y vuelva a enviar su mensaje.", "providerExitedRow": "{{agent}} se detuvo mientras esta respuesta estaba en curso. Puede continuar en esta conversación.", "providerExitedRejection": "{{agent}} se detuvo antes de que se enviara este mensaje.", - "providerRejected": "El proveedor no aceptó este mensaje.", - "providerRejectedQuoted": "El proveedor no aceptó este mensaje: {{detail}}.", + "providerRejected": "{{agent}} no aceptó este mensaje.", + "providerRejectedQuoted": "{{agent}} no aceptó este mensaje: {{detail}}.", "attachmentEmpty": "Una imagen de este mensaje está vacía, así que el mensaje no se envió.", "attachmentTooLarge": "Una imagen de este mensaje es demasiado grande, así que el mensaje no se envió.", "attachmentLargerThan": "Una imagen de este mensaje supera los {{size}} MB, así que el mensaje no se envió.", diff --git a/src/renderer/src/i18n/locales/fr.json b/src/renderer/src/i18n/locales/fr.json index a9eae06bb86d..6f06e2c815c4 100644 --- a/src/renderer/src/i18n/locales/fr.json +++ b/src/renderer/src/i18n/locales/fr.json @@ -17874,8 +17874,8 @@ "chooseClaudeAccountThenSend": "Choisissez-en un ou ajoutez-en un dans les paramètres Comptes Claude, puis renvoyez votre message.", "providerExitedRow": "{{agent}} s'est arrêté pendant que cette réponse était en cours. Vous pouvez continuer dans cette conversation.", "providerExitedRejection": "{{agent}} s'est arrêté avant l'envoi de ce message.", - "providerRejected": "Le fournisseur n'a pas accepté ce message.", - "providerRejectedQuoted": "Le fournisseur n'a pas accepté ce message : {{detail}}.", + "providerRejected": "{{agent}} n'a pas accepté ce message.", + "providerRejectedQuoted": "{{agent}} n'a pas accepté ce message : {{detail}}.", "attachmentEmpty": "Une image de ce message est vide, le message n'a donc pas été envoyé.", "attachmentTooLarge": "Une image de ce message est trop volumineuse, le message n'a donc pas été envoyé.", "attachmentLargerThan": "Une image de ce message dépasse {{size}} Mo, le message n'a donc pas été envoyé.", diff --git a/src/renderer/src/i18n/locales/ja.json b/src/renderer/src/i18n/locales/ja.json index ae613af9533f..ff22b23faa9e 100644 --- a/src/renderer/src/i18n/locales/ja.json +++ b/src/renderer/src/i18n/locales/ja.json @@ -17807,8 +17807,8 @@ "chooseClaudeAccountThenSend": "Claude アカウントの設定で選択または追加してから、メッセージをもう一度送信してください。", "providerExitedRow": "この応答の途中で {{agent}} が停止しました。この会話で続けることができます。", "providerExitedRejection": "このメッセージが送信される前に {{agent}} が停止しました。", - "providerRejected": "プロバイダーはこのメッセージを受け付けませんでした。", - "providerRejectedQuoted": "プロバイダーはこのメッセージを受け付けませんでした: {{detail}}。", + "providerRejected": "{{agent}} はこのメッセージを受け付けませんでした。", + "providerRejectedQuoted": "{{agent}} はこのメッセージを受け付けませんでした: {{detail}}。", "attachmentEmpty": "このメッセージの画像が空のため、メッセージは送信されませんでした。", "attachmentTooLarge": "このメッセージの画像が大きすぎるため、メッセージは送信されませんでした。", "attachmentLargerThan": "このメッセージの画像が {{size}} MB を超えているため、メッセージは送信されませんでした。", diff --git a/src/renderer/src/i18n/locales/ko.json b/src/renderer/src/i18n/locales/ko.json index 673eb9c6c06b..46e670286822 100644 --- a/src/renderer/src/i18n/locales/ko.json +++ b/src/renderer/src/i18n/locales/ko.json @@ -17807,8 +17807,8 @@ "chooseClaudeAccountThenSend": "Claude 계정 설정에서 선택하거나 추가한 다음 메시지를 다시 보내세요.", "providerExitedRow": "이 응답이 진행되는 동안 {{agent}}이(가) 중지되었습니다. 이 대화에서 계속할 수 있습니다.", "providerExitedRejection": "이 메시지가 전송되기 전에 {{agent}}이(가) 중지되었습니다.", - "providerRejected": "공급자가 이 메시지를 받아들이지 않았습니다.", - "providerRejectedQuoted": "공급자가 이 메시지를 받아들이지 않았습니다: {{detail}}.", + "providerRejected": "{{agent}}이(가) 이 메시지를 받아들이지 않았습니다.", + "providerRejectedQuoted": "{{agent}}이(가) 이 메시지를 받아들이지 않았습니다: {{detail}}.", "attachmentEmpty": "이 메시지의 이미지가 비어 있어 메시지가 전송되지 않았습니다.", "attachmentTooLarge": "이 메시지의 이미지가 너무 커서 메시지가 전송되지 않았습니다.", "attachmentLargerThan": "이 메시지의 이미지가 {{size}}MB보다 커서 메시지가 전송되지 않았습니다.", diff --git a/src/renderer/src/i18n/locales/zh.json b/src/renderer/src/i18n/locales/zh.json index 5920c46f849d..2e27ee49221d 100644 --- a/src/renderer/src/i18n/locales/zh.json +++ b/src/renderer/src/i18n/locales/zh.json @@ -17786,8 +17786,8 @@ "chooseClaudeAccountThenSend": "请在 Claude 账户设置中选择或添加一个,然后重新发送您的消息。", "providerExitedRow": "{{agent}} 在生成此回复时停止了。您可以在此对话中继续。", "providerExitedRejection": "{{agent}} 在发送此消息前已停止。", - "providerRejected": "提供商未接受此消息。", - "providerRejectedQuoted": "提供商未接受此消息:{{detail}}。", + "providerRejected": "{{agent}} 未接受此消息。", + "providerRejectedQuoted": "{{agent}} 未接受此消息:{{detail}}。", "attachmentEmpty": "此消息中的一张图片为空,因此消息未发送。", "attachmentTooLarge": "此消息中的一张图片过大,因此消息未发送。", "attachmentLargerThan": "此消息中的一张图片超过 {{size}} MB,因此消息未发送。", diff --git a/src/shared/agent-session-failure-copy.ts b/src/shared/agent-session-failure-copy.ts index d498565e3847..47c5cde1e3f2 100644 --- a/src/shared/agent-session-failure-copy.ts +++ b/src/shared/agent-session-failure-copy.ts @@ -76,8 +76,8 @@ export const AGENT_SESSION_FAILURE_COPY = { providerExitedRow: '{{agent}} stopped while this response was in progress. You can continue in this conversation.', providerExitedRejection: '{{agent}} stopped before this message was sent.', - providerRejected: 'The provider did not accept this message.', - providerRejectedQuoted: 'The provider did not accept this message: {{detail}}.', + providerRejected: "{{agent}} didn't accept this message.", + providerRejectedQuoted: "{{agent}} didn't accept this message: {{detail}}.", attachmentEmpty: 'An image on this message is empty, so the message was not sent.', attachmentTooLarge: 'An image on this message is too large, so the message was not sent.', attachmentLargerThan: diff --git a/src/shared/agent-session-failure-words.ts b/src/shared/agent-session-failure-words.ts index cccb145c8af3..f73d3536cf24 100644 --- a/src/shared/agent-session-failure-words.ts +++ b/src/shared/agent-session-failure-words.ts @@ -237,8 +237,14 @@ const FAILURE_SENTENCES = { providerExited: (context, _fact, surface, say) => say(surface === 'row' ? 'providerExitedRow' : 'providerExitedRejection', agent(say, context)), restartFailed: couldNot('couldNotRestart'), - providerRejected: (_context, fact, _surface, say) => - quotingPersonDetail(say, 'providerRejected', 'providerRejectedQuoted', fact.detail), + providerRejected: (context, fact, _surface, say) => + quotingPersonDetail( + say, + 'providerRejected', + 'providerRejectedQuoted', + fact.detail, + agent(say, context) + ), attachmentInvalid: (context, fact, _surface, say) => fact.attachment ? ATTACHMENT_SENTENCES[fact.attachment.reason](say, context, fact.attachment)