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)