diff --git a/core/http/react-ui/e2e/agents-effective.spec.js b/core/http/react-ui/e2e/agents-effective.spec.js new file mode 100644 index 0000000000..876db54396 --- /dev/null +++ b/core/http/react-ui/e2e/agents-effective.spec.js @@ -0,0 +1,236 @@ +import { test, expect } from './coverage-fixtures.js' +import { installAgents, AGENTS } from './agents-fixtures.js' + +// The agent editor, part 3: the Effective view (what the agent can do right +// now, from the form as it is, with the reason and the fix of anything +// blocked), Try it (a test chat with the unsaved settings) and the More menu. +// The API is stubbed. + +const SHOTS = process.env.EDITOR_SHOTS || '' +async function shot(page, name, options = {}) { + if (!SHOTS) return + const width = page.viewportSize().width + for (const theme of ['light', 'dark']) { + await page.evaluate((t) => document.documentElement.setAttribute('data-theme', t), theme) + await page.waitForTimeout(400) + await page.screenshot({ path: `${SHOTS}/${name}-${theme}-${width}.png`, ...options }) + } + await page.evaluate(() => document.documentElement.setAttribute('data-theme', 'light')) +} + +const eff = (page) => page.getByTestId('agent-effective') +const line = (page, id) => page.locator(`[data-testid=agent-effective-line][data-line="${id}"]`) +const memory = (page, enabled) => page.route('**/api/chats/memory', route => route.fulfill({ + json: { enabled, enabled_set: true, save_mode: 'ask', messaging_save: 'ask', save_mode_set: false, provider: 'builtin', available: true }, +})) + +const VIEW = { + binding: 'b1', + subjects: [ + { + id: 'anyone', title: 'Anyone on the list', + decisions: [ + { capability: 'files.upload', allowed: true }, + { capability: 'memory.write', allowed: false, code: 'agent_permission_off', blocked_by: 'agent', message: 'The agent has not been given this right.', fix: { kind: 'open_agent', target: 'a2', field: 'memory.write' } }, + { capability: 'triggers.run', allowed: false, code: 'connection_permission_off', blocked_by: 'connection', message: 'The connection does not allow this.', fix: { kind: 'open_connection', target: 'caps', field: 'triggers.run' } }, + ], + }, + ], + recent: [], preview: true, +} + +test.describe('Effective view', () => { + test('follows the form as it is, before anything is saved', async ({ page }) => { + const s = await installAgents(page) + await memory(page, true) + await page.goto('/app/agents/new') + await expect(eff(page)).toBeVisible() + await expect(line(page, 'tools')).toContainText('Your files') + await expect(page.getByTestId('agent-effective-summary')).toContainText('Nothing is blocked') + await expect(line(page, 'memory')).toContainText('Reads your notes and its own') + await expect(line(page, 'memory-level')).toContainText('waits for you') + await expect(line(page, 'knowledge')).toContainText('No knowledge collections') + await expect(line(page, 'connections')).toContainText('Save the agent') + + await page.getByTestId('agent-tools-panel').getByRole('switch', { name: /Your files/ }).click() + await expect(line(page, 'tools')).not.toContainText('Your files') + await page.getByRole('combobox', { name: 'Collections +' }).fill('handbook') + await page.getByRole('combobox', { name: 'Collections +' }).press('Enter') + await expect(line(page, 'knowledge')).toContainText('handbook') + await page.getByTestId('agent-memory-none').click() + await expect(line(page, 'memory')).toContainText('Keeps and reads no notes') + await expect(page.getByTestId('agent-effective-unsaved')).toBeVisible() + expect(s.calls.some(c => c.method === 'POST' || c.method === 'PUT')).toBe(false) + }) + + test('says memory is off when the person turned it off in Settings, and links to the fix', async ({ page }) => { + await installAgents(page) + await memory(page, false) + await page.goto('/app/agents/new') + const row = line(page, 'memory-off') + await expect(row).toContainText('Memory is off in your Settings') + await expect(row).toHaveAttribute('data-code', 'memory_off_user') + await expect(row.getByTestId('agent-effective-fix')).toHaveAttribute('href', /\/app\/account\?tab=memory/) + await expect(line(page, 'memory')).toHaveCount(0) + }) + + test('a right under a switch that is off is blocked, and the fix moves to the switch', async ({ page }) => { + await installAgents(page, { agents: [{ ...AGENTS[1], builtins: ['triggers.propose'], builtins_off: ['triggers'] }] }) + await memory(page, true) + await page.goto('/app/agents/a2/edit') + const row = line(page, 'grant-triggers.propose') + await expect(row).toHaveAttribute('data-state', 'blocked') + await expect(row).toHaveAttribute('data-code', 'tools_switch_off') + await expect(page.getByTestId('agent-effective-summary')).toContainText('blocked') + await row.getByTestId('agent-effective-fix').click() + await expect(page.locator('#aed-sec-capabilities')).toBeInViewport() + // Turning the switch on clears the line, without saving. + await page.getByTestId('agent-tools-panel').getByRole('switch', { name: 'Create and manage triggers' }).click() + await expect(line(page, 'grant-triggers.propose')).toHaveCount(0) + }) + + test('a saved connection is checked with the access preview and what is blocked is said with its fix', async ({ page }) => { + await installAgents(page, { bindings: [{ id: 'b1', name: 'Bender', kind: 'slack', agent_id: 'a2', enabled: true, caps: [] }] }) + await memory(page, true) + const asked = [] + await page.route(/\/api\/chats\/connectors\/b1\/access\/preview$/, route => { asked.push(route.request().postDataJSON()); return route.fulfill({ json: VIEW }) }) + await page.goto('/app/agents/a2/edit') + await expect(line(page, 'conn-b1')).toContainText('Slack Bender: 1 allowed, 2 not allowed') + expect(asked).toEqual([{ agent_id: 'a2' }]) + const agentSide = line(page, 'conn-b1-memory.write') + await expect(agentSide).toContainText('The agent has not been given this right.') + await expect(agentSide).toHaveAttribute('data-code', 'agent_permission_off') + await expect(agentSide.getByTestId('agent-effective-fix')).toHaveText('Fix it here') + const connSide = line(page, 'conn-b1-triggers.run') + await expect(connSide.getByTestId('agent-effective-fix')).toHaveAttribute('href', /apps\?binding=b1|chats\/connectors/) + // A change in the form does not ask again; the lines are for the saved connection. + await page.getByLabel('Description').fill('Changed') + await expect(page.getByTestId('agent-effective-unsaved')).toContainText('saved connection') + expect(asked).toHaveLength(1) + }) + + test('a connection that cannot be checked says so', async ({ page }) => { + await installAgents(page, { bindings: [{ id: 'b1', name: 'Bender', kind: 'slack', agent_id: 'a2', enabled: true, caps: [] }] }) + await memory(page, true) + await page.route(/\/api\/chats\/connectors\/b1\/access\/preview$/, route => route.fulfill({ status: 500, json: { error: { message: 'boom' } } })) + await page.goto('/app/agents/a2/edit') + await expect(line(page, 'conn-b1')).toContainText('Could not check Slack Bender') + }) + + test('every line names the section it explains', async ({ page }) => { + await installAgents(page) + await memory(page, true) + await page.goto('/app/agents/new') + await line(page, 'knowledge').getByTestId('agent-effective-goto').click() + await expect(page.locator('#aed-sec-memory')).toBeInViewport() + await expect(page.getByTestId('agent-nav-effective')).toBeVisible() + }) +}) + +test.describe('Try it and More', () => { + async function chatStub(page) { + const seen = { create: null, patch: null, sent: null, deleted: false, running: 1 } + await page.route(/\/api\/chats(\?.*)?$/, route => { + if (route.request().method() !== 'POST') return route.fallback() + seen.create = route.request().postDataJSON() + return route.fulfill({ status: 201, json: { id: 't1', title: 'Test', model: seen.create.model } }) + }) + await page.route(/\/api\/chats\/t1$/, route => { + const m = route.request().method() + if (m === 'PATCH') { seen.patch = route.request().postDataJSON(); return route.fulfill({ json: { id: 't1' } }) } + if (m === 'DELETE') { seen.deleted = true; return route.fulfill({ status: 204, body: '' }) } + seen.running -= 1 + return route.fulfill({ json: { id: 't1', running: seen.running > 0 } }) + }) + await page.route(/\/api\/chats\/t1\/messages(\?.*)?$/, route => { + if (route.request().method() === 'POST') { seen.sent = route.request().postDataJSON(); return route.fulfill({ json: { ok: true } }) } + return route.fulfill({ json: { messages: [ + { seq: 1, role: 'user', text: seen.sent?.text || '' }, + { seq: 2, role: 'tool', text: 'web_search\n{"q":"x"}' }, + { seq: 3, role: 'assistant', text: 'Bonjour, voici la réponse.' }, + ] } }) + }) + await page.route(/\/api\/chats\/t1\/stop$/, route => route.fulfill({ json: {} })) + return seen + } + + test('sends a message with the settings in the form, saves nothing, and deletes the test chat on close', async ({ page }) => { + const s = await installAgents(page, { agents: [{ ...AGENTS[1], builtins: ['memory.write'] }] }) + await memory(page, true) + const seen = await chatStub(page) + await page.goto('/app/agents/a2/edit') + await page.getByLabel('Instructions').fill('Answer in French.') + await page.getByTestId('agent-tools-panel').getByRole('switch', { name: /Your files/ }).click() + await page.getByTestId('agent-try-open').click() + const sheet = page.getByTestId('agent-try') + await expect(sheet).toBeVisible() + await expect(page.getByTestId('agent-try-skipped')).toContainText('permissions') + await page.getByTestId('agent-try-input').fill('Hello') + await page.getByTestId('agent-try-send').click() + await expect(page.getByTestId('agent-try-log')).toContainText('Bonjour, voici la réponse.') + await expect(page.getByTestId('agent-try-log')).toContainText('Used a tool: web_search') + expect(seen.create.model).toBeTruthy() + expect(seen.create.switches.builtins_off).toEqual(['files']) + expect(seen.patch).toEqual({ settings: { system_prompt: 'Answer in French.' } }) + expect(seen.sent.text).toBe('Hello') + expect(s.calls.some(c => c.method === 'POST' || c.method === 'PUT')).toBe(false) + await shot(page, 'try-it') + await page.keyboard.press('Escape') + await expect(sheet).toHaveCount(0) + await expect.poll(() => seen.deleted).toBe(true) + // The form still holds its unsaved changes. + await expect(page.getByLabel('Instructions')).toHaveValue('Answer in French.') + }) + + test('the More menu exports a saved agent and is not offered for a new one', async ({ page }) => { + await installAgents(page) + await memory(page, true) + await page.goto('/app/agents/new') + await expect(page.getByRole('button', { name: 'More actions' })).toHaveCount(0) + await page.goto('/app/agents/a2/edit') + await page.getByRole('button', { name: 'More actions' }).click() + const download = page.waitForEvent('download') + await page.getByRole('menuitem', { name: 'Export agent' }).click() + expect((await download).suggestedFilename()).toBe('code-reviewer.json') + }) + + test('the sheet and the Effective view stay inside a 320 px screen', async ({ page }) => { + await page.setViewportSize({ width: 320, height: 700 }) + await installAgents(page, { agents: [{ ...AGENTS[1], name: `reviewer_${'x'.repeat(60)}`, collections: ['a'.repeat(70)] }] }) + await memory(page, false) + await page.goto('/app/agents/a2/edit') + await expect(eff(page)).toBeVisible() + const wide = () => page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth) + expect(await wide()).toBeLessThanOrEqual(0) + await page.getByTestId('agent-try-open').click() + await expect(page.getByTestId('agent-try')).toBeVisible() + expect(await wide()).toBeLessThanOrEqual(0) + const box = await page.getByTestId('agent-try').boundingBox() + expect(box.x + box.width).toBeLessThanOrEqual(320) + }) +}) + +test.describe('Screenshots', () => { + test.skip(!SHOTS, 'set EDITOR_SHOTS to take them') + for (const width of [1280, 768, 375]) { + test(`effective view at ${width}`, async ({ page }) => { + await page.setViewportSize({ width, height: 900 }) + await installAgents(page, { + agents: [{ ...AGENTS[1], builtins: ['triggers.propose', 'act.send'], builtins_off: ['triggers'], collections: ['handbook'] }], + bindings: [{ id: 'b1', name: 'Bender', kind: 'slack', agent_id: 'a2', enabled: true, caps: [] }], + }) + await memory(page, false) + await page.route(/\/api\/chats\/connectors\/b1\/access\/preview$/, route => route.fulfill({ json: VIEW })) + await page.goto('/app/agents/a2/edit') + await expect(line(page, 'conn-b1-memory.write')).toBeVisible() + await page.getByTestId('agent-nav-effective').click() + await page.waitForTimeout(700) + await shot(page, 'effective') + await page.evaluate(() => window.scrollTo(0, 0)) + await page.waitForTimeout(300) + await shot(page, 'top') + await page.getByTestId('agent-try-open').click() + await shot(page, 'try-empty') + }) + } +}) diff --git a/core/http/react-ui/public/locales/de/agents.json b/core/http/react-ui/public/locales/de/agents.json index b4f25c341d..b43484606c 100644 --- a/core/http/react-ui/public/locales/de/agents.json +++ b/core/http/react-ui/public/locales/de/agents.json @@ -83,7 +83,8 @@ "Files": "Dateien", "Tools": "Werkzeuge", "Notes": "Gedächtnis", - "Connections": "Verbindungen" + "Connections": "Verbindungen", + "Effective": "Wirksame Ansicht" }, "name": "Name", "description": "Description", @@ -159,14 +160,16 @@ "capabilities": "Fähigkeiten", "memory": "Gedächtnis und Wissen", "advanced": "Erweitert", - "connections": "Verbindungen" + "connections": "Verbindungen", + "effective": "Wirksame Ansicht" }, "lead": { "identity": "Wer der Agent ist und wie er sich verhält.", "capabilities": "Was der Agent nutzen und erreichen darf.", "memory": "Woran sich der Agent erinnert und was er nachschlagen kann.", "advanced": "Zusätzliche Server und Export.", - "connections": "Welche Verbindungen dieser Agent nutzen darf." + "connections": "Welche Verbindungen dieser Agent nutzen darf.", + "effective": "Was dieser Agent gerade tun kann." }, "header": { "unnamed": "Unbenannter Agent", @@ -226,6 +229,110 @@ "perChat": "Nichts angehakt: Jeder Chat wählt selbst.", "summary_one": "{{count}} Verbindung", "summary_other": "{{count}} Verbindungen" + }, + "more": "Weitere Aktionen", + "eff": { + "summaryOk": "Nichts ist blockiert.", + "summaryBlocked_one": "{{count}} Sache ist blockiert.", + "summaryBlocked_other": "{{count}} Dinge sind blockiert.", + "unsaved": "Diese Liste folgt dem Formular, wie es jetzt ist, auch mit nicht gespeicherten Änderungen.", + "unsavedConn": "Werkzeuge, Gedächtnis und Wissen folgen dem Formular, wie es jetzt ist. Die Zeilen zu Verbindungen stammen vom gespeicherten Agenten und der gespeicherten Verbindung.", + "state": { + "allowed": "Kann", + "asks": "Fragt zuerst", + "off": "Aus", + "blocked": "Blockiert", + "info": "Hinweis" + }, + "more_one": "und {{count}} weitere", + "more_other": "und {{count}} weitere", + "fixHere": "Hier beheben", + "fixOpen": "Die Seite öffnen, die es behebt", + "model": { + "fixed": "Läuft mit {{model}}.", + "any": "Nutzt das Modell, das in jedem Chat gewählt wird." + }, + "tools": { + "none": "Keine Werkzeuge sind an. Er kann nur aus seinem Wissen antworten.", + "some_one": "Kann {{count}} Werkzeug nutzen: {{names}}.", + "some_other": "Kann {{count}} Werkzeuge nutzen: {{names}}.", + "blocked": "{{name}} ist an, kann aber jetzt nicht arbeiten. {{reason}}" + }, + "skills": { + "some_one": "Kann {{count}} Skill nutzen: {{names}}.", + "some_other": "Kann {{count}} Skills nutzen: {{names}}." + }, + "files": { + "all": "Kann alle Ihre Dateien erreichen.", + "folders_one": "Kann nur den {{count}} gewählten Ordner erreichen.", + "folders_other": "Kann nur die {{count}} gewählten Ordner erreichen." + }, + "grants": { + "parentOff": "{{name}} ist erlaubt, funktioniert aber nicht, solange {{parent}} aus ist. Schalten Sie {{parent}} ein.", + "connection": "{{name}} ist für den Agenten erlaubt, aber nicht auf dieser Verbindung: {{connection}}", + "some_one": "Hat {{count}} zusätzliches Recht: {{names}}.", + "some_other": "Hat {{count}} zusätzliche Rechte: {{names}}.", + "unattended_one": "Wenn niemand zusieht, darf er {{count}} Recht selbst nutzen: {{names}}.", + "unattended_other": "Wenn niemand zusieht, darf er {{count}} Rechte selbst nutzen: {{names}}." + }, + "memory": { + "userOff": "Das Gedächtnis ist in Ihren Einstellungen aus. Dieser Agent liest und speichert daher keine Notizen, egal was er hier wählt.", + "none": "Behält und liest keine Notizen.", + "mine_and_own": "Liest Ihre Notizen und seine eigenen und speichert in seinen eigenen.", + "own": "Liest und speichert nur seine eigenen Notizen.", + "mine": "Liest Ihre Notizen und speichert darin.", + "asBefore": "Das Gedächtnis arbeitet wie bisher: Er liest Notizen, wenn ein Add-on Memory nennt.", + "noGrant": "Er soll Notizen speichern, aber das Recht, sich Dinge zu merken, ist aus. Er speichert also nichts. Schalten Sie es unter Gedächtnis ein.", + "level": { + "auto": "Notizen werden sofort gespeichert.", + "ask": "Jede Notiz wartet auf Ihre Bestätigung.", + "always": "Jede Notiz wartet auf Sie, und nichts lockert das.", + "never": "Er speichert keine Notizen." + } + }, + "knowledge": { + "some_one": "Kann {{count}} Sammlung durchsuchen: {{names}}.", + "some_other": "Kann {{count}} Sammlungen durchsuchen: {{names}}.", + "none": "Keine Wissenssammlungen zum Durchsuchen." + }, + "connections": { + "unsaved": "Noch in keiner Messaging-App genutzt. Speichern Sie den Agenten und fügen Sie dann eine Verbindung hinzu.", + "none": "In keiner Messaging-App genutzt.", + "loading": "{{name}} wird geprüft ...", + "error": "{{name}} konnte nicht geprüft werden. Öffnen Sie sie, um die Berechtigungen zu sehen.", + "summary": "{{name}}: {{allowed}} erlaubt, {{blocked}} nicht erlaubt.", + "blocked": "{{name}} kann {{capability}} nicht nutzen. {{message}}" + } + }, + "try": { + "open": "Ausprobieren", + "title": "Diesen Agenten ausprobieren", + "desc": "Senden Sie eine Nachricht an einen Test-Chat mit den Einstellungen dieses Formulars. Nichts wird gespeichert.", + "noModel": "Kein Chat-Modell ist installiert. Installieren oder wählen Sie zuerst ein Modell.", + "defaultModel": "Kein Modell ist gesetzt, daher nutzt der Test {{model}}.", + "skipped": "Der Test nutzt nicht: {{what}}. Das gehört zu einem gespeicherten Agenten.", + "skip": { + "grants": "Berechtigungen", + "memory": "Gedächtnis", + "knowledge": "Wissenssammlungen", + "folders": "geteilte Ordner" + }, + "empty": "Senden Sie eine Nachricht, um zu beginnen.", + "role": { + "user": "Sie", + "assistant": "Agent", + "tool": "Werkzeug" + }, + "toolRan": "Werkzeug genutzt: {{name}}", + "working": "Arbeitet ...", + "label": "Nachricht an den Agenten", + "placeholder": "Fragen Sie etwas, das dieser Agent können soll", + "send": "Senden", + "stop": "Stopp", + "deleted": "Der Test-Chat wird gelöscht, wenn Sie dieses Fenster schließen.", + "chatTitle": "Test von {{name}}", + "failed": "Der Test ist fehlgeschlagen: {{message}}", + "slow": "Der Agent arbeitet noch. Stoppen Sie ihn oder schließen Sie das Fenster." } }, "run": { diff --git a/core/http/react-ui/public/locales/en/agents.json b/core/http/react-ui/public/locales/en/agents.json index d207aff8b2..2102b61e42 100644 --- a/core/http/react-ui/public/locales/en/agents.json +++ b/core/http/react-ui/public/locales/en/agents.json @@ -196,7 +196,8 @@ "Files": "Files", "Tools": "Tools", "Notes": "Memory", - "Connections": "Connections" + "Connections": "Connections", + "Effective": "Effective view" }, "grantsNoticeTitle": "Some messaging features will turn off.", "grantsNotice": "This agent had no permission list, so it kept these on its messaging connections: {{grants}}. They stop working until you tick them here.", @@ -266,14 +267,16 @@ "capabilities": "Capabilities", "memory": "Memory and knowledge", "advanced": "Advanced", - "connections": "Connections" + "connections": "Connections", + "effective": "Effective view" }, "lead": { "identity": "Who the agent is and how it behaves.", "capabilities": "What the agent may use and reach.", "memory": "What the agent remembers and what it can look up.", "advanced": "Extra servers and export.", - "connections": "Which connections this agent may use." + "connections": "Which connections this agent may use.", + "effective": "What this agent can do right now." }, "header": { "unnamed": "Unnamed agent", @@ -333,6 +336,110 @@ "perChat": "None ticked: each chat chooses its own.", "summary_one": "{{count}} connection", "summary_other": "{{count}} connections" + }, + "more": "More actions", + "eff": { + "summaryOk": "Nothing is blocked.", + "summaryBlocked_one": "{{count}} thing is blocked.", + "summaryBlocked_other": "{{count}} things are blocked.", + "unsaved": "This list follows the form as it is now, including changes you have not saved.", + "unsavedConn": "Tools, memory and knowledge follow the form as it is now. Connection lines come from the saved agent and the saved connection.", + "state": { + "allowed": "Can", + "asks": "Asks first", + "off": "Off", + "blocked": "Blocked", + "info": "Note" + }, + "more_one": "and {{count}} more", + "more_other": "and {{count}} more", + "fixHere": "Fix it here", + "fixOpen": "Open the page that fixes it", + "model": { + "fixed": "Runs on {{model}}.", + "any": "Uses the model picked in each chat." + }, + "tools": { + "none": "No tools are on. It can only answer from what it knows.", + "some_one": "Can use {{count}} tool: {{names}}.", + "some_other": "Can use {{count}} tools: {{names}}.", + "blocked": "{{name}} is on but cannot work now. {{reason}}" + }, + "skills": { + "some_one": "Can use {{count}} skill: {{names}}.", + "some_other": "Can use {{count}} skills: {{names}}." + }, + "files": { + "all": "Can reach all your files.", + "folders_one": "Can reach only the {{count}} folder you chose.", + "folders_other": "Can reach only the {{count}} folders you chose." + }, + "grants": { + "parentOff": "{{name}} is allowed, but it cannot work while {{parent}} is off. Turn {{parent}} on.", + "connection": "{{name}} is allowed for the agent, but not on this connection: {{connection}}", + "some_one": "Has {{count}} extra right: {{names}}.", + "some_other": "Has {{count}} extra rights: {{names}}.", + "unattended_one": "When nobody is watching, it may use {{count}} right on its own: {{names}}.", + "unattended_other": "When nobody is watching, it may use {{count}} rights on its own: {{names}}." + }, + "memory": { + "userOff": "Memory is off in your Settings, so this agent reads and saves no notes, whatever it chooses here.", + "none": "Keeps and reads no notes.", + "mine_and_own": "Reads your notes and its own, and saves to its own.", + "own": "Reads and saves only its own notes.", + "mine": "Reads your notes and saves to them.", + "asBefore": "Memory works as before: it reads notes when an add-on names Memory.", + "noGrant": "It is set to save notes, but the right to remember things is off, so it saves none. Turn it on in Memory.", + "level": { + "auto": "Notes are saved at once.", + "ask": "Each note waits for you to confirm it.", + "always": "Every note waits for you, and nothing loosens that.", + "never": "It saves no notes." + } + }, + "knowledge": { + "some_one": "Can search {{count}} collection: {{names}}.", + "some_other": "Can search {{count}} collections: {{names}}.", + "none": "No knowledge collections to search." + }, + "connections": { + "unsaved": "Not used in messaging apps yet. Save the agent, then add a connection.", + "none": "Not used in any messaging app.", + "loading": "Checking {{name}}...", + "error": "Could not check {{name}}. Open it to see its permissions.", + "summary": "{{name}}: {{allowed}} allowed, {{blocked}} not allowed.", + "blocked": "{{name}} cannot use {{capability}}. {{message}}" + } + }, + "try": { + "open": "Try it", + "title": "Try this agent", + "desc": "Send a message to a test chat that uses the settings in this form. Nothing is saved.", + "noModel": "No chat model is installed. Install or pick a model first.", + "defaultModel": "No model is set, so the test uses {{model}}.", + "skipped": "The test does not use: {{what}}. Those belong to a saved agent.", + "skip": { + "grants": "permissions", + "memory": "memory", + "knowledge": "knowledge collections", + "folders": "shared folders" + }, + "empty": "Send a message to start.", + "role": { + "user": "You", + "assistant": "Agent", + "tool": "Tool" + }, + "toolRan": "Used a tool: {{name}}", + "working": "Working...", + "label": "Message to the agent", + "placeholder": "Ask something this agent should handle", + "send": "Send", + "stop": "Stop", + "deleted": "The test chat is deleted when you close this panel.", + "chatTitle": "Test of {{name}}", + "failed": "The test failed: {{message}}", + "slow": "The agent is still working. Stop it or close the panel." } }, "status": { diff --git a/core/http/react-ui/public/locales/es/agents.json b/core/http/react-ui/public/locales/es/agents.json index 6daab5e07a..241e660db1 100644 --- a/core/http/react-ui/public/locales/es/agents.json +++ b/core/http/react-ui/public/locales/es/agents.json @@ -83,7 +83,8 @@ "Files": "Archivos", "Tools": "Herramientas", "Notes": "Memoria", - "Connections": "Conexiones" + "Connections": "Conexiones", + "Effective": "Vista efectiva" }, "name": "Name", "description": "Description", @@ -159,14 +160,16 @@ "capabilities": "Capacidades", "memory": "Memoria y conocimiento", "advanced": "Avanzado", - "connections": "Conexiones" + "connections": "Conexiones", + "effective": "Vista efectiva" }, "lead": { "identity": "Quién es el agente y cómo se comporta.", "capabilities": "Lo que el agente puede usar y alcanzar.", "memory": "Lo que el agente recuerda y lo que puede consultar.", "advanced": "Servidores adicionales y exportación.", - "connections": "Qué conexiones puede usar este agente." + "connections": "Qué conexiones puede usar este agente.", + "effective": "Lo que este agente puede hacer ahora." }, "header": { "unnamed": "Agente sin nombre", @@ -226,6 +229,110 @@ "perChat": "Ninguna marcada: cada chat elige la suya.", "summary_one": "{{count}} conexión", "summary_other": "{{count}} conexiones" + }, + "more": "Más acciones", + "eff": { + "summaryOk": "Nada está bloqueado.", + "summaryBlocked_one": "{{count}} cosa está bloqueada.", + "summaryBlocked_other": "{{count}} cosas están bloqueadas.", + "unsaved": "Esta lista sigue el formulario tal como está ahora, con los cambios sin guardar.", + "unsavedConn": "Herramientas, memoria y conocimiento siguen el formulario tal como está ahora. Las líneas de conexiones vienen del agente guardado y de la conexión guardada.", + "state": { + "allowed": "Puede", + "asks": "Pregunta antes", + "off": "Desactivado", + "blocked": "Bloqueado", + "info": "Nota" + }, + "more_one": "y {{count}} más", + "more_other": "y {{count}} más", + "fixHere": "Corregirlo aquí", + "fixOpen": "Abrir la página que lo corrige", + "model": { + "fixed": "Se ejecuta con {{model}}.", + "any": "Usa el modelo elegido en cada chat." + }, + "tools": { + "none": "No hay herramientas activadas. Solo puede responder con lo que sabe.", + "some_one": "Puede usar {{count}} herramienta: {{names}}.", + "some_other": "Puede usar {{count}} herramientas: {{names}}.", + "blocked": "{{name}} está activado pero no puede funcionar ahora. {{reason}}" + }, + "skills": { + "some_one": "Puede usar {{count}} habilidad: {{names}}.", + "some_other": "Puede usar {{count}} habilidades: {{names}}." + }, + "files": { + "all": "Puede acceder a todos sus archivos.", + "folders_one": "Solo puede acceder a la {{count}} carpeta elegida.", + "folders_other": "Solo puede acceder a las {{count}} carpetas elegidas." + }, + "grants": { + "parentOff": "{{name}} está permitido, pero no funciona mientras {{parent}} esté desactivado. Active {{parent}}.", + "connection": "{{name}} está permitido para el agente, pero no en esta conexión: {{connection}}", + "some_one": "Tiene {{count}} permiso adicional: {{names}}.", + "some_other": "Tiene {{count}} permisos adicionales: {{names}}.", + "unattended_one": "Cuando nadie mira, puede usar {{count}} permiso por su cuenta: {{names}}.", + "unattended_other": "Cuando nadie mira, puede usar {{count}} permisos por su cuenta: {{names}}." + }, + "memory": { + "userOff": "La memoria está desactivada en sus ajustes, así que este agente no lee ni guarda notas, elija lo que elija aquí.", + "none": "No guarda ni lee notas.", + "mine_and_own": "Lee sus notas y las suyas, y guarda en las suyas.", + "own": "Lee y guarda solo sus propias notas.", + "mine": "Lee sus notas y guarda en ellas.", + "asBefore": "La memoria funciona como antes: lee notas cuando un complemento nombra Memory.", + "noGrant": "Está configurado para guardar notas, pero el permiso de recordar cosas está desactivado, así que no guarda ninguna. Actívelo en Memoria.", + "level": { + "auto": "Las notas se guardan al instante.", + "ask": "Cada nota espera su confirmación.", + "always": "Cada nota espera su confirmación y nada lo relaja.", + "never": "No guarda notas." + } + }, + "knowledge": { + "some_one": "Puede buscar en {{count}} colección: {{names}}.", + "some_other": "Puede buscar en {{count}} colecciones: {{names}}.", + "none": "No hay colecciones de conocimiento donde buscar." + }, + "connections": { + "unsaved": "Aún no se usa en aplicaciones de mensajería. Guarde el agente y añada una conexión.", + "none": "No se usa en ninguna aplicación de mensajería.", + "loading": "Comprobando {{name}}...", + "error": "No se pudo comprobar {{name}}. Ábrala para ver sus permisos.", + "summary": "{{name}}: {{allowed}} permitidos, {{blocked}} no permitidos.", + "blocked": "{{name}} no puede usar {{capability}}. {{message}}" + } + }, + "try": { + "open": "Probar", + "title": "Probar este agente", + "desc": "Envíe un mensaje a un chat de prueba que usa los ajustes de este formulario. No se guarda nada.", + "noModel": "No hay ningún modelo de chat instalado. Instale o elija un modelo primero.", + "defaultModel": "No hay modelo definido, así que la prueba usa {{model}}.", + "skipped": "La prueba no usa: {{what}}. Eso pertenece a un agente guardado.", + "skip": { + "grants": "permisos", + "memory": "memoria", + "knowledge": "colecciones de conocimiento", + "folders": "carpetas compartidas" + }, + "empty": "Envíe un mensaje para empezar.", + "role": { + "user": "Usted", + "assistant": "Agente", + "tool": "Herramienta" + }, + "toolRan": "Usó una herramienta: {{name}}", + "working": "Trabajando...", + "label": "Mensaje al agente", + "placeholder": "Pregunte algo que este agente deba resolver", + "send": "Enviar", + "stop": "Detener", + "deleted": "El chat de prueba se elimina al cerrar este panel.", + "chatTitle": "Prueba de {{name}}", + "failed": "La prueba falló: {{message}}", + "slow": "El agente sigue trabajando. Deténgalo o cierre el panel." } }, "run": { diff --git a/core/http/react-ui/public/locales/fr/agents.json b/core/http/react-ui/public/locales/fr/agents.json index 6bb9f17550..d4122b0545 100644 --- a/core/http/react-ui/public/locales/fr/agents.json +++ b/core/http/react-ui/public/locales/fr/agents.json @@ -83,7 +83,8 @@ "Files": "Fichiers", "Tools": "Outils", "Notes": "Mémoire", - "Connections": "Connexions" + "Connections": "Connexions", + "Effective": "Vue effective" }, "name": "Name", "description": "Description", @@ -159,14 +160,16 @@ "capabilities": "Capacités", "memory": "Mémoire et connaissances", "advanced": "Avancé", - "connections": "Connexions" + "connections": "Connexions", + "effective": "Vue effective" }, "lead": { "identity": "Qui est l'agent et comment il se comporte.", "capabilities": "Ce que l'agent peut utiliser et atteindre.", "memory": "Ce dont l'agent se souvient et ce qu'il peut consulter.", "advanced": "Serveurs supplémentaires et export.", - "connections": "Les connexions que cet agent peut utiliser." + "connections": "Les connexions que cet agent peut utiliser.", + "effective": "Ce que cet agent peut faire en ce moment." }, "header": { "unnamed": "Agent sans nom", @@ -226,6 +229,110 @@ "perChat": "Aucune cochée : chaque discussion choisit la sienne.", "summary_one": "{{count}} connexion", "summary_other": "{{count}} connexions" + }, + "more": "Plus d'actions", + "eff": { + "summaryOk": "Rien n'est bloqué.", + "summaryBlocked_one": "{{count}} chose est bloquée.", + "summaryBlocked_other": "{{count}} choses sont bloquées.", + "unsaved": "Cette liste suit le formulaire tel qu'il est maintenant, avec les changements non enregistrés.", + "unsavedConn": "Les outils, la mémoire et les connaissances suivent le formulaire tel qu'il est maintenant. Les lignes de connexion viennent de l'agent enregistré et de la connexion enregistrée.", + "state": { + "allowed": "Peut", + "asks": "Demande d'abord", + "off": "Désactivé", + "blocked": "Bloqué", + "info": "Remarque" + }, + "more_one": "et {{count}} de plus", + "more_other": "et {{count}} de plus", + "fixHere": "Corriger ici", + "fixOpen": "Ouvrir la page qui le corrige", + "model": { + "fixed": "Fonctionne avec {{model}}.", + "any": "Utilise le modèle choisi dans chaque discussion." + }, + "tools": { + "none": "Aucun outil n'est activé. Il ne peut répondre qu'avec ce qu'il sait.", + "some_one": "Peut utiliser {{count}} outil : {{names}}.", + "some_other": "Peut utiliser {{count}} outils : {{names}}.", + "blocked": "{{name}} est activé mais ne peut pas fonctionner pour l'instant. {{reason}}" + }, + "skills": { + "some_one": "Peut utiliser {{count}} compétence : {{names}}.", + "some_other": "Peut utiliser {{count}} compétences : {{names}}." + }, + "files": { + "all": "Peut accéder à tous vos fichiers.", + "folders_one": "Ne peut accéder qu'au {{count}} dossier choisi.", + "folders_other": "Ne peut accéder qu'aux {{count}} dossiers choisis." + }, + "grants": { + "parentOff": "{{name}} est autorisé, mais ne fonctionne pas tant que {{parent}} est désactivé. Activez {{parent}}.", + "connection": "{{name}} est autorisé pour l'agent, mais pas sur cette connexion : {{connection}}", + "some_one": "A {{count}} droit supplémentaire : {{names}}.", + "some_other": "A {{count}} droits supplémentaires : {{names}}.", + "unattended_one": "Quand personne ne regarde, il peut utiliser {{count}} droit seul : {{names}}.", + "unattended_other": "Quand personne ne regarde, il peut utiliser {{count}} droits seul : {{names}}." + }, + "memory": { + "userOff": "La mémoire est désactivée dans vos réglages : cet agent ne lit ni n'enregistre de notes, quoi qu'il choisisse ici.", + "none": "Ne garde et ne lit aucune note.", + "mine_and_own": "Lit vos notes et les siennes, et enregistre dans les siennes.", + "own": "Lit et enregistre seulement ses propres notes.", + "mine": "Lit vos notes et y enregistre.", + "asBefore": "La mémoire fonctionne comme avant : il lit les notes quand un module nomme Memory.", + "noGrant": "Il doit enregistrer des notes, mais le droit de mémoriser est désactivé, donc il n'en enregistre aucune. Activez-le dans Mémoire.", + "level": { + "auto": "Les notes sont enregistrées tout de suite.", + "ask": "Chaque note attend votre confirmation.", + "always": "Chaque note attend votre confirmation, et rien ne l'assouplit.", + "never": "Il n'enregistre aucune note." + } + }, + "knowledge": { + "some_one": "Peut chercher dans {{count}} collection : {{names}}.", + "some_other": "Peut chercher dans {{count}} collections : {{names}}.", + "none": "Aucune collection de connaissances où chercher." + }, + "connections": { + "unsaved": "Pas encore utilisé dans une messagerie. Enregistrez l'agent, puis ajoutez une connexion.", + "none": "Utilisé dans aucune messagerie.", + "loading": "Vérification de {{name}}...", + "error": "Impossible de vérifier {{name}}. Ouvrez-la pour voir ses autorisations.", + "summary": "{{name}} : {{allowed}} autorisés, {{blocked}} non autorisés.", + "blocked": "{{name}} ne peut pas utiliser {{capability}}. {{message}}" + } + }, + "try": { + "open": "Essayer", + "title": "Essayer cet agent", + "desc": "Envoyez un message à une discussion de test qui utilise les réglages de ce formulaire. Rien n'est enregistré.", + "noModel": "Aucun modèle de discussion n'est installé. Installez ou choisissez d'abord un modèle.", + "defaultModel": "Aucun modèle n'est défini, le test utilise donc {{model}}.", + "skipped": "Le test n'utilise pas : {{what}}. Cela appartient à un agent enregistré.", + "skip": { + "grants": "autorisations", + "memory": "mémoire", + "knowledge": "collections de connaissances", + "folders": "dossiers partagés" + }, + "empty": "Envoyez un message pour commencer.", + "role": { + "user": "Vous", + "assistant": "Agent", + "tool": "Outil" + }, + "toolRan": "A utilisé un outil : {{name}}", + "working": "En cours...", + "label": "Message à l'agent", + "placeholder": "Demandez quelque chose que cet agent doit savoir faire", + "send": "Envoyer", + "stop": "Arrêter", + "deleted": "La discussion de test est supprimée à la fermeture de ce panneau.", + "chatTitle": "Test de {{name}}", + "failed": "Le test a échoué : {{message}}", + "slow": "L'agent travaille encore. Arrêtez-le ou fermez le panneau." } }, "run": { diff --git a/core/http/react-ui/public/locales/id/agents.json b/core/http/react-ui/public/locales/id/agents.json index 7e7322bfff..94a814d37c 100644 --- a/core/http/react-ui/public/locales/id/agents.json +++ b/core/http/react-ui/public/locales/id/agents.json @@ -83,7 +83,8 @@ "Files": "File", "Tools": "Alat", "Notes": "Memori", - "Connections": "Koneksi" + "Connections": "Koneksi", + "Effective": "Tampilan efektif" }, "name": "Name", "description": "Description", @@ -159,14 +160,16 @@ "capabilities": "Kemampuan", "memory": "Memori dan pengetahuan", "advanced": "Lanjutan", - "connections": "Koneksi" + "connections": "Koneksi", + "effective": "Tampilan efektif" }, "lead": { "identity": "Siapa agen ini dan bagaimana ia bersikap.", "capabilities": "Apa yang boleh digunakan dan dijangkau agen.", "memory": "Apa yang diingat agen dan apa yang bisa dicarinya.", "advanced": "Server tambahan dan ekspor.", - "connections": "Koneksi mana yang boleh dipakai agen ini." + "connections": "Koneksi mana yang boleh dipakai agen ini.", + "effective": "Apa yang bisa dilakukan agen ini sekarang." }, "header": { "unnamed": "Agen tanpa nama", @@ -226,6 +229,110 @@ "perChat": "Tidak ada yang dicentang: tiap obrolan memilih sendiri.", "summary_one": "{{count}} koneksi", "summary_other": "{{count}} koneksi" + }, + "more": "Tindakan lain", + "eff": { + "summaryOk": "Tidak ada yang diblokir.", + "summaryBlocked_one": "{{count}} hal diblokir.", + "summaryBlocked_other": "{{count}} hal diblokir.", + "unsaved": "Daftar ini mengikuti formulir saat ini, termasuk perubahan yang belum disimpan.", + "unsavedConn": "Alat, memori, dan pengetahuan mengikuti formulir saat ini. Baris koneksi berasal dari agen dan koneksi yang tersimpan.", + "state": { + "allowed": "Bisa", + "asks": "Bertanya dulu", + "off": "Mati", + "blocked": "Diblokir", + "info": "Catatan" + }, + "more_one": "dan {{count}} lagi", + "more_other": "dan {{count}} lagi", + "fixHere": "Perbaiki di sini", + "fixOpen": "Buka halaman yang memperbaikinya", + "model": { + "fixed": "Berjalan dengan {{model}}.", + "any": "Memakai model yang dipilih di tiap obrolan." + }, + "tools": { + "none": "Tidak ada alat yang aktif. Agen hanya bisa menjawab dari yang diketahuinya.", + "some_one": "Bisa memakai {{count}} alat: {{names}}.", + "some_other": "Bisa memakai {{count}} alat: {{names}}.", + "blocked": "{{name}} aktif tetapi belum bisa bekerja. {{reason}}" + }, + "skills": { + "some_one": "Bisa memakai {{count}} keahlian: {{names}}.", + "some_other": "Bisa memakai {{count}} keahlian: {{names}}." + }, + "files": { + "all": "Bisa mengakses semua berkas Anda.", + "folders_one": "Hanya bisa mengakses {{count}} folder yang dipilih.", + "folders_other": "Hanya bisa mengakses {{count}} folder yang dipilih." + }, + "grants": { + "parentOff": "{{name}} diizinkan, tetapi tidak bekerja selama {{parent}} mati. Nyalakan {{parent}}.", + "connection": "{{name}} diizinkan untuk agen, tetapi tidak pada koneksi ini: {{connection}}", + "some_one": "Punya {{count}} hak tambahan: {{names}}.", + "some_other": "Punya {{count}} hak tambahan: {{names}}.", + "unattended_one": "Saat tidak ada yang mengawasi, agen boleh memakai {{count}} hak sendiri: {{names}}.", + "unattended_other": "Saat tidak ada yang mengawasi, agen boleh memakai {{count}} hak sendiri: {{names}}." + }, + "memory": { + "userOff": "Memori mati di pengaturan Anda, jadi agen ini tidak membaca atau menyimpan catatan, apa pun pilihannya di sini.", + "none": "Tidak menyimpan dan tidak membaca catatan.", + "mine_and_own": "Membaca catatan Anda dan miliknya, dan menyimpan ke miliknya.", + "own": "Hanya membaca dan menyimpan catatannya sendiri.", + "mine": "Membaca catatan Anda dan menyimpan ke sana.", + "asBefore": "Memori bekerja seperti sebelumnya: membaca catatan saat add-on menyebut Memory.", + "noGrant": "Agen diatur menyimpan catatan, tetapi hak untuk mengingat mati, jadi tidak ada yang disimpan. Nyalakan di Memori.", + "level": { + "auto": "Catatan disimpan langsung.", + "ask": "Setiap catatan menunggu konfirmasi Anda.", + "always": "Setiap catatan menunggu Anda, dan tidak ada yang melonggarkannya.", + "never": "Tidak menyimpan catatan." + } + }, + "knowledge": { + "some_one": "Bisa mencari di {{count}} koleksi: {{names}}.", + "some_other": "Bisa mencari di {{count}} koleksi: {{names}}.", + "none": "Tidak ada koleksi pengetahuan untuk dicari." + }, + "connections": { + "unsaved": "Belum dipakai di aplikasi pesan. Simpan agen, lalu tambahkan koneksi.", + "none": "Tidak dipakai di aplikasi pesan mana pun.", + "loading": "Memeriksa {{name}}...", + "error": "Tidak bisa memeriksa {{name}}. Buka untuk melihat izinnya.", + "summary": "{{name}}: {{allowed}} diizinkan, {{blocked}} tidak diizinkan.", + "blocked": "{{name}} tidak bisa memakai {{capability}}. {{message}}" + } + }, + "try": { + "open": "Coba", + "title": "Coba agen ini", + "desc": "Kirim pesan ke obrolan uji yang memakai pengaturan di formulir ini. Tidak ada yang disimpan.", + "noModel": "Belum ada model obrolan terpasang. Pasang atau pilih model dulu.", + "defaultModel": "Model belum diatur, jadi uji memakai {{model}}.", + "skipped": "Uji tidak memakai: {{what}}. Itu milik agen yang tersimpan.", + "skip": { + "grants": "izin", + "memory": "memori", + "knowledge": "koleksi pengetahuan", + "folders": "folder bersama" + }, + "empty": "Kirim pesan untuk memulai.", + "role": { + "user": "Anda", + "assistant": "Agen", + "tool": "Alat" + }, + "toolRan": "Memakai alat: {{name}}", + "working": "Bekerja...", + "label": "Pesan untuk agen", + "placeholder": "Tanyakan sesuatu yang harus bisa ditangani agen ini", + "send": "Kirim", + "stop": "Berhenti", + "deleted": "Obrolan uji dihapus saat panel ini ditutup.", + "chatTitle": "Uji {{name}}", + "failed": "Uji gagal: {{message}}", + "slow": "Agen masih bekerja. Hentikan atau tutup panel." } }, "run": { diff --git a/core/http/react-ui/public/locales/it/agents.json b/core/http/react-ui/public/locales/it/agents.json index 91bd094769..bc87bd91bc 100644 --- a/core/http/react-ui/public/locales/it/agents.json +++ b/core/http/react-ui/public/locales/it/agents.json @@ -83,7 +83,8 @@ "Files": "File", "Tools": "Strumenti", "Notes": "Memoria", - "Connections": "Connessioni" + "Connections": "Connessioni", + "Effective": "Vista effettiva" }, "name": "Name", "description": "Description", @@ -159,14 +160,16 @@ "capabilities": "Capacità", "memory": "Memoria e conoscenza", "advanced": "Avanzate", - "connections": "Connessioni" + "connections": "Connessioni", + "effective": "Vista effettiva" }, "lead": { "identity": "Chi è l'agente e come si comporta.", "capabilities": "Cosa può usare e raggiungere l'agente.", "memory": "Cosa ricorda l'agente e cosa può consultare.", "advanced": "Server aggiuntivi ed esportazione.", - "connections": "Quali connessioni può usare questo agente." + "connections": "Quali connessioni può usare questo agente.", + "effective": "Cosa può fare questo agente adesso." }, "header": { "unnamed": "Agente senza nome", @@ -226,6 +229,110 @@ "perChat": "Nessuna selezionata: ogni chat sceglie la sua.", "summary_one": "{{count}} connessione", "summary_other": "{{count}} connessioni" + }, + "more": "Altre azioni", + "eff": { + "summaryOk": "Niente è bloccato.", + "summaryBlocked_one": "{{count}} cosa è bloccata.", + "summaryBlocked_other": "{{count}} cose sono bloccate.", + "unsaved": "Questo elenco segue il modulo com'è ora, con le modifiche non salvate.", + "unsavedConn": "Strumenti, memoria e conoscenza seguono il modulo com'è ora. Le righe delle connessioni vengono dall'agente salvato e dalla connessione salvata.", + "state": { + "allowed": "Può", + "asks": "Chiede prima", + "off": "Disattivato", + "blocked": "Bloccato", + "info": "Nota" + }, + "more_one": "e altri {{count}}", + "more_other": "e altri {{count}}", + "fixHere": "Correggi qui", + "fixOpen": "Apri la pagina che lo corregge", + "model": { + "fixed": "Usa {{model}}.", + "any": "Usa il modello scelto in ogni chat." + }, + "tools": { + "none": "Nessuno strumento è attivo. Può rispondere solo con ciò che sa.", + "some_one": "Può usare {{count}} strumento: {{names}}.", + "some_other": "Può usare {{count}} strumenti: {{names}}.", + "blocked": "{{name}} è attivo ma ora non può funzionare. {{reason}}" + }, + "skills": { + "some_one": "Può usare {{count}} competenza: {{names}}.", + "some_other": "Può usare {{count}} competenze: {{names}}." + }, + "files": { + "all": "Può raggiungere tutti i tuoi file.", + "folders_one": "Può raggiungere solo la {{count}} cartella scelta.", + "folders_other": "Può raggiungere solo le {{count}} cartelle scelte." + }, + "grants": { + "parentOff": "{{name}} è consentito, ma non funziona finché {{parent}} è disattivato. Attiva {{parent}}.", + "connection": "{{name}} è consentito per l'agente, ma non su questa connessione: {{connection}}", + "some_one": "Ha {{count}} permesso in più: {{names}}.", + "some_other": "Ha {{count}} permessi in più: {{names}}.", + "unattended_one": "Quando nessuno guarda, può usare {{count}} permesso da solo: {{names}}.", + "unattended_other": "Quando nessuno guarda, può usare {{count}} permessi da solo: {{names}}." + }, + "memory": { + "userOff": "La memoria è disattivata nelle tue impostazioni, quindi questo agente non legge né salva note, qualunque cosa scelga qui.", + "none": "Non tiene e non legge note.", + "mine_and_own": "Legge le tue note e le sue, e salva nelle sue.", + "own": "Legge e salva solo le proprie note.", + "mine": "Legge le tue note e salva in esse.", + "asBefore": "La memoria funziona come prima: legge le note quando un add-on nomina Memory.", + "noGrant": "È impostato per salvare note, ma il permesso di ricordare è disattivato, quindi non ne salva. Attivalo in Memoria.", + "level": { + "auto": "Le note vengono salvate subito.", + "ask": "Ogni nota aspetta la tua conferma.", + "always": "Ogni nota aspetta te e nulla lo allenta.", + "never": "Non salva note." + } + }, + "knowledge": { + "some_one": "Può cercare in {{count}} raccolta: {{names}}.", + "some_other": "Può cercare in {{count}} raccolte: {{names}}.", + "none": "Nessuna raccolta di conoscenza in cui cercare." + }, + "connections": { + "unsaved": "Non ancora usato nelle app di messaggistica. Salva l'agente, poi aggiungi una connessione.", + "none": "Non usato in nessuna app di messaggistica.", + "loading": "Controllo di {{name}}...", + "error": "Impossibile controllare {{name}}. Aprila per vedere i suoi permessi.", + "summary": "{{name}}: {{allowed}} consentiti, {{blocked}} non consentiti.", + "blocked": "{{name}} non può usare {{capability}}. {{message}}" + } + }, + "try": { + "open": "Prova", + "title": "Prova questo agente", + "desc": "Invia un messaggio a una chat di prova che usa le impostazioni di questo modulo. Non viene salvato nulla.", + "noModel": "Nessun modello di chat installato. Installa o scegli prima un modello.", + "defaultModel": "Nessun modello impostato, quindi la prova usa {{model}}.", + "skipped": "La prova non usa: {{what}}. Appartengono a un agente salvato.", + "skip": { + "grants": "permessi", + "memory": "memoria", + "knowledge": "raccolte di conoscenza", + "folders": "cartelle condivise" + }, + "empty": "Invia un messaggio per iniziare.", + "role": { + "user": "Tu", + "assistant": "Agente", + "tool": "Strumento" + }, + "toolRan": "Ha usato uno strumento: {{name}}", + "working": "Al lavoro...", + "label": "Messaggio all'agente", + "placeholder": "Chiedi qualcosa che questo agente deve saper gestire", + "send": "Invia", + "stop": "Ferma", + "deleted": "La chat di prova viene eliminata alla chiusura di questo pannello.", + "chatTitle": "Prova di {{name}}", + "failed": "La prova non è riuscita: {{message}}", + "slow": "L'agente sta ancora lavorando. Fermalo o chiudi il pannello." } }, "run": { diff --git a/core/http/react-ui/public/locales/ko/agents.json b/core/http/react-ui/public/locales/ko/agents.json index bcbfbbb2e4..83415ee4db 100644 --- a/core/http/react-ui/public/locales/ko/agents.json +++ b/core/http/react-ui/public/locales/ko/agents.json @@ -83,7 +83,8 @@ "Files": "파일", "Tools": "도구", "Notes": "메모리", - "Connections": "연결" + "Connections": "연결", + "Effective": "유효 보기" }, "name": "Name", "description": "Description", @@ -159,14 +160,16 @@ "capabilities": "기능", "memory": "메모리와 지식", "advanced": "고급", - "connections": "연결" + "connections": "연결", + "effective": "유효 보기" }, "lead": { "identity": "에이전트가 누구이고 어떻게 행동하는지 정합니다.", "capabilities": "에이전트가 사용하고 접근할 수 있는 것을 정합니다.", "memory": "에이전트가 기억하는 것과 찾아볼 수 있는 것을 정합니다.", "advanced": "추가 서버와 내보내기.", - "connections": "이 에이전트가 사용할 수 있는 연결입니다." + "connections": "이 에이전트가 사용할 수 있는 연결입니다.", + "effective": "이 에이전트가 지금 할 수 있는 일입니다." }, "header": { "unnamed": "이름 없는 에이전트", @@ -226,6 +229,110 @@ "perChat": "선택 없음: 채팅마다 직접 고릅니다.", "summary_one": "연결 {{count}}개", "summary_other": "연결 {{count}}개" + }, + "more": "더 많은 작업", + "eff": { + "summaryOk": "막힌 것이 없습니다.", + "summaryBlocked_one": "{{count}}개가 막혀 있습니다.", + "summaryBlocked_other": "{{count}}개가 막혀 있습니다.", + "unsaved": "이 목록은 저장하지 않은 변경을 포함해 지금의 양식을 따릅니다.", + "unsavedConn": "도구, 메모리, 지식은 지금의 양식을 따릅니다. 연결 줄은 저장된 에이전트와 저장된 연결에서 옵니다.", + "state": { + "allowed": "가능", + "asks": "먼저 물어봄", + "off": "꺼짐", + "blocked": "막힘", + "info": "참고" + }, + "more_one": "외 {{count}}개", + "more_other": "외 {{count}}개", + "fixHere": "여기서 고치기", + "fixOpen": "고칠 수 있는 페이지 열기", + "model": { + "fixed": "{{model}}로 실행됩니다.", + "any": "채팅마다 고른 모델을 씁니다." + }, + "tools": { + "none": "켜진 도구가 없습니다. 아는 것만으로 답할 수 있습니다.", + "some_one": "도구 {{count}}개를 쓸 수 있습니다: {{names}}.", + "some_other": "도구 {{count}}개를 쓸 수 있습니다: {{names}}.", + "blocked": "{{name}}은(는) 켜져 있지만 지금은 동작하지 않습니다. {{reason}}" + }, + "skills": { + "some_one": "스킬 {{count}}개를 쓸 수 있습니다: {{names}}.", + "some_other": "스킬 {{count}}개를 쓸 수 있습니다: {{names}}." + }, + "files": { + "all": "내 파일 전체에 접근할 수 있습니다.", + "folders_one": "고른 폴더 {{count}}개에만 접근할 수 있습니다.", + "folders_other": "고른 폴더 {{count}}개에만 접근할 수 있습니다." + }, + "grants": { + "parentOff": "{{name}}은(는) 허용되지만 {{parent}}이(가) 꺼져 있는 동안은 동작하지 않습니다. {{parent}}을(를) 켜세요.", + "connection": "{{name}}은(는) 에이전트에는 허용되지만 이 연결에서는 아닙니다: {{connection}}", + "some_one": "추가 권한 {{count}}개가 있습니다: {{names}}.", + "some_other": "추가 권한 {{count}}개가 있습니다: {{names}}.", + "unattended_one": "아무도 보지 않을 때 권한 {{count}}개를 스스로 쓸 수 있습니다: {{names}}.", + "unattended_other": "아무도 보지 않을 때 권한 {{count}}개를 스스로 쓸 수 있습니다: {{names}}." + }, + "memory": { + "userOff": "설정에서 메모리가 꺼져 있어, 여기서 무엇을 고르든 이 에이전트는 메모를 읽거나 저장하지 않습니다.", + "none": "메모를 보관하거나 읽지 않습니다.", + "mine_and_own": "내 메모와 자기 메모를 읽고 자기 메모에 저장합니다.", + "own": "자기 메모만 읽고 저장합니다.", + "mine": "내 메모를 읽고 거기에 저장합니다.", + "asBefore": "메모리는 이전처럼 동작합니다. 애드온이 Memory를 지정하면 메모를 읽습니다.", + "noGrant": "메모를 저장하도록 설정되어 있지만 기억할 권한이 꺼져 있어 저장하지 않습니다. 메모리에서 켜세요.", + "level": { + "auto": "메모가 바로 저장됩니다.", + "ask": "메모마다 확인을 기다립니다.", + "always": "메모마다 확인을 기다리며 이를 완화하는 것은 없습니다.", + "never": "메모를 저장하지 않습니다." + } + }, + "knowledge": { + "some_one": "컬렉션 {{count}}개를 검색할 수 있습니다: {{names}}.", + "some_other": "컬렉션 {{count}}개를 검색할 수 있습니다: {{names}}.", + "none": "검색할 지식 컬렉션이 없습니다." + }, + "connections": { + "unsaved": "아직 메시징 앱에서 쓰이지 않습니다. 에이전트를 저장한 뒤 연결을 추가하세요.", + "none": "어떤 메시징 앱에서도 쓰이지 않습니다.", + "loading": "{{name}} 확인 중...", + "error": "{{name}}을(를) 확인할 수 없습니다. 열어서 권한을 확인하세요.", + "summary": "{{name}}: 허용 {{allowed}}개, 불허 {{blocked}}개.", + "blocked": "{{name}}은(는) {{capability}}을(를) 쓸 수 없습니다. {{message}}" + } + }, + "try": { + "open": "체험", + "title": "이 에이전트 체험", + "desc": "이 양식의 설정을 쓰는 테스트 채팅에 메시지를 보냅니다. 아무것도 저장되지 않습니다.", + "noModel": "설치된 채팅 모델이 없습니다. 먼저 모델을 설치하거나 고르세요.", + "defaultModel": "모델이 정해지지 않아 테스트는 {{model}}을(를) 씁니다.", + "skipped": "테스트는 {{what}}을(를) 쓰지 않습니다. 저장된 에이전트의 것입니다.", + "skip": { + "grants": "권한", + "memory": "메모리", + "knowledge": "지식 컬렉션", + "folders": "공유 폴더" + }, + "empty": "메시지를 보내 시작하세요.", + "role": { + "user": "나", + "assistant": "에이전트", + "tool": "도구" + }, + "toolRan": "도구 사용: {{name}}", + "working": "작업 중...", + "label": "에이전트에게 보낼 메시지", + "placeholder": "이 에이전트가 처리해야 할 것을 물어보세요", + "send": "보내기", + "stop": "중지", + "deleted": "이 패널을 닫으면 테스트 채팅이 삭제됩니다.", + "chatTitle": "{{name}} 테스트", + "failed": "테스트 실패: {{message}}", + "slow": "에이전트가 아직 작업 중입니다. 중지하거나 패널을 닫으세요." } }, "run": { diff --git a/core/http/react-ui/public/locales/pt-BR/agents.json b/core/http/react-ui/public/locales/pt-BR/agents.json index e473dda4c9..a33caa9abc 100644 --- a/core/http/react-ui/public/locales/pt-BR/agents.json +++ b/core/http/react-ui/public/locales/pt-BR/agents.json @@ -83,7 +83,8 @@ "Files": "Arquivos", "Tools": "Ferramentas", "Notes": "Memória", - "Connections": "Conexões" + "Connections": "Conexões", + "Effective": "Visão efetiva" }, "name": "Name", "description": "Description", @@ -159,14 +160,16 @@ "capabilities": "Capacidades", "memory": "Memória e conhecimento", "advanced": "Avançado", - "connections": "Conexões" + "connections": "Conexões", + "effective": "Visão efetiva" }, "lead": { "identity": "Quem é o agente e como ele se comporta.", "capabilities": "O que o agente pode usar e alcançar.", "memory": "O que o agente lembra e o que ele pode consultar.", "advanced": "Servidores extras e exportação.", - "connections": "Quais conexões este agente pode usar." + "connections": "Quais conexões este agente pode usar.", + "effective": "O que este agente pode fazer agora." }, "header": { "unnamed": "Agente sem nome", @@ -226,6 +229,110 @@ "perChat": "Nenhuma marcada: cada chat escolhe a sua.", "summary_one": "{{count}} conexão", "summary_other": "{{count}} conexões" + }, + "more": "Mais ações", + "eff": { + "summaryOk": "Nada está bloqueado.", + "summaryBlocked_one": "{{count}} coisa está bloqueada.", + "summaryBlocked_other": "{{count}} coisas estão bloqueadas.", + "unsaved": "Esta lista segue o formulário como está agora, com as alterações não salvas.", + "unsavedConn": "Ferramentas, memória e conhecimento seguem o formulário como está agora. As linhas de conexões vêm do agente salvo e da conexão salva.", + "state": { + "allowed": "Pode", + "asks": "Pergunta antes", + "off": "Desligado", + "blocked": "Bloqueado", + "info": "Nota" + }, + "more_one": "e mais {{count}}", + "more_other": "e mais {{count}}", + "fixHere": "Corrigir aqui", + "fixOpen": "Abrir a página que corrige", + "model": { + "fixed": "Roda com {{model}}.", + "any": "Usa o modelo escolhido em cada conversa." + }, + "tools": { + "none": "Nenhuma ferramenta está ligada. Só pode responder com o que sabe.", + "some_one": "Pode usar {{count}} ferramenta: {{names}}.", + "some_other": "Pode usar {{count}} ferramentas: {{names}}.", + "blocked": "{{name}} está ligado, mas não pode funcionar agora. {{reason}}" + }, + "skills": { + "some_one": "Pode usar {{count}} habilidade: {{names}}.", + "some_other": "Pode usar {{count}} habilidades: {{names}}." + }, + "files": { + "all": "Pode acessar todos os seus arquivos.", + "folders_one": "Só pode acessar a {{count}} pasta escolhida.", + "folders_other": "Só pode acessar as {{count}} pastas escolhidas." + }, + "grants": { + "parentOff": "{{name}} é permitido, mas não funciona enquanto {{parent}} estiver desligado. Ligue {{parent}}.", + "connection": "{{name}} é permitido para o agente, mas não nesta conexão: {{connection}}", + "some_one": "Tem {{count}} permissão extra: {{names}}.", + "some_other": "Tem {{count}} permissões extras: {{names}}.", + "unattended_one": "Quando ninguém está olhando, pode usar {{count}} permissão por conta própria: {{names}}.", + "unattended_other": "Quando ninguém está olhando, pode usar {{count}} permissões por conta própria: {{names}}." + }, + "memory": { + "userOff": "A memória está desligada nas suas configurações, então este agente não lê nem salva notas, seja qual for a escolha aqui.", + "none": "Não guarda nem lê notas.", + "mine_and_own": "Lê as suas notas e as próprias, e salva nas próprias.", + "own": "Lê e salva só as próprias notas.", + "mine": "Lê as suas notas e salva nelas.", + "asBefore": "A memória funciona como antes: lê notas quando um complemento cita Memory.", + "noGrant": "Está configurado para salvar notas, mas a permissão de lembrar está desligada, então não salva nenhuma. Ligue em Memória.", + "level": { + "auto": "As notas são salvas na hora.", + "ask": "Cada nota espera a sua confirmação.", + "always": "Cada nota espera por você, e nada afrouxa isso.", + "never": "Não salva notas." + } + }, + "knowledge": { + "some_one": "Pode pesquisar {{count}} coleção: {{names}}.", + "some_other": "Pode pesquisar {{count}} coleções: {{names}}.", + "none": "Nenhuma coleção de conhecimento para pesquisar." + }, + "connections": { + "unsaved": "Ainda não usado em apps de mensagens. Salve o agente e depois adicione uma conexão.", + "none": "Não usado em nenhum app de mensagens.", + "loading": "Verificando {{name}}...", + "error": "Não foi possível verificar {{name}}. Abra-a para ver as permissões.", + "summary": "{{name}}: {{allowed}} permitidos, {{blocked}} não permitidos.", + "blocked": "{{name}} não pode usar {{capability}}. {{message}}" + } + }, + "try": { + "open": "Testar", + "title": "Testar este agente", + "desc": "Envie uma mensagem a uma conversa de teste que usa as configurações deste formulário. Nada é salvo.", + "noModel": "Nenhum modelo de conversa instalado. Instale ou escolha um modelo primeiro.", + "defaultModel": "Nenhum modelo definido, então o teste usa {{model}}.", + "skipped": "O teste não usa: {{what}}. Isso pertence a um agente salvo.", + "skip": { + "grants": "permissões", + "memory": "memória", + "knowledge": "coleções de conhecimento", + "folders": "pastas compartilhadas" + }, + "empty": "Envie uma mensagem para começar.", + "role": { + "user": "Você", + "assistant": "Agente", + "tool": "Ferramenta" + }, + "toolRan": "Usou uma ferramenta: {{name}}", + "working": "Trabalhando...", + "label": "Mensagem para o agente", + "placeholder": "Pergunte algo que este agente deve resolver", + "send": "Enviar", + "stop": "Parar", + "deleted": "A conversa de teste é excluída quando você fecha este painel.", + "chatTitle": "Teste de {{name}}", + "failed": "O teste falhou: {{message}}", + "slow": "O agente ainda está trabalhando. Pare-o ou feche o painel." } }, "run": { diff --git a/core/http/react-ui/public/locales/zh-CN/agents.json b/core/http/react-ui/public/locales/zh-CN/agents.json index c13ed91516..b6450839b0 100644 --- a/core/http/react-ui/public/locales/zh-CN/agents.json +++ b/core/http/react-ui/public/locales/zh-CN/agents.json @@ -83,7 +83,8 @@ "Files": "文件", "Tools": "工具", "Notes": "记忆", - "Connections": "连接" + "Connections": "连接", + "Effective": "生效视图" }, "name": "Name", "description": "Description", @@ -159,14 +160,16 @@ "capabilities": "能力", "memory": "记忆与知识", "advanced": "高级", - "connections": "连接" + "connections": "连接", + "effective": "生效视图" }, "lead": { "identity": "智能体是谁,以及它如何行事。", "capabilities": "智能体可以使用和访问的内容。", "memory": "智能体记住什么,以及可以查找什么。", "advanced": "额外的服务器和导出。", - "connections": "此代理可以使用哪些连接。" + "connections": "此代理可以使用哪些连接。", + "effective": "这个智能体现在能做什么。" }, "header": { "unnamed": "未命名的智能体", @@ -226,6 +229,110 @@ "perChat": "未勾选:每个聊天自行选择。", "summary_one": "{{count}} 个连接", "summary_other": "{{count}} 个连接" + }, + "more": "更多操作", + "eff": { + "summaryOk": "没有被阻止的内容。", + "summaryBlocked_one": "{{count}} 项被阻止。", + "summaryBlocked_other": "{{count}} 项被阻止。", + "unsaved": "此列表按表单当前的样子生成,包括尚未保存的更改。", + "unsavedConn": "工具、记忆和知识按表单当前的样子生成。连接行来自已保存的智能体和已保存的连接。", + "state": { + "allowed": "可以", + "asks": "先询问", + "off": "关闭", + "blocked": "已阻止", + "info": "说明" + }, + "more_one": "以及另外 {{count}} 项", + "more_other": "以及另外 {{count}} 项", + "fixHere": "在此修复", + "fixOpen": "打开可修复它的页面", + "model": { + "fixed": "使用 {{model}} 运行。", + "any": "使用每次聊天中选择的模型。" + }, + "tools": { + "none": "没有开启任何工具。它只能凭已有知识回答。", + "some_one": "可以使用 {{count}} 个工具:{{names}}。", + "some_other": "可以使用 {{count}} 个工具:{{names}}。", + "blocked": "{{name}} 已开启,但现在无法工作。{{reason}}" + }, + "skills": { + "some_one": "可以使用 {{count}} 个技能:{{names}}。", + "some_other": "可以使用 {{count}} 个技能:{{names}}。" + }, + "files": { + "all": "可以访问你的所有文件。", + "folders_one": "只能访问你选择的 {{count}} 个文件夹。", + "folders_other": "只能访问你选择的 {{count}} 个文件夹。" + }, + "grants": { + "parentOff": "{{name}} 已允许,但在 {{parent}} 关闭时无法工作。请打开 {{parent}}。", + "connection": "{{name}} 对智能体已允许,但在此连接上不行:{{connection}}", + "some_one": "另有 {{count}} 项权限:{{names}}。", + "some_other": "另有 {{count}} 项权限:{{names}}。", + "unattended_one": "无人看管时,它可以自行使用 {{count}} 项权限:{{names}}。", + "unattended_other": "无人看管时,它可以自行使用 {{count}} 项权限:{{names}}。" + }, + "memory": { + "userOff": "你的设置中记忆已关闭,因此无论在此选择什么,这个智能体都不会读取或保存笔记。", + "none": "不保存也不读取笔记。", + "mine_and_own": "读取你的笔记和它自己的笔记,并保存到它自己的笔记。", + "own": "只读取并保存它自己的笔记。", + "mine": "读取你的笔记并保存到其中。", + "asBefore": "记忆照旧工作:当附加组件提到 Memory 时读取笔记。", + "noGrant": "它被设置为保存笔记,但“记住内容”的权限已关闭,所以什么都不会保存。请在记忆中打开。", + "level": { + "auto": "笔记会立即保存。", + "ask": "每条笔记都等你确认。", + "always": "每条笔记都等你确认,没有任何放宽。", + "never": "它不保存笔记。" + } + }, + "knowledge": { + "some_one": "可以搜索 {{count}} 个集合:{{names}}。", + "some_other": "可以搜索 {{count}} 个集合:{{names}}。", + "none": "没有可搜索的知识集合。" + }, + "connections": { + "unsaved": "尚未用于消息应用。请先保存智能体,再添加连接。", + "none": "未用于任何消息应用。", + "loading": "正在检查 {{name}}...", + "error": "无法检查 {{name}}。打开它查看权限。", + "summary": "{{name}}:允许 {{allowed}} 项,不允许 {{blocked}} 项。", + "blocked": "{{name}} 无法使用 {{capability}}。{{message}}" + } + }, + "try": { + "open": "试用", + "title": "试用这个智能体", + "desc": "向使用此表单设置的测试聊天发送一条消息。不会保存任何内容。", + "noModel": "尚未安装聊天模型。请先安装或选择一个模型。", + "defaultModel": "未设置模型,因此测试使用 {{model}}。", + "skipped": "测试不使用:{{what}}。这些属于已保存的智能体。", + "skip": { + "grants": "权限", + "memory": "记忆", + "knowledge": "知识集合", + "folders": "共享文件夹" + }, + "empty": "发送一条消息开始。", + "role": { + "user": "你", + "assistant": "智能体", + "tool": "工具" + }, + "toolRan": "使用了工具:{{name}}", + "working": "处理中...", + "label": "给智能体的消息", + "placeholder": "问一件这个智能体应能处理的事", + "send": "发送", + "stop": "停止", + "deleted": "关闭此面板时,测试聊天会被删除。", + "chatTitle": "{{name}} 的测试", + "failed": "测试失败:{{message}}", + "slow": "智能体仍在工作。请停止它或关闭面板。" } }, "run": { diff --git a/core/http/react-ui/src/components/agents/AgentEffective.jsx b/core/http/react-ui/src/components/agents/AgentEffective.jsx new file mode 100644 index 0000000000..295efdbe66 --- /dev/null +++ b/core/http/react-ui/src/components/agents/AgentEffective.jsx @@ -0,0 +1,47 @@ +/* eslint-disable no-unused-vars -- components used only inside JSX look unused to this config, which has no eslint-plugin-react */ +import { Link } from 'react-router-dom' +import { useTranslation } from 'react-i18next' +import Icon from '../Icon' +import { blockedCount } from '../../utils/agentEffective' +import './agentparts.css' + +const ICON = { allowed: 'check', asks: 'info', off: 'minus', blocked: 'warning', info: 'info' } + +// The Effective view: what the agent can do right now, line by line, from the +// form as it stands. Each line names the section it explains and, when +// something is blocked, the one place that fixes it. Nothing here changes the +// form: a fix on this page only moves the reader to the section. +export default function AgentEffective({ lines, dirty, isEdit, hasConnections, onGoTo }) { + const { t } = useTranslation('agents') + const blocked = blockedCount(lines) + return ( +
+ {blocked ? t('create.eff.summaryBlocked', { count: blocked }) : t('create.eff.summaryOk')} +
+ {dirty &&{t(isEdit && hasConnections ? 'create.eff.unsavedConn' : 'create.eff.unsaved')}
} +{l.code}}
+ {t('create.try.desc')}
+{t('create.try.defaultModel', { model: request.model })}
} + {skipped.length > 0 && ( ++ {t('create.try.skipped', { what: skipped.map((k) => t(`create.try.skip.${k}`)).join(', ') })} +
+ )} +{t('create.try.deleted')}
+ +