diff --git a/docs/.generated/plugin-sdk-api-baseline.sha256 b/docs/.generated/plugin-sdk-api-baseline.sha256 index 746f44c0667e..1ef9bb2583f2 100644 --- a/docs/.generated/plugin-sdk-api-baseline.sha256 +++ b/docs/.generated/plugin-sdk-api-baseline.sha256 @@ -1,2 +1,2 @@ -74c6b635c822358e61473a5b1bf7e6786592c459289057db2fddf807ffa022ec plugin-sdk-api-baseline.json -4db87f9b57209632cd3887d791277f6c30c4a894b09785a2b51cb50cb5aedb78 plugin-sdk-api-baseline.jsonl +4272d9b4edc35fbdf9e1980c109845f59283a5c1e120235fb158a9db3c054b01 plugin-sdk-api-baseline.json +e24313a7fadaad09b58c1b683e2906973ff01d8b1bb3f403b9cef30bdcb89ee6 plugin-sdk-api-baseline.jsonl diff --git a/docs/plugins/sdk-channel-plugins.md b/docs/plugins/sdk-channel-plugins.md index a3c291367f64..0b26b874f0a5 100644 --- a/docs/plugins/sdk-channel-plugins.md +++ b/docs/plugins/sdk-channel-plugins.md @@ -155,6 +155,7 @@ Most channel plugins do not need approval-specific code. - If custom approval auth intentionally allows only same-chat fallback, return `markImplicitSameChatApprovalAuthorization({ authorized: true })` from `openclaw/plugin-sdk/approval-auth-runtime`; otherwise core treats the result as explicit approver authorization. - If a channel-owned native callback resolves approvals directly, use `isImplicitSameChatApprovalAuthorization(...)` before resolving so implicit fallback still goes through the channel's normal actor authorization. - If a channel needs native approval delivery, keep channel code focused on target normalization plus transport/presentation facts. Use `createChannelExecApprovalProfile`, `createChannelNativeOriginTargetResolver`, `createChannelApproverDmTargetResolver`, and `createApproverRestrictedNativeApprovalCapability` from `openclaw/plugin-sdk/approval-runtime`. Put the channel-specific facts behind `approvalCapability.nativeRuntime`, ideally via `createChannelApprovalNativeRuntimeAdapter(...)` or `createLazyChannelApprovalNativeRuntimeAdapter(...)`, so core can assemble the handler and own request filtering, routing, dedupe, expiry, gateway subscription, and routed-elsewhere notices. `nativeRuntime` is split into a few smaller seams: +- Use `createNativeApprovalChannelRouteGates` from `openclaw/plugin-sdk/approval-native-runtime` when a channel supports both session-origin native delivery and explicit approval forwarding targets. The helper centralizes approval config selection, `mode` handling, agent/session filters, account binding, session-target matching, and target-list matching while callers still own the channel id, default forwarding mode, account lookup, transport-enabled check, target normalization, and turn-source target resolution. Do not use it to create core-owned channel policy defaults; pass the channel's documented default mode explicitly. - `createChannelNativeOriginTargetResolver` uses the shared channel-route matcher by default for `{ to, accountId, threadId }` targets. Pass `targetsMatch` only when a channel has provider-specific equivalence rules, such as Slack timestamp prefix matching. - Pass `normalizeTargetForMatch` to `createChannelNativeOriginTargetResolver` when the channel needs to canonicalize provider ids before the default route matcher or a custom `targetsMatch` callback runs, while preserving the original target for delivery. Use `normalizeTarget` only when the resolved delivery target itself should be canonicalized. - `availability` - whether the account is configured and whether a request should be handled diff --git a/docs/plugins/sdk-subpaths.md b/docs/plugins/sdk-subpaths.md index 521fef501180..732bff70bdfc 100644 --- a/docs/plugins/sdk-subpaths.md +++ b/docs/plugins/sdk-subpaths.md @@ -179,7 +179,7 @@ and pairing-path families. | `plugin-sdk/approval-gateway-runtime` | Shared approval gateway-resolution helper | | `plugin-sdk/approval-handler-adapter-runtime` | Lightweight native approval adapter loading helpers for hot channel entrypoints | | `plugin-sdk/approval-handler-runtime` | Broader approval handler runtime helpers; prefer the narrower adapter/gateway seams when they are enough | - | `plugin-sdk/approval-native-runtime` | Native approval target + account-binding helpers and local native exec prompt suppression | + | `plugin-sdk/approval-native-runtime` | Native approval target, account-binding, route-gate, forwarding fallback, and local native exec prompt suppression helpers | | `plugin-sdk/approval-reaction-runtime` | Hardcoded approval reaction bindings, reaction prompt payloads, reaction target stores, and compatibility export for local native exec prompt suppression | | `plugin-sdk/approval-reply-runtime` | Exec/plugin approval reply payload helpers | | `plugin-sdk/approval-runtime` | Exec/plugin approval payload helpers, native approval routing/runtime helpers, and structured approval display helpers such as `formatApprovalDisplayPath` | diff --git a/extensions/imessage/src/approval-handler.runtime.ts b/extensions/imessage/src/approval-handler.runtime.ts index 537a5a4bc801..7c6ae247937c 100644 --- a/extensions/imessage/src/approval-handler.runtime.ts +++ b/extensions/imessage/src/approval-handler.runtime.ts @@ -79,6 +79,18 @@ function buildConversationKeyForTarget(to: string): IMessageApprovalConversation } } +function shouldThreadApprovalUpdate(to: string): boolean { + try { + const parsed = parseIMessageTarget(to); + if (parsed.kind === "handle" && parsed.service === "sms") { + return false; + } + } catch { + return true; + } + return true; +} + export const imessageApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter< IMessagePendingDelivery, PreparedIMessageApprovalTarget, @@ -151,7 +163,7 @@ export const imessageApprovalNativeRuntime = createChannelApprovalNativeRuntimeA await sendMessageIMessage(entry.to, payload.text, { config: cfg, ...(entry.accountId ? { accountId: entry.accountId } : {}), - replyToId: entry.messageId, + ...(shouldThreadApprovalUpdate(entry.to) ? { replyToId: entry.messageId } : {}), }); }, }, diff --git a/extensions/imessage/src/approval-native.ts b/extensions/imessage/src/approval-native.ts index 8320dca51e2d..431388775cce 100644 --- a/extensions/imessage/src/approval-native.ts +++ b/extensions/imessage/src/approval-native.ts @@ -5,12 +5,10 @@ import { import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; import type { ChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; import { - createChannelApprovalForwardingEvaluator, createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, + createNativeApprovalChannelRouteGates, createNativeApprovalForwardingFallbackSuppressor, - nativeApprovalTargetsMatch, - resolveApprovalRequestSessionTarget, shouldSuppressLocalNativeExecApprovalPrompt, } from "openclaw/plugin-sdk/approval-native-runtime"; import { @@ -48,8 +46,8 @@ import { normalizeIMessageMessagingTarget } from "./normalize.js"; import { inferIMessageTargetChatType } from "./targets.js"; type ApprovalRequest = ExecApprovalRequest | PluginApprovalRequest; -type ApprovalKind = "exec" | "plugin"; type ApprovalForwardingConfig = NonNullable["exec"]>; +type ApprovalForwardingMode = NonNullable; type ChannelApprovalForwardTarget = Parameters< NonNullable< NonNullable["shouldSuppressForwardingFallback"] @@ -61,6 +59,7 @@ type IMessageApprovalTarget = { threadId?: string | number | null; }; +const DEFAULT_APPROVAL_FORWARDING_MODE: ApprovalForwardingMode = "session"; const DEFAULT_PLUGIN_APPROVAL_DECISIONS: readonly ExecApprovalReplyDecision[] = [ "allow-once", "allow-always", @@ -74,35 +73,6 @@ function isIMessageApprovalTransportEnabled(params: { return resolveIMessageAccount({ cfg: params.cfg, accountId: params.accountId }).enabled; } -function targetAccountMatchesIMessageAccount(params: { - cfg: OpenClawConfig; - targetAccountId?: string | null; - accountId?: string | null; -}): boolean { - const targetAccountId = normalizeOptionalString(params.targetAccountId); - const accountId = normalizeOptionalString(params.accountId); - if (targetAccountId) { - return !accountId || normalizeAccountId(targetAccountId) === normalizeAccountId(accountId); - } - if (!accountId) { - return true; - } - const normalizedAccountId = normalizeAccountId(accountId); - const defaultAccountId = normalizeAccountId(resolveDefaultIMessageAccountId(params.cfg)); - if (normalizedAccountId === defaultAccountId) { - return true; - } - const enabledAccountIds = listIMessageAccountIds(params.cfg) - .filter((candidateAccountId) => - isIMessageApprovalTransportEnabled({ - cfg: params.cfg, - accountId: candidateAccountId, - }), - ) - .map((candidateAccountId) => normalizeAccountId(candidateAccountId)); - return enabledAccountIds.length === 1 && enabledAccountIds[0] === normalizedAccountId; -} - function normalizeIMessageForwardTarget( target: Pick, ): IMessageApprovalTarget | null { @@ -120,73 +90,6 @@ function normalizeIMessageForwardTarget( }; } -function hasMatchingIMessageTarget(params: { - cfg: OpenClawConfig; - config: ApprovalForwardingConfig; - accountId?: string | null; - target?: ChannelApprovalForwardTarget; -}): boolean { - const candidateTarget = params.target ? normalizeIMessageForwardTarget(params.target) : null; - return (params.config.targets ?? []).some((target) => { - const configuredTarget = normalizeIMessageForwardTarget(target); - if (!configuredTarget) { - return false; - } - if ( - !targetAccountMatchesIMessageAccount({ - cfg: params.cfg, - targetAccountId: configuredTarget.accountId, - accountId: params.accountId, - }) - ) { - return false; - } - if (!candidateTarget) { - return true; - } - return nativeApprovalTargetsMatch({ - channel: "imessage", - left: configuredTarget, - right: candidateTarget, - }); - }); -} - -function hasIMessageOriginOrSessionTarget(params: { - cfg: OpenClawConfig; - accountId?: string | null; - request: ApprovalRequest; -}): boolean { - if (resolveTurnSourceIMessageOriginTarget(params.request)) { - return true; - } - - const sessionTarget = resolveApprovalRequestSessionTarget({ - cfg: params.cfg, - request: params.request, - }); - return ( - normalizeLowercaseStringOrEmpty(sessionTarget?.channel) === "imessage" && - targetAccountMatchesIMessageAccount({ - cfg: params.cfg, - targetAccountId: sessionTarget?.accountId, - accountId: params.accountId, - }) - ); -} - -const imessageApprovalForwarding = createChannelApprovalForwardingEvaluator({ - channel: "imessage", - isTransportEnabled: isIMessageApprovalTransportEnabled, - hasMatchingTarget: hasMatchingIMessageTarget, - hasOriginOrSessionTarget: hasIMessageOriginOrSessionTarget, -}); - -const canApprovalPotentiallyRouteToIMessage = imessageApprovalForwarding.isPotentialRoute; -const canAnyApprovalPotentiallyRouteToIMessage = imessageApprovalForwarding.canAnyPotentiallyRoute; -const isIMessageSessionApprovalEligible = imessageApprovalForwarding.isSessionEligible; -const isIMessageExplicitTargetEligible = imessageApprovalForwarding.isExplicitTargetEligible; - function resolveTurnSourceIMessageOriginTarget( request: ApprovalRequest, ): IMessageApprovalTarget | null { @@ -212,6 +115,24 @@ function resolveSessionIMessageOriginTarget(sessionTarget: { return to ? { to, accountId: normalizeOptionalString(sessionTarget.accountId) } : null; } +const imessageApprovalRouteGates = createNativeApprovalChannelRouteGates({ + channel: "imessage", + defaultForwardingMode: DEFAULT_APPROVAL_FORWARDING_MODE, + isTransportEnabled: isIMessageApprovalTransportEnabled, + listAccountIds: listIMessageAccountIds, + resolveDefaultAccountId: resolveDefaultIMessageAccountId, + normalizeForwardTarget: normalizeIMessageForwardTarget, + resolveTurnSourceTarget: resolveTurnSourceIMessageOriginTarget, +}); + +const { + canApprovalPotentiallyRouteToChannel: canApprovalPotentiallyRouteToIMessage, + canAnyApprovalPotentiallyRouteToChannel: canAnyApprovalPotentiallyRouteToIMessage, + isSessionApprovalEligible: isIMessageSessionApprovalEligible, + isExplicitTargetEligible: isIMessageExplicitTargetEligible, + shouldHandleApprovalRequest: shouldHandleIMessageApprovalRequest, +} = imessageApprovalRouteGates; + function resolveIMessageSessionTargetFromSessionKey( sessionKey?: string | null, ): IMessageApprovalTarget | null { @@ -308,15 +229,6 @@ export function shouldSuppressLocalIMessageExecApprovalPrompt(params: { }); } -function shouldHandleIMessageApprovalRequest(params: { - cfg: OpenClawConfig; - accountId?: string | null; - approvalKind?: ApprovalKind; - request: ApprovalRequest; -}): boolean { - return imessageApprovalForwarding.shouldHandleRequest(params); -} - const resolveIMessageOriginTargetBase = createChannelNativeOriginTargetResolver({ channel: "imessage", shouldHandleRequest: shouldHandleIMessageApprovalRequest, diff --git a/extensions/signal/src/approval-native.ts b/extensions/signal/src/approval-native.ts index b51e5413aeb6..5970fa41fb6b 100644 --- a/extensions/signal/src/approval-native.ts +++ b/extensions/signal/src/approval-native.ts @@ -5,12 +5,10 @@ import { import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; import type { ChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; import { - createChannelApprovalForwardingEvaluator, createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, + createNativeApprovalChannelRouteGates, createNativeApprovalForwardingFallbackSuppressor, - nativeApprovalTargetsMatch, - resolveApprovalRequestSessionTarget, shouldSuppressLocalNativeExecApprovalPrompt, } from "openclaw/plugin-sdk/approval-native-runtime"; import { buildApprovalReactionPendingContentForRequest } from "openclaw/plugin-sdk/approval-reaction-runtime"; @@ -24,7 +22,7 @@ import type { } from "openclaw/plugin-sdk/channel-contract"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts"; import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; -import { normalizeAccountId, parseAgentSessionKey } from "openclaw/plugin-sdk/routing"; +import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing"; import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, @@ -40,6 +38,7 @@ import { normalizeSignalMessagingTarget } from "./normalize.js"; type ApprovalRequest = ExecApprovalRequest | PluginApprovalRequest; type ApprovalKind = "exec" | "plugin"; type ApprovalForwardingConfig = NonNullable["exec"]>; +type ApprovalForwardingMode = NonNullable; type ChannelApprovalForwardTarget = Parameters< NonNullable< NonNullable["shouldSuppressForwardingFallback"] @@ -51,6 +50,8 @@ type SignalApprovalTarget = { threadId?: string | number | null; }; +const DEFAULT_APPROVAL_FORWARDING_MODE: ApprovalForwardingMode = "session"; + function isSignalApprovalTransportEnabled(params: { cfg: OpenClawConfig; accountId?: string | null; @@ -58,35 +59,6 @@ function isSignalApprovalTransportEnabled(params: { return resolveSignalAccount({ cfg: params.cfg, accountId: params.accountId }).enabled; } -function targetAccountMatchesSignalAccount(params: { - cfg: OpenClawConfig; - targetAccountId?: string | null; - accountId?: string | null; -}): boolean { - const targetAccountId = normalizeOptionalString(params.targetAccountId); - const accountId = normalizeOptionalString(params.accountId); - if (targetAccountId) { - return !accountId || normalizeAccountId(targetAccountId) === normalizeAccountId(accountId); - } - if (!accountId) { - return true; - } - const normalizedAccountId = normalizeAccountId(accountId); - const defaultAccountId = normalizeAccountId(resolveDefaultSignalAccountId(params.cfg)); - if (normalizedAccountId === defaultAccountId) { - return true; - } - const enabledAccountIds = listSignalAccountIds(params.cfg) - .filter((candidateAccountId) => - isSignalApprovalTransportEnabled({ - cfg: params.cfg, - accountId: candidateAccountId, - }), - ) - .map((candidateAccountId) => normalizeAccountId(candidateAccountId)); - return enabledAccountIds.length === 1 && enabledAccountIds[0] === normalizedAccountId; -} - function normalizeSignalForwardTarget( target: Pick, ): SignalApprovalTarget | null { @@ -104,82 +76,6 @@ function normalizeSignalForwardTarget( }; } -function hasMatchingSignalTarget(params: { - cfg: OpenClawConfig; - config: ApprovalForwardingConfig; - accountId?: string | null; - target?: ChannelApprovalForwardTarget; -}): boolean { - const candidateTarget = params.target ? normalizeSignalForwardTarget(params.target) : null; - return (params.config.targets ?? []).some((target) => { - const configuredTarget = normalizeSignalForwardTarget(target); - if (!configuredTarget) { - return false; - } - if ( - !targetAccountMatchesSignalAccount({ - cfg: params.cfg, - targetAccountId: configuredTarget.accountId, - accountId: params.accountId, - }) - ) { - return false; - } - if (!candidateTarget) { - return true; - } - return nativeApprovalTargetsMatch({ - channel: "signal", - left: configuredTarget, - right: candidateTarget, - }); - }); -} - -function hasSignalOriginOrSessionTarget(params: { - cfg: OpenClawConfig; - accountId?: string | null; - request: ApprovalRequest; -}): boolean { - if (resolveTurnSourceSignalOriginTarget(params.request)) { - return true; - } - - const sessionTarget = resolveApprovalRequestSessionTarget({ - cfg: params.cfg, - request: params.request, - }); - return ( - normalizeLowercaseStringOrEmpty(sessionTarget?.channel) === "signal" && - targetAccountMatchesSignalAccount({ - cfg: params.cfg, - targetAccountId: sessionTarget?.accountId, - accountId: params.accountId, - }) - ); -} - -const signalApprovalForwarding = createChannelApprovalForwardingEvaluator({ - channel: "signal", - isTransportEnabled: isSignalApprovalTransportEnabled, - hasMatchingTarget: hasMatchingSignalTarget, - hasOriginOrSessionTarget: hasSignalOriginOrSessionTarget, -}); - -const canApprovalPotentiallyRouteToSignal = signalApprovalForwarding.isPotentialRoute; -const canAnyApprovalPotentiallyRouteToSignal = signalApprovalForwarding.canAnyPotentiallyRoute; -const isSignalSessionApprovalEligible = signalApprovalForwarding.isSessionEligible; - -export function isSignalNativeApprovalHandlerConfigured(params: { - cfg: OpenClawConfig; - accountId?: string | null; -}): boolean { - return canAnyApprovalPotentiallyRouteToSignal({ - ...params, - nativeSessionOnly: true, - }); -} - function resolveTurnSourceSignalOriginTarget( request: ApprovalRequest, ): SignalApprovalTarget | null { @@ -205,13 +101,29 @@ function resolveSessionSignalOriginTarget(sessionTarget: { return to ? { to, accountId: normalizeOptionalString(sessionTarget.accountId) } : null; } -function shouldHandleSignalApprovalRequest(params: { +const signalApprovalRouteGates = createNativeApprovalChannelRouteGates({ + channel: "signal", + defaultForwardingMode: DEFAULT_APPROVAL_FORWARDING_MODE, + isTransportEnabled: isSignalApprovalTransportEnabled, + listAccountIds: listSignalAccountIds, + resolveDefaultAccountId: resolveDefaultSignalAccountId, + normalizeForwardTarget: normalizeSignalForwardTarget, + resolveTurnSourceTarget: resolveTurnSourceSignalOriginTarget, +}); + +const { + canApprovalPotentiallyRouteToChannel: canApprovalPotentiallyRouteToSignal, + canAnyApprovalPotentiallyRouteToChannel: canAnyApprovalPotentiallyRouteToSignal, + isNativeApprovalHandlerConfigured: isSignalNativeApprovalHandlerConfiguredBase, + isSessionApprovalEligible: isSignalSessionApprovalEligible, + shouldHandleApprovalRequest: shouldHandleSignalApprovalRequest, +} = signalApprovalRouteGates; + +export function isSignalNativeApprovalHandlerConfigured(params: { cfg: OpenClawConfig; accountId?: string | null; - approvalKind?: ApprovalKind; - request: ApprovalRequest; }): boolean { - return signalApprovalForwarding.shouldHandleRequest(params); + return isSignalNativeApprovalHandlerConfiguredBase(params); } function resolveSignalSessionTargetFromSessionKey(sessionKey?: string | null): string | null { diff --git a/extensions/whatsapp/src/approval-native.ts b/extensions/whatsapp/src/approval-native.ts index ce7010f6023b..56228290533c 100644 --- a/extensions/whatsapp/src/approval-native.ts +++ b/extensions/whatsapp/src/approval-native.ts @@ -5,12 +5,10 @@ import { import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; import type { ChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; import { - createChannelApprovalForwardingEvaluator, createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, + createNativeApprovalChannelRouteGates, createNativeApprovalForwardingFallbackSuppressor, - nativeApprovalTargetsMatch, - resolveApprovalRequestSessionTarget, } from "openclaw/plugin-sdk/approval-native-runtime"; import { buildApprovalReactionPromptPayloadForRequest } from "openclaw/plugin-sdk/approval-reaction-runtime"; import type { @@ -19,7 +17,6 @@ import type { } from "openclaw/plugin-sdk/approval-runtime"; import type { ChannelApprovalCapability } from "openclaw/plugin-sdk/channel-contract"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts"; -import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, @@ -33,8 +30,8 @@ import { getWhatsAppApprovalApprovers, whatsappApprovalAuth } from "./approval-a import { isWhatsAppGroupJid, normalizeWhatsAppMessagingTarget } from "./normalize.js"; type ApprovalRequest = ExecApprovalRequest | PluginApprovalRequest; -type ApprovalKind = "exec" | "plugin"; type ApprovalForwardingConfig = NonNullable["exec"]>; +type ApprovalForwardingMode = NonNullable; type ChannelApprovalForwardTarget = Parameters< NonNullable< NonNullable["shouldSuppressForwardingFallback"] @@ -46,6 +43,8 @@ type WhatsAppApprovalTarget = { threadId?: string | number | null; }; +const DEFAULT_APPROVAL_FORWARDING_MODE: ApprovalForwardingMode = "session"; + function isWhatsAppApprovalTransportEnabled(params: { cfg: OpenClawConfig; accountId?: string | null; @@ -53,35 +52,6 @@ function isWhatsAppApprovalTransportEnabled(params: { return resolveWhatsAppAccount({ cfg: params.cfg, accountId: params.accountId }).enabled; } -function targetAccountMatchesWhatsAppAccount(params: { - cfg: OpenClawConfig; - targetAccountId?: string | null; - accountId?: string | null; -}): boolean { - const targetAccountId = normalizeOptionalString(params.targetAccountId); - const accountId = normalizeOptionalString(params.accountId); - if (targetAccountId) { - return !accountId || normalizeAccountId(targetAccountId) === normalizeAccountId(accountId); - } - if (!accountId) { - return true; - } - const normalizedAccountId = normalizeAccountId(accountId); - const defaultAccountId = normalizeAccountId(resolveDefaultWhatsAppAccountId(params.cfg)); - if (normalizedAccountId === defaultAccountId) { - return true; - } - const enabledAccountIds = listWhatsAppAccountIds(params.cfg) - .filter((candidateAccountId) => - isWhatsAppApprovalTransportEnabled({ - cfg: params.cfg, - accountId: candidateAccountId, - }), - ) - .map((candidateAccountId) => normalizeAccountId(candidateAccountId)); - return enabledAccountIds.length === 1 && enabledAccountIds[0] === normalizedAccountId; -} - function normalizeWhatsAppForwardTarget( target: Pick, ): WhatsAppApprovalTarget | null { @@ -99,73 +69,6 @@ function normalizeWhatsAppForwardTarget( }; } -function hasMatchingWhatsAppTarget(params: { - cfg: OpenClawConfig; - config: ApprovalForwardingConfig; - accountId?: string | null; - target?: ChannelApprovalForwardTarget; -}): boolean { - const candidateTarget = params.target ? normalizeWhatsAppForwardTarget(params.target) : null; - return (params.config.targets ?? []).some((target) => { - const configuredTarget = normalizeWhatsAppForwardTarget(target); - if (!configuredTarget) { - return false; - } - if ( - !targetAccountMatchesWhatsAppAccount({ - cfg: params.cfg, - targetAccountId: configuredTarget.accountId, - accountId: params.accountId, - }) - ) { - return false; - } - if (!candidateTarget) { - return true; - } - return nativeApprovalTargetsMatch({ - channel: "whatsapp", - left: configuredTarget, - right: candidateTarget, - }); - }); -} - -function hasWhatsAppOriginOrSessionTarget(params: { - cfg: OpenClawConfig; - accountId?: string | null; - request: ApprovalRequest; -}): boolean { - if (resolveTurnSourceWhatsAppOriginTarget(params.request)) { - return true; - } - - const sessionTarget = resolveApprovalRequestSessionTarget({ - cfg: params.cfg, - request: params.request, - }); - return ( - normalizeLowercaseStringOrEmpty(sessionTarget?.channel) === "whatsapp" && - targetAccountMatchesWhatsAppAccount({ - cfg: params.cfg, - targetAccountId: sessionTarget?.accountId, - accountId: params.accountId, - }) - ); -} - -const whatsappApprovalForwarding = createChannelApprovalForwardingEvaluator({ - channel: "whatsapp", - isTransportEnabled: isWhatsAppApprovalTransportEnabled, - hasMatchingTarget: hasMatchingWhatsAppTarget, - hasOriginOrSessionTarget: hasWhatsAppOriginOrSessionTarget, -}); - -const canApprovalPotentiallyRouteToWhatsApp = whatsappApprovalForwarding.isPotentialRoute; -const canAnyApprovalPotentiallyRouteToWhatsApp = whatsappApprovalForwarding.canAnyPotentiallyRoute; -const isWhatsAppSessionApprovalEligible = whatsappApprovalForwarding.isSessionEligible; -const isWhatsAppExplicitTargetEligible = whatsappApprovalForwarding.isExplicitTargetEligible; - function resolveTurnSourceWhatsAppOriginTarget( request: ApprovalRequest, ): WhatsAppApprovalTarget | null { @@ -191,14 +94,23 @@ function resolveSessionWhatsAppOriginTarget(sessionTarget: { return to ? { to, accountId: normalizeOptionalString(sessionTarget.accountId) } : null; } -function shouldHandleWhatsAppApprovalRequest(params: { - cfg: OpenClawConfig; - accountId?: string | null; - approvalKind?: ApprovalKind; - request: ApprovalRequest; -}): boolean { - return whatsappApprovalForwarding.shouldHandleRequest(params); -} +const whatsappApprovalRouteGates = createNativeApprovalChannelRouteGates({ + channel: "whatsapp", + defaultForwardingMode: DEFAULT_APPROVAL_FORWARDING_MODE, + isTransportEnabled: isWhatsAppApprovalTransportEnabled, + listAccountIds: listWhatsAppAccountIds, + resolveDefaultAccountId: resolveDefaultWhatsAppAccountId, + normalizeForwardTarget: normalizeWhatsAppForwardTarget, + resolveTurnSourceTarget: resolveTurnSourceWhatsAppOriginTarget, +}); + +const { + canApprovalPotentiallyRouteToChannel: canApprovalPotentiallyRouteToWhatsApp, + canAnyApprovalPotentiallyRouteToChannel: canAnyApprovalPotentiallyRouteToWhatsApp, + isSessionApprovalEligible: isWhatsAppSessionApprovalEligible, + isExplicitTargetEligible: isWhatsAppExplicitTargetEligible, + shouldHandleApprovalRequest: shouldHandleWhatsAppApprovalRequest, +} = whatsappApprovalRouteGates; const resolveWhatsAppOriginTargetBase = createChannelNativeOriginTargetResolver({ channel: "whatsapp", diff --git a/scripts/protocol-gen-swift.ts b/scripts/protocol-gen-swift.ts index 9bce73f9ae4c..cd242f42f0fc 100644 --- a/scripts/protocol-gen-swift.ts +++ b/scripts/protocol-gen-swift.ts @@ -42,19 +42,7 @@ const STRICT_LITERAL_STRUCTS = new Set([ const DEFAULTED_OPTIONAL_INIT_PARAMS: Record> = { SessionsAbortParams: new Set(["agentId"]), - SessionOperationEvent: new Set(["agentId"]), SessionsUsageParams: new Set(["agentId", "agentScope"]), - SessionsCompactionListParams: new Set(["agentId"]), - SessionsCompactionGetParams: new Set(["agentId"]), - SessionsCompactionBranchParams: new Set(["agentId"]), - SessionsCompactionRestoreParams: new Set(["agentId"]), - SessionsSendParams: new Set(["agentId"]), - SessionsMessagesSubscribeParams: new Set(["agentId"]), - SessionsMessagesUnsubscribeParams: new Set(["agentId"]), - SessionsPatchParams: new Set(["agentId"]), - SessionsResetParams: new Set(["agentId"]), - SessionsDeleteParams: new Set(["agentId"]), - SessionsCompactParams: new Set(["agentId"]), ArtifactsListParams: new Set(["agentId"]), ArtifactsGetParams: new Set(["agentId"]), ArtifactsDownloadParams: new Set(["agentId"]), diff --git a/src/agents/embedded-agent-runner/run/attempt.spawn-workspace.test-support.ts b/src/agents/embedded-agent-runner/run/attempt.spawn-workspace.test-support.ts index 216d4a4cc81b..21c3e5372843 100644 --- a/src/agents/embedded-agent-runner/run/attempt.spawn-workspace.test-support.ts +++ b/src/agents/embedded-agent-runner/run/attempt.spawn-workspace.test-support.ts @@ -927,6 +927,7 @@ export function resetEmbeddedAttemptHarness( } hoisted.createAgentSessionMock.mockReset(); hoisted.sessionManagerOpenMock.mockReset().mockReturnValue(hoisted.sessionManager); + hoisted.defaultResourceLoaderInitMock.mockReset(); hoisted.resolveSandboxContextMock.mockReset(); hoisted.ensureGlobalUndiciEnvProxyDispatcherMock.mockReset(); hoisted.ensureGlobalUndiciDispatcherStreamTimeoutsMock.mockReset(); diff --git a/src/plugin-sdk/approval-native-helpers.test.ts b/src/plugin-sdk/approval-native-helpers.test.ts index 30e471d31709..34fd3be804c6 100644 --- a/src/plugin-sdk/approval-native-helpers.test.ts +++ b/src/plugin-sdk/approval-native-helpers.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest"; import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, + createNativeApprovalChannelRouteGates, createNativeApprovalForwardingFallbackSuppressor, type NativeApprovalTarget, nativeApprovalTargetsMatch, @@ -15,6 +16,215 @@ const EMPTY_SESSION_CFG = { }, } satisfies OpenClawConfig; +function createMatrixRouteGates(options?: { + enabledAccounts?: readonly string[]; + accountIds?: readonly string[]; + defaultAccountId?: string; +}) { + const enabledAccounts = new Set(options?.enabledAccounts ?? ["default"]); + return createNativeApprovalChannelRouteGates({ + channel: "matrix", + defaultForwardingMode: "session", + isTransportEnabled: ({ accountId }) => enabledAccounts.has(accountId ?? "default"), + listAccountIds: () => options?.accountIds ?? ["default"], + resolveDefaultAccountId: () => options?.defaultAccountId ?? "default", + normalizeForwardTarget: (target) => + target.channel === "matrix" + ? { + to: target.to, + accountId: target.accountId ?? undefined, + threadId: target.threadId ?? undefined, + } + : null, + resolveTurnSourceTarget: (request) => + request.request.turnSourceChannel === "matrix" && request.request.turnSourceTo + ? { + to: request.request.turnSourceTo, + accountId: request.request.turnSourceAccountId ?? undefined, + threadId: request.request.turnSourceThreadId ?? undefined, + } + : null, + }); +} + +const matrixExecRequest = { + id: "req-1", + request: { + agentId: "agent-a", + command: "echo hi", + sessionKey: "agent:agent-a:matrix:room-1", + turnSourceAccountId: "default", + turnSourceChannel: "matrix", + turnSourceTo: "room-1", + }, + createdAtMs: 0, + expiresAtMs: 1000, +} as const; + +const matrixPluginRequest = { + id: "plugin:req-1", + request: { + agentId: "agent-a", + description: "Allow access", + sessionKey: "agent:agent-a:matrix:room-1", + title: "Plugin approval", + turnSourceAccountId: "default", + turnSourceChannel: "matrix", + turnSourceTo: "room-1", + }, + createdAtMs: 0, + expiresAtMs: 1000, +} as const; + +describe("createNativeApprovalChannelRouteGates", () => { + it("separates session-native and explicit target routing by approval family", () => { + const gates = createMatrixRouteGates(); + const cfg = { + approvals: { + exec: { + enabled: true, + mode: "targets", + targets: [{ channel: "matrix", to: "room-1" }], + }, + plugin: { + enabled: true, + mode: "session", + }, + }, + } satisfies OpenClawConfig; + + expect( + gates.canApprovalPotentiallyRouteToChannel({ + cfg, + approvalKind: "exec", + }), + ).toBe(true); + expect( + gates.canApprovalPotentiallyRouteToChannel({ + cfg, + approvalKind: "exec", + nativeSessionOnly: true, + }), + ).toBe(false); + expect( + gates.canApprovalPotentiallyRouteToChannel({ + cfg, + approvalKind: "plugin", + nativeSessionOnly: true, + }), + ).toBe(true); + expect(gates.isNativeApprovalHandlerConfigured({ cfg })).toBe(true); + + expect( + gates.shouldHandleApprovalRequest({ + cfg, + request: matrixExecRequest, + }), + ).toBe(false); + expect( + gates.shouldHandleApprovalRequest({ + cfg, + request: matrixPluginRequest, + }), + ).toBe(true); + expect( + gates.isExplicitTargetEligible({ + cfg, + approvalKind: "exec", + request: matrixExecRequest, + target: { channel: "matrix", to: "room-1", source: "target" }, + }), + ).toBe(true); + }); + + it("applies forwarding filters before accepting a session route", () => { + const gates = createMatrixRouteGates(); + const cfg = { + approvals: { + exec: { + enabled: true, + agentFilter: ["agent-a"], + sessionFilter: ["matrix:room"], + }, + }, + } satisfies OpenClawConfig; + + expect( + gates.isSessionApprovalEligible({ + cfg, + approvalKind: "exec", + request: matrixExecRequest, + }), + ).toBe(true); + expect( + gates.isSessionApprovalEligible({ + cfg, + approvalKind: "exec", + request: { + ...matrixExecRequest, + request: { + ...matrixExecRequest.request, + agentId: "agent-b", + sessionKey: "agent:agent-b:matrix:room-1", + }, + }, + }), + ).toBe(false); + }); + + it("uses default and single-enabled account fallback for unscoped targets", () => { + const cfg = { + approvals: { + exec: { + enabled: true, + mode: "targets", + targets: [{ channel: "matrix", to: "room-1" }], + }, + }, + } satisfies OpenClawConfig; + const target = { channel: "matrix", to: "room-1", source: "target" } as const; + + expect( + createMatrixRouteGates({ + accountIds: ["default", "work"], + enabledAccounts: ["default", "work"], + }).isExplicitTargetEligible({ + cfg, + accountId: "default", + approvalKind: "exec", + request: matrixExecRequest, + target, + }), + ).toBe(true); + + expect( + createMatrixRouteGates({ + accountIds: ["default", "work"], + enabledAccounts: ["work"], + }).isExplicitTargetEligible({ + cfg, + accountId: "work", + approvalKind: "exec", + request: matrixExecRequest, + target, + }), + ).toBe(true); + + expect( + createMatrixRouteGates({ + accountIds: ["default", "work"], + enabledAccounts: ["default", "work"], + }).isExplicitTargetEligible({ + cfg, + accountId: "work", + approvalKind: "exec", + request: matrixExecRequest, + target, + }), + ).toBe(false); + }); +}); + describe("createChannelNativeOriginTargetResolver", () => { it("reuses shared turn-source routing and respects shouldHandle gating", () => { const resolveOriginTarget = createChannelNativeOriginTargetResolver({ diff --git a/src/plugin-sdk/approval-native-helpers.ts b/src/plugin-sdk/approval-native-helpers.ts index 8f2cba905c64..6dbcff8c0041 100644 --- a/src/plugin-sdk/approval-native-helpers.ts +++ b/src/plugin-sdk/approval-native-helpers.ts @@ -9,9 +9,17 @@ import { type ExecApprovalReplyMetadata, } from "../infra/exec-approval-reply.js"; import type { ExecApprovalSessionTarget } from "../infra/exec-approval-session-target.js"; -import { resolveApprovalRequestOriginTarget } from "../infra/exec-approval-session-target.js"; +import { + resolveApprovalRequestOriginTarget, + resolveApprovalRequestSessionTarget, +} from "../infra/exec-approval-session-target.js"; import type { ExecApprovalRequest } from "../infra/exec-approvals.js"; import type { PluginApprovalRequest } from "../infra/plugin-approvals.js"; +import { normalizeAccountId } from "../routing/session-key.js"; +import { + normalizeLowercaseStringOrEmpty, + normalizeOptionalString, +} from "../shared/string-coerce.js"; import type { ChannelApprovalCapability, ChannelOutboundPayloadHint } from "./channel-contract.js"; import { channelRouteTargetsMatchExact } from "./channel-route.js"; import type { OpenClawConfig } from "./config-runtime.js"; @@ -127,6 +135,54 @@ type NativeApprovalForwardingFallbackSuppressorParams boolean; }; +type NativeApprovalChannelRouteGateParams = { + channel: string; + defaultForwardingMode: ExecApprovalForwardingMode; + isTransportEnabled: (params: { cfg: OpenClawConfig; accountId?: string | null }) => boolean; + listAccountIds: (cfg: OpenClawConfig) => readonly string[]; + resolveDefaultAccountId: (cfg: OpenClawConfig) => string; + normalizeForwardTarget: (target: NativeApprovalForwardTarget) => TTarget | null; + resolveTurnSourceTarget: (request: ApprovalRequest) => TTarget | null; + targetsMatch?: (left: TTarget, right: TTarget) => boolean; +}; + +type NativeApprovalChannelRouteGates = { + canApprovalPotentiallyRouteToChannel: (params: { + cfg: OpenClawConfig; + accountId?: string | null; + approvalKind: ApprovalKind; + nativeSessionOnly?: boolean; + }) => boolean; + canAnyApprovalPotentiallyRouteToChannel: (params: { + cfg: OpenClawConfig; + accountId?: string | null; + nativeSessionOnly?: boolean; + }) => boolean; + isNativeApprovalHandlerConfigured: (params: { + cfg: OpenClawConfig; + accountId?: string | null; + }) => boolean; + isSessionApprovalEligible: (params: { + cfg: OpenClawConfig; + accountId?: string | null; + approvalKind: ApprovalKind; + request: ApprovalRequest; + }) => boolean; + isExplicitTargetEligible: (params: { + cfg: OpenClawConfig; + accountId?: string | null; + approvalKind: ApprovalKind; + request: ApprovalRequest; + target: NativeApprovalForwardTarget; + }) => boolean; + shouldHandleApprovalRequest: (params: { + cfg: OpenClawConfig; + accountId?: string | null; + approvalKind?: ApprovalKind; + request: ApprovalRequest; + }) => boolean; +}; + type NativeOriginResolverParams = { channel: string; shouldHandleRequest?: (params: ApprovalResolverParams) => boolean; @@ -435,6 +491,242 @@ export function createChannelApprovalForwardingEvaluator( }; } +function normalizeApprovalForwardingModeWithDefault(params: { + config: ExecApprovalForwardingConfig; + defaultForwardingMode: ExecApprovalForwardingMode; +}): ExecApprovalForwardingMode { + return params.config.mode ?? params.defaultForwardingMode; +} + +export function createNativeApprovalChannelRouteGates( + params: NativeApprovalChannelRouteGateParams, +): NativeApprovalChannelRouteGates { + const targetsMatch = + params.targetsMatch ?? + ((left: TTarget, right: TTarget) => + nativeApprovalTargetsMatch({ channel: params.channel, left, right })); + + const targetAccountMatchesChannelAccount = (input: { + cfg: OpenClawConfig; + targetAccountId?: string | null; + accountId?: string | null; + }): boolean => { + const targetAccountId = normalizeOptionalString(input.targetAccountId); + const accountId = normalizeOptionalString(input.accountId); + if (targetAccountId) { + return !accountId || normalizeAccountId(targetAccountId) === normalizeAccountId(accountId); + } + if (!accountId) { + return true; + } + const normalizedAccountId = normalizeAccountId(accountId); + const defaultAccountId = normalizeAccountId(params.resolveDefaultAccountId(input.cfg)); + if (normalizedAccountId === defaultAccountId) { + return true; + } + const enabledAccountIds = params + .listAccountIds(input.cfg) + .filter((candidateAccountId) => + params.isTransportEnabled({ + cfg: input.cfg, + accountId: candidateAccountId, + }), + ) + .map((candidateAccountId) => normalizeAccountId(candidateAccountId)); + return enabledAccountIds.length === 1 && enabledAccountIds[0] === normalizedAccountId; + }; + + const hasMatchingChannelTarget = (input: { + cfg: OpenClawConfig; + config: ExecApprovalForwardingConfig; + accountId?: string | null; + target?: NativeApprovalForwardTarget; + }): boolean => { + const candidateTarget = input.target ? params.normalizeForwardTarget(input.target) : null; + return (input.config.targets ?? []).some((target) => { + const configuredTarget = params.normalizeForwardTarget(target); + if (!configuredTarget) { + return false; + } + if ( + !targetAccountMatchesChannelAccount({ + cfg: input.cfg, + targetAccountId: configuredTarget.accountId, + accountId: input.accountId, + }) + ) { + return false; + } + if (!candidateTarget) { + return true; + } + return targetsMatch(configuredTarget, candidateTarget); + }); + }; + + const hasChannelOriginOrSessionTarget = (input: { + cfg: OpenClawConfig; + accountId?: string | null; + request: ApprovalRequest; + }): boolean => { + if (params.resolveTurnSourceTarget(input.request)) { + return true; + } + + const sessionTarget = resolveApprovalRequestSessionTarget({ + cfg: input.cfg, + request: input.request, + }); + return ( + normalizeLowercaseStringOrEmpty(sessionTarget?.channel) === params.channel && + targetAccountMatchesChannelAccount({ + cfg: input.cfg, + targetAccountId: sessionTarget?.accountId, + accountId: input.accountId, + }) + ); + }; + + const canApprovalPotentiallyRouteToChannel = (input: { + cfg: OpenClawConfig; + accountId?: string | null; + approvalKind: ApprovalKind; + nativeSessionOnly?: boolean; + }): boolean => { + if (!params.isTransportEnabled(input)) { + return false; + } + const config = resolveApprovalForwardingConfig(input); + if (!config?.enabled) { + return false; + } + const mode = normalizeApprovalForwardingModeWithDefault({ + config, + defaultForwardingMode: params.defaultForwardingMode, + }); + if (approvalModeIncludesSession(mode)) { + return true; + } + if (input.nativeSessionOnly) { + return false; + } + return ( + approvalModeIncludesTargets(mode) && + hasMatchingChannelTarget({ + cfg: input.cfg, + config, + accountId: input.accountId, + }) + ); + }; + + const canAnyApprovalPotentiallyRouteToChannel = (input: { + cfg: OpenClawConfig; + accountId?: string | null; + nativeSessionOnly?: boolean; + }): boolean => + canApprovalPotentiallyRouteToChannel({ + ...input, + approvalKind: "exec", + }) || + canApprovalPotentiallyRouteToChannel({ + ...input, + approvalKind: "plugin", + }); + + const isSessionApprovalEligible = (input: { + cfg: OpenClawConfig; + accountId?: string | null; + approvalKind: ApprovalKind; + request: ApprovalRequest; + }): boolean => { + if (!params.isTransportEnabled(input)) { + return false; + } + const config = resolveApprovalForwardingConfig(input); + if (!config?.enabled) { + return false; + } + const mode = normalizeApprovalForwardingModeWithDefault({ + config, + defaultForwardingMode: params.defaultForwardingMode, + }); + if (!approvalModeIncludesSession(mode)) { + return false; + } + if (!matchesForwardingFilters({ config, request: input.request })) { + return false; + } + if ( + !doesApprovalRequestMatchChannelAccount({ + cfg: input.cfg, + request: input.request, + channel: params.channel, + accountId: input.accountId, + }) + ) { + return false; + } + return hasChannelOriginOrSessionTarget(input); + }; + + const isExplicitTargetEligible = (input: { + cfg: OpenClawConfig; + accountId?: string | null; + approvalKind: ApprovalKind; + request: ApprovalRequest; + target: NativeApprovalForwardTarget; + }): boolean => { + if (!params.isTransportEnabled(input)) { + return false; + } + const config = resolveApprovalForwardingConfig(input); + if (!config?.enabled) { + return false; + } + const mode = normalizeApprovalForwardingModeWithDefault({ + config, + defaultForwardingMode: params.defaultForwardingMode, + }); + if (!approvalModeIncludesTargets(mode)) { + return false; + } + if (!matchesForwardingFilters({ config, request: input.request })) { + return false; + } + return hasMatchingChannelTarget({ + cfg: input.cfg, + config, + accountId: input.accountId, + target: input.target, + }); + }; + + const shouldHandleApprovalRequest = (input: { + cfg: OpenClawConfig; + accountId?: string | null; + approvalKind?: ApprovalKind; + request: ApprovalRequest; + }): boolean => + isSessionApprovalEligible({ + ...input, + approvalKind: resolveApprovalKind(input.request, input.approvalKind), + }); + + return { + canApprovalPotentiallyRouteToChannel, + canAnyApprovalPotentiallyRouteToChannel, + isNativeApprovalHandlerConfigured: (input) => + canAnyApprovalPotentiallyRouteToChannel({ + ...input, + nativeSessionOnly: true, + }), + isSessionApprovalEligible, + isExplicitTargetEligible, + shouldHandleApprovalRequest, + }; +} + function normalizeOptionalAccountId(value?: string | null): string | undefined { return value?.trim() || undefined; } diff --git a/src/plugin-sdk/approval-native-runtime.ts b/src/plugin-sdk/approval-native-runtime.ts index 940d8d5ce788..d4eda02cbbe2 100644 --- a/src/plugin-sdk/approval-native-runtime.ts +++ b/src/plugin-sdk/approval-native-runtime.ts @@ -2,6 +2,7 @@ export { createChannelApprovalForwardingEvaluator, createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, + createNativeApprovalChannelRouteGates, createNativeApprovalForwardingFallbackSuppressor, nativeApprovalTargetsMatch, resolveApprovalKind, diff --git a/ui/src/i18n/.i18n/ar.meta.json b/ui/src/i18n/.i18n/ar.meta.json index 2e04b99fb080..f08ad8374b16 100644 --- a/ui/src/i18n/.i18n/ar.meta.json +++ b/ui/src/i18n/.i18n/ar.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:07.578Z", + "generatedAt": "2026-05-29T21:01:05.561Z", "locale": "ar", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/ar.tm.jsonl b/ui/src/i18n/.i18n/ar.tm.jsonl new file mode 100644 index 000000000000..f32de6763b3f --- /dev/null +++ b/ui/src/i18n/.i18n/ar.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"31baf5b9e4f804c6e3a61e02532c991cbb3d27c24b36ad51b9505cdc8bdf9f97","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"ar","translated":"ملاحظة الهدف","updated_at":"2026-05-29T21:01:05.556Z"} +{"cache_key":"b83a08557f604af51d1d904a15fd37755f3e3f311e32b5dff3c7218cfd75183d","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/ar.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"ar","translated":"الهدف","updated_at":"2026-05-29T21:01:05.553Z"} diff --git a/ui/src/i18n/.i18n/de.meta.json b/ui/src/i18n/.i18n/de.meta.json index 368b06399603..57c722c34781 100644 --- a/ui/src/i18n/.i18n/de.meta.json +++ b/ui/src/i18n/.i18n/de.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:09:57.996Z", + "generatedAt": "2026-05-29T21:00:05.360Z", "locale": "de", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/de.tm.jsonl b/ui/src/i18n/.i18n/de.tm.jsonl new file mode 100644 index 000000000000..142e8fdf7a25 --- /dev/null +++ b/ui/src/i18n/.i18n/de.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"3291b27d87c9b085d83645bf3d093be323f1809505f54b9edf8bd2691601fde6","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"de","translated":"Ziel","updated_at":"2026-05-29T21:00:05.331Z"} +{"cache_key":"e50aa42b44fa61de5322d01701b08a1460b315ebf5beb258a7b68d1c40200a02","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/de.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"de","translated":"Zielnotiz","updated_at":"2026-05-29T21:00:05.331Z"} diff --git a/ui/src/i18n/.i18n/es.meta.json b/ui/src/i18n/.i18n/es.meta.json index 9acf4285640b..48e617ed2927 100644 --- a/ui/src/i18n/.i18n/es.meta.json +++ b/ui/src/i18n/.i18n/es.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:00.520Z", + "generatedAt": "2026-05-29T21:00:16.244Z", "locale": "es", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/es.tm.jsonl b/ui/src/i18n/.i18n/es.tm.jsonl new file mode 100644 index 000000000000..66681e86a4d4 --- /dev/null +++ b/ui/src/i18n/.i18n/es.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"9d69982042ae98028cd211bab9a9b5f33b1ddaa2a7ee8231a6540e9e63302e25","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"es","translated":"Nota del objetivo","updated_at":"2026-05-29T21:00:16.236Z"} +{"cache_key":"b626995f71c58bfb263806f12b5eece5091a529999f3f1bfccbc5df135f6a178","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/es.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"es","translated":"Objetivo","updated_at":"2026-05-29T21:00:16.236Z"} diff --git a/ui/src/i18n/.i18n/fa.meta.json b/ui/src/i18n/.i18n/fa.meta.json index 2f1620622d30..cd7f81f97d77 100644 --- a/ui/src/i18n/.i18n/fa.meta.json +++ b/ui/src/i18n/.i18n/fa.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:21.090Z", + "generatedAt": "2026-05-29T21:02:42.653Z", "locale": "fa", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/fa.tm.jsonl b/ui/src/i18n/.i18n/fa.tm.jsonl new file mode 100644 index 000000000000..9c4bc995fdb0 --- /dev/null +++ b/ui/src/i18n/.i18n/fa.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"4a2cd58d849e04841d7cc035ec2c90d722c4fed30f648da173044275addefb73","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"fa","translated":"یادداشت هدف","updated_at":"2026-05-29T21:02:42.628Z"} +{"cache_key":"71d09491009ef87d3af376ce4162e9b18d97162c0d76ba6553a489cc3cd638c6","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/fa.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"fa","translated":"هدف","updated_at":"2026-05-29T21:02:42.628Z"} diff --git a/ui/src/i18n/.i18n/fr.meta.json b/ui/src/i18n/.i18n/fr.meta.json index 3019d1b9f9b2..f19a9ceba0ae 100644 --- a/ui/src/i18n/.i18n/fr.meta.json +++ b/ui/src/i18n/.i18n/fr.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:06.134Z", + "generatedAt": "2026-05-29T21:00:46.756Z", "locale": "fr", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/fr.tm.jsonl b/ui/src/i18n/.i18n/fr.tm.jsonl new file mode 100644 index 000000000000..db5a55c528ca --- /dev/null +++ b/ui/src/i18n/.i18n/fr.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"a87418ac5fda24f3add83f591aa5c4b8ebd1d3914f11b428e8eac9cc3b959fc5","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"fr","translated":"Note d’objectif","updated_at":"2026-05-29T21:00:46.685Z"} +{"cache_key":"d0488f998b840872ae71bc8d8209e714ef16aa4216a6b422006b4762744e1289","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/fr.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"fr","translated":"Objectif","updated_at":"2026-05-29T21:00:46.685Z"} diff --git a/ui/src/i18n/.i18n/id.meta.json b/ui/src/i18n/.i18n/id.meta.json index 8295210da240..fc9ecac9c5d7 100644 --- a/ui/src/i18n/.i18n/id.meta.json +++ b/ui/src/i18n/.i18n/id.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:13.111Z", + "generatedAt": "2026-05-29T21:01:44.176Z", "locale": "id", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/id.tm.jsonl b/ui/src/i18n/.i18n/id.tm.jsonl new file mode 100644 index 000000000000..869d69641a62 --- /dev/null +++ b/ui/src/i18n/.i18n/id.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"2b375a43961fdfcfdd974503b29314f06a33027760f2592eace136fda36732fd","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"id","translated":"Catatan tujuan","updated_at":"2026-05-29T21:01:43.534Z"} +{"cache_key":"7781d543931e105b5b122201b4f1913e29c028cc7b6e0695c5a91ec2d84dce0c","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/id.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"id","translated":"Tujuan","updated_at":"2026-05-29T21:01:43.511Z"} diff --git a/ui/src/i18n/.i18n/it.meta.json b/ui/src/i18n/.i18n/it.meta.json index cde86cea17ec..449556490961 100644 --- a/ui/src/i18n/.i18n/it.meta.json +++ b/ui/src/i18n/.i18n/it.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:08.751Z", + "generatedAt": "2026-05-29T21:01:19.882Z", "locale": "it", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/it.tm.jsonl b/ui/src/i18n/.i18n/it.tm.jsonl new file mode 100644 index 000000000000..286e88538f95 --- /dev/null +++ b/ui/src/i18n/.i18n/it.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"10f9390d7ed31c5188b9663412768c8d085c4311c703765a09cee4309636e530","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"it","translated":"Nota sull'obiettivo","updated_at":"2026-05-29T21:01:19.873Z"} +{"cache_key":"31e985892e47fba1b0d3c69810e7c70676c475936ca1382069c2ccc3c82a6a85","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/it.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"it","translated":"Obiettivo","updated_at":"2026-05-29T21:01:19.873Z"} diff --git a/ui/src/i18n/.i18n/ja-JP.meta.json b/ui/src/i18n/.i18n/ja-JP.meta.json index 4128eb5c39cf..1b28f9d65ac0 100644 --- a/ui/src/i18n/.i18n/ja-JP.meta.json +++ b/ui/src/i18n/.i18n/ja-JP.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:01.779Z", + "generatedAt": "2026-05-29T21:00:25.952Z", "locale": "ja-JP", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/ja-JP.tm.jsonl b/ui/src/i18n/.i18n/ja-JP.tm.jsonl new file mode 100644 index 000000000000..27d4de11f47a --- /dev/null +++ b/ui/src/i18n/.i18n/ja-JP.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"385cee2f0cb4a83b0e53424167bef43a488ba00da62ea56753a393ec6b6960b2","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"ja-JP","translated":"目標","updated_at":"2026-05-29T21:00:25.945Z"} +{"cache_key":"d18570791fe4a33cac91265fb875e2e15cb4c0172d17e4ba14bd8208a1df3401","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/ja-JP.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"ja-JP","translated":"目標メモ","updated_at":"2026-05-29T21:00:25.945Z"} diff --git a/ui/src/i18n/.i18n/ko.meta.json b/ui/src/i18n/.i18n/ko.meta.json index 03b452021de3..914f77d84596 100644 --- a/ui/src/i18n/.i18n/ko.meta.json +++ b/ui/src/i18n/.i18n/ko.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:03.892Z", + "generatedAt": "2026-05-29T21:00:36.567Z", "locale": "ko", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/ko.tm.jsonl b/ui/src/i18n/.i18n/ko.tm.jsonl new file mode 100644 index 000000000000..9f0e2bd3c04f --- /dev/null +++ b/ui/src/i18n/.i18n/ko.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"6661a8580f033e530995fca7fa9a21141d4c43f499c3bac4b5bcde8e4f085a50","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"ko","translated":"목표 메모","updated_at":"2026-05-29T21:00:36.520Z"} +{"cache_key":"c4aa03b43d324f829c9cea82c3296e21c9b65f7388dba7979b5dd57318a5f957","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/ko.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"ko","translated":"목표","updated_at":"2026-05-29T21:00:36.520Z"} diff --git a/ui/src/i18n/.i18n/nl.meta.json b/ui/src/i18n/.i18n/nl.meta.json index 8b5ff50feaae..f0f883f47667 100644 --- a/ui/src/i18n/.i18n/nl.meta.json +++ b/ui/src/i18n/.i18n/nl.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:19.671Z", + "generatedAt": "2026-05-29T21:02:33.330Z", "locale": "nl", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/nl.tm.jsonl b/ui/src/i18n/.i18n/nl.tm.jsonl new file mode 100644 index 000000000000..bf2f757cad0a --- /dev/null +++ b/ui/src/i18n/.i18n/nl.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"61322d7dd6c6f6ecd12429935bddd35cf29c24771475df989fb28ab6a579b26b","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"nl","translated":"Doelnotitie","updated_at":"2026-05-29T21:02:33.311Z"} +{"cache_key":"e6f48f62b167833335d714cc2380e3b71081a01e7888678832b137bde4f4a747","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/nl.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"nl","translated":"Doel","updated_at":"2026-05-29T21:02:33.311Z"} diff --git a/ui/src/i18n/.i18n/pl.meta.json b/ui/src/i18n/.i18n/pl.meta.json index 0fd50a7cb245..b4f9b2f19b98 100644 --- a/ui/src/i18n/.i18n/pl.meta.json +++ b/ui/src/i18n/.i18n/pl.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:14.758Z", + "generatedAt": "2026-05-29T21:02:00.415Z", "locale": "pl", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/pl.tm.jsonl b/ui/src/i18n/.i18n/pl.tm.jsonl new file mode 100644 index 000000000000..06311e73af15 --- /dev/null +++ b/ui/src/i18n/.i18n/pl.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"6c2c3123ea0674e55540119ca248b61ae9e719eb05a4140cda4be98d621b39e2","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"pl","translated":"Notatka dotycząca celu","updated_at":"2026-05-29T21:02:00.343Z"} +{"cache_key":"773fde7f04e9c87f69cc58984950611863dcac306cfbb15353f410e900533db6","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/pl.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"pl","translated":"Cel","updated_at":"2026-05-29T21:02:00.339Z"} diff --git a/ui/src/i18n/.i18n/pt-BR.meta.json b/ui/src/i18n/.i18n/pt-BR.meta.json index 1deb46165209..67f63f71b4cc 100644 --- a/ui/src/i18n/.i18n/pt-BR.meta.json +++ b/ui/src/i18n/.i18n/pt-BR.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:09:56.842Z", + "generatedAt": "2026-05-29T20:59:56.115Z", "locale": "pt-BR", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/pt-BR.tm.jsonl b/ui/src/i18n/.i18n/pt-BR.tm.jsonl new file mode 100644 index 000000000000..5ec89b701c22 --- /dev/null +++ b/ui/src/i18n/.i18n/pt-BR.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"0ec17d42d507c693995aa202c0aa2c38d62fb7aa0c0663165a00896f206b352d","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"pt-BR","translated":"Objetivo","updated_at":"2026-05-29T20:59:56.109Z"} +{"cache_key":"3d4dcc4505a4934b851fcc18f8b4c646a4f02c41d5117c454c501a37f3004697","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/pt-BR.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"pt-BR","translated":"Nota do objetivo","updated_at":"2026-05-29T20:59:56.109Z"} diff --git a/ui/src/i18n/.i18n/th.meta.json b/ui/src/i18n/.i18n/th.meta.json index 2ad70994324c..1c5511af2b12 100644 --- a/ui/src/i18n/.i18n/th.meta.json +++ b/ui/src/i18n/.i18n/th.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:16.172Z", + "generatedAt": "2026-05-29T21:02:14.037Z", "locale": "th", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/th.tm.jsonl b/ui/src/i18n/.i18n/th.tm.jsonl new file mode 100644 index 000000000000..78d23a9db067 --- /dev/null +++ b/ui/src/i18n/.i18n/th.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"6d49f61e8daf29818cae027ae36136a2ebff9dc4e819e22d841c22f70ffae4cf","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"th","translated":"เป้าหมาย","updated_at":"2026-05-29T21:02:14.030Z"} +{"cache_key":"ea705a9b3cb50a40d6d20d46fb239b99b37ae3745afebcef9150ae0922120b9f","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/th.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"th","translated":"หมายเหตุเป้าหมาย","updated_at":"2026-05-29T21:02:14.030Z"} diff --git a/ui/src/i18n/.i18n/tr.meta.json b/ui/src/i18n/.i18n/tr.meta.json index b76157c9de2c..abe88cac9de1 100644 --- a/ui/src/i18n/.i18n/tr.meta.json +++ b/ui/src/i18n/.i18n/tr.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:10.102Z", + "generatedAt": "2026-05-29T21:01:26.035Z", "locale": "tr", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/tr.tm.jsonl b/ui/src/i18n/.i18n/tr.tm.jsonl new file mode 100644 index 000000000000..7b51240eeff4 --- /dev/null +++ b/ui/src/i18n/.i18n/tr.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"2425436cbd6df1e63399e29ead2cc39b64f74162add08ff66575a408f31b6868","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"tr","translated":"Hedef notu","updated_at":"2026-05-29T21:01:25.865Z"} +{"cache_key":"89dc18d52451cd19d966cefb92e113df76f096c54ef2c6c44a745639484261be","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/tr.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"tr","translated":"Hedef","updated_at":"2026-05-29T21:01:25.865Z"} diff --git a/ui/src/i18n/.i18n/uk.meta.json b/ui/src/i18n/.i18n/uk.meta.json index 1ef9b37c9297..b53a797b5385 100644 --- a/ui/src/i18n/.i18n/uk.meta.json +++ b/ui/src/i18n/.i18n/uk.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:11.525Z", + "generatedAt": "2026-05-29T21:01:33.693Z", "locale": "uk", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/uk.tm.jsonl b/ui/src/i18n/.i18n/uk.tm.jsonl new file mode 100644 index 000000000000..bbbe3bbdeb4f --- /dev/null +++ b/ui/src/i18n/.i18n/uk.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"10837b29e8b086f86bfe06bb6fe52ff30536ac329d213f4fd6efddf12ac6c18d","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"uk","translated":"Примітка до мети","updated_at":"2026-05-29T21:01:33.548Z"} +{"cache_key":"a7d851a926019e2bd61845a835cdb17a9a048573abc8e000276b4c4f79fe979d","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/uk.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"uk","translated":"Мета","updated_at":"2026-05-29T21:01:33.548Z"} diff --git a/ui/src/i18n/.i18n/vi.meta.json b/ui/src/i18n/.i18n/vi.meta.json index ab431ede26be..32e0ac60f6bd 100644 --- a/ui/src/i18n/.i18n/vi.meta.json +++ b/ui/src/i18n/.i18n/vi.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:10:17.905Z", + "generatedAt": "2026-05-29T21:02:23.397Z", "locale": "vi", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/vi.tm.jsonl b/ui/src/i18n/.i18n/vi.tm.jsonl new file mode 100644 index 000000000000..0291995e1f50 --- /dev/null +++ b/ui/src/i18n/.i18n/vi.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"37e1b972340d8c2b5d14328166f22dff7683c48e7e618680b94cf4a5846e3395","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"vi","translated":"Ghi chú mục tiêu","updated_at":"2026-05-29T21:02:23.226Z"} +{"cache_key":"687bcca75327bc0dfd9262a5ad1ae85b09522d2ad3e1b408819c9c6ac632aeab","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/vi.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"vi","translated":"Mục tiêu","updated_at":"2026-05-29T21:02:23.226Z"} diff --git a/ui/src/i18n/.i18n/zh-CN.meta.json b/ui/src/i18n/.i18n/zh-CN.meta.json index 80e162831df1..4bc6bcb41f81 100644 --- a/ui/src/i18n/.i18n/zh-CN.meta.json +++ b/ui/src/i18n/.i18n/zh-CN.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:09:54.364Z", + "generatedAt": "2026-05-29T20:59:45.228Z", "locale": "zh-CN", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/zh-CN.tm.jsonl b/ui/src/i18n/.i18n/zh-CN.tm.jsonl new file mode 100644 index 000000000000..8f662a24405b --- /dev/null +++ b/ui/src/i18n/.i18n/zh-CN.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"09ed15bb12e7e25d15337bb2d8b7e301d3838eea96f0fdc749c73cbb6e734b1f","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"zh-CN","translated":"目标","updated_at":"2026-05-29T20:59:45.212Z"} +{"cache_key":"a22243320fa56f3a951b9a6a9a033efaee999643c0de514174713dbc0d6983b9","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/zh-CN.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"zh-CN","translated":"目标备注","updated_at":"2026-05-29T20:59:45.213Z"} diff --git a/ui/src/i18n/.i18n/zh-TW.meta.json b/ui/src/i18n/.i18n/zh-TW.meta.json index 077cc32290aa..afda0f9d71d0 100644 --- a/ui/src/i18n/.i18n/zh-TW.meta.json +++ b/ui/src/i18n/.i18n/zh-TW.meta.json @@ -1,11 +1,11 @@ { "fallbackKeys": [], - "generatedAt": "2026-05-29T18:09:55.672Z", + "generatedAt": "2026-05-29T20:59:52.034Z", "locale": "zh-TW", "model": "gpt-5.5", "provider": "openai", - "sourceHash": "1ddd9306566b37255394133ec48e05dfe9dd502fd57a34d3c9c96152331730e1", - "totalKeys": 1269, - "translatedKeys": 1269, + "sourceHash": "d51c5347e718c0fbe7353fccf82cefc0ef09b95b25acbc840a2f19b0c17b9296", + "totalKeys": 1271, + "translatedKeys": 1271, "workflow": 1 } diff --git a/ui/src/i18n/.i18n/zh-TW.tm.jsonl b/ui/src/i18n/.i18n/zh-TW.tm.jsonl new file mode 100644 index 000000000000..b711dbe222cb --- /dev/null +++ b/ui/src/i18n/.i18n/zh-TW.tm.jsonl @@ -0,0 +1,2 @@ +{"cache_key":"9979d886403e24df60997801e043da82148173019f9df8141fce453200283ac0","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goalNote","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Goal note","text_hash":"1afb7855a394ef7078728de1c804d6b995413db4eafe7d74190076cb9ed2c9f5","tgt_lang":"zh-TW","translated":"目標備註","updated_at":"2026-05-29T20:59:51.845Z"} +{"cache_key":"d4a6c06bfdfedcffd1b6e7ad155ea4138c82ffa07146a06a5747b8b69310a82d","model":"gpt-5.5","provider":"openai","segment_id":"sessionsView.goal","source_path":"ui/src/i18n/locales/zh-TW.ts","src_lang":"en","text":"Goal","text_hash":"cdbf6975e8a35b0d03558be6822dfae166482c24fb86b0433f60e8167f5c91e4","tgt_lang":"zh-TW","translated":"目標","updated_at":"2026-05-29T20:59:51.845Z"} diff --git a/ui/src/i18n/locales/ar.ts b/ui/src/i18n/locales/ar.ts index 5fcd781208ca..fe9cbc2fda07 100644 --- a/ui/src/i18n/locales/ar.ts +++ b/ui/src/i18n/locales/ar.ts @@ -184,6 +184,8 @@ export const ar: TranslationMap = { updated: "تم التحديث", tokens: "الرموز", compaction: "الضغط", + goal: "الهدف", + goalNote: "ملاحظة الهدف", thinking: "التفكير", fast: "سريع", verbose: "مطوّل", diff --git a/ui/src/i18n/locales/de.ts b/ui/src/i18n/locales/de.ts index d2a05c694ddf..eed074a9081e 100644 --- a/ui/src/i18n/locales/de.ts +++ b/ui/src/i18n/locales/de.ts @@ -188,6 +188,8 @@ export const de: TranslationMap = { updated: "Aktualisiert", tokens: "Tokens", compaction: "Kompaktierung", + goal: "Ziel", + goalNote: "Zielnotiz", thinking: "Denken", fast: "Schnell", verbose: "Ausführlich", diff --git a/ui/src/i18n/locales/en.ts b/ui/src/i18n/locales/en.ts index b09caa6c398c..e4153b881394 100644 --- a/ui/src/i18n/locales/en.ts +++ b/ui/src/i18n/locales/en.ts @@ -183,6 +183,8 @@ export const en: TranslationMap = { updated: "Updated", tokens: "Tokens", compaction: "Compaction", + goal: "Goal", + goalNote: "Goal note", thinking: "Thinking", fast: "Fast", verbose: "Verbose", diff --git a/ui/src/i18n/locales/es.ts b/ui/src/i18n/locales/es.ts index 7849b4244bb4..59fe297ce421 100644 --- a/ui/src/i18n/locales/es.ts +++ b/ui/src/i18n/locales/es.ts @@ -185,6 +185,8 @@ export const es: TranslationMap = { updated: "Actualizado", tokens: "Tokens", compaction: "Compactación", + goal: "Objetivo", + goalNote: "Nota del objetivo", thinking: "Pensamiento", fast: "Rápido", verbose: "Detallado", diff --git a/ui/src/i18n/locales/fa.ts b/ui/src/i18n/locales/fa.ts index 1ba41cc7eb9e..2f3a1f96d69d 100644 --- a/ui/src/i18n/locales/fa.ts +++ b/ui/src/i18n/locales/fa.ts @@ -186,6 +186,8 @@ export const fa: TranslationMap = { updated: "به‌روزشده", tokens: "توکن‌ها", compaction: "فشرده‌سازی", + goal: "هدف", + goalNote: "یادداشت هدف", thinking: "تفکر", fast: "سریع", verbose: "پرگویی", diff --git a/ui/src/i18n/locales/fr.ts b/ui/src/i18n/locales/fr.ts index 093f2fcac87b..46604271da1b 100644 --- a/ui/src/i18n/locales/fr.ts +++ b/ui/src/i18n/locales/fr.ts @@ -187,6 +187,8 @@ export const fr: TranslationMap = { updated: "Mis à jour", tokens: "Jetons", compaction: "Compactage", + goal: "Objectif", + goalNote: "Note d’objectif", thinking: "Réflexion", fast: "Rapide", verbose: "Détaillé", diff --git a/ui/src/i18n/locales/id.ts b/ui/src/i18n/locales/id.ts index 9acab5db5fd4..c33cae09be4f 100644 --- a/ui/src/i18n/locales/id.ts +++ b/ui/src/i18n/locales/id.ts @@ -185,6 +185,8 @@ export const id: TranslationMap = { updated: "Diperbarui", tokens: "Token", compaction: "Pemadatan", + goal: "Tujuan", + goalNote: "Catatan tujuan", thinking: "Thinking", fast: "Cepat", verbose: "Verbose", diff --git a/ui/src/i18n/locales/it.ts b/ui/src/i18n/locales/it.ts index f8290ceee775..741a81a79350 100644 --- a/ui/src/i18n/locales/it.ts +++ b/ui/src/i18n/locales/it.ts @@ -185,6 +185,8 @@ export const it: TranslationMap = { updated: "Aggiornato", tokens: "Token", compaction: "Compattazione", + goal: "Obiettivo", + goalNote: "Nota sull'obiettivo", thinking: "Thinking", fast: "Veloce", verbose: "Dettagliato", diff --git a/ui/src/i18n/locales/ja-JP.ts b/ui/src/i18n/locales/ja-JP.ts index c20099e91461..0717049122ad 100644 --- a/ui/src/i18n/locales/ja-JP.ts +++ b/ui/src/i18n/locales/ja-JP.ts @@ -188,6 +188,8 @@ export const ja_JP: TranslationMap = { updated: "更新日時", tokens: "トークン", compaction: "圧縮", + goal: "目標", + goalNote: "目標メモ", thinking: "Thinking", fast: "高速", verbose: "詳細", diff --git a/ui/src/i18n/locales/ko.ts b/ui/src/i18n/locales/ko.ts index 10a9d2397e5f..41fe35a87d03 100644 --- a/ui/src/i18n/locales/ko.ts +++ b/ui/src/i18n/locales/ko.ts @@ -184,6 +184,8 @@ export const ko: TranslationMap = { updated: "업데이트됨", tokens: "토큰", compaction: "압축", + goal: "목표", + goalNote: "목표 메모", thinking: "생각 수준", fast: "빠름", verbose: "상세", diff --git a/ui/src/i18n/locales/nl.ts b/ui/src/i18n/locales/nl.ts index 5f5837a26d88..f99407e7a039 100644 --- a/ui/src/i18n/locales/nl.ts +++ b/ui/src/i18n/locales/nl.ts @@ -187,6 +187,8 @@ export const nl: TranslationMap = { updated: "Bijgewerkt", tokens: "Tokens", compaction: "Compactie", + goal: "Doel", + goalNote: "Doelnotitie", thinking: "Denken", fast: "Snel", verbose: "Uitgebreid", diff --git a/ui/src/i18n/locales/pl.ts b/ui/src/i18n/locales/pl.ts index 78fe00637715..c12d0195b4ab 100644 --- a/ui/src/i18n/locales/pl.ts +++ b/ui/src/i18n/locales/pl.ts @@ -186,6 +186,8 @@ export const pl: TranslationMap = { updated: "Zaktualizowano", tokens: "Tokeny", compaction: "Kompaktowanie", + goal: "Cel", + goalNote: "Notatka dotycząca celu", thinking: "Myślenie", fast: "Szybko", verbose: "Szczegółowo", diff --git a/ui/src/i18n/locales/pt-BR.ts b/ui/src/i18n/locales/pt-BR.ts index 98adb48129f9..8551808ac739 100644 --- a/ui/src/i18n/locales/pt-BR.ts +++ b/ui/src/i18n/locales/pt-BR.ts @@ -185,6 +185,8 @@ export const pt_BR: TranslationMap = { updated: "Atualizado", tokens: "Tokens", compaction: "Compactação", + goal: "Objetivo", + goalNote: "Nota do objetivo", thinking: "Pensamento", fast: "Rápido", verbose: "Detalhado", diff --git a/ui/src/i18n/locales/th.ts b/ui/src/i18n/locales/th.ts index 0c62db7f669c..47c30ff83222 100644 --- a/ui/src/i18n/locales/th.ts +++ b/ui/src/i18n/locales/th.ts @@ -183,6 +183,8 @@ export const th: TranslationMap = { updated: "อัปเดตแล้ว", tokens: "โทเค็น", compaction: "การบีบอัด", + goal: "เป้าหมาย", + goalNote: "หมายเหตุเป้าหมาย", thinking: "Thinking", fast: "เร็ว", verbose: "ละเอียด", diff --git a/ui/src/i18n/locales/tr.ts b/ui/src/i18n/locales/tr.ts index aa83974c5eb7..857927e0cc3d 100644 --- a/ui/src/i18n/locales/tr.ts +++ b/ui/src/i18n/locales/tr.ts @@ -187,6 +187,8 @@ export const tr: TranslationMap = { updated: "Güncellendi", tokens: "Tokenlar", compaction: "Sıkıştırma", + goal: "Hedef", + goalNote: "Hedef notu", thinking: "Düşünme", fast: "Hızlı", verbose: "Ayrıntılı", diff --git a/ui/src/i18n/locales/uk.ts b/ui/src/i18n/locales/uk.ts index 6d38cefdaa0d..80e65d6d3204 100644 --- a/ui/src/i18n/locales/uk.ts +++ b/ui/src/i18n/locales/uk.ts @@ -186,6 +186,8 @@ export const uk: TranslationMap = { updated: "Оновлено", tokens: "Токени", compaction: "Стиснення", + goal: "Мета", + goalNote: "Примітка до мети", thinking: "Обмірковування", fast: "Швидко", verbose: "Докладно", diff --git a/ui/src/i18n/locales/vi.ts b/ui/src/i18n/locales/vi.ts index 07606703a291..5b6a8f2ae1e8 100644 --- a/ui/src/i18n/locales/vi.ts +++ b/ui/src/i18n/locales/vi.ts @@ -185,6 +185,8 @@ export const vi: TranslationMap = { updated: "Đã cập nhật", tokens: "Token", compaction: "Nén", + goal: "Mục tiêu", + goalNote: "Ghi chú mục tiêu", thinking: "Suy nghĩ", fast: "Nhanh", verbose: "Chi tiết", diff --git a/ui/src/i18n/locales/zh-CN.ts b/ui/src/i18n/locales/zh-CN.ts index 503e707a12e9..2f7b96685b6f 100644 --- a/ui/src/i18n/locales/zh-CN.ts +++ b/ui/src/i18n/locales/zh-CN.ts @@ -183,6 +183,8 @@ export const zh_CN: TranslationMap = { updated: "已更新", tokens: "Token", compaction: "压缩", + goal: "目标", + goalNote: "目标备注", thinking: "思考", fast: "快速", verbose: "详细", diff --git a/ui/src/i18n/locales/zh-TW.ts b/ui/src/i18n/locales/zh-TW.ts index 43e363635039..b1481fae3c80 100644 --- a/ui/src/i18n/locales/zh-TW.ts +++ b/ui/src/i18n/locales/zh-TW.ts @@ -183,6 +183,8 @@ export const zh_TW: TranslationMap = { updated: "已更新", tokens: "Token", compaction: "壓縮", + goal: "目標", + goalNote: "目標備註", thinking: "思考", fast: "快速", verbose: "詳細", diff --git a/ui/src/ui/views/sessions.ts b/ui/src/ui/views/sessions.ts index 13c10f4b5c1f..ee8bb8bf7e56 100644 --- a/ui/src/ui/views/sessions.ts +++ b/ui/src/ui/views/sessions.ts @@ -434,9 +434,9 @@ function sessionDetailItems(params: { }; add(t("sessionsView.status"), row.status); if (row.goal) { - details.push({ label: "Goal", value: formatGoalDetail(row.goal) }); + details.push({ label: t("sessionsView.goal"), value: formatGoalDetail(row.goal) }); } - add("Goal note", row.goal?.lastStatusNote); + add(t("sessionsView.goalNote"), row.goal?.lastStatusNote); add(t("sessionsView.model"), row.model); add(t("sessionsView.provider"), row.modelProvider); add(t("sessionsView.runtime"), formatRuntimeMs(row.runtimeMs));