Files
hermes/web/src/i18n/en.ts
Teknium d7528d43ac fix(web): scope dashboard config Reset button to the current tab (#16813)
* Port from Kilo-Org/kilocode#9448: roll up subagent costs into parent session total

Child subagents built by delegate_task() each track their own
session_estimated_cost_usd, but the parent agent's total never folded
those numbers in.  On runs where the parent mostly delegates and the
children do the expensive work, the footer/UI was reporting a fraction
of the actual spend — sometimes $0.00 when the parent itself made no
billed calls.

Fix:
- Capture each child's session_estimated_cost_usd into _child_cost_usd
  on the result entry (before child.close() drops the counter).
- After the existing subagent_stop hook loop, sum the children's costs
  and add the total to parent.session_estimated_cost_usd.
- Promote session_cost_source from 'none' -> 'subagent' when the parent
  had no direct spend but children did, so the UI doesn't label the
  total as having unknown provenance.  Real sources (openrouter,
  anthropic, etc.) are preserved.

Nested orchestrator -> worker trees roll up naturally: each layer's own
delegate_task() folds its direct children in, and when the orchestrator
itself returns, its parent folds the orchestrator's now-inflated total
on top.

Internal fields (_child_cost_usd, _child_role) are stripped from the
results dict before it's serialised back to the model — same contract
as _child_role already followed.

Tests: TestSubagentCostRollup (5 cases) covers single-child, batch,
zero-cost-children, preserved-source, and legacy-fixture paths.

Source: https://github.com/Kilo-Org/kilocode/pull/9448

* fix(web): scope dashboard config Reset button to the current tab

Reported by @ykmfb001 via X: clicking 'Restore Defaults' (恢复默认值) on
the Auxiliary page wiped the entire config.yaml to defaults, not just
the auxiliary section. The button sits next to the category tabs and
users reasonably assumed 'reset this tab', not 'reset everything'.

Changes:
- handleReset now scopes to the fields in the current view:
  active category's fields (form mode) or search-matched fields
  (search mode). Only those keys are copied from defaults; the rest
  of the config is left alone.
- Added a window.confirm() with the scope name before applying.
- Button is hidden in YAML mode (scoping doesn't apply there).
- Tooltip/aria-label now name the scope, e.g. 'Reset Auxiliary to
  defaults'.
- i18n: new resetScopeTooltip / confirmResetScope / resetScopeToast
  strings in en + zh; resetDefaults key preserved for compat.
2026-04-27 21:09:14 -07:00

341 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { Translations } from "./types";
export const en: Translations = {
common: {
save: "Save",
saving: "Saving...",
cancel: "Cancel",
close: "Close",
confirm: "Confirm",
delete: "Delete",
refresh: "Refresh",
retry: "Retry",
search: "Search...",
loading: "Loading...",
create: "Create",
creating: "Creating...",
set: "Set",
replace: "Replace",
clear: "Clear",
live: "Live",
off: "Off",
enabled: "enabled",
disabled: "disabled",
active: "active",
inactive: "inactive",
unknown: "unknown",
untitled: "Untitled",
none: "None",
form: "Form",
noResults: "No results",
of: "of",
page: "Page",
msgs: "msgs",
tools: "tools",
match: "match",
other: "Other",
configured: "configured",
removed: "removed",
failedToToggle: "Failed to toggle",
failedToRemove: "Failed to remove",
failedToReveal: "Failed to reveal",
collapse: "Collapse",
expand: "Expand",
general: "General",
messaging: "Messaging",
pluginLoadFailed:
"Could not load this plugins script. Check the Network tab (dashboard-plugins/…) and the servers plugin path.",
pluginNotRegistered:
"The plugins script did not call register(), or the script errored. Open the browser console for details.",
},
app: {
brand: "Hermes Agent",
brandShort: "HA",
closeNavigation: "Close navigation",
closeModelTools: "Close model and tools",
footer: {
org: "Nous Research",
},
activeSessionsLabel: "Active Sessions:",
gatewayStatusLabel: "Gateway Status:",
gatewayStrip: {
failed: "Start failed",
off: "Off",
running: "Running",
starting: "Starting",
stopped: "Stopped",
},
nav: {
analytics: "Analytics",
chat: "Chat",
config: "Config",
cron: "Cron",
documentation: "Documentation",
keys: "Keys",
logs: "Logs",
sessions: "Sessions",
skills: "Skills",
},
modelToolsSheetSubtitle: "& tools",
modelToolsSheetTitle: "Model",
navigation: "Navigation",
openDocumentation: "Open documentation in a new tab",
openNavigation: "Open navigation",
sessionsActiveCount: "{count} active",
statusOverview: "Status overview",
system: "System",
webUi: "Web UI",
},
status: {
actionFailed: "Action failed",
actionFinished: "Finished",
actions: "Actions",
agent: "Agent",
activeSessions: "Active Sessions",
connected: "Connected",
connectedPlatforms: "Connected Platforms",
disconnected: "Disconnected",
error: "Error",
failed: "Failed",
gateway: "Gateway",
gatewayFailedToStart: "Gateway failed to start",
lastUpdate: "Last update",
noneRunning: "None",
notRunning: "Not running",
pid: "PID",
platformDisconnected: "disconnected",
platformError: "error",
recentSessions: "Recent Sessions",
restartGateway: "Restart Gateway",
restartingGateway: "Restarting gateway…",
running: "Running",
runningRemote: "Running (remote)",
startFailed: "Start failed",
starting: "Starting",
startedInBackground: "Started in background — check logs for progress",
stopped: "Stopped",
updateHermes: "Update Hermes",
updatingHermes: "Updating Hermes…",
waitingForOutput: "Waiting for output…",
},
sessions: {
title: "Sessions",
searchPlaceholder: "Search message content...",
noSessions: "No sessions yet",
noMatch: "No sessions match your search",
startConversation: "Start a conversation to see it here",
noMessages: "No messages",
untitledSession: "Untitled session",
deleteSession: "Delete session",
confirmDeleteTitle: "Delete session?",
confirmDeleteMessage:
"This permanently removes the conversation and all of its messages. This cannot be undone.",
sessionDeleted: "Session deleted",
failedToDelete: "Failed to delete session",
resumeInChat: "Resume in Chat",
previousPage: "Previous page",
nextPage: "Next page",
roles: {
user: "User",
assistant: "Assistant",
system: "System",
tool: "Tool",
},
},
analytics: {
period: "Period:",
totalTokens: "Total Tokens",
totalSessions: "Total Sessions",
apiCalls: "API Calls",
dailyTokenUsage: "Daily Token Usage",
dailyBreakdown: "Daily Breakdown",
perModelBreakdown: "Per-Model Breakdown",
topSkills: "Top Skills",
skill: "Skill",
loads: "Agent Loaded",
edits: "Agent Managed",
lastUsed: "Last Used",
input: "Input",
output: "Output",
total: "Total",
noUsageData: "No usage data for this period",
startSession: "Start a session to see analytics here",
date: "Date",
model: "Model",
tokens: "Tokens",
perDayAvg: "/day avg",
acrossModels: "across {count} models",
inOut: "{input} in / {output} out",
},
logs: {
title: "Logs",
autoRefresh: "Auto-refresh",
file: "File",
level: "Level",
component: "Component",
lines: "Lines",
noLogLines: "No log lines found",
},
cron: {
confirmDeleteMessage:
"This removes the job from the schedule. This cannot be undone.",
confirmDeleteTitle: "Delete scheduled job?",
newJob: "New Cron Job",
nameOptional: "Name (optional)",
namePlaceholder: "e.g. Daily summary",
prompt: "Prompt",
promptPlaceholder: "What should the agent do on each run?",
schedule: "Schedule (cron expression)",
schedulePlaceholder: "0 9 * * *",
deliverTo: "Deliver to",
scheduledJobs: "Scheduled Jobs",
noJobs: "No cron jobs configured. Create one above.",
last: "Last",
next: "Next",
pause: "Pause",
resume: "Resume",
triggerNow: "Trigger now",
delivery: {
local: "Local",
telegram: "Telegram",
discord: "Discord",
slack: "Slack",
email: "Email",
},
},
skills: {
title: "Skills",
searchPlaceholder: "Search skills and toolsets...",
enabledOf: "{enabled}/{total} enabled",
all: "All",
categories: "Categories",
filters: "Filters",
noSkills: "No skills found. Skills are loaded from ~/.hermes/skills/",
noSkillsMatch: "No skills match your search or filter.",
skillCount: "{count} skill{s}",
resultCount: "{count} result{s}",
noDescription: "No description available.",
toolsets: "Toolsets",
toolsetLabel: "{name} toolset",
noToolsetsMatch: "No toolsets match the search.",
setupNeeded: "Setup needed",
disabledForCli: "Disabled for CLI",
more: "+{count} more",
},
config: {
configPath: "~/.hermes/config.yaml",
filters: "Filters",
sections: "Sections",
exportConfig: "Export config as JSON",
importConfig: "Import config from JSON",
resetDefaults: "Reset to defaults",
resetScopeTooltip: "Reset {scope} to defaults",
confirmResetScope: "Reset all {scope} settings to their defaults? This only updates the form — changes aren't written to config.yaml until you press Save.",
resetScopeToast: "{scope} reset to defaults — review and Save to persist",
rawYaml: "Raw YAML Configuration",
searchResults: "Search Results",
fields: "field{s}",
noFieldsMatch: 'No fields match "{query}"',
configSaved: "Configuration saved",
yamlConfigSaved: "YAML config saved",
failedToSave: "Failed to save",
failedToSaveYaml: "Failed to save YAML",
failedToLoadRaw: "Failed to load raw config",
configImported: "Config imported — review and save",
invalidJson: "Invalid JSON file",
categories: {
general: "General",
agent: "Agent",
terminal: "Terminal",
display: "Display",
delegation: "Delegation",
memory: "Memory",
compression: "Compression",
security: "Security",
browser: "Browser",
voice: "Voice",
tts: "Text-to-Speech",
stt: "Speech-to-Text",
logging: "Logging",
discord: "Discord",
auxiliary: "Auxiliary",
},
},
env: {
changesNote: "Changes are saved to disk immediately. Active sessions pick up new keys automatically.",
confirmClearMessage:
"The stored value for this variable will be removed from your .env file. This cannot be undone from the UI.",
confirmClearTitle: "Clear this key?",
description: "Manage API keys and secrets stored in",
hideAdvanced: "Hide Advanced",
showAdvanced: "Show Advanced",
llmProviders: "LLM Providers",
providersConfigured: "{configured} of {total} providers configured",
getKey: "Get key",
notConfigured: "{count} not configured",
notSet: "Not set",
keysCount: "{count} key{s}",
enterValue: "Enter value...",
replaceCurrentValue: "Replace current value ({preview})",
showValue: "Show real value",
hideValue: "Hide value",
},
oauth: {
title: "Provider Logins (OAuth)",
providerLogins: "Provider Logins (OAuth)",
description: "{connected} of {total} OAuth providers connected. Login flows currently run via the CLI; click Copy command and paste into a terminal to set up.",
connected: "Connected",
expired: "Expired",
notConnected: "Not connected. Run {command} in a terminal.",
runInTerminal: "in a terminal.",
noProviders: "No OAuth-capable providers detected.",
login: "Login",
disconnect: "Disconnect",
managedExternally: "Managed externally",
copied: "Copied ✓",
cli: "CLI",
copyCliCommand: "Copy CLI command (for external / fallback)",
connect: "Connect",
sessionExpires: "Session expires in {time}",
initiatingLogin: "Initiating login flow…",
exchangingCode: "Exchanging code for tokens…",
connectedClosing: "Connected! Closing…",
loginFailed: "Login failed.",
sessionExpired: "Session expired. Click Retry to start a new login.",
reOpenAuth: "Re-open auth page",
reOpenVerification: "Re-open verification page",
submitCode: "Submit code",
pasteCode: "Paste authorization code (with #state suffix is fine)",
waitingAuth: "Waiting for you to authorize in the browser…",
enterCodePrompt: "A new tab opened. Enter this code if prompted:",
pkceStep1: "A new tab opened to claude.ai. Sign in and click Authorize.",
pkceStep2: "Copy the authorization code shown after authorizing.",
pkceStep3: "Paste it below and submit.",
flowLabels: {
pkce: "Browser login (PKCE)",
device_code: "Device code",
external: "External CLI",
},
expiresIn: "expires in {time}",
},
language: {
switchTo: "Switch to Chinese",
},
theme: {
title: "Theme",
switchTheme: "Switch theme",
},
};