feat(i18n): add message cross-target forwarded key

User-facing notice posted back to origin chat when the agent forwards a
message to a different target per explicit user request. Translations
added for en/vi/zh.
This commit is contained in:
viettranx committed 2026-04-18 17:44:50 +07:00
1 parent feca0a25e4
commit 5b2d856896
4 files changed
+134 -124

No files matched your search

+9 -6
View File
@@ -94,12 +94,12 @@ func init() {
MsgNotImplemented: "%s not yet implemented",
// Agent links
MsgLinksNotConfigured: "agent links not configured",
MsgInvalidDirection: "direction must be outbound, inbound, or bidirectional",
MsgSourceTargetSame: "source and target must be different agents",
MsgCannotDelegateOpen: "cannot delegate to open agents — only predefined agents can be delegation targets",
MsgNoUpdatesProvided: "no updates provided",
MsgInvalidLinkStatus: "status must be active or disabled",
MsgLinksNotConfigured: "agent links not configured",
MsgInvalidDirection: "direction must be outbound, inbound, or bidirectional",
MsgSourceTargetSame: "source and target must be different agents",
MsgCannotDelegateOpen: "cannot delegate to open agents — only predefined agents can be delegation targets",
MsgNoUpdatesProvided: "no updates provided",
MsgInvalidLinkStatus: "status must be active or disabled",
// Teams
MsgTeamsNotConfigured: "teams not configured",
@@ -216,5 +216,8 @@ func init() {
MsgHookBudgetExceeded: "tenant hook token budget exceeded",
MsgHookPerTurnCapReached: "hook invocation per-turn cap reached",
MsgHookBuiltinReadOnly: "builtin hooks are read-only except for the enabled toggle",
// Message tool cross-target forward notice
MessageCrossTargetForwarded: "📤 Forwarded to %s as requested: %q",
})
}
+9 -6
View File
@@ -94,12 +94,12 @@ func init() {
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",
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",
@@ -216,5 +216,8 @@ func init() {
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",
// Message tool cross-target forward notice
MessageCrossTargetForwarded: "📤 Đã forward sang %s theo yêu cầu: %q",
})
}
+9 -6
View File
@@ -94,12 +94,12 @@ func init() {
MsgNotImplemented: "%s 尚未实现",
// Agent links
MsgLinksNotConfigured: "Agent链接未配置",
MsgInvalidDirection: "方向必须是 outbound、inbound 或 bidirectional",
MsgSourceTargetSame: "源和目标必须是不同的Agent",
MsgCannotDelegateOpen: "无法委派给开放型Agent — 只有预定义Agent才能作为委派目标",
MsgNoUpdatesProvided: "未提供更新内容",
MsgInvalidLinkStatus: "状态必须是 active 或 disabled",
MsgLinksNotConfigured: "Agent链接未配置",
MsgInvalidDirection: "方向必须是 outbound、inbound 或 bidirectional",
MsgSourceTargetSame: "源和目标必须是不同的Agent",
MsgCannotDelegateOpen: "无法委派给开放型Agent — 只有预定义Agent才能作为委派目标",
MsgNoUpdatesProvided: "未提供更新内容",
MsgInvalidLinkStatus: "状态必须是 active 或 disabled",
// Teams
MsgTeamsNotConfigured: "团队未配置",
@@ -216,5 +216,8 @@ func init() {
MsgHookBudgetExceeded: "租户钩子令牌预算已耗尽",
MsgHookPerTurnCapReached: "单轮钩子调用次数已达上限",
MsgHookBuiltinReadOnly: "内置钩子只读,仅允许切换启用状态",
// Message tool cross-target forward notice
MessageCrossTargetForwarded: "📤 已按请求转发至 %s:%q",
})
}
+107 -106
View File
@@ -4,33 +4,33 @@ package i18n
// Grouped by domain for easier maintenance.
const (
// --- Common validation ---
MsgRequired = "error.required" // "%s is required"
MsgInvalidID = "error.invalid_id" // "invalid %s ID"
MsgNotFound = "error.not_found" // "%s not found: %s"
MsgAlreadyExists = "error.already_exists" // "%s already exists: %s"
MsgInvalidRequest = "error.invalid_request" // "invalid request: %s"
MsgInvalidJSON = "error.invalid_json" // "invalid JSON"
MsgUnauthorized = "error.unauthorized" // "unauthorized"
MsgPermissionDenied = "error.permission_denied" // "permission denied: %s"
MsgInternalError = "error.internal" // "internal error: %s"
MsgInvalidSlug = "error.invalid_slug" // "%s must be a valid slug (lowercase letters, numbers, hyphens only)"
MsgFailedToList = "error.failed_to_list" // "failed to list %s"
MsgFailedToCreate = "error.failed_to_create" // "failed to create %s: %s"
MsgFailedToUpdate = "error.failed_to_update" // "failed to update %s: %s"
MsgFailedToDelete = "error.failed_to_delete" // "failed to delete %s: %s"
MsgFailedToSave = "error.failed_to_save" // "failed to save %s: %s"
MsgInvalidUpdates = "error.invalid_updates" // "invalid updates"
MsgRequired = "error.required" // "%s is required"
MsgInvalidID = "error.invalid_id" // "invalid %s ID"
MsgNotFound = "error.not_found" // "%s not found: %s"
MsgAlreadyExists = "error.already_exists" // "%s already exists: %s"
MsgInvalidRequest = "error.invalid_request" // "invalid request: %s"
MsgInvalidJSON = "error.invalid_json" // "invalid JSON"
MsgUnauthorized = "error.unauthorized" // "unauthorized"
MsgPermissionDenied = "error.permission_denied" // "permission denied: %s"
MsgInternalError = "error.internal" // "internal error: %s"
MsgInvalidSlug = "error.invalid_slug" // "%s must be a valid slug (lowercase letters, numbers, hyphens only)"
MsgFailedToList = "error.failed_to_list" // "failed to list %s"
MsgFailedToCreate = "error.failed_to_create" // "failed to create %s: %s"
MsgFailedToUpdate = "error.failed_to_update" // "failed to update %s: %s"
MsgFailedToDelete = "error.failed_to_delete" // "failed to delete %s: %s"
MsgFailedToSave = "error.failed_to_save" // "failed to save %s: %s"
MsgInvalidUpdates = "error.invalid_updates" // "invalid updates"
// --- Agent ---
MsgAgentNotFound = "error.agent_not_found" // "agent not found: %s"
MsgCannotDeleteDefault = "error.cannot_delete_default" // "cannot delete the default agent"
MsgUserCtxRequired = "error.user_ctx_required" // "user context required"
MsgAgentNotFound = "error.agent_not_found" // "agent not found: %s"
MsgCannotDeleteDefault = "error.cannot_delete_default" // "cannot delete the default agent"
MsgUserCtxRequired = "error.user_ctx_required" // "user context required"
// --- Chat ---
MsgRateLimitExceeded = "error.rate_limit" // "rate limit exceeded — please wait"
MsgNoUserMessage = "error.no_user_message" // "no user message found"
MsgUserIDRequired = "error.user_id_required" // "user_id is required"
MsgMsgRequired = "error.message_required" // "message is required"
MsgRateLimitExceeded = "error.rate_limit" // "rate limit exceeded — please wait"
MsgNoUserMessage = "error.no_user_message" // "no user message found"
MsgUserIDRequired = "error.user_id_required" // "user_id is required"
MsgMsgRequired = "error.message_required" // "message is required"
// --- Abort ---
MsgAbortStopped = "abort.stopped" // "run stopped"
@@ -60,30 +60,30 @@ const (
MsgSenderIDRequired = "error.sender_id_required" // "sender_id is required"
// --- HTTP API ---
MsgInvalidAuth = "error.invalid_auth" // "invalid authentication"
MsgMsgsRequired = "error.messages_required" // "messages is required"
MsgUserIDHeader = "error.user_id_header" // "X-GoClaw-User-Id header is required"
MsgFileTooLarge = "error.file_too_large" // "file too large or invalid multipart form"
MsgMissingFileField = "error.missing_file_field" // "missing 'file' field"
MsgInvalidFilename = "error.invalid_filename" // "invalid filename"
MsgChannelKeyReq = "error.channel_key_required" // "channel and key are required"
MsgMethodNotAllowed = "error.method_not_allowed" // "method not allowed"
MsgStreamingNotSupported = "error.streaming_not_supported" // "streaming not supported"
MsgOwnerOnly = "error.owner_only" // "only owner can %s"
MsgNoAccess = "error.no_access" // "no access to this %s"
MsgAlreadySummoning = "error.already_summoning" // "agent is already being summoned"
MsgSummoningUnavailable = "error.summoning_unavailable" // "summoning not available"
MsgNoDescription = "error.no_description" // "agent has no description to resummon from"
MsgSummonCancelled = "info.summon_cancelled" // "summon cancelled by user"
MsgCannotCancel = "error.cannot_cancel_summon" // "agent is not being summoned"
MsgInvalidPath = "error.invalid_path" // "invalid path"
MsgInvalidAuth = "error.invalid_auth" // "invalid authentication"
MsgMsgsRequired = "error.messages_required" // "messages is required"
MsgUserIDHeader = "error.user_id_header" // "X-GoClaw-User-Id header is required"
MsgFileTooLarge = "error.file_too_large" // "file too large or invalid multipart form"
MsgMissingFileField = "error.missing_file_field" // "missing 'file' field"
MsgInvalidFilename = "error.invalid_filename" // "invalid filename"
MsgChannelKeyReq = "error.channel_key_required" // "channel and key are required"
MsgMethodNotAllowed = "error.method_not_allowed" // "method not allowed"
MsgStreamingNotSupported = "error.streaming_not_supported" // "streaming not supported"
MsgOwnerOnly = "error.owner_only" // "only owner can %s"
MsgNoAccess = "error.no_access" // "no access to this %s"
MsgAlreadySummoning = "error.already_summoning" // "agent is already being summoned"
MsgSummoningUnavailable = "error.summoning_unavailable" // "summoning not available"
MsgNoDescription = "error.no_description" // "agent has no description to resummon from"
MsgSummonCancelled = "info.summon_cancelled" // "summon cancelled by user"
MsgCannotCancel = "error.cannot_cancel_summon" // "agent is not being summoned"
MsgInvalidPath = "error.invalid_path" // "invalid path"
// --- Tenant backup / restore ---
MsgRestoreNewModeRejectsTenantID = "error.restore_new_mode_rejects_tenant_id" // "mode=new uses tenant_slug; tenant_id is not accepted"
// --- Scheduler ---
MsgQueueFull = "error.queue_full" // "session queue is full"
MsgShuttingDown = "error.shutting_down" // "gateway is shutting down, please retry shortly"
MsgQueueFull = "error.queue_full" // "session queue is full"
MsgShuttingDown = "error.shutting_down" // "gateway is shutting down, please retry shortly"
// --- Provider ---
MsgProviderReqFailed = "error.provider_request_failed" // "%s: request failed: %s"
@@ -95,12 +95,12 @@ const (
MsgNotImplemented = "error.not_implemented" // "%s not yet implemented"
// --- Agent links ---
MsgLinksNotConfigured = "error.links_not_configured" // "agent links not configured"
MsgInvalidDirection = "error.invalid_direction" // "direction must be outbound, inbound, or bidirectional"
MsgSourceTargetSame = "error.source_target_same" // "source and target must be different agents"
MsgCannotDelegateOpen = "error.cannot_delegate_open" // "cannot delegate to open agents — only predefined agents can be delegation targets"
MsgNoUpdatesProvided = "error.no_updates_provided" // "no updates provided"
MsgInvalidLinkStatus = "error.invalid_link_status" // "status must be active or disabled"
MsgLinksNotConfigured = "error.links_not_configured" // "agent links not configured"
MsgInvalidDirection = "error.invalid_direction" // "direction must be outbound, inbound, or bidirectional"
MsgSourceTargetSame = "error.source_target_same" // "source and target must be different agents"
MsgCannotDelegateOpen = "error.cannot_delegate_open" // "cannot delegate to open agents — only predefined agents can be delegation targets"
MsgNoUpdatesProvided = "error.no_updates_provided" // "no updates provided"
MsgInvalidLinkStatus = "error.invalid_link_status" // "status must be active or disabled"
// --- Teams ---
MsgTeamsNotConfigured = "error.teams_not_configured" // "teams not configured"
@@ -108,8 +108,8 @@ const (
MsgCannotRemoveTeamLead = "error.cannot_remove_team_lead" // "cannot remove the team lead"
// --- Channels ---
MsgCannotDeleteDefaultInst = "error.cannot_delete_default_inst" // "cannot delete default channel instance"
MsgCannotRemoveLastWriter = "error.cannot_remove_last_writer" // "cannot remove the last file writer"
MsgCannotDeleteDefaultInst = "error.cannot_delete_default_inst" // "cannot delete default channel instance"
MsgCannotRemoveLastWriter = "error.cannot_remove_last_writer" // "cannot remove the last file writer"
// --- Skills ---
MsgSkillsUpdateNotSupported = "error.skills_update_not_supported" // "skills.update not supported for file-based skills"
@@ -119,10 +119,10 @@ const (
MsgInvalidLogAction = "error.invalid_log_action" // "action must be 'start' or 'stop'"
// --- Config ---
MsgRawConfigRequired = "error.raw_config_required" // "raw config is required"
MsgRawPatchRequired = "error.raw_patch_required" // "raw patch is required"
MsgConfigMasterScopeOnly = "error.config_master_scope_only" // "config.* methods are master-scope only"
MsgMasterScopeRequired = "error.master_scope_required" // "this action requires master tenant scope"
MsgRawConfigRequired = "error.raw_config_required" // "raw config is required"
MsgRawPatchRequired = "error.raw_patch_required" // "raw patch is required"
MsgConfigMasterScopeOnly = "error.config_master_scope_only" // "config.* methods are master-scope only"
MsgMasterScopeRequired = "error.master_scope_required" // "this action requires master tenant scope"
// --- Storage / File ---
MsgCannotDeleteSkillsDir = "error.cannot_delete_skills_dir" // "cannot delete skills directories"
@@ -133,7 +133,7 @@ const (
MsgFailedToDeleteFile = "error.failed_to_delete_file" // "failed to delete"
// --- OAuth ---
MsgNoPendingOAuth = "error.no_pending_oauth" // "no pending OAuth flow"
MsgNoPendingOAuth = "error.no_pending_oauth" // "no pending OAuth flow"
MsgFailedToSaveToken = "error.failed_to_save_token" // "failed to save token"
// --- Intent Classify (channel-facing status replies) ---
@@ -148,44 +148,45 @@ const (
MsgInjectedAck = "status.injected_ack" // "Got it, I'll incorporate that into what I'm working on."
// --- Knowledge Graph ---
MsgEntityIDRequired = "error.entity_id_required" // "entity_id is required"
MsgEntityFieldsRequired = "error.entity_fields_required" // "external_id, name, and entity_type are required"
MsgTextRequired = "error.text_required" // "text is required"
MsgProviderModelRequired = "error.provider_model_required" // "provider and model are required"
MsgInvalidProviderOrModel = "error.invalid_provider_or_model" // "invalid provider or model"
MsgEntityIDRequired = "error.entity_id_required" // "entity_id is required"
MsgEntityFieldsRequired = "error.entity_fields_required" // "external_id, name, and entity_type are required"
MsgTextRequired = "error.text_required" // "text is required"
MsgProviderModelRequired = "error.provider_model_required" // "provider and model are required"
MsgInvalidProviderOrModel = "error.invalid_provider_or_model" // "invalid provider or model"
// --- Builtin tool descriptions (i18n key = core.tool.<name>) ---
MsgToolReadFile = "core.tool.read_file"
MsgToolWriteFile = "core.tool.write_file"
MsgToolListFiles = "core.tool.list_files"
MsgToolEdit = "core.tool.edit"
MsgToolExec = "core.tool.exec"
MsgToolWebSearch = "core.tool.web_search"
MsgToolWebFetch = "core.tool.web_fetch"
MsgToolMemorySearch = "core.tool.memory_search"
MsgToolMemoryGet = "core.tool.memory_get"
MsgToolKGSearch = "core.tool.knowledge_graph_search"
MsgToolReadImage = "core.tool.read_image"
MsgToolReadDocument = "core.tool.read_document"
MsgToolCreateImage = "core.tool.create_image"
MsgToolReadAudio = "core.tool.read_audio"
MsgToolReadVideo = "core.tool.read_video"
MsgToolCreateVideo = "core.tool.create_video"
MsgToolCreateAudio = "core.tool.create_audio"
MsgToolTTS = "core.tool.tts"
MsgToolBrowser = "core.tool.browser"
MsgToolSessionsList = "core.tool.sessions_list"
MsgToolSessionStatus = "core.tool.session_status"
MsgToolSessionsHistory = "core.tool.sessions_history"
MsgToolSessionsSend = "core.tool.sessions_send"
MsgToolMessage = "core.tool.message"
MsgToolCron = "core.tool.cron"
MsgToolSpawn = "core.tool.spawn"
MsgToolSkillSearch = "core.tool.skill_search"
MsgToolUseSkill = "core.tool.use_skill"
MsgToolSkillManage = "core.tool.skill_manage"
MsgToolPublishSkill = "core.tool.publish_skill"
MsgToolTeamTasks = "core.tool.team_tasks"
MsgToolReadFile = "core.tool.read_file"
MsgToolWriteFile = "core.tool.write_file"
MsgToolListFiles = "core.tool.list_files"
MsgToolEdit = "core.tool.edit"
MsgToolExec = "core.tool.exec"
MsgToolWebSearch = "core.tool.web_search"
MsgToolWebFetch = "core.tool.web_fetch"
MsgToolMemorySearch = "core.tool.memory_search"
MsgToolMemoryGet = "core.tool.memory_get"
MsgToolKGSearch = "core.tool.knowledge_graph_search"
MsgToolReadImage = "core.tool.read_image"
MsgToolReadDocument = "core.tool.read_document"
MsgToolCreateImage = "core.tool.create_image"
MsgToolReadAudio = "core.tool.read_audio"
MsgToolReadVideo = "core.tool.read_video"
MsgToolCreateVideo = "core.tool.create_video"
MsgToolCreateAudio = "core.tool.create_audio"
MsgToolTTS = "core.tool.tts"
MsgToolBrowser = "core.tool.browser"
MsgToolSessionsList = "core.tool.sessions_list"
MsgToolSessionStatus = "core.tool.session_status"
MsgToolSessionsHistory = "core.tool.sessions_history"
MsgToolSessionsSend = "core.tool.sessions_send"
MsgToolMessage = "core.tool.message"
MessageCrossTargetForwarded = "tools.message.cross_target_forwarded"
MsgToolCron = "core.tool.cron"
MsgToolSpawn = "core.tool.spawn"
MsgToolSkillSearch = "core.tool.skill_search"
MsgToolUseSkill = "core.tool.use_skill"
MsgToolSkillManage = "core.tool.skill_manage"
MsgToolPublishSkill = "core.tool.publish_skill"
MsgToolTeamTasks = "core.tool.team_tasks"
// Skill evolution nudges (user-facing)
MsgSkillNudgePostscript = "skill.nudge_postscript"
@@ -196,28 +197,28 @@ const (
MsgInvalidRole = "error.invalid_role" // "invalid role: allowed values are owner, admin, operator, member, viewer"
// --- TTS / Voices ---
MsgTtsUnknownModel = "error.tts_unknown_model" // "unknown tts model: %s"
MsgVoicesListFailed = "error.voices_list_failed" // "failed to list voices: %s"
MsgTtsUnknownModel = "error.tts_unknown_model" // "unknown tts model: %s"
MsgVoicesListFailed = "error.voices_list_failed" // "failed to list voices: %s"
// --- STT ---
MsgSTTAllProvidersFailed = "error.stt_all_providers_failed" // "All STT providers failed"
MsgSTTAllProvidersFailed = "error.stt_all_providers_failed" // "All STT providers failed"
MsgSTTLegacyConfigDeprecated = "warn.stt_legacy_config_deprecated" // "Legacy STT config deprecated; migrate to builtin_tools[stt]"
MsgSTTWhatsappPrivacyWarning = "warn.stt_whatsapp_privacy" // "Enabling STT for WhatsApp breaks end-to-end encryption for voice messages sent to this agent."
MsgVoiceMessageFallback = "channel.voice_message_fallback" // "[Voice message]" — used when STT unavailable/disabled/timed-out
MsgVoiceMessageFallback = "channel.voice_message_fallback" // "[Voice message]" — used when STT unavailable/disabled/timed-out
// --- Contact merge ---
MsgContactIDsRequired = "error.contact_ids_required" // "contact_ids is required"
MsgMergeTargetRequired = "error.merge_target_required" // "exactly one of tenant_user_id or create_user is required"
MsgTenantUserNotFound = "error.tenant_user_not_found" // "tenant user not found"
MsgTenantMismatch = "error.tenant_mismatch" // "tenant user does not belong to this tenant"
MsgTenantScopeRequired = "error.tenant_scope_required" // "tenant scope is required for this operation"
MsgMergeTargetRequired = "error.merge_target_required" // "exactly one of tenant_user_id or create_user is required"
MsgTenantUserNotFound = "error.tenant_user_not_found" // "tenant user not found"
MsgTenantMismatch = "error.tenant_mismatch" // "tenant user does not belong to this tenant"
MsgTenantScopeRequired = "error.tenant_scope_required" // "tenant scope is required for this operation"
// --- Hooks ---
MsgHookInvalidMatcher = "hook.invalid_matcher" // "invalid matcher regex: %s"
MsgHookCommandDisabledStandard = "hook.command_disabled_standard" // "command-type hooks are only available on Lite edition"
MsgHookPromptRequiresMatcher = "hook.prompt_requires_matcher" // "prompt hooks require a matcher or if_expr (runaway-cost guard)"
MsgHookCircuitBreakerTripped = "hook.circuit_breaker_tripped" // "hook auto-disabled after repeated failures"
MsgHookBudgetExceeded = "hook.budget_exceeded" // "tenant hook token budget exceeded"
MsgHookPerTurnCapReached = "hook.per_turn_cap_reached" // "hook invocation per-turn cap reached"
MsgHookBuiltinReadOnly = "hook.builtin_readonly" // "builtin hooks are read-only except for the enabled toggle"
MsgHookInvalidMatcher = "hook.invalid_matcher" // "invalid matcher regex: %s"
MsgHookCommandDisabledStandard = "hook.command_disabled_standard" // "command-type hooks are only available on Lite edition"
MsgHookPromptRequiresMatcher = "hook.prompt_requires_matcher" // "prompt hooks require a matcher or if_expr (runaway-cost guard)"
MsgHookCircuitBreakerTripped = "hook.circuit_breaker_tripped" // "hook auto-disabled after repeated failures"
MsgHookBudgetExceeded = "hook.budget_exceeded" // "tenant hook token budget exceeded"
MsgHookPerTurnCapReached = "hook.per_turn_cap_reached" // "hook invocation per-turn cap reached"
MsgHookBuiltinReadOnly = "hook.builtin_readonly" // "builtin hooks are read-only except for the enabled toggle"
)