Initialize repository with harness code and assets

Initial import of all source code, config, and README assets: the
packages workspace (cli, core, server, web, docs, landing, skills),
build scripts, tooling config, and CI workflows.

Includes the data-layout revision made on this branch: the local data
root defaults to ~/.penguin/data (PENGUIN_HOME still overrides; the
installer keeps its binaries in ~/.penguin), and every Agent lives
under <project>/agents/<agent>/ — path helpers, the three
agent-enumeration scans, the system prompt, built-in Skills, tests
and docs all follow the new layout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ihk8iQuo3kv2aPjAYEPuR
This commit is contained in:
Yaowei Zheng
2026-07-19 14:06:53 +08:00
committed by GitHub
parent 056bed7aeb
commit 45bfae6e94
543 changed files with 92949 additions and 0 deletions
+732
View File
@@ -0,0 +1,732 @@
/**
* English dictionary (constrained by the `Strings` type to the same shape as zh):
* locale switching goes through state/locale.tsx.
* Keep domain term capitalization consistent with zh — Agent, Workspace, Token, Task, etc.
*/
import type { Strings } from "./strings";
export const en: Strings = {
appName: "PenguinHarness",
nav: {
chat: "Chat",
newChat: "New chat",
agents: "Agents",
skills: "Skills",
models: "Models",
usage: "Costs",
traces: "Trajectory",
benchmark: "Evaluation Center",
collapseSidebar: "Collapse sidebar",
expandSidebar: "Expand sidebar",
collapseGroup: "Collapse",
expandGroup: "Expand",
},
settings: {
language: "Language",
theme: "Theme",
themeLight: "Light",
themeDark: "Dark",
followSystem: "System",
langZh: "中文",
langEn: "English",
fontSize: "Font size",
fontSmall: "S",
fontMedium: "M",
fontLarge: "L",
accent: "Accent",
accentNames: {
neutral: "Neutral",
blue: "Blue",
green: "Green",
violet: "Violet",
rose: "Rose",
amber: "Amber",
} as Record<string, string>,
},
common: {
save: "Save",
cancel: "Cancel",
create: "Create",
delete: "Delete",
edit: "Edit",
settings: "Settings",
confirm: "Confirm",
close: "Close",
loading: "Loading…",
loadMore: "Load more",
saved: "Saved",
saving: "Saving…",
none: "(none)",
retry: "Retry",
unknownError: "Request failed, please try again later",
requiredField: "This field is required",
copied: "Copied",
ownerOnly: "Only the owner can modify this",
},
auth: {
loginTitle: "Sign in to PenguinHarness",
username: "Username",
usernameHint:
"2–32 chars: starts with a lowercase letter; lowercase letters, digits and underscores only",
password: "Password",
passwordHint: "At least 8 characters",
showPassword: "Show password",
hidePassword: "Hide password",
login: "Sign in",
logout: "Sign out",
admin: "Admin",
defaultAdminNote:
"First run: sign in as the built-in admin (admin / admin123), then change the password soon",
},
account: {
changePassword: "Change password",
oldPassword: "Current password",
newPassword: "New password",
confirmPassword: "Confirm new password",
passwordMismatch: "New passwords do not match",
initialPasswordBanner: "This account is using its initial password. Please change it soon.",
changeNow: "Change now",
},
admin: {
users: "Users",
userId: "Username",
role: "Role",
roleAdmin: "Admin",
roleUser: "User",
createdAt: "Created",
actions: "Actions",
createUser: "Add user",
initialPassword: "Initial password",
initialPasswordFlag: "initial password",
defaultProjectNote: (id: string): string => `A default Project will be created: ${id}`,
resetPassword: "Reset password",
resetPasswordTitle: (u: string): string => `Reset password for ${u}`,
resetPasswordNote:
"All sign-in sessions of this user will be revoked; they must sign in with the new password",
deleteUser: "Delete",
deleteUserTitle: (u: string): string => `Delete user ${u}`,
deleteUserConfirm: (u: string): string =>
`This deletes user ${u} and every Project they own (including data directories). This cannot be undone.`,
},
project: {
switcher: "Project",
create: "New Project",
createTitle: "New Project",
id: "Project id",
idHint:
"2–64 chars: starts with a lowercase letter; lowercase letters, digits and underscores only. Cannot be changed later.",
idPrefixHint:
"The id is prefixed with your username and a hyphen; append lowercase letters, digits or underscores. Cannot be changed later.",
name: "Display name (optional, defaults to the Project id)",
settings: "Project settings",
settingsTitle: "Project settings",
members: "Members",
addMember: "Add member",
memberUsername: "Username",
memberRole: "Role",
memberActions: "Actions",
removeMember: "Remove",
owner: "owner",
member: "member",
deleteProject: "Delete Project",
deleteConfirm:
"Delete this Project? Its directory will be removed recursively and cannot be recovered.",
deleteLastForbidden:
"This is the last Project on this account; create another Project before deleting it",
deleteDefaultForbidden:
"default_project is shared with the CLI and cannot be deleted from the web",
noCredentialTitle: "No model credential configured",
noCredentialBody:
"The default model of this Project has no API key yet. Configure it on the Models page before chatting.",
goToModels: "Go to Models",
later: "Later",
},
agent: {
listTitle: "Agents",
create: "Create Agent",
createTitle: "Create Agent",
id: "Agent id",
idHint:
"2–64 chars: starts with a lowercase letter; lowercase letters, digits and underscores only. Cannot be changed later.",
name: "Name",
nameHint: "Leave empty to use the Agent id as the name",
description: "Description",
activeSessions: "Active Sessions",
sessionCount: (n: number): string => `${n} session${n === 1 ? "" : "s"}`,
toolCount: (n: number): string => `${n} tool${n === 1 ? "" : "s"}`,
vaultKeyCount: (n: number): string => `${n} vault key${n === 1 ? "" : "s"}`,
scheduleCount: (n: number): string => `${n} scheduled task${n === 1 ? "" : "s"}`,
updatedAt: "Last modified",
activity: (days: number): string => `${days}-day session activity`,
settings: "Agent settings",
backToList: "Back to Agents",
tabOverview: "Overview",
tabPrompt: "Prompt",
tabRuntime: "Runtime",
tabTools: "Tools",
tabVault: "Vault",
tabSchedules: "Schedules",
stateDir: "State path",
agentsMd: "AGENTS.md",
systemPrompt: "system_prompt template",
placeholdersTitle: "Available placeholders (click to insert)",
insertPlaceholder: "Insert at the system_prompt cursor",
/** Order must match the default system prompt (core default-config.ts DEFAULT_SYSTEM_PROMPT). */
placeholders: [
["{{AGENTS_MD}}", "Injects the AGENTS.md content"],
["{{VAULT_KEYS}}", "Injects the vault key-name section (empty when no keys)"],
["{{PLATFORM}}", "Runtime platform"],
["{{OS_VERSION}}", "Operating system version"],
["{{DATE}}", "Current date"],
["{{CWD}}", "Absolute Workspace path"],
["{{AGENT_ID}}", "Current Agent id"],
["{{PROJECT_DIR}}", "Absolute Project directory (Agent State/scratchpad derive from it)"],
["{{SESSION_ID}}", "Current Session id"],
] as ReadonlyArray<readonly [string, string]>,
maxTurns: "max_turns (max turns per Task, -1 = unlimited)",
maxTokens: "model.max_tokens",
thinkingLevel: "model.thinking_level",
thinkingLevelOptions: [
["", "Send no override — keep whatever is currently configured."],
["none", "Disables extended reasoning; the fastest responses."],
["low", "Enables a lower tier of extended reasoning."],
[
"medium",
"Enables a medium tier of extended reasoning (the default tier for a newly created agent).",
],
["high", "Enables a higher tier of extended reasoning; slower responses."],
[
"xhigh",
"Enables the highest tier of extended reasoning; identical to high on some models.",
],
] as ReadonlyArray<readonly [string, string]>,
timeoutMs: "model.timeoutMs",
timeoutMsHint: "Per-request timeout, ms",
compaction: "Context compaction",
maxContextLength: "max_context_length",
maxContextLengthHint: "Context threshold that triggers compaction",
maxSessionTurns: "max_session_turns",
maxSessionTurnsHint: "Turn threshold that triggers compaction",
compactionMode: "mode (compaction strategy)",
compactionModeOptions: [
["", "Send no override — keep whatever is currently configured."],
[
"summarize",
"Summarizes the old context with the model, then continues from that summary in a fresh window (default).",
],
[
"discard",
"Drops the old context without summarizing; the next turn starts fresh in a new window.",
],
] as ReadonlyArray<readonly [string, string]>,
compactionPrompt: "prompt (summarization prompt)",
maxTurnsInvalid: "max_turns must be > 0 or -1",
timeoutInvalid: "timeoutMs must be > 0 or -1",
toolFieldInvalid: (name: string, field: string) =>
`${name}: ${field} must be a positive integer or -1`,
builtinTools: "Built-in tools",
toolName: "Name",
toolPermission: "permission",
permissionReadLabel: "Read-only",
permissionReadDescription: "Only reads. Auto-approved when the approval mode is read-only.",
permissionReadWriteLabel: "Read & write",
permissionReadWriteDescription:
"Can modify things. Needs manual confirmation when the approval mode is read-only.",
toolTimeout: "timeoutMs",
toolMaxOutput: "maxOutputLength",
mcpServers: "MCP Servers (read-only)",
defaultValue: "(default)",
deleteAgent: "Delete Agent",
builtinUndeletable: "Built-in Agents cannot be deleted",
deleteConfirm: (name: string): string =>
`Delete Agent "${name}"? Its directory (including all Traces) will be removed recursively and cannot be recovered.`,
stateVersion: "Agent State version",
transferTitle: "Export / import",
transferDesc:
"Export the current Agent State snapshot (tar.gz); importing overwrites the whole directory and adopts the version inside the package.",
exportSnapshot: "Export snapshot",
importSnapshot: "Import snapshot",
importing: "Importing…",
importDone: (v: number): string => `Import finished, Agent State version v${v}`,
importConflictTitle: "Version conflict",
importConflictBody:
"The snapshot's version is not newer than the current one; importing will overwrite the existing Agent State. Continue?",
},
models: {
title: "Models",
addCustom: "Add custom model",
addToGroup: "Add model",
editTitle: "Model settings",
addTitle: "Add model (OpenAI protocol)",
addTitleVendor: "Add model (auto-routed by id)",
addProtocolHint:
"New models always use the OpenAI Chat Completions protocol (no auto-routing by model id); set the base URL to a compatible endpoint",
addAutoRouteHint:
"New models in this group are auto-routed by their upstream id to the vendor's official client: leave the base URL empty for the official endpoint, and an empty API key falls back to the resolved client's environment variable",
autoRouteNone:
"AgentHub cannot auto-route this id: double-check it, or add the model under Custom / a user-defined group with the OpenAI protocol",
addGroup: "Add group",
addGroupTitle: "Add group",
addGroupDesc:
"User-defined groups share Custom semantics: models use the OpenAI Chat Completions protocol (base URL required; an empty API key reads OPENAI_API_KEY). Groups live on model entries — the group appears once its first model is saved.",
groupNameLabel: "Group name",
groupNameHint: "Starts with a lowercase letter / digit; may contain - and _",
groupNameInvalid:
"Group names may only use lowercase letters, digits, - and _ (starting with a letter or digit), up to 32 characters",
groupNameExists: "This name is taken by a built-in group or an existing entry",
groupEmptyHint: "No models in this group yet; use “Add model” to create one",
searchPlaceholder: "Search models: id / name / provider",
noSearchResults: "No matching models",
modelCount: (n: number): string => `${n} model${n === 1 ? "" : "s"}`,
modelId: "Model ID",
modelIdHint: "The upstream API model id, e.g. gpt-5.5",
displayName: "Display name",
displayNameHint: "Defaults to the model ID",
providerGroup: "Group",
contextWindow: "Context window",
contextWindowUnit: "tokens",
contextWindowHint: "Leave empty if unknown",
clientTypeLocked: (t: string): string => `Protocol: ${t} (kept as configured; not editable)`,
vision: "Supports image input (vision / multimodal)",
visionHint:
"When unchecked, chat images are passed as file paths and read via describe_image (vision model)",
visionBadge: "Vision",
visionModelBadge: "Proxy vision",
setVisionModel: "Set as proxy vision model",
visionModelHint: "Describes images via describe_image for models without vision",
priceUnitShort: "/M tok",
testConnection: "Test connection",
testing: "Testing…",
testOk: (ms: number): string => `Connected (${ms} ms)`,
testFailed: (msg: string): string => `Failed: ${msg}`,
modelIdRenameHint: "Renaming migrates the existing config and API key",
priceCacheRead: "Cache read",
priceCacheWrite: "Cache write",
priceOutput: "Output",
pricing: "Pricing",
priceUnit: "per 1M tokens",
currency: "Currency",
currencyUsd: "USD $",
currencyCny: "CNY ¥",
currencyHint: "Prices convert at 1 USD ≈ 7 CNY; always stored in USD",
firstModelDefault: "Set as the default model",
credential: "Credential",
apiKey: "API key",
apiKeyKeepHint: "Leave empty to keep the current key",
apiKeyEnvHint: (envKey: string): string => `Leave empty to use the ${envKey} env var`,
useEnvVar: (envKey: string): string => `env ${envKey}`,
keyConfigured: "Key configured",
clearApiKey: "Clear stored API key",
baseUrl: "Custom base URL",
baseUrlHint: "Leave empty to use the provider default",
baseUrlRequired: "A base URL is required",
contextWindowDefaultHint: (n: number): string => `Defaults to ${n} if empty`,
visionOnHint: "Images are read with read_image and fed to the model directly",
visionOffHint:
"Images are read with describe_image: described by the proxy vision model, text only; chat uploads are passed as file paths",
confirmDeleteTitle: "Delete model",
confirmDelete: (name: string): string =>
`Delete "${name}"? Its configuration and API key will be removed.`,
groupApiKey: "Set API key for group",
groupApiKeyTitle: (label: string): string => `Set the API key for ${label}`,
groupApiKeyHint: (n: number): string =>
`Applies to all ${n} models in this group; leave empty to keep them unchanged.`,
getApiKey: "Get API key",
getModelIds: "Get model IDs",
groupKeyApplied: (n: number): string => `API key set for ${n} models`,
providerEnvNotes: {
zhipu:
"Defaults to the Z.AI global endpoint (api.z.ai); keys from bigmodel.cn need base URL https://open.bigmodel.cn/api/paas/v4",
moonshot:
"Defaults to the China endpoint (api.moonshot.cn); keys from platform.kimi.com need base URL https://api.moonshot.ai/v1",
},
confirmVisionModelTitle: "Set as proxy vision model",
confirmVisionModel: (name: string): string =>
`Make "${name}" the proxy vision model? Models without vision will read images through it via describe_image.`,
confirmSaveTitle: "Save model settings",
confirmSave: (name: string): string => `Save the changes to "${name}"?`,
confirmDefaultTitle: "Set as default model",
confirmDefault: (name: string): string =>
`Make "${name}" the default model? New sessions will use it by default.`,
createdAt: "Created",
default: "Default",
setDefault: "Set as default model",
remove: "Delete model",
saveAll: "Save all",
readOnlyHint: "Members have read-only access; only owners can change models and credentials",
empty: "No models configured yet",
noKey: "No key",
pendingSave: "(pending save)",
modelIdExists: "This model id already exists",
pricingAllOrNone: "Fill all three prices",
pricingInvalid: "Must be a number",
contextWindowInvalid: "Must be a number",
},
vault: {
desc: "Environment variables owned by this Agent (stored in agent_state/.vault.toml), injected into the environment of its shell commands (exec_command); key names are shared with the model, values never enter the model context. Subagents use their own vaults and do not inherit this one.",
key: "Name",
value: "Value",
valueMasked: "Value (masked)",
add: "Add",
addTitle: "Add variable",
remove: "Remove",
deleteTitle: "Delete variable",
deleteConfirm: (key: string): string =>
`Delete variable "${key}"? Its value cannot be recovered.`,
empty: "No variables configured yet",
readOnlyHint: "Members are read-only; only the owner can edit the vault",
keyHint: "Letters, digits and underscores; must not start with a digit",
keyInvalid: "Invalid name: only letters, digits and underscores, not starting with a digit",
valueRequired: "Value must not be empty",
},
schedule: {
desc: "Scheduled tasks (agent_state/schedule/*.toml): the prompt is sent to the target Session on schedule; files can also be edited by hand, and changes made here take effect immediately.",
readOnlyHint: "Members are read-only; only the owner can modify schedules",
colName: "Name",
colStatus: "Status",
colPeriod: "Period",
colTarget: "Target",
colFireTimes: "Next / last fired",
colQueued: "Queue",
statusNames: {
active: "Active",
disabled: "Disabled",
expired: "Expired",
done: "Done",
missed: "Missed",
invalid: "Invalid",
} as Record<string, string>,
queued: "Queued",
once: "One-off",
newSession: "New session",
invalidFiles: "Files that failed to parse (skipped by the scheduler)",
empty: "No scheduled tasks yet",
enable: "Enable",
disable: "Disable",
addTitle: "New scheduled task",
editTitle: (name: string): string => `Edit scheduled task "${name}"`,
name: "Name",
nameHint: "The file name (without .toml); cannot be changed later",
prompt: "Prompt",
enabled: "Enabled",
startAt: "Start at",
endAt: "End at (optional)",
period: "Period",
periodPlaceholder: "30m / 12h / 7d; leave empty for a one-off task",
target: "Target",
targetNew: "New session each time",
targetSession: "Bound Session",
sessionId: "Session id",
workspace: "Workspace (optional, auto-created when empty)",
model: "Model",
modelDefault: "Project default",
deleteTitle: "Delete scheduled task",
deleteConfirm: (name: string): string => `Delete scheduled task "${name}"?`,
},
skills: {
pageTitle: "Skill library",
pageDesc: "Built-in skill library: browse, quick-start a chat, or install to agents.",
quickInvoke: "Quick start",
quickInvokeText: (name: string): string => `use the ${name} skill`,
manageInstall: "Manage installs",
manageInstallTitle: (name: string): string => `Manage installs: ${name}`,
install: "Install",
installed: "Installed",
uninstall: "Uninstall",
skillCount: (n: number): string => (n === 1 ? "1 skill" : `${n} skills`),
usedByAgents: (n: number): string =>
n === 0 ? "not used yet" : n === 1 ? "used by 1 agent" : `used by ${n} agents`,
installedToast: (skill: string, agent: string): string => `Installed ${skill} to ${agent}`,
uninstalledToast: (skill: string, agent: string): string =>
`Uninstalled ${skill} from ${agent}`,
},
chat: {
newSessionMenu: "New chat",
chooseAgent: "Choose agent",
chooseModel: "Choose model",
workspaceUseThis: "Use this dir",
workspaceUp: "Parent dir",
workspaceNoSubdirs: "No subdirectories",
workspaceAuto: "Auto temp directory",
workspaceClear: "Use auto temp directory instead",
workspaceDirInvalid: "Directory does not exist or is inaccessible; reverted",
draftSubtitle: "The self-evolving agent that excels at AI development tasks",
sessionList: "Sessions",
defaultSessionTitle: "New chat",
model: "Model",
workspace: "Workspace",
workspaceHint:
"Leave empty for an auto-created temp directory; if set, it must be an existing directory on the server",
approvalMode: "Approval mode",
approvalModeNames: {
"allow-all": "Approve everything",
"deny-all": "Deny everything",
"read-only": "Approve read-only",
"always-ask": "Ask every time",
} as Record<string, string>,
approvalModes: {
"allow-all": "Approve everything (allow-all)",
"deny-all": "Deny everything (deny-all)",
"read-only": "Approve read-only (read-only)",
"always-ask": "Ask every time (always-ask)",
} as Record<string, string>,
statusIdle: "Idle",
statusRunning: "Running",
statusCompacting: "Compacting",
pendingApprovals: (n: number) => `${n} pending approval${n > 1 ? "s" : ""}`,
inputPlaceholder: "Type a message. Enter to send, Shift+Enter for newline, paste images",
inputPlaceholderShort: "Type a message…",
send: "Send",
stop: "Stop",
compactingHint: "Compacting context, input is temporarily disabled",
compact: "Compact context",
approve: "Allow",
deny: "Deny",
decisionAllow: "Approved",
decisionDeny: "Denied",
decisionManual: "manual",
decisionAuto: "auto",
thinking: "Thinking",
subagent: "Subagent",
subagentRunning: "Running",
aborted: (reason?: string) => `[Aborted]${reason ? `: ${reason}` : ""}`,
reconnect: (
status: "timeout" | "malformed",
state: "waiting" | "retried" | "gaveUp",
attempt: number,
) => {
const cause =
status === "timeout" ? "Connection timed out" : "Response incomplete or unparseable";
const action =
state === "gaveUp"
? "no further retries"
: state === "retried"
? `retry #${attempt} sent`
: `starting retry #${attempt}…`;
return `[Retry] ${cause}; ${action}`;
},
imageAlt: "Image uploaded by user",
toolImageAlt: "Image from tool output",
imagesAsPathHint:
"This model cannot view images directly: on send, images are saved to the session scratchpad and passed as file paths (viewed via describe_image)",
infoPanel: "Session info",
sessionStats: "Stats",
statTokens: "Total Tokens",
statCost: "Cost",
statElapsed: "Elapsed",
statInput: "Input tokens",
statOutput: "Output tokens",
statTps: "Output TPS",
noSessions: "No Sessions yet",
emptyStream: "Send a message to start the conversation",
historyLoadFailed: "Failed to load history",
sessionHealed: "Session healed with a new id",
statsLabel: "Stats",
removeImage: "Remove image",
openWorkspace: "Open workspace",
filesInMessage: (n: number) => `${n} ${n === 1 ? "file" : "files"}`,
openPreview: "Click to preview",
showMoreFiles: (n: number) => `Show ${n} more ${n === 1 ? "file" : "files"}`,
showLess: "Show less",
contextUsage: "Context usage",
contextUnknown: "Context usage: unknown until the next request reports it",
slashHint: "Type / for commands",
mentionHint: "@ to handoff to another agent",
mentionRemove: "Remove @ target",
skillsSelect: "Skills",
skillsSearchPlaceholder: "Search skills",
skillsNoMatch: "No matching skills",
skillsEmptyHint: "No skills installed yet — add some from the skill library",
skillsAutoMessage: (names: string[]): string =>
names.length === 1 ? `use the ${names[0]} skill` : `use the ${names.join(", ")} skills`,
handoffFrom: (agent: string) => `Handed off from ${agent}'s conversation`,
handoffBack: (title?: string) =>
title ? `Back to the original conversation: ${title}` : "Back to the original conversation",
scheduledFrom: (name: string) => `Triggered by scheduled task "${name}"`,
/** Source badge on session list rows (user-created sessions have no source). */
sourceNames: {
schedule: "Scheduled",
subagent: "Sub",
} as Record<string, string>,
commandCompact: "/compact",
emptyGreeting: "Start a new conversation",
compactionRunning: (mode: string) => `Compaction in progress (${mode})…`,
compactionDone: (mode: string) =>
mode === "discard"
? "[Compaction] done, old context discarded"
: "[Compaction] done, switched to the summarized context",
compactionFailed: (status: string) =>
`[Compaction] ${status === "aborted" ? "aborted" : "failed"}, keeping current context`,
unknownTool: "(unknown tool)",
toolCall: "Tool call",
workGroupTitle: "Reasoning & tools",
workRunning: "Running",
workDone: "Done",
workGroupSteps: (n: number) => `${n} ${n === 1 ? "step" : "steps"}`,
approvalWaiting: "awaiting approval",
copyCode: "Copy code",
copyStats: "Copy stats",
copyReply: "Copy reply",
copyMessage: "Copy message",
copied: "Copied",
deleteSession: "Delete chat",
renameSession: "Rename chat",
renameSessionLabel: "Title",
deleteSessionConfirm: (title: string) =>
`Delete "${title}"? Its messages and Trace will be removed permanently.`,
archiveSession: "Archive",
unarchiveSession: "Unarchive",
archivedGroup: (n: number) => `Archived (${n})`,
skillsBanner: (names: string[]): string =>
`Using skill${names.length === 1 ? "" : "s"}: ${names.join(", ")}`,
},
files: {
title: "Files",
upload: "Upload",
download: "Download",
refresh: "Refresh",
root: "Workspace root",
empty: "Empty directory",
name: "Name",
size: "Size",
modified: "Modified",
previewUnsupported: "Preview not supported for this type; download instead",
uploaded: "Uploaded",
loadFailed: "Failed to load",
previewTruncated: "File too large; preview truncated, download for the full file",
details: "Details",
workspacePath: "Workspace path",
htmlRendered: "Rendered",
htmlSource: "Source",
backToList: "Back to list",
resizeHandle: "Drag to resize, double-click to reset",
},
usage: {
title: "Costs & usage",
today: "Today",
last7d: "Last 7 days",
total: "Total",
tokens: "Tokens",
cost: "Cost",
requests: "Requests",
from: "From",
to: "To",
colCacheRead: "cache_read",
colCacheWrite: "cache_write",
colOutput: "output",
colCost: "Cost",
trendTitle: "30-day trend",
uncostedNote: "* Includes records without pricing; cost is a partial figure",
filterAllAgents: "All Agents",
filterAllModels: "All models",
chartAgentCalls: "Calls per Agent",
chartSuccessRate: "Model success rate",
chartTokenTrend: "Daily token trend",
chartCostTrend: "Daily cost trend",
empty: "No usage records",
successAborted: "Aborted (excluded)",
errors: "Errors",
errorsTotal: "Total",
errorsUnexpected: "Unexpected",
errorsExpected: "Expected",
errorsTopCode: "Most common",
errorsColTime: "Time",
errorsColCode: "Source · code",
errorsColKind: "Type",
errorsColMessage: "Message",
errorsEmpty: "No errors",
},
traces: {
title: "Traces",
filterAll: "All",
filterModel: "model_msg",
filterEvent: "event_msg",
analysis: "Trajectory view",
timeline: "Execution timeline",
laneLLM: "Model",
laneTools: "Tools",
phaseApproval: "approval",
phaseExec: "exec",
kindThinking: "thinking",
kindModelReply: "model reply",
kindToolGen: "tool call gen",
legendToolExec: "tool exec",
legendApprovalWait: "approval wait",
task: (n: number) => `Turn ${n}`,
globalSummary: "Overall",
tasksLabel: "Turns",
messages: "Messages",
truncatedNote: (shown: number, total: number) => `Showing first ${shown} / ${total} messages`,
zoom: "Zoom",
zoomReset: "Double-click to reset zoom",
zoomOut: "Zoom out",
zoomIn: "Zoom in",
linkHint:
"Hover a timeline segment or event row to cross-highlight, click a segment to jump to its message; legend highlights its kind; drag the bar below to pan/zoom",
filesTitle: "Trace files",
selectSession: "Select a Session on the left",
toolCalls: "Tool calls",
taskInput: "Input tokens this turn",
taskOutput: "Output tokens this turn",
cacheHit: "Cache hits",
hitRate: "Hit rate",
toolFailRate: "failure rate",
compactions: "compactions",
compactionRound: "Compaction",
usageTrend: "Token usage trend",
selectFile: "Select a Trace file on the left",
empty: "No Traces for this Agent",
colTime: "Time",
colType: "Type",
colSummary: "Summary",
lines: (n: number) => `${n} lines`,
inProgress: "in progress",
systemPrompt: "System prompt",
toolDefs: (n: number) => `Tool definitions (${n})`,
},
benchmark: {
title: "Evaluation Center",
selectBenchmark: "Select a Benchmark on the left",
emptyAgent: "No Benchmarks for this Agent",
caseCount: (n: number): string => `${n} case${n === 1 ? "" : "s"}`,
trendTitle: (metric: string): string => `${metric} over time`,
evaluations: "Evaluations",
noEvaluations: "No evaluations yet",
summaryLabel: "Summary",
legendUnlabeled: "unlabeled model",
colTime: "Time",
colVersion: "Version",
colModel: "Model",
colScore: "Score",
colCost: "Cost",
colDuration: "Duration",
colCase: "Case",
colRun: "Run",
colSession: "Session",
},
errors: {
unauthorized: "Session expired, please sign in again",
networkError: "Network error, please check your connection",
modelCredentialMissing: (modelId: string) =>
`Model ${modelId} has no API key yet — configure it on the Models page first`,
noDefaultModel: "This project has no default model yet — add one on the Models page first",
},
};