From 10b2c1180c7ef306d93db6003de9a790e34ecba5 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Fri, 23 Oct 2026 20:15:05 -0700 Subject: [PATCH 1/2] Explain unavailable Policy saves Co-authored-by: tern Agent-Model: codex/gpt-6-sol/medium --- frontend/src/i18n/locales/en.json | 1 + frontend/src/i18n/locales/zh-CN.json | 1 + .../src/v2/__tests__/V2AgentPolicy.test.tsx | 21 +++++++++++++++++++ frontend/src/v2/agents/V2AgentPolicy.tsx | 5 ++++- 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 5824c870cb..6d79165cc4 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -2447,6 +2447,7 @@ "turnsPerDay": "Hosted turns per day", "userRunCeiling": "Runs per day", "contextInvalid": "Check the context limits.", + "profileUnavailable": "Policy is unavailable for this installation. No changes were saved.", "loadError": "Could not load policy data.", "saveError": "Could not save changes.", "saved": "Saved" diff --git a/frontend/src/i18n/locales/zh-CN.json b/frontend/src/i18n/locales/zh-CN.json index a74df2e5d7..9984d3e196 100644 --- a/frontend/src/i18n/locales/zh-CN.json +++ b/frontend/src/i18n/locales/zh-CN.json @@ -2438,6 +2438,7 @@ "turnsPerDay": "托管运行次数/天", "userRunCeiling": "运行次数/天", "contextInvalid": "请检查上下文限制。", + "profileUnavailable": "此安装的策略不可用。更改未保存。", "loadError": "无法加载策略数据。", "saveError": "无法保存更改。", "saved": "已保存" diff --git a/frontend/src/v2/__tests__/V2AgentPolicy.test.tsx b/frontend/src/v2/__tests__/V2AgentPolicy.test.tsx index 69e4ef420a..2ea11e3098 100644 --- a/frontend/src/v2/__tests__/V2AgentPolicy.test.tsx +++ b/frontend/src/v2/__tests__/V2AgentPolicy.test.tsx @@ -53,6 +53,27 @@ it('writes approval and context policy through the shared settings hook', async })); }); +it('saves an edit immediately on the first click and confirms it', async () => { + renderPolicy(); + fireEvent.change(screen.getByLabelText('Allowed tools'), { target: { value: 'commonly, Read' } }); + fireEvent.click(screen.getByRole('button', { name: 'Save policy' })); + + expect(update).toHaveBeenCalledTimes(1); + expect(update).toHaveBeenCalledWith(expect.objectContaining({ + toolPolicy: { allowed: ['commonly', 'Read'], blocked: [], requireApproval: ['Bash'] }, + })); + expect(await screen.findByRole('status')).toHaveTextContent('Saved'); +}); + +it('explains why an installation without a profile cannot save policy', async () => { + renderPolicy({ ...installation, profile: null }); + fireEvent.change(screen.getByLabelText('Allowed tools'), { target: { value: 'Read' } }); + fireEvent.click(screen.getByRole('button', { name: 'Save policy' })); + + expect(update).not.toHaveBeenCalled(); + expect(await screen.findByRole('alert')).toHaveTextContent('No changes were saved'); +}); + it('writes only the chosen trust mode and edits memory with its revision', async () => { renderPolicy(); await screen.findByDisplayValue('Original'); diff --git a/frontend/src/v2/agents/V2AgentPolicy.tsx b/frontend/src/v2/agents/V2AgentPolicy.tsx index 78720c4529..d58fe06785 100644 --- a/frontend/src/v2/agents/V2AgentPolicy.tsx +++ b/frontend/src/v2/agents/V2AgentPolicy.tsx @@ -93,6 +93,9 @@ const V2AgentPolicy: React.FC = ({ agentName, instanceId, installation, u }, [agentName, instanceId, memoryUrl, t]); const savePolicy = async () => { + if (!installation?.profile) { + setFeedback({ group: 'policy', kind: 'error', text: t('agentPolicy.profileUnavailable') }); return; + } if (!Number.isInteger(maxTokens) || maxTokens < 1 || !Number.isInteger(compactionThreshold) || compactionThreshold < 1 || compactionThreshold > maxTokens || !Number.isInteger(summaryHours) || summaryHours < 1) { @@ -168,7 +171,7 @@ const V2AgentPolicy: React.FC = ({ agentName, instanceId, installation, u - + {groupFeedback('policy')} {canSetTrust &&
From 769774381b5cc7da4c1df7e4d5b4f1924c60e723 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Fri, 23 Oct 2026 20:19:32 -0700 Subject: [PATCH 2/2] Show Policy availability before editing Co-authored-by: tern Agent-Model: codex/gpt-6-sol/medium --- frontend/src/i18n/locales/en.json | 3 ++- frontend/src/i18n/locales/zh-CN.json | 3 ++- frontend/src/v2/__tests__/V2AgentPolicy.test.tsx | 3 ++- frontend/src/v2/agents/V2AgentPolicy.tsx | 5 ++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 6d79165cc4..ea49991968 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -2447,7 +2447,8 @@ "turnsPerDay": "Hosted turns per day", "userRunCeiling": "Runs per day", "contextInvalid": "Check the context limits.", - "profileUnavailable": "Policy is unavailable for this installation. No changes were saved.", + "profileUnavailable": "This agent's policy can't be changed in this pod yet.", + "profileUnavailableSave": "This agent's policy can't be changed in this pod yet, so nothing was saved.", "loadError": "Could not load policy data.", "saveError": "Could not save changes.", "saved": "Saved" diff --git a/frontend/src/i18n/locales/zh-CN.json b/frontend/src/i18n/locales/zh-CN.json index 9984d3e196..dff99eddb5 100644 --- a/frontend/src/i18n/locales/zh-CN.json +++ b/frontend/src/i18n/locales/zh-CN.json @@ -2438,7 +2438,8 @@ "turnsPerDay": "托管运行次数/天", "userRunCeiling": "运行次数/天", "contextInvalid": "请检查上下文限制。", - "profileUnavailable": "此安装的策略不可用。更改未保存。", + "profileUnavailable": "此智能体在这个 Pod 中的策略暂时无法修改。", + "profileUnavailableSave": "此智能体在这个 Pod 中的策略暂时无法修改,更改未保存。", "loadError": "无法加载策略数据。", "saveError": "无法保存更改。", "saved": "已保存" diff --git a/frontend/src/v2/__tests__/V2AgentPolicy.test.tsx b/frontend/src/v2/__tests__/V2AgentPolicy.test.tsx index 2ea11e3098..a14de9f2b7 100644 --- a/frontend/src/v2/__tests__/V2AgentPolicy.test.tsx +++ b/frontend/src/v2/__tests__/V2AgentPolicy.test.tsx @@ -67,11 +67,12 @@ it('saves an edit immediately on the first click and confirms it', async () => { it('explains why an installation without a profile cannot save policy', async () => { renderPolicy({ ...installation, profile: null }); + expect(screen.getByRole('alert')).toHaveTextContent("This agent's policy can't be changed in this pod yet."); fireEvent.change(screen.getByLabelText('Allowed tools'), { target: { value: 'Read' } }); fireEvent.click(screen.getByRole('button', { name: 'Save policy' })); expect(update).not.toHaveBeenCalled(); - expect(await screen.findByRole('alert')).toHaveTextContent('No changes were saved'); + expect(await screen.findByRole('alert')).toHaveTextContent('nothing was saved'); }); it('writes only the chosen trust mode and edits memory with its revision', async () => { diff --git a/frontend/src/v2/agents/V2AgentPolicy.tsx b/frontend/src/v2/agents/V2AgentPolicy.tsx index d58fe06785..debfe64854 100644 --- a/frontend/src/v2/agents/V2AgentPolicy.tsx +++ b/frontend/src/v2/agents/V2AgentPolicy.tsx @@ -94,7 +94,7 @@ const V2AgentPolicy: React.FC = ({ agentName, instanceId, installation, u const savePolicy = async () => { if (!installation?.profile) { - setFeedback({ group: 'policy', kind: 'error', text: t('agentPolicy.profileUnavailable') }); return; + setFeedback({ group: 'policy', kind: 'error', text: t('agentPolicy.profileUnavailableSave') }); return; } if (!Number.isInteger(maxTokens) || maxTokens < 1 || !Number.isInteger(compactionThreshold) || compactionThreshold < 1 || compactionThreshold > maxTokens @@ -152,6 +152,9 @@ const V2AgentPolicy: React.FC = ({ agentName, instanceId, installation, u return

{t('agentPolicy.title')}

+ {!installation?.profile && feedback?.group !== 'policy' && ( +

{t('agentPolicy.profileUnavailable')}

+ )}

{t('agentPolicy.approvals')}

{t('agentPolicy.commaHint')}