Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions frontend/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "this connection's tool list does not include this tool",
"reasonToolNotFound": "this tool is not registered with Commonly",
"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",
"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",
"owner": "owner",
"readInTesting": "read in testing",
"readOrWrite": "read, or read and write",
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/i18n/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2733,6 +2733,20 @@
"reasonUpstreamToolError": "服务商工具返回了错误",
"reasonBrokerUnavailable": "代理服务不可用",
"reasonBrokerError": "代理服务出错",
"reasonToolDrift": "服务商在 Commonly 核对后改动了此工具",
"reasonToolUnavailable": "此连接的工具列表中没有这个工具",
"reasonToolNotFound": "此工具未在 Commonly 中注册",
"reasonToolChangedSinceApproval": "工具在申请审批后有变动,需要重新审批",
"reasonArgsChangedSinceApproval": "参数与提交审批时的不一致",
"reasonRepoChangedSinceApproval": "连接的仓库在申请审批后有变动",
"reasonPrChangedSinceApproval": "PR 在申请审批后有变动",
"reasonPrHeadUnavailable": "无法读取 PR 的最新提交",
"reasonTaskPodMismatch": "此授权只能在其任务所在的 Pod 中使用",
"reasonTaskClaimRequired": "智能体需要先认领绑定的任务",
"reasonTaskClosed": "绑定的任务在授权签发后关闭过",
"reasonTaskNotFound": "绑定的任务已不存在",
"reasonAgentIdentityRequired": "调用没有说明是哪个智能体发起的",
"reasonGrantNotFound": "授权已不存在",
"owner": "所有者",
"readInTesting": "只读功能测试中",
"readOrWrite": "读取,或读取和写入",
Expand Down
43 changes: 43 additions & 0 deletions frontend/src/v2/__tests__/ConnectorsPage.tools.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,49 @@ 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).
// 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 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', '授权已不存在'],
];
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: REFUSAL_LABELS.map(([reason], i) => (
{ ...trail.calls[0], callId: `r${i}`, outcome: 'refused', reason, at: iso(-60000 * (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(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'); });
}
});

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();
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/v2/connectors/useToolConnectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: "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 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' }),
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' }),
};
// 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;
Expand Down
Loading