mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-27 11:22:03 +00:00
fix(desktop): limit pending tool shimmer to action verb
Localize tool titles and split pending rows so only the action segment shimmers — paths, commands, and URLs stay static.
This commit is contained in:
parent
cbe5c5689f
commit
f2c45e2c81
8 changed files with 548 additions and 90 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { type ToolTitleKey, translateNow } from '@/i18n'
|
||||
import { normalizeExternalUrl } from '@/lib/external-link'
|
||||
import { extractToolErrorMessage, formatToolResultSummary } from '@/lib/tool-result-summary'
|
||||
import { translateNow } from '@/i18n'
|
||||
|
||||
export type ToolTone = 'agent' | 'browser' | 'default' | 'file' | 'image' | 'terminal' | 'web'
|
||||
export type ToolStatus = 'error' | 'running' | 'success' | 'warning'
|
||||
|
|
@ -20,6 +20,12 @@ export interface SearchResultRow {
|
|||
url: string
|
||||
}
|
||||
|
||||
export interface ToolTitleAction {
|
||||
prefix: string
|
||||
suffix: string
|
||||
text: string
|
||||
}
|
||||
|
||||
interface CountMetric {
|
||||
count: number
|
||||
noun: string
|
||||
|
|
@ -51,6 +57,7 @@ export interface ToolView {
|
|||
status: ToolStatus
|
||||
subtitle: string
|
||||
title: string
|
||||
titleAction?: ToolTitleAction
|
||||
tone: ToolTone
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +65,12 @@ interface ToolMeta {
|
|||
done: string
|
||||
icon?: string
|
||||
pending: string
|
||||
pendingAction: string
|
||||
tone: ToolTone
|
||||
}
|
||||
|
||||
interface ToolMetaSpec {
|
||||
icon?: string
|
||||
tone: ToolTone
|
||||
}
|
||||
|
||||
|
|
@ -112,44 +125,78 @@ function fileEditBasename(path: string): string {
|
|||
return normalized.split('/').filter(Boolean).pop() || normalized
|
||||
}
|
||||
|
||||
const TOOL_META: Record<string, ToolMeta> = {
|
||||
browser_click: { done: 'Clicked page element', pending: 'Clicking page element', icon: 'globe', tone: 'browser' },
|
||||
browser_fill: { done: 'Filled form field', pending: 'Filling form field', icon: 'globe', tone: 'browser' },
|
||||
browser_navigate: { done: 'Opened page', pending: 'Opening page', icon: 'globe', tone: 'browser' },
|
||||
const TOOL_META: Record<ToolTitleKey, ToolMetaSpec> = {
|
||||
browser_click: {
|
||||
icon: 'globe',
|
||||
tone: 'browser'
|
||||
},
|
||||
browser_fill: {
|
||||
icon: 'globe',
|
||||
tone: 'browser'
|
||||
},
|
||||
browser_navigate: {
|
||||
icon: 'globe',
|
||||
tone: 'browser'
|
||||
},
|
||||
browser_snapshot: {
|
||||
done: 'Captured page snapshot',
|
||||
pending: 'Capturing page snapshot',
|
||||
icon: 'globe',
|
||||
tone: 'browser'
|
||||
},
|
||||
browser_take_screenshot: {
|
||||
done: 'Captured screenshot',
|
||||
pending: 'Capturing screenshot',
|
||||
icon: 'file-media',
|
||||
tone: 'browser'
|
||||
},
|
||||
browser_type: { done: 'Typed on page', pending: 'Typing on page', icon: 'globe', tone: 'browser' },
|
||||
clarify: { done: 'Asked a question', pending: 'Asking a question', icon: 'question', tone: 'agent' },
|
||||
cronjob: { done: 'Cron job', pending: 'Scheduling cron job', icon: 'watch', tone: 'agent' },
|
||||
edit_file: { done: 'Edited file', pending: 'Editing file', icon: 'edit', tone: 'file' },
|
||||
execute_code: { done: 'Ran code', pending: 'Running code', icon: 'terminal', tone: 'terminal' },
|
||||
image_generate: { done: 'Generated image', pending: 'Generating image', icon: 'file-media', tone: 'image' },
|
||||
list_files: { done: 'Listed files', pending: 'Listing files', icon: 'files', tone: 'file' },
|
||||
patch: { done: 'Patched file', pending: 'Patching file', icon: 'edit', tone: 'file' },
|
||||
read_file: { done: 'Read file', pending: 'Reading file', icon: 'file', tone: 'file' },
|
||||
search_files: { done: 'Searched files', pending: 'Searching files', icon: 'search', tone: 'file' },
|
||||
browser_type: {
|
||||
icon: 'globe',
|
||||
tone: 'browser'
|
||||
},
|
||||
clarify: {
|
||||
icon: 'question',
|
||||
tone: 'agent'
|
||||
},
|
||||
cronjob: {
|
||||
icon: 'watch',
|
||||
tone: 'agent'
|
||||
},
|
||||
edit_file: { icon: 'edit', tone: 'file' },
|
||||
execute_code: {
|
||||
icon: 'terminal',
|
||||
tone: 'terminal'
|
||||
},
|
||||
image_generate: {
|
||||
icon: 'file-media',
|
||||
tone: 'image'
|
||||
},
|
||||
list_files: {
|
||||
icon: 'files',
|
||||
tone: 'file'
|
||||
},
|
||||
patch: { icon: 'edit', tone: 'file' },
|
||||
read_file: { icon: 'file', tone: 'file' },
|
||||
search_files: {
|
||||
icon: 'search',
|
||||
tone: 'file'
|
||||
},
|
||||
session_search_recall: {
|
||||
done: 'Searched session history',
|
||||
pending: 'Searching session history',
|
||||
icon: 'search',
|
||||
tone: 'agent'
|
||||
},
|
||||
terminal: { done: 'Ran command', pending: 'Running command', icon: 'terminal', tone: 'terminal' },
|
||||
todo: { done: 'Updated todos', pending: 'Updating todos', icon: 'tools', tone: 'agent' },
|
||||
vision_analyze: { done: 'Analyzed image', pending: 'Analyzing image', icon: 'eye', tone: 'image' },
|
||||
web_extract: { done: 'Read webpage', pending: 'Reading webpage', icon: 'globe', tone: 'web' },
|
||||
web_search: { done: 'Searched web', pending: 'Searching web', icon: 'search', tone: 'web' },
|
||||
write_file: { done: 'Edited file', pending: 'Editing file', icon: 'edit', tone: 'file' }
|
||||
terminal: {
|
||||
icon: 'terminal',
|
||||
tone: 'terminal'
|
||||
},
|
||||
todo: { icon: 'tools', tone: 'agent' },
|
||||
vision_analyze: {
|
||||
icon: 'eye',
|
||||
tone: 'image'
|
||||
},
|
||||
web_extract: { icon: 'globe', tone: 'web' },
|
||||
web_search: { icon: 'search', tone: 'web' },
|
||||
write_file: { icon: 'edit', tone: 'file' }
|
||||
}
|
||||
|
||||
function isToolTitleKey(name: string): name is ToolTitleKey {
|
||||
return name in TOOL_META
|
||||
}
|
||||
|
||||
const INLINE_CODE_SPLIT_RE = /(`[^`\n]+`)/g
|
||||
|
|
@ -171,27 +218,45 @@ function titleForTool(name: string): string {
|
|||
)
|
||||
}
|
||||
|
||||
const PREFIX_META: { icon?: string; prefix: string; tone: ToolTone; verb: string }[] = [
|
||||
{ prefix: 'browser_', verb: 'Browser', icon: 'globe', tone: 'browser' },
|
||||
{ prefix: 'web_', verb: 'Web', icon: 'globe', tone: 'web' }
|
||||
const PREFIX_META: { icon?: string; labelKey: string; prefix: string; tone: ToolTone }[] = [
|
||||
{ prefix: 'browser_', labelKey: 'browser', icon: 'globe', tone: 'browser' },
|
||||
{ prefix: 'web_', labelKey: 'web', icon: 'globe', tone: 'web' }
|
||||
]
|
||||
|
||||
function toolMeta(name: string): ToolMeta {
|
||||
if (TOOL_META[name]) {
|
||||
return TOOL_META[name]
|
||||
if (isToolTitleKey(name)) {
|
||||
const meta = TOOL_META[name]
|
||||
|
||||
return {
|
||||
done: translateNow(`assistant.tool.titles.${name}.done`),
|
||||
pending: translateNow(`assistant.tool.titles.${name}.pending`),
|
||||
pendingAction: translateNow(`assistant.tool.titles.${name}.pendingAction`),
|
||||
icon: meta.icon,
|
||||
tone: meta.tone
|
||||
}
|
||||
}
|
||||
|
||||
const action = titleForTool(name)
|
||||
const prefix = PREFIX_META.find(p => name.startsWith(p.prefix))
|
||||
|
||||
return prefix
|
||||
? {
|
||||
done: `${prefix.verb} ${action}`,
|
||||
pending: `Running ${prefix.verb.toLowerCase()} ${action.toLowerCase()}`,
|
||||
icon: prefix.icon,
|
||||
tone: prefix.tone
|
||||
}
|
||||
: { done: action, pending: `Running ${action.toLowerCase()}`, tone: 'default' }
|
||||
if (prefix) {
|
||||
const prefixLabel = translateNow(`assistant.tool.prefixes.${prefix.labelKey}`)
|
||||
|
||||
return {
|
||||
done: translateNow('assistant.tool.titleTemplates.prefixedDone', prefixLabel, action),
|
||||
pending: translateNow('assistant.tool.titleTemplates.runningPrefixedTool', prefixLabel, action),
|
||||
pendingAction: translateNow('assistant.tool.actions.running'),
|
||||
icon: prefix.icon,
|
||||
tone: prefix.tone
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
done: action,
|
||||
pending: translateNow('assistant.tool.titleTemplates.runningTool', action),
|
||||
pendingAction: translateNow('assistant.tool.actions.running'),
|
||||
tone: 'default'
|
||||
}
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
|
|
@ -967,8 +1032,13 @@ function fallbackDetailText(args: unknown, result: unknown): string {
|
|||
}
|
||||
|
||||
function cronScalar(value: unknown): string {
|
||||
if (typeof value === 'string') return value.trim()
|
||||
if (typeof value === 'number' && Number.isFinite(value)) return String(value)
|
||||
if (typeof value === 'string') {
|
||||
return value.trim()
|
||||
}
|
||||
|
||||
if (typeof value === 'number' && Number.isFinite(value)) {
|
||||
return String(value)
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
|
@ -976,7 +1046,9 @@ function cronScalar(value: unknown): string {
|
|||
function formatCronTime(iso: string): string {
|
||||
const ts = Date.parse(iso)
|
||||
|
||||
if (Number.isNaN(ts)) return iso
|
||||
if (Number.isNaN(ts)) {
|
||||
return iso
|
||||
}
|
||||
|
||||
return new Date(ts).toLocaleString(undefined, {
|
||||
month: 'short',
|
||||
|
|
@ -986,10 +1058,7 @@ function formatCronTime(iso: string): string {
|
|||
})
|
||||
}
|
||||
|
||||
function cronjobSubtitle(
|
||||
argsRecord: Record<string, unknown>,
|
||||
resultRecord: Record<string, unknown>
|
||||
): string {
|
||||
function cronjobSubtitle(argsRecord: Record<string, unknown>, resultRecord: Record<string, unknown>): string {
|
||||
const jobs = Array.isArray(resultRecord.jobs) ? resultRecord.jobs : null
|
||||
|
||||
if (jobs) {
|
||||
|
|
@ -998,7 +1067,9 @@ function cronjobSubtitle(
|
|||
|
||||
const message = firstStringField(resultRecord, ['message'])
|
||||
|
||||
if (message) return message
|
||||
if (message) {
|
||||
return message
|
||||
}
|
||||
|
||||
const action = firstStringField(argsRecord, ['action']) || 'manage'
|
||||
const name = firstStringField(resultRecord, ['name']) || firstStringField(argsRecord, ['name', 'job_id'])
|
||||
|
|
@ -1007,14 +1078,13 @@ function cronjobSubtitle(
|
|||
return name ? `${label} ${name}` : `Cron ${action}`
|
||||
}
|
||||
|
||||
function cronjobDetail(
|
||||
argsRecord: Record<string, unknown>,
|
||||
resultRecord: Record<string, unknown>
|
||||
): string {
|
||||
function cronjobDetail(argsRecord: Record<string, unknown>, resultRecord: Record<string, unknown>): string {
|
||||
const jobs = Array.isArray(resultRecord.jobs) ? resultRecord.jobs : null
|
||||
|
||||
if (jobs) {
|
||||
if (!jobs.length) return 'No cron jobs scheduled'
|
||||
if (!jobs.length) {
|
||||
return 'No cron jobs scheduled'
|
||||
}
|
||||
|
||||
return jobs
|
||||
.slice(0, 20)
|
||||
|
|
@ -1029,12 +1099,14 @@ function cronjobDetail(
|
|||
}
|
||||
|
||||
const nextRun = cronScalar(resultRecord.next_run_at)
|
||||
|
||||
const rows: [string, string][] = [
|
||||
['Schedule', cronScalar(resultRecord.schedule)],
|
||||
['Repeat', cronScalar(resultRecord.repeat)],
|
||||
['Delivery', cronScalar(resultRecord.deliver)],
|
||||
['Next run', nextRun ? formatCronTime(nextRun) : '']
|
||||
]
|
||||
|
||||
const lines = rows.filter(([, value]) => value).map(([key, value]) => `${key}: ${value}`)
|
||||
|
||||
return lines.length ? lines.join('\n') : fallbackDetailText(argsRecord, resultRecord)
|
||||
|
|
@ -1277,6 +1349,7 @@ export function toolCopyPayload(part: ToolPart, view: ToolView): { label: string
|
|||
url: translateNow('assistant.tool.copyUrl'),
|
||||
generic: translateNow('common.copy')
|
||||
}
|
||||
|
||||
const args = parseMaybeObject(part.args)
|
||||
const result = parseMaybeObject(part.result)
|
||||
const detail = view.detail.trim()
|
||||
|
|
@ -1359,39 +1432,90 @@ export function toolCopyPayload(part: ToolPart, view: ToolView): { label: string
|
|||
return { label: copy.generic, text: view.title }
|
||||
}
|
||||
|
||||
interface ToolTitleParts {
|
||||
action?: ToolTitleAction
|
||||
title: string
|
||||
}
|
||||
|
||||
function titlePartsFromAction(title: string, action?: string): ToolTitleParts {
|
||||
if (!action) {
|
||||
return { title }
|
||||
}
|
||||
|
||||
const actionStart = title.indexOf(action)
|
||||
|
||||
if (actionStart < 0) {
|
||||
return { title }
|
||||
}
|
||||
|
||||
return {
|
||||
action: {
|
||||
prefix: title.slice(0, actionStart),
|
||||
suffix: title.slice(actionStart + action.length),
|
||||
text: action
|
||||
},
|
||||
title
|
||||
}
|
||||
}
|
||||
|
||||
function dynamicTitle(
|
||||
part: ToolPart,
|
||||
args: Record<string, unknown>,
|
||||
result: Record<string, unknown>,
|
||||
fallback: string
|
||||
): string {
|
||||
fallback: ToolTitleParts
|
||||
): ToolTitleParts {
|
||||
const verb = (gerund: string, past: string) => (part.result === undefined ? gerund : past)
|
||||
|
||||
const titledAction = (action: string, title: string): ToolTitleParts =>
|
||||
titlePartsFromAction(title, part.result === undefined ? action : undefined)
|
||||
|
||||
if (part.toolName === 'web_extract') {
|
||||
const url = findFirstUrl(args, result)
|
||||
const action = verb(translateNow('assistant.tool.actions.reading'), translateNow('assistant.tool.actions.read'))
|
||||
|
||||
return url ? `${verb('Reading', 'Read')} ${hostnameOf(url)}` : fallback
|
||||
return url
|
||||
? titledAction(action, translateNow('assistant.tool.titleTemplates.actionTarget', action, hostnameOf(url)))
|
||||
: fallback
|
||||
}
|
||||
|
||||
if (part.toolName === 'browser_navigate') {
|
||||
const url = findFirstUrl(args, result)
|
||||
const action = verb(translateNow('assistant.tool.actions.opening'), translateNow('assistant.tool.actions.opened'))
|
||||
|
||||
return url ? `${verb('Opening', 'Opened')} ${hostnameOf(url)}` : fallback
|
||||
return url
|
||||
? titledAction(action, translateNow('assistant.tool.titleTemplates.actionTarget', action, hostnameOf(url)))
|
||||
: fallback
|
||||
}
|
||||
|
||||
if (part.toolName === 'web_search') {
|
||||
const query = firstStringField(args, ['search_term', 'query']) || contextValue(args)
|
||||
|
||||
return query ? `${verb('Searching', 'Searched')} “${compactPreview(query, 48)}”` : fallback
|
||||
const action = verb(
|
||||
translateNow('assistant.tool.actions.searching'),
|
||||
translateNow('assistant.tool.actions.searched')
|
||||
)
|
||||
|
||||
return query
|
||||
? titledAction(
|
||||
action,
|
||||
translateNow('assistant.tool.titleTemplates.actionQuoted', action, compactPreview(query, 48))
|
||||
)
|
||||
: fallback
|
||||
}
|
||||
|
||||
if (part.toolName === 'terminal' || part.toolName === 'execute_code') {
|
||||
const command = firstStringField(args, ['command', 'code']) || contextValue(args)
|
||||
|
||||
if (command) {
|
||||
const verbText = part.toolName === 'execute_code' ? verb('Running code', 'Ran code') : verb('Running', 'Ran')
|
||||
const action =
|
||||
part.toolName === 'execute_code'
|
||||
? verb(translateNow('assistant.tool.actions.runningCode'), translateNow('assistant.tool.actions.ranCode'))
|
||||
: verb(translateNow('assistant.tool.actions.running'), translateNow('assistant.tool.actions.ran'))
|
||||
|
||||
return `${verbText} · ${compactPreview(command, 160)}`
|
||||
return titledAction(
|
||||
action,
|
||||
translateNow('assistant.tool.titleTemplates.actionCommand', action, compactPreview(command, 160))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1399,7 +1523,7 @@ function dynamicTitle(
|
|||
const path = fileEditPath(args, result)
|
||||
|
||||
if (path) {
|
||||
return fileEditBasename(path)
|
||||
return { title: fileEditBasename(path) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1413,7 +1537,15 @@ export function buildToolView(part: ToolPart, inlineDiff: string): ToolView {
|
|||
const status = toolStatus(part, resultRecord)
|
||||
const error = toolErrorText(part, resultRecord)
|
||||
const baseTitle = part.result === undefined ? meta.pending : meta.done
|
||||
const title = dynamicTitle(part, argsRecord, resultRecord, baseTitle)
|
||||
|
||||
const titleParts = dynamicTitle(
|
||||
part,
|
||||
argsRecord,
|
||||
resultRecord,
|
||||
titlePartsFromAction(baseTitle, part.result === undefined ? meta.pendingAction : undefined)
|
||||
)
|
||||
|
||||
const title = titleParts.title
|
||||
const titleEnriched = title !== baseTitle
|
||||
const baseSubtitle = error || toolSubtitle(part, argsRecord, resultRecord)
|
||||
|
||||
|
|
@ -1467,6 +1599,7 @@ export function buildToolView(part: ToolPart, inlineDiff: string): ToolView {
|
|||
status,
|
||||
subtitle,
|
||||
title,
|
||||
titleAction: titleParts.action,
|
||||
tone: meta.tone
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ import {
|
|||
toolCopyPayload,
|
||||
type ToolPart,
|
||||
toolPartDisclosureId,
|
||||
type ToolStatus
|
||||
type ToolStatus,
|
||||
type ToolTitleAction
|
||||
} from './tool-fallback-model'
|
||||
|
||||
// `true` when a ToolEntry is rendered inside an embedding wrapper that owns
|
||||
|
|
@ -203,6 +204,39 @@ function LinkifiedText({ className, text }: { className?: string; text: string }
|
|||
return <SharedLinkifiedText className={className} pretty text={cleanVisibleText(text)} />
|
||||
}
|
||||
|
||||
function ToolTitle({
|
||||
isPending,
|
||||
status,
|
||||
title,
|
||||
titleAction
|
||||
}: {
|
||||
isPending: boolean
|
||||
status: ToolStatus
|
||||
title: string
|
||||
titleAction?: ToolTitleAction
|
||||
}) {
|
||||
return (
|
||||
<FadeText
|
||||
className={cn(
|
||||
TOOL_HEADER_TITLE_CLASS,
|
||||
isPending && 'text-(--ui-text-tertiary)',
|
||||
status === 'error' && 'text-destructive',
|
||||
status === 'warning' && 'text-amber-700 dark:text-amber-300'
|
||||
)}
|
||||
>
|
||||
{isPending && titleAction ? (
|
||||
<>
|
||||
{titleAction.prefix}
|
||||
<span className="shimmer">{titleAction.text}</span>
|
||||
{titleAction.suffix}
|
||||
</>
|
||||
) : (
|
||||
title
|
||||
)}
|
||||
</FadeText>
|
||||
)
|
||||
}
|
||||
|
||||
interface ToolEntryProps {
|
||||
part: ToolPart
|
||||
}
|
||||
|
|
@ -414,16 +448,7 @@ function ToolEntry({ part }: ToolEntryProps) {
|
|||
icon={view.icon}
|
||||
status={leadingStatus(isPending, view.status)}
|
||||
/>
|
||||
<FadeText
|
||||
className={cn(
|
||||
TOOL_HEADER_TITLE_CLASS,
|
||||
isPending && 'shimmer text-(--ui-text-tertiary)',
|
||||
view.status === 'error' && 'text-destructive',
|
||||
view.status === 'warning' && 'text-amber-700 dark:text-amber-300'
|
||||
)}
|
||||
>
|
||||
{view.title}
|
||||
</FadeText>
|
||||
<ToolTitle isPending={isPending} status={view.status} title={view.title} titleAction={view.titleAction} />
|
||||
{!isPending && view.countLabel && <span className={TOOL_HEADER_DURATION_CLASS}>{view.countLabel}</span>}
|
||||
{showDiffStats && diffStats && (
|
||||
<span className="flex shrink-0 items-center gap-1 font-mono text-[0.625rem] tabular-nums">
|
||||
|
|
|
|||
|
|
@ -1845,7 +1845,8 @@ export const en: Translations = {
|
|||
restoreCheckpoint: 'Restore checkpoint',
|
||||
restoreFromHere: 'Restore checkpoint — rerun from this prompt',
|
||||
restoreTitle: 'Restore to this checkpoint?',
|
||||
restoreBody: 'Everything after this prompt is removed from the conversation, and the prompt runs again from here.',
|
||||
restoreBody:
|
||||
'Everything after this prompt is removed from the conversation, and the prompt runs again from here.',
|
||||
restoreConfirm: 'Restore & rerun',
|
||||
restoreNext: 'Restore next checkpoint',
|
||||
goForward: 'Go forward',
|
||||
|
|
@ -1901,7 +1902,67 @@ export const en: Translations = {
|
|||
statusRunning: 'Running',
|
||||
statusError: 'Error',
|
||||
statusRecovered: 'Recovered',
|
||||
statusDone: 'Done'
|
||||
statusDone: 'Done',
|
||||
actions: {
|
||||
read: 'Read',
|
||||
reading: 'Reading',
|
||||
opened: 'Opened',
|
||||
opening: 'Opening',
|
||||
searched: 'Searched',
|
||||
searching: 'Searching',
|
||||
ran: 'Ran',
|
||||
running: 'Running',
|
||||
ranCode: 'Ran code',
|
||||
runningCode: 'Scripting'
|
||||
},
|
||||
prefixes: {
|
||||
browser: 'Browser',
|
||||
web: 'Web'
|
||||
},
|
||||
titleTemplates: {
|
||||
actionCommand: (action, command) => `${action} · ${command}`,
|
||||
actionQuoted: (action, value) => `${action} “${value}”`,
|
||||
actionTarget: (action, target) => `${action} ${target}`,
|
||||
prefixedDone: (prefix, action) => `${prefix} ${action}`,
|
||||
runningPrefixedTool: (prefix, action) => `Running ${prefix.toLowerCase()} ${action.toLowerCase()}`,
|
||||
runningTool: action => `Running ${action.toLowerCase()}`
|
||||
},
|
||||
titles: {
|
||||
browser_click: { done: 'Clicked page element', pending: 'Clicking page element', pendingAction: 'Clicking' },
|
||||
browser_fill: { done: 'Filled form field', pending: 'Filling form field', pendingAction: 'Filling' },
|
||||
browser_navigate: { done: 'Opened page', pending: 'Opening page', pendingAction: 'Opening' },
|
||||
browser_snapshot: {
|
||||
done: 'Captured page snapshot',
|
||||
pending: 'Capturing page snapshot',
|
||||
pendingAction: 'Capturing'
|
||||
},
|
||||
browser_take_screenshot: {
|
||||
done: 'Captured screenshot',
|
||||
pending: 'Capturing screenshot',
|
||||
pendingAction: 'Capturing'
|
||||
},
|
||||
browser_type: { done: 'Typed on page', pending: 'Typing on page', pendingAction: 'Typing' },
|
||||
clarify: { done: 'Asked a question', pending: 'Asking a question', pendingAction: 'Asking' },
|
||||
cronjob: { done: 'Cron job', pending: 'Scheduling cron job', pendingAction: 'Scheduling' },
|
||||
edit_file: { done: 'Edited file', pending: 'Editing file', pendingAction: 'Editing' },
|
||||
execute_code: { done: 'Ran code', pending: 'Scripting', pendingAction: 'Scripting' },
|
||||
image_generate: { done: 'Generated image', pending: 'Generating image', pendingAction: 'Generating' },
|
||||
list_files: { done: 'Listed files', pending: 'Listing files', pendingAction: 'Listing' },
|
||||
patch: { done: 'Patched file', pending: 'Patching file', pendingAction: 'Patching' },
|
||||
read_file: { done: 'Read file', pending: 'Reading file', pendingAction: 'Reading' },
|
||||
search_files: { done: 'Searched files', pending: 'Searching files', pendingAction: 'Searching' },
|
||||
session_search_recall: {
|
||||
done: 'Searched session history',
|
||||
pending: 'Searching session history',
|
||||
pendingAction: 'Searching'
|
||||
},
|
||||
terminal: { done: 'Ran command', pending: 'Running command', pendingAction: 'Running' },
|
||||
todo: { done: 'Updated todos', pending: 'Updating todos', pendingAction: 'Updating' },
|
||||
vision_analyze: { done: 'Analyzed image', pending: 'Analyzing image', pendingAction: 'Analyzing' },
|
||||
web_extract: { done: 'Read webpage', pending: 'Reading webpage', pendingAction: 'Reading' },
|
||||
web_search: { done: 'Searched web', pending: 'Searching web', pendingAction: 'Searching' },
|
||||
write_file: { done: 'Edited file', pending: 'Editing file', pendingAction: 'Editing' }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -1944,7 +2005,8 @@ export const en: Translations = {
|
|||
editFailed: 'Edit failed',
|
||||
resumeFailed: 'Resume failed',
|
||||
resumeStrandedTitle: "Couldn't load this session",
|
||||
resumeStrandedBody: 'The connection to this session failed and automatic retries gave up. Check that the gateway is running, then try again.',
|
||||
resumeStrandedBody:
|
||||
'The connection to this session failed and automatic retries gave up. Check that the gateway is running, then try again.',
|
||||
resumeRetry: 'Retry',
|
||||
nothingToBranch: 'Nothing to branch',
|
||||
branchNeedsChat: 'Start or resume a chat before branching.',
|
||||
|
|
|
|||
|
|
@ -17,4 +17,4 @@ export {
|
|||
normalizeLocale
|
||||
} from './languages'
|
||||
export { setRuntimeI18nLocale, translateNow } from './runtime'
|
||||
export type { Locale, Translations } from './types'
|
||||
export type { Locale, ToolTitleKey, Translations } from './types'
|
||||
|
|
|
|||
|
|
@ -201,8 +201,7 @@ export const ja = defineLocale({
|
|||
},
|
||||
notifications: {
|
||||
title: '通知',
|
||||
intro:
|
||||
'アプリ内トーストとは別の、ネイティブのデスクトップ通知です。設定は端末ごとに保存されます。',
|
||||
intro: 'アプリ内トーストとは別の、ネイティブのデスクトップ通知です。設定は端末ごとに保存されます。',
|
||||
enableAll: '通知を有効にする',
|
||||
enableAllDesc: 'マスタースイッチ。オフにすると以下のすべての通知を無効にします。',
|
||||
focusedHint: '完了通知は Hermes がバックグラウンドにあるときのみ表示されます。',
|
||||
|
|
@ -1498,7 +1497,8 @@ export const ja = defineLocale({
|
|||
queueSend: '送信',
|
||||
queueDelete: '削除',
|
||||
queueStuckTitle: 'キュー内のメッセージを送信できません',
|
||||
queueStuckBody: 'キューに入れたターンの送信が繰り返し失敗しました。まだキューに残っています。もう一度送信してください。',
|
||||
queueStuckBody:
|
||||
'キューに入れたターンの送信が繰り返し失敗しました。まだキューに残っています。もう一度送信してください。',
|
||||
previewUnavailable: 'プレビューは利用できません',
|
||||
previewLabel: label => `${label} のプレビュー`,
|
||||
couldNotPreview: label => `${label} をプレビューできませんでした`,
|
||||
|
|
@ -1597,7 +1597,8 @@ export const ja = defineLocale({
|
|||
copy: 'コピー',
|
||||
copied: 'コピーしました',
|
||||
done: '完了',
|
||||
applyingBody: 'Hermes アップデーターが独自のウィンドウで引き継ぎ、完了後に自動的に Hermes を再度開きます。更新中はご自分で Hermes を開き直さないでください。',
|
||||
applyingBody:
|
||||
'Hermes アップデーターが独自のウィンドウで引き継ぎ、完了後に自動的に Hermes を再度開きます。更新中はご自分で Hermes を開き直さないでください。',
|
||||
applyingBodyBackend: 'リモートバックエンドが更新を適用して再起動します。復帰すると Hermes が自動的に再接続します。',
|
||||
applyingClose: 'このウィンドウは更新中に閉じ、その後 Hermes が自動的に再度開きます。',
|
||||
errorTitle: '更新が完了しませんでした',
|
||||
|
|
@ -2029,7 +2030,83 @@ export const ja = defineLocale({
|
|||
statusRunning: '実行中',
|
||||
statusError: 'エラー',
|
||||
statusRecovered: '回復しました',
|
||||
statusDone: '完了'
|
||||
statusDone: '完了',
|
||||
actions: {
|
||||
read: '読み取り完了',
|
||||
reading: '読み取り中',
|
||||
opened: 'オープン済み',
|
||||
opening: 'オープン中',
|
||||
searched: '検索完了',
|
||||
searching: '検索中',
|
||||
ran: '実行完了',
|
||||
running: '実行中',
|
||||
ranCode: 'コード実行完了',
|
||||
runningCode: 'スクリプト作成中'
|
||||
},
|
||||
prefixes: {
|
||||
browser: 'ブラウザー',
|
||||
web: 'Web'
|
||||
},
|
||||
titleTemplates: {
|
||||
actionCommand: (action, command) => `${action} · ${command}`,
|
||||
actionQuoted: (action, value) => `「${value}」を${action}`,
|
||||
actionTarget: (action, target) => `${target} を${action}`,
|
||||
prefixedDone: (prefix, action) => `${prefix} ${action}`,
|
||||
runningPrefixedTool: (prefix, action) => `${prefix} ${action}を実行中`,
|
||||
runningTool: action => `${action}を実行中`
|
||||
},
|
||||
titles: {
|
||||
browser_click: {
|
||||
done: 'ページ要素をクリックしました',
|
||||
pending: 'ページ要素をクリック中',
|
||||
pendingAction: 'クリック中'
|
||||
},
|
||||
browser_fill: { done: 'フォーム欄に入力しました', pending: 'フォーム欄に入力中', pendingAction: '入力中' },
|
||||
browser_navigate: { done: 'ページを開きました', pending: 'ページをオープン中', pendingAction: 'オープン中' },
|
||||
browser_snapshot: {
|
||||
done: 'ページスナップショットを取得しました',
|
||||
pending: 'ページスナップショットを取得中',
|
||||
pendingAction: '取得中'
|
||||
},
|
||||
browser_take_screenshot: {
|
||||
done: 'スクリーンショットを取得しました',
|
||||
pending: 'スクリーンショットを取得中',
|
||||
pendingAction: '取得中'
|
||||
},
|
||||
browser_type: { done: 'ページに入力しました', pending: 'ページに入力中', pendingAction: '入力中' },
|
||||
clarify: { done: '質問しました', pending: '質問中', pendingAction: '質問中' },
|
||||
cronjob: { done: 'Cron ジョブ', pending: 'Cron ジョブをスケジュール中', pendingAction: 'スケジュール中' },
|
||||
edit_file: { done: 'ファイルを編集しました', pending: 'ファイルを編集中', pendingAction: '編集中' },
|
||||
execute_code: { done: 'コードを実行しました', pending: 'スクリプト作成中', pendingAction: 'スクリプト作成中' },
|
||||
image_generate: { done: '画像を生成しました', pending: '画像を生成中', pendingAction: '生成中' },
|
||||
list_files: {
|
||||
done: 'ファイルを一覧表示しました',
|
||||
pending: 'ファイルを一覧表示中',
|
||||
pendingAction: '一覧表示中'
|
||||
},
|
||||
patch: {
|
||||
done: 'ファイルにパッチを適用しました',
|
||||
pending: 'ファイルにパッチ適用中',
|
||||
pendingAction: 'パッチ適用中'
|
||||
},
|
||||
read_file: { done: 'ファイルを読み取りました', pending: 'ファイルを読み取り中', pendingAction: '読み取り中' },
|
||||
search_files: { done: 'ファイルを検索しました', pending: 'ファイルを検索中', pendingAction: '検索中' },
|
||||
session_search_recall: {
|
||||
done: 'セッション履歴を検索しました',
|
||||
pending: 'セッション履歴を検索中',
|
||||
pendingAction: '検索中'
|
||||
},
|
||||
terminal: { done: 'コマンドを実行しました', pending: 'コマンドを実行中', pendingAction: '実行中' },
|
||||
todo: { done: 'Todo を更新しました', pending: 'Todo を更新中', pendingAction: '更新中' },
|
||||
vision_analyze: { done: '画像を分析しました', pending: '画像を分析中', pendingAction: '分析中' },
|
||||
web_extract: {
|
||||
done: 'Web ページを読み取りました',
|
||||
pending: 'Web ページを読み取り中',
|
||||
pendingAction: '読み取り中'
|
||||
},
|
||||
web_search: { done: 'Web を検索しました', pending: 'Web を検索中', pendingAction: '検索中' },
|
||||
write_file: { done: 'ファイルを編集しました', pending: 'ファイルを編集中', pendingAction: '編集中' }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -2073,7 +2150,8 @@ export const ja = defineLocale({
|
|||
editFailed: '編集に失敗しました',
|
||||
resumeFailed: '再開に失敗しました',
|
||||
resumeStrandedTitle: 'このセッションを読み込めませんでした',
|
||||
resumeStrandedBody: 'このセッションへの接続に失敗し、自動再試行も停止しました。ゲートウェイが実行中か確認してから、もう一度お試しください。',
|
||||
resumeStrandedBody:
|
||||
'このセッションへの接続に失敗し、自動再試行も停止しました。ゲートウェイが実行中か確認してから、もう一度お試しください。',
|
||||
resumeRetry: '再試行',
|
||||
nothingToBranch: 'ブランチするものがありません',
|
||||
branchNeedsChat: 'ブランチする前にチャットを開始または再開してください。',
|
||||
|
|
|
|||
|
|
@ -7,6 +7,36 @@
|
|||
|
||||
export type Locale = 'en' | 'zh' | 'zh-hant' | 'ja'
|
||||
|
||||
export type ToolTitleKey =
|
||||
| 'browser_click'
|
||||
| 'browser_fill'
|
||||
| 'browser_navigate'
|
||||
| 'browser_snapshot'
|
||||
| 'browser_take_screenshot'
|
||||
| 'browser_type'
|
||||
| 'clarify'
|
||||
| 'cronjob'
|
||||
| 'edit_file'
|
||||
| 'execute_code'
|
||||
| 'image_generate'
|
||||
| 'list_files'
|
||||
| 'patch'
|
||||
| 'read_file'
|
||||
| 'search_files'
|
||||
| 'session_search_recall'
|
||||
| 'terminal'
|
||||
| 'todo'
|
||||
| 'vision_analyze'
|
||||
| 'web_extract'
|
||||
| 'web_search'
|
||||
| 'write_file'
|
||||
|
||||
interface ToolTitleCopy {
|
||||
done: string
|
||||
pending: string
|
||||
pendingAction: string
|
||||
}
|
||||
|
||||
interface ModeOptionCopy {
|
||||
label: string
|
||||
description: string
|
||||
|
|
@ -1533,6 +1563,31 @@ export interface Translations {
|
|||
statusError: string
|
||||
statusRecovered: string
|
||||
statusDone: string
|
||||
actions: {
|
||||
read: string
|
||||
reading: string
|
||||
opened: string
|
||||
opening: string
|
||||
searched: string
|
||||
searching: string
|
||||
ran: string
|
||||
running: string
|
||||
ranCode: string
|
||||
runningCode: string
|
||||
}
|
||||
prefixes: {
|
||||
browser: string
|
||||
web: string
|
||||
}
|
||||
titleTemplates: {
|
||||
actionCommand: (action: string, command: string) => string
|
||||
actionQuoted: (action: string, value: string) => string
|
||||
actionTarget: (action: string, target: string) => string
|
||||
prefixedDone: (prefix: string, action: string) => string
|
||||
runningPrefixedTool: (prefix: string, action: string) => string
|
||||
runningTool: (action: string) => string
|
||||
}
|
||||
titles: Record<ToolTitleKey, ToolTitleCopy>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -280,7 +280,8 @@ export const zhHant = defineLocale({
|
|||
importedBadge: '已匯入',
|
||||
pet: {
|
||||
title: '寵物',
|
||||
intro: '領養一隻懸浮在應用上的 petdex 動畫寵物,它會根據 Hermes 的狀態做出反應——工具執行時奔跑、成功時歡呼、出錯時沮喪。',
|
||||
intro:
|
||||
'領養一隻懸浮在應用上的 petdex 動畫寵物,它會根據 Hermes 的狀態做出反應——工具執行時奔跑、成功時歡呼、出錯時沮喪。',
|
||||
restartHint: '寵物功能需要重新啟動——目前執行的應用在此功能加入前啟動。請結束並重新開啟 Hermes,然後回到此處。',
|
||||
scaleTitle: '大小',
|
||||
scaleDesc: '調整懸浮寵物的大小,所有介面即時生效。',
|
||||
|
|
@ -1546,7 +1547,8 @@ export const zhHant = defineLocale({
|
|||
copy: '複製',
|
||||
copied: '已複製',
|
||||
done: '完成',
|
||||
applyingBody: 'Hermes 更新程式會在自己的視窗中接管,並在完成後自動重新開啟 Hermes。更新期間請勿自行重新開啟 Hermes。',
|
||||
applyingBody:
|
||||
'Hermes 更新程式會在自己的視窗中接管,並在完成後自動重新開啟 Hermes。更新期間請勿自行重新開啟 Hermes。',
|
||||
applyingBodyBackend: '遠端後端正在套用更新並將重新啟動。恢復後 Hermes 會自動重新連線。',
|
||||
applyingClose: '此視窗會在更新期間關閉,隨後 Hermes 會自動重新開啟。',
|
||||
errorTitle: '更新未完成',
|
||||
|
|
@ -1968,7 +1970,59 @@ export const zhHant = defineLocale({
|
|||
statusRunning: '執行中',
|
||||
statusError: '錯誤',
|
||||
statusRecovered: '已復原',
|
||||
statusDone: '完成'
|
||||
statusDone: '完成',
|
||||
actions: {
|
||||
read: '已讀取',
|
||||
reading: '正在讀取',
|
||||
opened: '已開啟',
|
||||
opening: '正在開啟',
|
||||
searched: '已搜尋',
|
||||
searching: '正在搜尋',
|
||||
ran: '已執行',
|
||||
running: '正在執行',
|
||||
ranCode: '已執行程式碼',
|
||||
runningCode: '正在撰寫腳本'
|
||||
},
|
||||
prefixes: {
|
||||
browser: '瀏覽器',
|
||||
web: '網頁'
|
||||
},
|
||||
titleTemplates: {
|
||||
actionCommand: (action, command) => `${action} · ${command}`,
|
||||
actionQuoted: (action, value) => `${action}「${value}」`,
|
||||
actionTarget: (action, target) => `${action} ${target}`,
|
||||
prefixedDone: (prefix, action) => `${prefix}${action}`,
|
||||
runningPrefixedTool: (prefix, action) => `正在執行${prefix}${action}`,
|
||||
runningTool: action => `正在執行 ${action}`
|
||||
},
|
||||
titles: {
|
||||
browser_click: { done: '已點擊頁面元素', pending: '正在點擊頁面元素', pendingAction: '正在點擊' },
|
||||
browser_fill: { done: '已填寫表單欄位', pending: '正在填寫表單欄位', pendingAction: '正在填寫' },
|
||||
browser_navigate: { done: '已開啟頁面', pending: '正在開啟頁面', pendingAction: '正在開啟' },
|
||||
browser_snapshot: { done: '已擷取頁面快照', pending: '正在擷取頁面快照', pendingAction: '正在擷取' },
|
||||
browser_take_screenshot: { done: '已擷取截圖', pending: '正在擷取截圖', pendingAction: '正在擷取' },
|
||||
browser_type: { done: '已在頁面輸入', pending: '正在頁面輸入', pendingAction: '正在輸入' },
|
||||
clarify: { done: '已提問', pending: '正在提問', pendingAction: '正在提問' },
|
||||
cronjob: { done: 'Cron 工作', pending: '正在安排 Cron 工作', pendingAction: '正在安排' },
|
||||
edit_file: { done: '已編輯檔案', pending: '正在編輯檔案', pendingAction: '正在編輯' },
|
||||
execute_code: { done: '已執行程式碼', pending: '正在撰寫腳本', pendingAction: '正在撰寫腳本' },
|
||||
image_generate: { done: '已生成圖片', pending: '正在生成圖片', pendingAction: '正在生成' },
|
||||
list_files: { done: '已列出檔案', pending: '正在列出檔案', pendingAction: '正在列出' },
|
||||
patch: { done: '已修補檔案', pending: '正在修補檔案', pendingAction: '正在修補' },
|
||||
read_file: { done: '已讀取檔案', pending: '正在讀取檔案', pendingAction: '正在讀取' },
|
||||
search_files: { done: '已搜尋檔案', pending: '正在搜尋檔案', pendingAction: '正在搜尋' },
|
||||
session_search_recall: {
|
||||
done: '已搜尋工作階段歷史',
|
||||
pending: '正在搜尋工作階段歷史',
|
||||
pendingAction: '正在搜尋'
|
||||
},
|
||||
terminal: { done: '已執行指令', pending: '正在執行指令', pendingAction: '正在執行' },
|
||||
todo: { done: '已更新待辦', pending: '正在更新待辦', pendingAction: '正在更新' },
|
||||
vision_analyze: { done: '已分析圖片', pending: '正在分析圖片', pendingAction: '正在分析' },
|
||||
web_extract: { done: '已讀取網頁', pending: '正在讀取網頁', pendingAction: '正在讀取' },
|
||||
web_search: { done: '已搜尋網頁', pending: '正在搜尋網頁', pendingAction: '正在搜尋' },
|
||||
write_file: { done: '已編輯檔案', pending: '正在編輯檔案', pendingAction: '正在編輯' }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -369,7 +369,8 @@ export const zh: Translations = {
|
|||
importedBadge: '已导入',
|
||||
pet: {
|
||||
title: '宠物',
|
||||
intro: '领养一只悬浮在应用上的 petdex 动画宠物,它会根据 Hermes 的状态做出反应——工具执行时奔跑、成功时欢呼、出错时沮丧。',
|
||||
intro:
|
||||
'领养一只悬浮在应用上的 petdex 动画宠物,它会根据 Hermes 的状态做出反应——工具执行时奔跑、成功时欢呼、出错时沮丧。',
|
||||
restartHint: '宠物功能需要重启——当前运行的应用在此功能加入前启动。请退出并重新打开 Hermes,然后回到此处。',
|
||||
scaleTitle: '大小',
|
||||
scaleDesc: '调整悬浮宠物的大小,所有界面即时生效。',
|
||||
|
|
@ -1647,11 +1648,13 @@ export const zh: Translations = {
|
|||
manualBody: '你是从命令行安装的 Hermes,因此更新也需要在那里运行。请将此命令粘贴到终端:',
|
||||
manualPickedUp: '下次启动 Hermes 时会使用新版本。',
|
||||
guiSkewTitle: '请更新桌面应用',
|
||||
guiSkewBody: '后端已更新,但此桌面应用包未更改。请更新或重新安装 Hermes 桌面应用(你的 AppImage / .deb / .rpm)以保持一致。',
|
||||
guiSkewBody:
|
||||
'后端已更新,但此桌面应用包未更改。请更新或重新安装 Hermes 桌面应用(你的 AppImage / .deb / .rpm)以保持一致。',
|
||||
copy: '复制',
|
||||
copied: '已复制',
|
||||
done: '完成',
|
||||
applyingBody: 'Hermes 更新器会在自己的窗口中接管,并在完成后自动重新打开 Hermes。更新期间请不要自行重新打开 Hermes。',
|
||||
applyingBody:
|
||||
'Hermes 更新器会在自己的窗口中接管,并在完成后自动重新打开 Hermes。更新期间请不要自行重新打开 Hermes。',
|
||||
applyingBodyBackend: '远程后端正在应用更新并将重启。恢复后 Hermes 会自动重新连接。',
|
||||
applyingClose: '此窗口会在更新期间关闭,随后 Hermes 会自动重新打开。',
|
||||
errorTitle: '更新未完成',
|
||||
|
|
@ -2075,7 +2078,55 @@ export const zh: Translations = {
|
|||
statusRunning: '运行中',
|
||||
statusError: '错误',
|
||||
statusRecovered: '已恢复',
|
||||
statusDone: '完成'
|
||||
statusDone: '完成',
|
||||
actions: {
|
||||
read: '已读取',
|
||||
reading: '正在读取',
|
||||
opened: '已打开',
|
||||
opening: '正在打开',
|
||||
searched: '已搜索',
|
||||
searching: '正在搜索',
|
||||
ran: '已运行',
|
||||
running: '正在运行',
|
||||
ranCode: '已运行代码',
|
||||
runningCode: '正在编写脚本'
|
||||
},
|
||||
prefixes: {
|
||||
browser: '浏览器',
|
||||
web: '网页'
|
||||
},
|
||||
titleTemplates: {
|
||||
actionCommand: (action, command) => `${action} · ${command}`,
|
||||
actionQuoted: (action, value) => `${action}“${value}”`,
|
||||
actionTarget: (action, target) => `${action} ${target}`,
|
||||
prefixedDone: (prefix, action) => `${prefix}${action}`,
|
||||
runningPrefixedTool: (prefix, action) => `正在运行${prefix}${action}`,
|
||||
runningTool: action => `正在运行 ${action}`
|
||||
},
|
||||
titles: {
|
||||
browser_click: { done: '已点击页面元素', pending: '正在点击页面元素', pendingAction: '正在点击' },
|
||||
browser_fill: { done: '已填写表单字段', pending: '正在填写表单字段', pendingAction: '正在填写' },
|
||||
browser_navigate: { done: '已打开页面', pending: '正在打开页面', pendingAction: '正在打开' },
|
||||
browser_snapshot: { done: '已捕获页面快照', pending: '正在捕获页面快照', pendingAction: '正在捕获' },
|
||||
browser_take_screenshot: { done: '已捕获截图', pending: '正在捕获截图', pendingAction: '正在捕获' },
|
||||
browser_type: { done: '已在页面输入', pending: '正在页面输入', pendingAction: '正在输入' },
|
||||
clarify: { done: '已提问', pending: '正在提问', pendingAction: '正在提问' },
|
||||
cronjob: { done: 'Cron 任务', pending: '正在安排 Cron 任务', pendingAction: '正在安排' },
|
||||
edit_file: { done: '已编辑文件', pending: '正在编辑文件', pendingAction: '正在编辑' },
|
||||
execute_code: { done: '已运行代码', pending: '正在编写脚本', pendingAction: '正在编写脚本' },
|
||||
image_generate: { done: '已生成图片', pending: '正在生成图片', pendingAction: '正在生成' },
|
||||
list_files: { done: '已列出文件', pending: '正在列出文件', pendingAction: '正在列出' },
|
||||
patch: { done: '已修补文件', pending: '正在修补文件', pendingAction: '正在修补' },
|
||||
read_file: { done: '已读取文件', pending: '正在读取文件', pendingAction: '正在读取' },
|
||||
search_files: { done: '已搜索文件', pending: '正在搜索文件', pendingAction: '正在搜索' },
|
||||
session_search_recall: { done: '已搜索会话历史', pending: '正在搜索会话历史', pendingAction: '正在搜索' },
|
||||
terminal: { done: '已运行命令', pending: '正在运行命令', pendingAction: '正在运行' },
|
||||
todo: { done: '已更新待办', pending: '正在更新待办', pendingAction: '正在更新' },
|
||||
vision_analyze: { done: '已分析图片', pending: '正在分析图片', pendingAction: '正在分析' },
|
||||
web_extract: { done: '已读取网页', pending: '正在读取网页', pendingAction: '正在读取' },
|
||||
web_search: { done: '已搜索网页', pending: '正在搜索网页', pendingAction: '正在搜索' },
|
||||
write_file: { done: '已编辑文件', pending: '正在编辑文件', pendingAction: '正在编辑' }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue