Files
thotam 3f90057c24 fix(pipeline): stop aborting runs on heuristic context budget estimates (#1587)
Runs on models without a registered tokenizer (e.g. 9router brand models)
ended with the generic "Agent couldn't generate a response" fallback even
though the real request used about 55% of the context window.

PruneStage counted history with TokenCounter, which falls back to a
chars/2 heuristic for unregistered models and overcounted about 1.8x.
Once over budget it ran memory flush (~35s, invisible in traces), then
mid-loop compaction, which cannot summarize a history made only of tool
call/result pairs. The callback reported the untouched history as
compacted, PruneStage still saw it over budget and returned AbortRun
before any LLM call, and FinalizeStage replaced the empty reply with the
fallback.

- PruneStage and ContextStage overhead count with the request guard's
  BudgetCounter. PruneStage no longer controls loop flow; the final
  request guard in ThinkStage decides.
- CompactMessages returns ErrNotCompacted when history is unchanged.
  Callers stop counting it as a compaction and do not retry it in the
  same run, while post-run summarization still sees the pressure.
- When the guard exhausts every reduction step, ThinkStage stops the run
  with a localized chat.context_budget_exceeded notice instead of an
  error, so the run's tool results are still persisted. The stop reason
  marks the trace and agent span as error; team tasks, cron and
  heartbeat treat it as a failure via RunOutcome.Failure().
- Memory flush and mid-loop compaction emit event spans.
- Web and desktop UIs treat an unset context_pruning as enabled (the
  backend default since 7639a8c0), keep it unset when untouched, and can
  re-enable pruning after it was turned off.
2026-09-29 18:04:08 +07:00

375 lines
25 KiB
Go

package i18n
func init() {
register(LocaleVI, map[string]string{
// Common validation
MsgRequired: "%s là bắt buộc",
MsgInvalidID: "ID %s không hợp lệ",
MsgNotFound: "không tìm thấy %s: %s",
MsgAlreadyExists: "%s đã tồn tại: %s",
MsgInvalidRequest: "yêu cầu không hợp lệ: %s",
MsgInvalidJSON: "JSON không hợp lệ",
MsgUnauthorized: "chưa xác thực",
MsgPermissionDenied: "từ chối quyền truy cập: %s",
MsgInternalError: "lỗi nội bộ: %s",
MsgInvalidSlug: "%s phải là slug hợp lệ (chữ thường, số, dấu gạch ngang)",
MsgFailedToList: "không thể liệt kê %s",
MsgFailedToCreate: "không thể tạo %s: %s",
MsgFailedToUpdate: "không thể cập nhật %s: %s",
MsgFailedToDelete: "không thể xóa %s: %s",
MsgFailedToSave: "không thể lưu %s: %s",
MsgInvalidUpdates: "cập nhật không hợp lệ",
// Agent
MsgAgentNotFound: "không tìm thấy agent: %s",
MsgCannotDeleteDefault: "không thể xóa agent mặc định",
MsgUserCtxRequired: "yêu cầu ngữ cảnh người dùng",
MsgGatewayOperatorSecureCLIUnavailable: "Đã bỏ qua quyền gateway operator vì kho SecureCLI chưa khả dụng.",
MsgGatewayOperatorEligibilityFailed: "Agent đã được tạo, nhưng không thể xác minh đây là agent đầu tiên để cấp quyền gateway operator.",
MsgGatewayOperatorNotFirstAgent: "Không cấp quyền gateway operator vì đây không phải agent đầu tiên.",
MsgGatewayOperatorTokenMissing: "Đã bỏ qua quyền gateway operator vì gateway token chưa được cấu hình.",
MsgGatewayOperatorBinaryMissing: "Đã bỏ qua quyền gateway operator vì không tìm thấy binary goclaw.",
MsgGatewayOperatorExistingReview: "Đã bỏ qua quyền gateway operator vì credential CLI goclaw hiện có cần kiểm tra thủ công.",
MsgGatewayOperatorRegisterFailed: "Đã bỏ qua quyền gateway operator vì không thể đăng ký credential CLI goclaw.",
MsgGatewayOperatorCredentialFailed: "Đã bỏ qua quyền gateway operator vì không thể lưu credential.",
// Chat
MsgRateLimitExceeded: "vượt quá giới hạn tốc độ — vui lòng đợi",
MsgNoUserMessage: "không tìm thấy tin nhắn người dùng",
MsgUserIDRequired: "user_id là bắt buộc",
MsgMsgRequired: "tin nhắn là bắt buộc",
// Abort
MsgAbortStopped: "đã dừng tác vụ",
MsgAbortForced: "buộc dừng tác vụ (vượt quá thời gian chờ 3s)",
MsgAbortAlreadyAborting: "đang dừng tác vụ",
MsgAbortNotFound: "không tìm thấy tác vụ hoặc đã kết thúc",
MsgAbortUnauthorized: "không có quyền dừng tác vụ này",
MsgAbortFailed: "không thể dừng tác vụ: %s",
// Channel instances
MsgInvalidChannelType: "loại channel không hợp lệ",
MsgInstanceNotFound: "không tìm thấy phiên bản",
// Cron
MsgJobNotFound: "không tìm thấy tác vụ",
MsgInvalidCronExpr: "biểu thức cron không hợp lệ: %s",
MsgCommandCronDisabled: "tác vụ cron dạng lệnh đang bị tắt trên gateway này (đặt cron.command_enabled=true để cho phép)",
// Config
MsgConfigHashMismatch: "cấu hình đã thay đổi (hash không khớp)",
// Exec approval
MsgExecApprovalDisabled: "phê duyệt thực thi chưa được bật",
// Pairing
MsgSenderChannelRequired: "senderId và channel là bắt buộc",
MsgCodeRequired: "mã là bắt buộc",
MsgSenderIDRequired: "sender_id là bắt buộc",
// HTTP API
MsgInvalidAuth: "xác thực không hợp lệ",
MsgMsgsRequired: "messages là bắt buộc",
MsgUserIDHeader: "header X-GoClaw-User-Id là bắt buộc",
MsgFileTooLarge: "tệp quá lớn hoặc form multipart không hợp lệ",
MsgMissingFileField: "thiếu trường 'file'",
MsgInvalidFilename: "tên tệp không hợp lệ",
MsgChannelKeyReq: "channel và key là bắt buộc",
MsgMethodNotAllowed: "phương thức không được phép",
MsgStreamingNotSupported: "streaming không được hỗ trợ",
MsgOwnerOnly: "chỉ chủ sở hữu mới có thể %s",
MsgNoAccess: "không có quyền truy cập %s này",
MsgAlreadySummoning: "agent đang được triệu hồi",
MsgSummoningUnavailable: "triệu hồi không khả dụng",
MsgRunTimelineUnavailable: "timeline lượt chạy không khả dụng",
MsgNoDescription: "agent không có mô tả để triệu hồi lại",
MsgSummonCancelled: "đã huỷ triệu hồi",
MsgCannotCancel: "agent không trong trạng thái đang triệu hồi",
MsgInvalidPath: "đường dẫn không hợp lệ",
// Browser cookies
MsgBrowserCookieTooMany: "quá nhiều cookie trình duyệt trong một yêu cầu đồng bộ",
MsgInvalidCookieURL: "URL cookie không hợp lệ",
MsgBrowserCookieValueTooLarge: "giá trị cookie quá lớn",
MsgBrowserCookieEncryptionRequired: "chưa cấu hình mã hoá cookie trình duyệt",
// Tenant backup / restore
MsgRestoreNewModeRejectsTenantID: "mode=new tạo tenant mới; dùng tenant_slug (không phải tenant_id) làm slug cho tenant mới",
// Scheduler
MsgQueueFull: "hàng đợi session đã đầy",
MsgShuttingDown: "cổng đang tắt, vui lòng thử lại sau",
// Provider
MsgProviderReqFailed: "%s: yêu cầu thất bại: %s",
// Usage caps / pricing
MsgUsageCapsListPoliciesFailed: "không thể liệt kê chính sách usage cap",
MsgUsageCapPolicyValidationFailed: "xác thực chính sách usage cap thất bại",
MsgUsageCapPolicyManaged: "không thể chỉnh sửa chính sách usage cap do hệ thống quản lý",
MsgUsageCapsDeletePolicyFailed: "không thể xóa chính sách usage cap",
MsgUsageCapsUtilizationFailed: "không thể tải mức sử dụng usage cap",
MsgUsageCapsEventsFailed: "không thể tải sự kiện usage cap",
MsgUsagePricingSyncOpenRouterFailed: "không thể đồng bộ giá OpenRouter: %s",
MsgUsagePricingStoreCatalogFailed: "không thể lưu catalog giá",
MsgUsagePricingListFailed: "không thể liệt kê giá model",
MsgUsagePricingProviderModelRequired: "provider_id và model_id là bắt buộc",
MsgUsagePricingOverrideValidationFailed: "xác thực override giá thất bại",
MsgUsagePricingListOverridesFailed: "không thể liệt kê override giá",
MsgUsagePricingDeleteOverrideFailed: "không thể xóa override giá",
// Unknown method
MsgUnknownMethod: "phương thức không xác định: %s",
// Not implemented
MsgNotImplemented: "%s chưa được triển khai",
// Agent links
MsgLinksNotConfigured: "liên kết agent chưa được cấu hình",
MsgInvalidDirection: "hướng phải là outbound, inbound hoặc bidirectional",
MsgSourceTargetSame: "nguồn và đích phải là các agent khác nhau",
MsgCannotDelegateOpen: "không thể ủy quyền cho agent mở — chỉ agent định sẵn mới có thể là đích ủy quyền",
MsgNoUpdatesProvided: "không có cập nhật nào được cung cấp",
MsgInvalidLinkStatus: "trạng thái phải là active hoặc disabled",
// Teams
MsgTeamsNotConfigured: "nhóm chưa được cấu hình",
MsgAgentIsTeamLead: "agent đã là trưởng nhóm",
MsgCannotRemoveTeamLead: "không thể xóa trưởng nhóm",
// Channels
MsgCannotDeleteDefaultInst: "không thể xóa phiên bản channel mặc định",
MsgCannotRemoveLastWriter: "không thể xóa người quản lý cuối cùng",
// Skills
MsgSkillsUpdateNotSupported: "skills.update không được hỗ trợ với skill dựa trên tệp",
MsgCannotResolveSkillID: "không thể xác định ID skill dựa trên tệp",
MsgInvalidVisibility: "visibility không hợp lệ %q: phải là private hoặc public",
MsgSkillEvolutionNotConfigured: "kho lưu skill evolution chưa được cấu hình",
MsgActivityStoreNotConfigured: "kho lưu activity chưa được cấu hình",
MsgInvalidEvolutionMode: "evolution mode không hợp lệ",
MsgSystemSkillMutationBlocked: "không được phép sửa skill hệ thống",
MsgSuggestionMustBeApproved: "phải duyệt suggestion trước khi apply",
MsgInvalidDraftPatch: "draft_patch không hợp lệ: %s",
MsgDraftPatchRequired: "draft_patch cần content hoặc find/replace",
MsgFindTextNotFound: "không tìm thấy đoạn cần thay trong tệp đích",
// Logs
MsgInvalidLogAction: "action phải là 'start' hoặc 'stop'",
// Config
MsgRawConfigRequired: "cấu hình raw là bắt buộc",
MsgRawPatchRequired: "patch raw là bắt buộc",
MsgConfigMasterScopeOnly: "config.* chỉ áp dụng cho master scope; dùng endpoint tenant tool config cho override theo tenant",
MsgMasterScopeRequired: "thao tác này yêu cầu phạm vi tenant chính",
// Storage / File
MsgCannotDeleteSkillsDir: "không thể xóa thư mục skill",
MsgFailedToReadFile: "không thể đọc tệp",
MsgFileNotFound: "không tìm thấy tệp",
MsgInvalidVersion: "phiên bản không hợp lệ",
MsgVersionNotFound: "không tìm thấy phiên bản",
MsgFailedToDeleteFile: "không thể xóa",
// OAuth
MsgNoPendingOAuth: "không có luồng OAuth đang chờ",
MsgFailedToSaveToken: "không thể lưu token",
MsgOAuthCallbackSuccess: "Ủy quyền thành công. Bạn có thể đóng cửa sổ này.",
MsgOAuthCallbackFailed: "Ủy quyền thất bại. Bạn có thể đóng cửa sổ này.",
// Intent Classify
MsgStatusWorking: "🔄 Mình đang xử lý yêu cầu của bạn... Vui lòng chờ.",
MsgStatusDetailed: "🔄 Mình đang xử lý yêu cầu của bạn...\n%s (lần lặp %d)\nĐã chạy: %s\n\nVui lòng chờ — mình sẽ phản hồi khi xong.",
MsgStatusPhaseThinking: "Giai đoạn: Đang suy nghĩ...",
MsgStatusPhaseToolExec: "Giai đoạn: Đang chạy %s",
MsgStatusPhaseTools: "Giai đoạn: Đang thực thi công cụ...",
MsgStatusPhaseCompact: "Giai đoạn: Đang nén ngữ cảnh...",
MsgStatusPhaseDefault: "Giai đoạn: Đang xử lý...",
MsgCancelledReply: "✋ Đã hủy. Bạn muốn làm gì tiếp?",
MsgInjectedAck: "Đã nhận, tôi sẽ xử lý trong tác vụ hiện tại.",
// Knowledge Graph
MsgEntityIDRequired: "entity_id là bắt buộc",
MsgEntityFieldsRequired: "external_id, name và entity_type là bắt buộc",
MsgTextRequired: "text là bắt buộc",
MsgProviderModelRequired: "provider và model là bắt buộc",
MsgInvalidProviderOrModel: "provider hoặc model không hợp lệ",
// Mô tả công cụ tích hợp
MsgToolReadFile: "Đọc nội dung tệp từ workspace của agent theo đường dẫn",
MsgToolWriteFile: "Ghi nội dung vào tệp trong workspace, tự động tạo thư mục nếu cần",
MsgToolListFiles: "Liệt kê tệp và thư mục trong đường dẫn chỉ định",
MsgToolEdit: "Chỉnh sửa tệp bằng cách tìm và thay thế đoạn văn bản cụ thể",
MsgToolExec: "Thực thi lệnh shell trong workspace và trả về kết quả",
MsgToolWebSearch: "Tìm kiếm thông tin trên web bằng công cụ tìm kiếm (Brave hoặc DuckDuckGo)",
MsgToolWebFetch: "Tải trang web hoặc API endpoint và trích xuất nội dung văn bản",
MsgToolMemorySearch: "Tìm kiếm trong bộ nhớ dài hạn của agent bằng độ tương đồng ngữ nghĩa",
MsgToolMemoryGet: "Lấy tài liệu bộ nhớ cụ thể theo đường dẫn tệp",
MsgToolKGSearch: "Tìm kiếm thực thể, quan hệ và ghi chú trong đồ thị tri thức của agent",
MsgToolReadImage: "Phân tích hình ảnh bằng nhà cung cấp LLM có khả năng nhìn",
MsgToolReadDocument: "Phân tích tài liệu (PDF, Word, Excel, PowerPoint, CSV, v.v.) bằng LLM",
MsgToolCreateImage: "Tạo hình ảnh từ mô tả văn bản bằng nhà cung cấp tạo ảnh AI",
MsgToolReadAudio: "Phân tích tệp âm thanh (giọng nói, nhạc, âm thanh) bằng LLM",
MsgToolReadVideo: "Phân tích tệp video bằng nhà cung cấp LLM có khả năng xử lý video",
MsgToolCreateVideo: "Tạo video từ mô tả văn bản bằng AI",
MsgToolCreateAudio: "Tạo nhạc hoặc hiệu ứng âm thanh từ mô tả văn bản bằng AI",
MsgToolTTS: "Chuyển văn bản thành giọng nói tự nhiên",
MsgToolBrowser: "Tự động hóa trình duyệt: điều hướng trang, click, điền form, chụp ảnh màn hình",
MsgToolSessionsList: "Liệt kê các phiên chat đang hoạt động trên tất cả kênh",
MsgToolSessionStatus: "Xem trạng thái và thông tin chi tiết của một phiên chat",
MsgToolSessionsHistory: "Xem lịch sử tin nhắn của một phiên chat cụ thể",
MsgToolSessionsSend: "Gửi tin nhắn vào một phiên chat đang hoạt động thay mặt agent",
MsgToolMessage: "Gửi tin nhắn chủ động đến người dùng trên kênh đã kết nối (Telegram, Discord, v.v.)",
MsgToolCron: "Lên lịch hoặc quản lý tác vụ định kỳ bằng biểu thức cron, giờ cố định, hoặc khoảng thời gian",
MsgToolSpawn: "Tạo subagent chạy nền hoặc giao việc cho agent đã liên kết",
MsgToolSkillSearch: "Tìm kiếm kỹ năng có sẵn theo từ khóa hoặc mô tả",
MsgToolUseSkill: "Kích hoạt kỹ năng để sử dụng khả năng chuyên biệt (đánh dấu tracing)",
MsgToolSkillManage: "Tạo, sửa hoặc xóa kỹ năng từ trải nghiệm hội thoại",
MsgToolPublishSkill: "Đăng ký thư mục kỹ năng vào hệ thống, cho phép tìm kiếm và cấp quyền",
MsgToolTeamTasks: "Xem, tạo, cập nhật và hoàn thành tác vụ trên bảng tác vụ nhóm",
MsgToolAnnouncementSingle: "Tôi sẽ dùng %s để xử lý bước tiếp theo.",
MsgToolAnnouncementMulti: "Tôi sẽ dùng %s để xử lý bước tiếp theo.",
MsgSkillNudgePostscript: "Tác vụ này cần nhiều bước. Bạn muốn tôi lưu quy trình này thành kỹ năng tái sử dụng không? Trả lời **\"lưu kỹ năng\"** hoặc **\"bỏ qua\"**.",
MsgSkillNudge70Pct: "[System] Bạn đã dùng 70% ngân sách vòng lặp. Cân nhắc xem các mẫu trong phiên này có nên lưu thành kỹ năng không.",
MsgSkillNudge90Pct: "[System] Bạn đã dùng 90% ngân sách vòng lặp. Nếu phiên này có quy trình tái sử dụng, hãy cân nhắc lưu thành kỹ năng trước khi hoàn thành.",
MsgEmptyReplyFallback: "⚠️ Agent không thể tạo phản hồi. Lưu ý: một số thao tác công cụ có thể đã được thực hiện — vui lòng kiểm tra trước khi thử lại",
MsgContextBudgetExceeded: "⚠️ Cuộc hội thoại đã quá dài so với cửa sổ ngữ cảnh của model nên tôi đã dừng trước khi trả lời. Một số thao tác công cụ trong lượt này có thể đã được thực hiện. Vui lòng mở phiên mới để tiếp tục.",
MsgInvalidRole: "vai trò không hợp lệ: giá trị cho phép là owner, admin, operator, member, viewer",
MsgContactIDsRequired: "contact_ids là bắt buộc",
MsgMergeTargetRequired: "cần chính xác một trong tenant_user_id hoặc create_user",
MsgTenantUserNotFound: "không tìm thấy tenant user",
MsgTenantMismatch: "tenant user không thuộc tenant này",
MsgTenantScopeRequired: "cần xác định tenant để thực hiện thao tác này",
// TTS / Giọng đọc
MsgTtsUnknownModel: "model tts không hỗ trợ: %s",
MsgVoicesListFailed: "không tải được danh sách giọng đọc: %s",
MsgTtsGeminiInvalidVoice: "giọng đọc Gemini không hợp lệ: %s",
MsgTtsGeminiSpeakerLimit: "Gemini TTS hỗ trợ tối đa 2 người nói",
MsgTtsGeminiInvalidModel: "mô hình Gemini TTS không hợp lệ: %s",
MsgTtsGeminiTextOnly: "Gemini từ chối tạo âm thanh. Vui lòng thử văn bản đơn giản hơn, không dịch hay bình luận.",
MsgTtsParamOutOfRange: "tham số TTS %q có giá trị %v nằm ngoài phạm vi [%v, %v]",
MsgTtsParamUnknownKey: "tham số TTS %q không được nhà cung cấp này hỗ trợ",
MsgTtsMiniMaxVoicesFailed: "không tải được danh sách giọng đọc MiniMax: %s",
// STT
MsgSTTAllProvidersFailed: "Tất cả nhà cung cấp STT đều thất bại",
MsgSTTLegacyConfigDeprecated: "Cấu hình STT cũ đã lỗi thời; hãy chuyển sang builtin_tools[stt]",
MsgSTTWhatsappPrivacyWarning: "Bật STT cho WhatsApp sẽ phá vỡ mã hóa đầu cuối cho tin nhắn thoại gửi đến agent này.",
MsgVoiceMessageFallback: "[Tin nhắn thoại]",
// Webhooks
MsgWebhookAuthFailed: "xác thực webhook thất bại",
MsgWebhookHMACInvalid: "chữ ký HMAC không hợp lệ",
MsgWebhookHMACTimestampSkew: "thời gian yêu cầu nằm ngoài cửa sổ chấp nhận",
MsgWebhookBearerRequiredHMAC: "webhook này yêu cầu xác thực HMAC",
MsgWebhookRevoked: "webhook đã bị thu hồi",
MsgWebhookKindMismatch: "loại yêu cầu không khớp cấu hình webhook",
MsgWebhookRateLimited: "vượt quá giới hạn tốc độ webhook",
MsgWebhookBodyTooLarge: "nội dung yêu cầu vượt quá giới hạn kích thước",
MsgWebhookIdempotencyConflict: "xung đột idempotency key: nội dung yêu cầu không khớp",
MsgWebhookTenantMismatch: "tenant của webhook không khớp",
MsgWebhookAgentNotFound: "không tìm thấy agent webhook",
MsgWebhookChannelNotFound: "không tìm thấy kênh webhook",
MsgWebhookMediaSSRFBlocked: "URL media bị chặn bởi chính sách SSRF",
MsgWebhookMediaTooLarge: "tệp media vượt quá giới hạn kích thước",
MsgWebhookMediaMIMEDenied: "loại MIME của media không được phép",
MsgWebhookCallbackURLInvalid: "URL callback không hợp lệ hoặc bị chặn",
MsgWebhookLLMTimeout: "LLM xử lý hết thời gian chờ",
MsgWebhookLaneSaturated: "làn xử lý webhook đã đầy",
MsgWebhookLocalhostOnlyViolation: "webhook này chỉ cho phép gọi từ localhost",
MsgWebhookMediaChannelUnsupported: "kênh không hỗ trợ tệp đính kèm media",
MsgWebhookIPDenied: "địa chỉ IP không nằm trong danh sách cho phép",
MsgWebhookEncryptionUnavailable: "khóa mã hóa webhook chưa được cấu hình; hãy đặt GOCLAW_ENCRYPTION_KEY để kích hoạt webhook",
MsgWebhookMessageTestRequiresStandard: "kiểm thử webhook loại message yêu cầu bản Standard",
// Hooks
// Workstation
MsgWorkstationNotFound: "không tìm thấy máy trạm: %s",
MsgWorkstationKeyExists: "khóa máy trạm đã được sử dụng: %s",
MsgInvalidBackend: "loại backend không hợp lệ: %s (phải là ssh|docker)",
MsgWorkstationInactive: "máy trạm không hoạt động: %s",
MsgInvalidMetadataShape: "metadata không hợp lệ cho backend %s: %s",
MsgWorkstationRequired: "agent chưa được gắn máy trạm; hãy truyền workstation_id",
MsgWorkstationAccessDenied: "agent %s không được phép truy cập máy trạm %s",
MsgBackendNotReady: "backend máy trạm chưa sẵn sàng: %s",
MsgHookInvalidMatcher: "biểu thức regex matcher không hợp lệ: %s",
MsgHookCommandDisabledStandard: "hook loại command chỉ khả dụng trên phiên bản Lite",
MsgHookPromptRequiresMatcher: "hook prompt bắt buộc có matcher hoặc if_expr (chống chi phí vượt kiểm soát)",
MsgHookCircuitBreakerTripped: "hook đã tự tắt sau nhiều lần thất bại liên tiếp",
MsgHookBudgetExceeded: "tenant đã vượt ngân sách token cho hook",
MsgHookPerTurnCapReached: "đã đạt giới hạn số lần gọi hook trong một lượt",
MsgHookBuiltinReadOnly: "hook dựng sẵn chỉ cho phép bật/tắt, không thể chỉnh sửa",
// Workstation permissions (Phase 6)
MsgWorkstationCmdDenied: "lệnh bị từ chối bởi chính sách workstation: %s",
MsgWorkstationEnvDenied: "biến môi trường bị từ chối bởi chính sách: %s",
MsgWorkstationInputInvalid: "lệnh chứa ký tự không hợp lệ: %s",
MsgWorkstationRateLimit: "đã vượt quá giới hạn tốc độ workstation",
MsgWorkstationPermNotFound: "không tìm thấy mục quyền: %s",
// Workstation activity (Phase 7)
MsgWorkstationActivityTitle: "Hoạt động gần đây",
MsgWorkstationActionExec: "Thực thi",
MsgWorkstationActionDeny: "Từ chối",
// Package updates (Phase 4+5)
MsgPackageNotInstalled: "Gói %s chưa được cài đặt",
MsgPackageUpdateLocked: "Gói %s đang được cập nhật bởi một yêu cầu khác",
MsgReleaseNotFound: "Không tìm thấy phiên bản %s cho %s",
MsgAssetNotFound: "Không có tệp tương thích cho %s/%s",
MsgChecksumMismatch: "Checksum không khớp cho %s",
MsgUpdateSwapFailed: "Không cài được %s; đã khôi phục phiên bản cũ",
MsgUpdateManifestDesync: "Binary đã cập nhật nhưng lưu manifest thất bại — cần khôi phục thủ công cho %s",
MsgUpdateCacheStale: "Cache cập nhật đã cũ; hãy refresh trước khi áp dụng",
// Grant env validation
MsgGrantEnvDeniedKeys: "các khóa env không được phép: %s",
MsgGrantEnvValueInvalid: "giá trị env không hợp lệ: %s",
MsgGrantEnvTooManyKeys: "quá nhiều khóa env: tối đa 50",
MsgGrantEnvRevealLimit: "đã vượt giới hạn yêu cầu xem env — vui lòng thử lại sau",
// Git credential adapter
MsgGitCredHostMismatch: "thông tin xác thực git đã lưu dành cho %s nhưng lệnh đang nhắm tới %s",
MsgGitCredNoMatch: "không có thông tin xác thực git cho host %s",
MsgGitCredUnsupportedType: "loại thông tin xác thực git %q không được hỗ trợ",
MsgGitCredTokenInvalid: "token git đã lưu không hợp lệ hoặc rỗng",
MsgGitCredTokenControlChar: "token git đã lưu chứa ký tự điều khiển bị cấm",
MsgGitCredHostUserinfoRejected: "URL git chứa userinfo nhúng bị từ chối vì gây nhập nhằng",
MsgGitCredSSHPassphraseUnsupported: "khóa SSH có passphrase chưa được hỗ trợ; chạy `ssh-keygen -p` để gỡ passphrase trước khi lưu",
MsgGitCredSSHKeyInvalid: "khóa riêng SSH không hợp lệ: %s",
MsgGitCredHostScopeRequired: "host_scope là bắt buộc cho credential_type %s",
MsgGitCredHostScopeInvalid: "host_scope %q không phải là tên máy chủ hợp lệ",
MsgGitCredBlobMissingField: "blob credential thiếu trường bắt buộc %q",
MsgGitCredUnsupportedCredType: "credential_type %q không được hỗ trợ",
// Message tool cross-target forward notice
MessageCrossTargetForwarded: "📤 Đã forward sang %s theo yêu cầu: %q",
// Package update source labels
MsgPackagesUpdatesSourceGithub: "GitHub",
MsgPackagesUpdatesSourcePip: "pip",
MsgPackagesUpdatesSourceNpm: "npm",
MsgPackagesUpdatesSourceApk: "apk",
// Package update availability messages
MsgPackagesUpdatesUnavailablePip: "pip chưa cài trên hệ thống",
MsgPackagesUpdatesUnavailableNpm: "npm chưa cài trên hệ thống",
MsgPackagesUpdatesUnavailableApk: "apk không khả dụng trên hệ thống này",
// Package update failure reasons
MsgPackagesUpdatesReasonDependencyConflict: "Xung đột phụ thuộc",
MsgPackagesUpdatesReasonPermission: "Bị từ chối quyền",
MsgPackagesUpdatesReasonNetwork: "Lỗi mạng",
MsgPackagesUpdatesReasonNotFound: "Không tìm thấy gói",
MsgPackagesUpdatesReasonTargetMissing: "Phiên bản không tồn tại",
MsgPackagesUpdatesReasonExternallyManaged: "Môi trường được quản lý bên ngoài",
MsgPackagesUpdatesReasonLocked: "Cơ sở dữ liệu gói đang bị khóa",
MsgPackagesUpdatesReasonDiskFull: "Đĩa đã đầy",
MsgPackagesUpdatesReasonHelperUnavailable: "Dịch vụ đặc quyền không khả dụng",
})
}