* 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.
341 lines
10 KiB
TypeScript
341 lines
10 KiB
TypeScript
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 plugin’s script. Check the Network tab (dashboard-plugins/…) and the server’s plugin path.",
|
||
pluginNotRegistered:
|
||
"The plugin’s 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",
|
||
},
|
||
};
|