From 11a739d178e86221ebfb4a0e2b0bfdfb5fc2b263 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sun, 1 Nov 2026 19:11:03 -0800 Subject: [PATCH 1/4] fix(connectors): the Tools trail names every refusal the broker records A refused call recorded a code the trail had no words for, and showed the code itself: a hosted tool whose schema drifted (`tool_drift`), one its provider stopped offering (`tool_unavailable`), an approved call whose PR, arguments, repository or tool changed after approval, and a task-bound grant used off its task, unclaimed, or after the task closed. The live trail on 11-02 shows a `tool_drift` refusal as the bare code in both languages. Fourteen labels, in en and zh-CN. A code that is still unknown keeps showing as itself (TASK-188). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015AKgpQ2pr6xRMhN5mcfoHF --- frontend/src/i18n/locales/en.json | 14 +++++++ frontend/src/i18n/locales/zh-CN.json | 14 +++++++ .../__tests__/ConnectorsPage.tools.test.tsx | 38 +++++++++++++++++++ .../src/v2/connectors/useToolConnectors.ts | 14 +++++++ 4 files changed, 80 insertions(+) diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 93cc27a60..86a9b634b 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -2730,6 +2730,20 @@ "reasonUpstreamToolError": "the provider tool returned an error", "reasonBrokerUnavailable": "the broker was unavailable", "reasonBrokerError": "the broker failed", + "reasonToolDrift": "the provider changed this tool since Commonly checked it", + "reasonToolUnavailable": "the provider no longer offers this tool on this connection", + "reasonToolNotFound": "this tool no longer exists", + "reasonToolChangedSinceApproval": "the tool changed after approval, so it needs asking again", + "reasonArgsChangedSinceApproval": "the arguments changed after approval", + "reasonRepoChangedSinceApproval": "the connected repository changed after approval", + "reasonPrChangedSinceApproval": "the pull request changed after approval", + "reasonPrHeadUnavailable": "the pull request's latest commit could not be read", + "reasonTaskPodMismatch": "this grant works only in its task's pod", + "reasonTaskClaimRequired": "the agent has to claim the bound task first", + "reasonTaskClosed": "the bound task is closed", + "reasonTaskNotFound": "the bound task no longer exists", + "reasonAgentIdentityRequired": "the call did not say which agent made it", + "reasonGrantNotFound": "the grant no longer exists", "owner": "owner", "readInTesting": "read in testing", "readOrWrite": "read, or read and write", diff --git a/frontend/src/i18n/locales/zh-CN.json b/frontend/src/i18n/locales/zh-CN.json index 595f37c7e..76850f1b7 100644 --- a/frontend/src/i18n/locales/zh-CN.json +++ b/frontend/src/i18n/locales/zh-CN.json @@ -2733,6 +2733,20 @@ "reasonUpstreamToolError": "服务商工具返回了错误", "reasonBrokerUnavailable": "代理服务不可用", "reasonBrokerError": "代理服务出错", + "reasonToolDrift": "服务商改动了此工具,等待重新核对", + "reasonToolUnavailable": "服务商在此连接上不再提供此工具", + "reasonToolNotFound": "此工具已不存在", + "reasonToolChangedSinceApproval": "工具在审批后有变动,需要重新审批", + "reasonArgsChangedSinceApproval": "参数在审批后有变动", + "reasonRepoChangedSinceApproval": "连接的仓库在审批后有变动", + "reasonPrChangedSinceApproval": "PR 在审批后有新的提交", + "reasonPrHeadUnavailable": "无法读取 PR 的最新提交", + "reasonTaskPodMismatch": "此授权只能在其任务所在的 Pod 中使用", + "reasonTaskClaimRequired": "智能体需要先认领绑定的任务", + "reasonTaskClosed": "绑定的任务已关闭", + "reasonTaskNotFound": "绑定的任务已不存在", + "reasonAgentIdentityRequired": "调用未带上发起它的智能体身份", + "reasonGrantNotFound": "授权已不存在", "owner": "所有者", "readInTesting": "只读功能测试中", "readOrWrite": "读取,或读取和写入", diff --git a/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx b/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx index 068195762..ed6aca4a1 100644 --- a/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx +++ b/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx @@ -428,6 +428,44 @@ describe('Connectors page: tools', () => { ]); }); + // The broker records any refusal it throws as the line's reason, and these were + // shown as raw codes: a hosted tool that drifted, an approved call whose PR or + // arguments moved, a task-bound grant used off its task (F18, 11-02 prod walk). + it.each([ + ['en', [ + ' · the provider changed this tool since Commonly checked it', + ' · the provider no longer offers this tool on this connection', + ' · the pull request changed after approval', + ' · the agent has to claim the bound task first', + ]], + ['zh-CN', [ + ' · 服务商改动了此工具,等待重新核对', + ' · 服务商在此连接上不再提供此工具', + ' · PR 在审批后有新的提交', + ' · 智能体需要先认领绑定的任务', + ]], + ])('F18: a refusal from a hosted tool, an approval or a task binding reads as words, in %s', async (language, expected) => { + await i18nReady; + await act(async () => { await i18n.changeLanguage(language); }); + try { + const refused = { + ...trail, + calls: ['tool_drift', 'tool_unavailable', 'merge_head_mismatch', 'task_claim_required'].map((reason, i) => ( + { ...trail.calls[0], callId: `r${i}`, outcome: 'refused', reason, at: iso(-120000 * (i + 1)) } + )), + }; + mockTools({ trails: { grant_live: refused } }); + renderPage(); + const drawer = await openTool('GitHub'); + fireEvent.click(drawer.querySelector('.v2-connector-row__selection')); + const aside = await screen.findByRole('complementary'); + await waitFor(() => expect(within(aside).getAllByRole('listitem')).toHaveLength(4)); + expect(Array.from(aside.querySelectorAll('.v2-tools__trail-reason')).map((node) => node.textContent)).toEqual(expected); + } finally { + await act(async () => { await i18n.changeLanguage('en'); }); + } + }); + it('TASK-050: a human member in the audience is named, not called "an agent"', async () => { mockTools({ grants: [{ ...grantLive, effectiveAudience: ['u1', 'a1'] }], seats: { p1: [scout] } }); renderPage(); diff --git a/frontend/src/v2/connectors/useToolConnectors.ts b/frontend/src/v2/connectors/useToolConnectors.ts index 1d0bee736..b705fcc70 100644 --- a/frontend/src/v2/connectors/useToolConnectors.ts +++ b/frontend/src/v2/connectors/useToolConnectors.ts @@ -251,6 +251,20 @@ export const useToolConnectors = ( upstream_tool_error: t('tools.reasonUpstreamToolError', { defaultValue: 'the provider tool returned an error' }), broker_unavailable: t('tools.reasonBrokerUnavailable', { defaultValue: 'the broker was unavailable' }), broker_error: t('tools.reasonBrokerError', { defaultValue: 'the broker failed' }), + tool_drift: t('tools.reasonToolDrift', { defaultValue: 'the provider changed this tool since Commonly checked it' }), + tool_unavailable: t('tools.reasonToolUnavailable', { defaultValue: 'the provider no longer offers this tool on this connection' }), + tool_not_found: t('tools.reasonToolNotFound', { defaultValue: 'this tool no longer exists' }), + definition_digest_mismatch: t('tools.reasonToolChangedSinceApproval', { defaultValue: 'the tool changed after approval, so it needs asking again' }), + args_digest_mismatch: t('tools.reasonArgsChangedSinceApproval', { defaultValue: 'the arguments changed after approval' }), + repo_mismatch: t('tools.reasonRepoChangedSinceApproval', { defaultValue: 'the connected repository changed after approval' }), + merge_head_mismatch: t('tools.reasonPrChangedSinceApproval', { defaultValue: 'the pull request changed after approval' }), + merge_head_unavailable: t('tools.reasonPrHeadUnavailable', { defaultValue: 'the pull request\'s latest commit could not be read' }), + task_pod_mismatch: t('tools.reasonTaskPodMismatch', { defaultValue: 'this grant works only in its task\'s pod' }), + task_claim_required: t('tools.reasonTaskClaimRequired', { defaultValue: 'the agent has to claim the bound task first' }), + task_closed: t('tools.reasonTaskClosed', { defaultValue: 'the bound task is closed' }), + task_not_found: t('tools.reasonTaskNotFound', { defaultValue: 'the bound task no longer exists' }), + agent_identity_required: t('tools.reasonAgentIdentityRequired', { defaultValue: 'the call did not say which agent made it' }), + grant_not_found: t('tools.reasonGrantNotFound', { defaultValue: 'the grant no longer exists' }), }; // Own keys only: a code such as `constructor` or `__proto__` must show as itself, not as an inherited member. return Object.prototype.hasOwnProperty.call(labels, reason) ? labels[reason] : reason; From 8a627dc0a7a1f75f3eff6f42a8f5e46b2be4581a Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sun, 1 Nov 2026 19:12:48 -0800 Subject: [PATCH 2/4] fix(connectors): a tool missing from a connection's list is not a vendor removal Review: `tool_unavailable` means the pinned tool is absent from this connection's tools/list, which can be the owner's own consent, so the label no longer says the provider stopped offering it. `tool_not_found` says the tool is not registered, as the broker does. zh-CN: `tool_drift` matches the en meaning, a changed PR head need not be a new commit, and the missing-identity line reads naturally. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015AKgpQ2pr6xRMhN5mcfoHF --- frontend/src/i18n/locales/en.json | 4 ++-- frontend/src/i18n/locales/zh-CN.json | 10 +++++----- .../src/v2/__tests__/ConnectorsPage.tools.test.tsx | 8 ++++---- frontend/src/v2/connectors/useToolConnectors.ts | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 86a9b634b..f80f775ad 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -2731,8 +2731,8 @@ "reasonBrokerUnavailable": "the broker was unavailable", "reasonBrokerError": "the broker failed", "reasonToolDrift": "the provider changed this tool since Commonly checked it", - "reasonToolUnavailable": "the provider no longer offers this tool on this connection", - "reasonToolNotFound": "this tool no longer exists", + "reasonToolUnavailable": "this connection's tool list does not include this tool", + "reasonToolNotFound": "this tool is not registered with Commonly", "reasonToolChangedSinceApproval": "the tool changed after approval, so it needs asking again", "reasonArgsChangedSinceApproval": "the arguments changed after approval", "reasonRepoChangedSinceApproval": "the connected repository changed after approval", diff --git a/frontend/src/i18n/locales/zh-CN.json b/frontend/src/i18n/locales/zh-CN.json index 76850f1b7..af27afef2 100644 --- a/frontend/src/i18n/locales/zh-CN.json +++ b/frontend/src/i18n/locales/zh-CN.json @@ -2733,19 +2733,19 @@ "reasonUpstreamToolError": "服务商工具返回了错误", "reasonBrokerUnavailable": "代理服务不可用", "reasonBrokerError": "代理服务出错", - "reasonToolDrift": "服务商改动了此工具,等待重新核对", - "reasonToolUnavailable": "服务商在此连接上不再提供此工具", - "reasonToolNotFound": "此工具已不存在", + "reasonToolDrift": "服务商在 Commonly 核对后改动了此工具", + "reasonToolUnavailable": "此连接的工具列表中没有这个工具", + "reasonToolNotFound": "此工具未在 Commonly 中注册", "reasonToolChangedSinceApproval": "工具在审批后有变动,需要重新审批", "reasonArgsChangedSinceApproval": "参数在审批后有变动", "reasonRepoChangedSinceApproval": "连接的仓库在审批后有变动", - "reasonPrChangedSinceApproval": "PR 在审批后有新的提交", + "reasonPrChangedSinceApproval": "PR 在审批后有变动", "reasonPrHeadUnavailable": "无法读取 PR 的最新提交", "reasonTaskPodMismatch": "此授权只能在其任务所在的 Pod 中使用", "reasonTaskClaimRequired": "智能体需要先认领绑定的任务", "reasonTaskClosed": "绑定的任务已关闭", "reasonTaskNotFound": "绑定的任务已不存在", - "reasonAgentIdentityRequired": "调用未带上发起它的智能体身份", + "reasonAgentIdentityRequired": "调用没有说明是哪个智能体发起的", "reasonGrantNotFound": "授权已不存在", "owner": "所有者", "readInTesting": "只读功能测试中", diff --git a/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx b/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx index ed6aca4a1..f155daf66 100644 --- a/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx +++ b/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx @@ -434,14 +434,14 @@ describe('Connectors page: tools', () => { it.each([ ['en', [ ' · the provider changed this tool since Commonly checked it', - ' · the provider no longer offers this tool on this connection', + " · this connection's tool list does not include this tool", ' · the pull request changed after approval', ' · the agent has to claim the bound task first', ]], ['zh-CN', [ - ' · 服务商改动了此工具,等待重新核对', - ' · 服务商在此连接上不再提供此工具', - ' · PR 在审批后有新的提交', + ' · 服务商在 Commonly 核对后改动了此工具', + ' · 此连接的工具列表中没有这个工具', + ' · PR 在审批后有变动', ' · 智能体需要先认领绑定的任务', ]], ])('F18: a refusal from a hosted tool, an approval or a task binding reads as words, in %s', async (language, expected) => { diff --git a/frontend/src/v2/connectors/useToolConnectors.ts b/frontend/src/v2/connectors/useToolConnectors.ts index b705fcc70..ee0861c41 100644 --- a/frontend/src/v2/connectors/useToolConnectors.ts +++ b/frontend/src/v2/connectors/useToolConnectors.ts @@ -252,8 +252,8 @@ export const useToolConnectors = ( broker_unavailable: t('tools.reasonBrokerUnavailable', { defaultValue: 'the broker was unavailable' }), broker_error: t('tools.reasonBrokerError', { defaultValue: 'the broker failed' }), tool_drift: t('tools.reasonToolDrift', { defaultValue: 'the provider changed this tool since Commonly checked it' }), - tool_unavailable: t('tools.reasonToolUnavailable', { defaultValue: 'the provider no longer offers this tool on this connection' }), - tool_not_found: t('tools.reasonToolNotFound', { defaultValue: 'this tool no longer exists' }), + tool_unavailable: t('tools.reasonToolUnavailable', { defaultValue: "this connection's tool list does not include this tool" }), + tool_not_found: t('tools.reasonToolNotFound', { defaultValue: 'this tool is not registered with Commonly' }), definition_digest_mismatch: t('tools.reasonToolChangedSinceApproval', { defaultValue: 'the tool changed after approval, so it needs asking again' }), args_digest_mismatch: t('tools.reasonArgsChangedSinceApproval', { defaultValue: 'the arguments changed after approval' }), repo_mismatch: t('tools.reasonRepoChangedSinceApproval', { defaultValue: 'the connected repository changed after approval' }), From 0a9debfa7707816d8c9e69c75add173f45c23300 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sun, 1 Nov 2026 19:22:20 -0800 Subject: [PATCH 3/4] fix(connectors): approval mismatches are measured from the request, and every label is tested CodeRabbit at 8a627dc0a: the broker snapshots the tool, repository and PR head when approval is requested, not when it is given, and `args_digest_mismatch` is the parked arguments failing their own digest. The four labels now say "after approval was asked for" and "no longer match the ones sent for approval", in en and zh-CN. The F18 test lists all fourteen codes with their en and zh-CN strings, so dropping any one label turns it red (checked with `task_closed`). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015AKgpQ2pr6xRMhN5mcfoHF --- frontend/src/i18n/locales/en.json | 8 ++-- frontend/src/i18n/locales/zh-CN.json | 8 ++-- .../__tests__/ConnectorsPage.tools.test.tsx | 41 +++++++++++-------- .../src/v2/connectors/useToolConnectors.ts | 8 ++-- 4 files changed, 35 insertions(+), 30 deletions(-) diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index f80f775ad..141d007f6 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -2733,10 +2733,10 @@ "reasonToolDrift": "the provider changed this tool since Commonly checked it", "reasonToolUnavailable": "this connection's tool list does not include this tool", "reasonToolNotFound": "this tool is not registered with Commonly", - "reasonToolChangedSinceApproval": "the tool changed after approval, so it needs asking again", - "reasonArgsChangedSinceApproval": "the arguments changed after approval", - "reasonRepoChangedSinceApproval": "the connected repository changed after approval", - "reasonPrChangedSinceApproval": "the pull request changed after approval", + "reasonToolChangedSinceApproval": "the tool changed after approval was asked for, so it needs asking again", + "reasonArgsChangedSinceApproval": "the arguments no longer match the ones sent for approval", + "reasonRepoChangedSinceApproval": "the connected repository changed after approval was asked for", + "reasonPrChangedSinceApproval": "the pull request changed after approval was asked for", "reasonPrHeadUnavailable": "the pull request's latest commit could not be read", "reasonTaskPodMismatch": "this grant works only in its task's pod", "reasonTaskClaimRequired": "the agent has to claim the bound task first", diff --git a/frontend/src/i18n/locales/zh-CN.json b/frontend/src/i18n/locales/zh-CN.json index af27afef2..d1cff337e 100644 --- a/frontend/src/i18n/locales/zh-CN.json +++ b/frontend/src/i18n/locales/zh-CN.json @@ -2736,10 +2736,10 @@ "reasonToolDrift": "服务商在 Commonly 核对后改动了此工具", "reasonToolUnavailable": "此连接的工具列表中没有这个工具", "reasonToolNotFound": "此工具未在 Commonly 中注册", - "reasonToolChangedSinceApproval": "工具在审批后有变动,需要重新审批", - "reasonArgsChangedSinceApproval": "参数在审批后有变动", - "reasonRepoChangedSinceApproval": "连接的仓库在审批后有变动", - "reasonPrChangedSinceApproval": "PR 在审批后有变动", + "reasonToolChangedSinceApproval": "工具在申请审批后有变动,需要重新审批", + "reasonArgsChangedSinceApproval": "参数与提交审批时的不一致", + "reasonRepoChangedSinceApproval": "连接的仓库在申请审批后有变动", + "reasonPrChangedSinceApproval": "PR 在申请审批后有变动", "reasonPrHeadUnavailable": "无法读取 PR 的最新提交", "reasonTaskPodMismatch": "此授权只能在其任务所在的 Pod 中使用", "reasonTaskClaimRequired": "智能体需要先认领绑定的任务", diff --git a/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx b/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx index f155daf66..d1b90d710 100644 --- a/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx +++ b/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx @@ -431,27 +431,31 @@ describe('Connectors page: tools', () => { // The broker records any refusal it throws as the line's reason, and these were // shown as raw codes: a hosted tool that drifted, an approved call whose PR or // arguments moved, a task-bound grant used off its task (F18, 11-02 prod walk). - it.each([ - ['en', [ - ' · the provider changed this tool since Commonly checked it', - " · this connection's tool list does not include this tool", - ' · the pull request changed after approval', - ' · the agent has to claim the bound task first', - ]], - ['zh-CN', [ - ' · 服务商在 Commonly 核对后改动了此工具', - ' · 此连接的工具列表中没有这个工具', - ' · PR 在审批后有变动', - ' · 智能体需要先认领绑定的任务', - ]], - ])('F18: a refusal from a hosted tool, an approval or a task binding reads as words, in %s', async (language, expected) => { + // Every code is listed, so dropping any one label turns this red. + const REFUSAL_LABELS = [ + ['tool_drift', 'the provider changed this tool since Commonly checked it', '服务商在 Commonly 核对后改动了此工具'], + ['tool_unavailable', 'this connection\'s tool list does not include this tool', '此连接的工具列表中没有这个工具'], + ['tool_not_found', 'this tool is not registered with Commonly', '此工具未在 Commonly 中注册'], + ['definition_digest_mismatch', 'the tool changed after approval was asked for, so it needs asking again', '工具在申请审批后有变动,需要重新审批'], + ['args_digest_mismatch', 'the arguments no longer match the ones sent for approval', '参数与提交审批时的不一致'], + ['repo_mismatch', 'the connected repository changed after approval was asked for', '连接的仓库在申请审批后有变动'], + ['merge_head_mismatch', 'the pull request changed after approval was asked for', 'PR 在申请审批后有变动'], + ['merge_head_unavailable', 'the pull request\'s latest commit could not be read', '无法读取 PR 的最新提交'], + ['task_pod_mismatch', 'this grant works only in its task\'s pod', '此授权只能在其任务所在的 Pod 中使用'], + ['task_claim_required', 'the agent has to claim the bound task first', '智能体需要先认领绑定的任务'], + ['task_closed', 'the bound task is closed', '绑定的任务已关闭'], + ['task_not_found', 'the bound task no longer exists', '绑定的任务已不存在'], + ['agent_identity_required', 'the call did not say which agent made it', '调用没有说明是哪个智能体发起的'], + ['grant_not_found', 'the grant no longer exists', '授权已不存在'], + ]; + it.each([['en', 1], ['zh-CN', 2]])('F18: every refusal the broker records reads as words, in %s', async (language, column) => { await i18nReady; await act(async () => { await i18n.changeLanguage(language); }); try { const refused = { ...trail, - calls: ['tool_drift', 'tool_unavailable', 'merge_head_mismatch', 'task_claim_required'].map((reason, i) => ( - { ...trail.calls[0], callId: `r${i}`, outcome: 'refused', reason, at: iso(-120000 * (i + 1)) } + calls: REFUSAL_LABELS.map(([reason], i) => ( + { ...trail.calls[0], callId: `r${i}`, outcome: 'refused', reason, at: iso(-60000 * (i + 1)) } )), }; mockTools({ trails: { grant_live: refused } }); @@ -459,8 +463,9 @@ describe('Connectors page: tools', () => { const drawer = await openTool('GitHub'); fireEvent.click(drawer.querySelector('.v2-connector-row__selection')); const aside = await screen.findByRole('complementary'); - await waitFor(() => expect(within(aside).getAllByRole('listitem')).toHaveLength(4)); - expect(Array.from(aside.querySelectorAll('.v2-tools__trail-reason')).map((node) => node.textContent)).toEqual(expected); + await waitFor(() => expect(within(aside).getAllByRole('listitem')).toHaveLength(REFUSAL_LABELS.length)); + expect(Array.from(aside.querySelectorAll('.v2-tools__trail-reason')).map((node) => node.textContent)) + .toEqual(REFUSAL_LABELS.map((row) => ` · ${row[column]}`)); } finally { await act(async () => { await i18n.changeLanguage('en'); }); } diff --git a/frontend/src/v2/connectors/useToolConnectors.ts b/frontend/src/v2/connectors/useToolConnectors.ts index ee0861c41..a643da089 100644 --- a/frontend/src/v2/connectors/useToolConnectors.ts +++ b/frontend/src/v2/connectors/useToolConnectors.ts @@ -254,10 +254,10 @@ export const useToolConnectors = ( tool_drift: t('tools.reasonToolDrift', { defaultValue: 'the provider changed this tool since Commonly checked it' }), tool_unavailable: t('tools.reasonToolUnavailable', { defaultValue: "this connection's tool list does not include this tool" }), tool_not_found: t('tools.reasonToolNotFound', { defaultValue: 'this tool is not registered with Commonly' }), - definition_digest_mismatch: t('tools.reasonToolChangedSinceApproval', { defaultValue: 'the tool changed after approval, so it needs asking again' }), - args_digest_mismatch: t('tools.reasonArgsChangedSinceApproval', { defaultValue: 'the arguments changed after approval' }), - repo_mismatch: t('tools.reasonRepoChangedSinceApproval', { defaultValue: 'the connected repository changed after approval' }), - merge_head_mismatch: t('tools.reasonPrChangedSinceApproval', { defaultValue: 'the pull request changed after approval' }), + definition_digest_mismatch: t('tools.reasonToolChangedSinceApproval', { defaultValue: 'the tool changed after approval was asked for, so it needs asking again' }), + args_digest_mismatch: t('tools.reasonArgsChangedSinceApproval', { defaultValue: 'the arguments no longer match the ones sent for approval' }), + repo_mismatch: t('tools.reasonRepoChangedSinceApproval', { defaultValue: 'the connected repository changed after approval was asked for' }), + merge_head_mismatch: t('tools.reasonPrChangedSinceApproval', { defaultValue: 'the pull request changed after approval was asked for' }), merge_head_unavailable: t('tools.reasonPrHeadUnavailable', { defaultValue: 'the pull request\'s latest commit could not be read' }), task_pod_mismatch: t('tools.reasonTaskPodMismatch', { defaultValue: 'this grant works only in its task\'s pod' }), task_claim_required: t('tools.reasonTaskClaimRequired', { defaultValue: 'the agent has to claim the bound task first' }), From 6b9ef8291daad4be29a914db33d013cad3cee3cc Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sun, 1 Nov 2026 19:35:37 -0800 Subject: [PATCH 4/4] fix(connectors): task_closed says the task closed after the grant was issued The broker raises task_closed for a task that is done now and for one whose grant epoch moved, i.e. closed and reopened since the grant was issued. "The bound task is closed" was wrong for the second. A grant can only be issued while its task is open, so "closed after this grant was issued" covers both. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015AKgpQ2pr6xRMhN5mcfoHF --- frontend/src/i18n/locales/en.json | 2 +- frontend/src/i18n/locales/zh-CN.json | 2 +- frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx | 2 +- frontend/src/v2/connectors/useToolConnectors.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 141d007f6..895e378fc 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -2740,7 +2740,7 @@ "reasonPrHeadUnavailable": "the pull request's latest commit could not be read", "reasonTaskPodMismatch": "this grant works only in its task's pod", "reasonTaskClaimRequired": "the agent has to claim the bound task first", - "reasonTaskClosed": "the bound task is closed", + "reasonTaskClosed": "the bound task closed after this grant was issued", "reasonTaskNotFound": "the bound task no longer exists", "reasonAgentIdentityRequired": "the call did not say which agent made it", "reasonGrantNotFound": "the grant no longer exists", diff --git a/frontend/src/i18n/locales/zh-CN.json b/frontend/src/i18n/locales/zh-CN.json index d1cff337e..cf87a12ec 100644 --- a/frontend/src/i18n/locales/zh-CN.json +++ b/frontend/src/i18n/locales/zh-CN.json @@ -2743,7 +2743,7 @@ "reasonPrHeadUnavailable": "无法读取 PR 的最新提交", "reasonTaskPodMismatch": "此授权只能在其任务所在的 Pod 中使用", "reasonTaskClaimRequired": "智能体需要先认领绑定的任务", - "reasonTaskClosed": "绑定的任务已关闭", + "reasonTaskClosed": "绑定的任务在授权签发后关闭过", "reasonTaskNotFound": "绑定的任务已不存在", "reasonAgentIdentityRequired": "调用没有说明是哪个智能体发起的", "reasonGrantNotFound": "授权已不存在", diff --git a/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx b/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx index d1b90d710..7ab653dd2 100644 --- a/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx +++ b/frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx @@ -443,7 +443,7 @@ describe('Connectors page: tools', () => { ['merge_head_unavailable', 'the pull request\'s latest commit could not be read', '无法读取 PR 的最新提交'], ['task_pod_mismatch', 'this grant works only in its task\'s pod', '此授权只能在其任务所在的 Pod 中使用'], ['task_claim_required', 'the agent has to claim the bound task first', '智能体需要先认领绑定的任务'], - ['task_closed', 'the bound task is closed', '绑定的任务已关闭'], + ['task_closed', 'the bound task closed after this grant was issued', '绑定的任务在授权签发后关闭过'], ['task_not_found', 'the bound task no longer exists', '绑定的任务已不存在'], ['agent_identity_required', 'the call did not say which agent made it', '调用没有说明是哪个智能体发起的'], ['grant_not_found', 'the grant no longer exists', '授权已不存在'], diff --git a/frontend/src/v2/connectors/useToolConnectors.ts b/frontend/src/v2/connectors/useToolConnectors.ts index a643da089..50a957f9b 100644 --- a/frontend/src/v2/connectors/useToolConnectors.ts +++ b/frontend/src/v2/connectors/useToolConnectors.ts @@ -261,7 +261,7 @@ export const useToolConnectors = ( merge_head_unavailable: t('tools.reasonPrHeadUnavailable', { defaultValue: 'the pull request\'s latest commit could not be read' }), task_pod_mismatch: t('tools.reasonTaskPodMismatch', { defaultValue: 'this grant works only in its task\'s pod' }), task_claim_required: t('tools.reasonTaskClaimRequired', { defaultValue: 'the agent has to claim the bound task first' }), - task_closed: t('tools.reasonTaskClosed', { defaultValue: 'the bound task is closed' }), + task_closed: t('tools.reasonTaskClosed', { defaultValue: 'the bound task closed after this grant was issued' }), task_not_found: t('tools.reasonTaskNotFound', { defaultValue: 'the bound task no longer exists' }), agent_identity_required: t('tools.reasonAgentIdentityRequired', { defaultValue: 'the call did not say which agent made it' }), grant_not_found: t('tools.reasonGrantNotFound', { defaultValue: 'the grant no longer exists' }),