diff --git a/core/http/react-ui/e2e/agents-fixtures.js b/core/http/react-ui/e2e/agents-fixtures.js index 1a3ee56060..b0f1759f97 100644 --- a/core/http/react-ui/e2e/agents-fixtures.js +++ b/core/http/react-ui/e2e/agents-fixtures.js @@ -101,7 +101,7 @@ const BODIES = { citations: 'Cite every claim.\n\n1. Number the sources.\n2. Lis export const DRAFT_TOOLS = { builtins: [ { group: 'files', tools: ['read_file'], off: false, usable: true, provider: 'builtin', providers: { read_file: 'builtin' }, title: 'Your files', description: 'The model can list, read, write, edit, move, delete and search your files, and read documents.', when_off: 'The model cannot see or change your files.' }, - { group: 'web', tools: ['web_search', 'web_fetch'], off: false, usable: true, provider: 'builtin', providers: { web_search: 'builtin', web_fetch: 'builtin' }, title: 'Web', description: 'The model can search the web and read a public page by its address.', when_off: 'The model cannot look anything up online.' }, + { group: 'web', tools: ['web_search', 'web_fetch'], off: false, usable: true, provider: 'builtin', providers: { web_search: 'builtin', web_fetch: 'builtin' }, title: 'Look things up online', description: 'The model can search the web and read a public page by its address.', when_off: 'The model cannot look anything up online.' }, { group: 'saved_agents', tools: ['list_agents'], off: true, opt_in: true, usable: true, provider: 'builtin', providers: { list_agents: 'builtin' }, title: 'Saved agents', description: 'The model can list your saved agents and start one as a sub-agent.', when_off: 'The model cannot see or start your saved agents.' }, { group: 'triggers', tools: ['propose_trigger'], off: false, usable: true, provider: 'builtin', providers: { propose_trigger: 'builtin' }, title: 'Triggers', description: 'The model can propose, list, change and delete triggers; a new one waits for your confirmation.', when_off: 'The model cannot create or manage triggers.' }, { group: 'changes', tools: ['propose_change'], off: false, usable: true, provider: 'builtin', providers: { propose_change: 'builtin' }, title: 'Memory and profile changes', description: 'The model can propose an edit to your memory notes; nothing changes until you confirm.', when_off: 'The model cannot propose edits to your memory.' }, diff --git a/core/http/react-ui/e2e/chats-triggers-group.spec.js b/core/http/react-ui/e2e/chats-triggers-group.spec.js index d103c524e0..3f27c2d579 100644 --- a/core/http/react-ui/e2e/chats-triggers-group.spec.js +++ b/core/http/react-ui/e2e/chats-triggers-group.spec.js @@ -66,7 +66,7 @@ test.describe('Chat tools menu: the Triggers group', () => { await open(page) await page.getByTestId('chat-tools-none').click() await expect(sw(page, 'Triggers')).toHaveAttribute('aria-checked', 'false') - await expect(sw(page, 'Web')).toHaveAttribute('aria-checked', 'false') + await expect(sw(page, 'Look things up online')).toHaveAttribute('aria-checked', 'false') await expect.poll(() => state.puts).toEqual([{ off: ['triggers', 'web'] }]) await page.getByTestId('chat-tools-all').click() await expect(sw(page, 'Triggers')).toHaveAttribute('aria-checked', 'true') diff --git a/core/http/react-ui/e2e/chats-ui.spec.js b/core/http/react-ui/e2e/chats-ui.spec.js index 8a891736f5..6c50788e80 100644 --- a/core/http/react-ui/e2e/chats-ui.spec.js +++ b/core/http/react-ui/e2e/chats-ui.spec.js @@ -631,7 +631,7 @@ test.describe('Chat tools menu: MCP', () => { let web = { group: 'web', tools: ['web_search', 'web_fetch'], off: false, provider: 'builtin', providers: { web_search: 'builtin', web_fetch: 'builtin' } } await page.route('**/api/chats/c1/addons', route => route.fulfill({ json: { addons: [] } })) await page.route('**/api/chats/c1/tools', route => route.fulfill({ json: { builtins: [web], addons: [], servers: [], connectors: [], off: [] } })) - const row = () => page.getByTestId('chat-tools-item').filter({ has: page.getByRole('switch', { name: 'Web' }) }) + const row = () => page.getByTestId('chat-tools-item').filter({ has: page.getByRole('switch', { name: 'Look things up online' }) }) const open = async () => { await page.goto('/app/chats/c1') await page.getByTestId('chat-tools-button').click() @@ -685,7 +685,7 @@ test.describe('Chat tools menu: built-in groups', () => { }) await page.goto('/app/chats/c1') await page.getByTestId('chat-tools-button').click() - await expect(page.getByRole('switch', { name: 'Web' })).toBeChecked() + await expect(page.getByRole('switch', { name: 'Look things up online' })).toBeChecked() await expect(page.getByRole('switch', { name: 'Saved agents' })).not.toBeChecked() await page.getByRole('switch', { name: 'Saved agents' }).check() await expect.poll(() => calls.at(-1)).toEqual({ off: [], on: ['saved_agents'] }) @@ -765,7 +765,7 @@ test.describe('Chat tools menu: every group of built-in tools', () => { await stubGroups(page) await open(page) const names = await page.getByTestId('chat-tools-group-builtins').locator('.swl-row__name').allTextContents() - expect(names).toEqual(['Run commands', 'Your files', 'Web', 'Images and audio', 'Collections', 'Sub-agents', 'Triggers']) + expect(names).toEqual(['Run commands', 'Your files', 'Look things up online', 'Images and audio', 'Collections', 'Sub-agents', 'Triggers']) await expect(row(page, 'Run commands').getByTestId('chat-tools-note')).toHaveText(['Served by add-on sandbox', 'Commands run isolated']) await expect(row(page, 'Your files')).toHaveAttribute('title', 'list_files, read_file, write_file ยท built-in') await expect(sw(page, 'Collections')).toBeDisabled() @@ -791,8 +791,8 @@ test.describe('Chat tools menu: every group of built-in tools', () => { const n = await rows.count() expect(n).toBe(10) for (let i = 0; i < n; i++) await expect(rows.nth(i).getByTestId('chat-tools-blurb')).not.toBeEmpty() - await sw(page, 'Web').click() - await expect(row(page, 'Web')).toContainText('The model cannot look anything up online.') + await sw(page, 'Look things up online').click() + await expect(row(page, 'Look things up online')).toContainText('The model cannot look anything up online.') }) test('switching a group off and on sends the list of groups that are off', async ({ page }) => { @@ -908,7 +908,7 @@ test.describe('Chat tools menu: switches and bulk actions', () => { await expect(manual).toHaveAttribute('aria-checked', 'false') await expect(manual).toHaveAccessibleDescription('the model does not use this server unless a saved agent names it') // The add-on that serves the web tools is a chip next to the name. - const web = page.getByTestId('chat-tools-item').filter({ has: sw(page, 'Web') }) + const web = page.getByTestId('chat-tools-item').filter({ has: sw(page, 'Look things up online') }) await expect(web.getByTestId('chat-tools-note')).toHaveText('Served by add-on searx') await expect(web.locator('.ui-chip')).toBeVisible() // The opt-in row says that Select all leaves it. diff --git a/core/http/react-ui/e2e/home-composer.spec.js b/core/http/react-ui/e2e/home-composer.spec.js index 3def8241f1..7a82752011 100644 --- a/core/http/react-ui/e2e/home-composer.spec.js +++ b/core/http/react-ui/e2e/home-composer.spec.js @@ -148,7 +148,7 @@ test.describe('Home composer', () => { await ready(page) await page.getByTestId('chat-tools-button').click() const tools = page.getByTestId('chat-tools-menu') - for (const name of ['Your files', 'Web', 'Images and audio', 'Sub-agents']) { + for (const name of ['Your files', 'Look things up online', 'Images and audio', 'Sub-agents']) { await expect(tools.getByRole('switch', { name, exact: true })).toHaveAttribute('aria-checked', 'true') } await tools.getByRole('switch', { name: 'Your files', exact: true }).click() diff --git a/core/http/routes/studio_web_test.go b/core/http/routes/studio_web_test.go index 051f8d504b..5f9886df35 100644 --- a/core/http/routes/studio_web_test.go +++ b/core/http/routes/studio_web_test.go @@ -65,7 +65,17 @@ var _ = Describe("Chats built-in web tools endpoints", func() { Expect(panel.Code).To(Equal(http.StatusOK), panel.Body.String()) // The panel lists more groups (shell, saved agents): the order is the // registry's, so the spec finds the web group by name. - Expect(groupOf(decodeJSON(panel), "web")).To(Equal(map[string]any{ + web := groupOf(decodeJSON(panel), "web") + // The picker texts come from the group info; the spec pins the title + // and only requires the other two to be present, so rewording the + // description does not break the routing check. + Expect(web).To(HaveKeyWithValue("title", "Look things up online")) + Expect(web["description"]).NotTo(BeEmpty()) + Expect(web["when_off"]).NotTo(BeEmpty()) + delete(web, "title") + delete(web, "description") + delete(web, "when_off") + Expect(web).To(Equal(map[string]any{ "group": "web", "tools": []any{"web_search", "web_fetch"}, "off": false, "usable": true, "provider": "builtin", "providers": map[string]any{"web_search": "builtin", "web_fetch": "builtin"}, })) diff --git a/core/schema/chats.go b/core/schema/chats.go index 29e15f62fb..911e5535b4 100644 --- a/core/schema/chats.go +++ b/core/schema/chats.go @@ -1664,7 +1664,7 @@ type ChatsBuiltinGroup struct { // Title and Description say what the group is and what the model can do // when its switch is on; WhenOff says what it cannot do when it is off. // They are English; the interface may translate them by group. - Title string `json:"title,omitempty" example:"Web"` + Title string `json:"title,omitempty" example:"Look things up online"` Description string `json:"description,omitempty" example:"The model can search the web and read a public page by its address."` WhenOff string `json:"when_off,omitempty" example:"The model cannot look anything up online."` } diff --git a/core/services/studio/groupinfo.go b/core/services/studio/groupinfo.go index deea9fa70f..f07ccde5d4 100644 --- a/core/services/studio/groupinfo.go +++ b/core/services/studio/groupinfo.go @@ -24,7 +24,7 @@ func (s *Service) describeGroups() { WhenOff: "The model cannot see or change your files.", }, builtins.GroupWeb: { - Title: "Web", + Title: "Look things up online", Description: "The model can search the web and read a public page by its address. Addresses inside your network are refused unless an administrator allows them.", WhenOff: "The model cannot look anything up online.", },