From c309be81fe0396748696bcdf64ac1209767af661 Mon Sep 17 00:00:00 2001 From: Cyrus Gray <144336577+graycyrus@users.noreply.github.com> Date: Tue, 21 Jul 2026 23:48:03 +0530 Subject: [PATCH] fix(flows): show plain-language step labels in the workflow proposal card (#5088) --- .../chat/WorkflowProposalCard.test.tsx | 78 ++++++++++++++++++- .../components/chat/WorkflowProposalCard.tsx | 73 +++++++++++++---- app/src/lib/i18n/ar.ts | 11 +++ app/src/lib/i18n/bn.ts | 11 +++ app/src/lib/i18n/de.ts | 11 +++ app/src/lib/i18n/en.ts | 14 ++++ app/src/lib/i18n/es.ts | 11 +++ app/src/lib/i18n/fr.ts | 11 +++ app/src/lib/i18n/hi.ts | 11 +++ app/src/lib/i18n/id.ts | 11 +++ app/src/lib/i18n/it.ts | 11 +++ app/src/lib/i18n/ko.ts | 11 +++ app/src/lib/i18n/pl.ts | 11 +++ app/src/lib/i18n/pt.ts | 11 +++ app/src/lib/i18n/ru.ts | 11 +++ app/src/lib/i18n/zh-CN.ts | 11 +++ 16 files changed, 290 insertions(+), 18 deletions(-) diff --git a/app/src/components/chat/WorkflowProposalCard.test.tsx b/app/src/components/chat/WorkflowProposalCard.test.tsx index 83f79fe6b..d29d98c0e 100644 --- a/app/src/components/chat/WorkflowProposalCard.test.tsx +++ b/app/src/components/chat/WorkflowProposalCard.test.tsx @@ -56,17 +56,89 @@ describe('WorkflowProposalCard', () => { mockNavigate.mockReset(); }); - it('renders the name, trigger, and steps with node-kind badges', () => { + it('renders the name, trigger, and steps with plain-language node-kind badges', () => { render(); expect(screen.getByText('Daily standup summary')).toBeInTheDocument(); expect(screen.getByText('schedule: 0 9 * * *')).toBeInTheDocument(); expect(screen.getByText('Summarize')).toBeInTheDocument(); expect(screen.getByText('Post to Slack')).toBeInTheDocument(); - expect(screen.getByText('agent')).toBeInTheDocument(); - expect(screen.getByText('tool_call')).toBeInTheDocument(); + // Badges show the friendly i18n key (useT is mocked to echo the key), + // never the raw snake_case wire `kind`. + expect(screen.getByText('chat.flowProposal.stepKind.agent')).toBeInTheDocument(); + expect(screen.getByText('chat.flowProposal.stepKind.toolCall')).toBeInTheDocument(); + expect(screen.queryByText('agent')).not.toBeInTheDocument(); + expect(screen.queryByText('tool_call')).not.toBeInTheDocument(); expect(screen.getAllByTestId('workflow-proposal-step-kind')).toHaveLength(2); }); + it('hides config_hint from the card even when present on the step', () => { + render(); + // `proposal()` sets a config_hint on the first step; the card must not + // surface it (it can leak internal identifiers like tool slugs or URLs). + expect(screen.queryByText("Summarize yesterday's messages")).not.toBeInTheDocument(); + }); + + it('falls back to a humanized label for an unrecognized step kind', () => { + render( + + ); + // Not in STEP_KIND_I18N_KEYS, so it must fall back to the pure + // capitalize + underscores-to-spaces helper rather than the raw kind. + expect(screen.getByText('Future thing')).toBeInTheDocument(); + expect(screen.queryByText('future_thing')).not.toBeInTheDocument(); + }); + + // `step.kind` is arbitrary wire data. A plain bracket index would resolve + // inherited Object members (e.g. `constructor` -> the Object function) and + // hand a non-string to t(), breaking the badge render. The own-property + // guard must send these through the humanized fallback instead. `constructor` + // and `toString` have no underscores, so the humanized label is just the + // capitalized kind. + it.each(['constructor', 'toString'])( + 'humanizes the inherited-property kind %s instead of resolving it on the prototype', + kind => { + render( + + ); + const expected = kind.charAt(0).toUpperCase() + kind.slice(1); + expect(screen.getByText(expected)).toBeInTheDocument(); + expect(screen.getByText('Edge-case step')).toBeInTheDocument(); + } + ); + + it('renders a __proto__ step kind without leaking an inherited property', () => { + render( + + ); + // The own-property guard treats __proto__ as unknown and humanizes it, so + // the row still renders (step name present) and the badge shows a real + // string. Assert the badge's exact (whitespace-normalized) content directly + // — not just the step name / absence of "function" — so a missing badge or + // an inherited-member leak like `[object Object]` would fail here too. + // `__proto__` humanizes (underscores -> spaces, first char already a space) + // to a lowercase "proto" badge. + expect(screen.getByText('Proto step')).toBeInTheDocument(); + expect(screen.getByTestId('workflow-proposal-step-kind')).toHaveTextContent(/^proto$/); + }); + it('has the expected root test id', () => { render(); expect(screen.getByTestId('workflow-proposal-card')).toBeInTheDocument(); diff --git a/app/src/components/chat/WorkflowProposalCard.tsx b/app/src/components/chat/WorkflowProposalCard.tsx index a5fd612e9..f3888baa8 100644 --- a/app/src/components/chat/WorkflowProposalCard.tsx +++ b/app/src/components/chat/WorkflowProposalCard.tsx @@ -16,6 +16,50 @@ import Button from '../ui/Button'; const log = debug('openhuman:chat:workflow-proposal-card'); +// Maps the wire `step.kind` (a `tinyflows` node type, snake_case, e.g. +// `tool_call`) to the i18n key for its plain-language badge label. Kinds not +// in this map (e.g. a future node type the frontend doesn't know about yet) +// fall back to `humanizeUnknownStepKind` below rather than showing the raw +// snake_case identifier to a non-technical user. +const STEP_KIND_I18N_KEYS: Record = { + agent: 'chat.flowProposal.stepKind.agent', + tool_call: 'chat.flowProposal.stepKind.toolCall', + http_request: 'chat.flowProposal.stepKind.httpRequest', + code: 'chat.flowProposal.stepKind.code', + condition: 'chat.flowProposal.stepKind.condition', + switch: 'chat.flowProposal.stepKind.switch', + merge: 'chat.flowProposal.stepKind.merge', + split_out: 'chat.flowProposal.stepKind.splitOut', + transform: 'chat.flowProposal.stepKind.transform', + output_parser: 'chat.flowProposal.stepKind.outputParser', + sub_workflow: 'chat.flowProposal.stepKind.subWorkflow', +}; + +/** + * Pure fallback for a `step.kind` the frontend doesn't recognize: capitalize + * the first letter and turn `_` into spaces (e.g. `future_thing` -> + * `Future thing`) so an unmapped kind still reads as plain language instead + * of a raw snake_case identifier. + */ +function humanizeUnknownStepKind(kind: string): string { + const spaced = kind.replace(/_/g, ' '); + return spaced.charAt(0).toUpperCase() + spaced.slice(1); +} + +/** + * Resolve the i18n key for a mapped `step.kind`, guarding against inherited + * Object properties. `step.kind` is arbitrary wire data, so a plain bracket + * index (`STEP_KIND_I18N_KEYS[step.kind]`) would resolve inherited members for + * values like `constructor` or `__proto__` — handing a function/object to + * `t()` and breaking the badge render. Only own keys count; anything else + * returns `undefined` so the caller falls back to `humanizeUnknownStepKind`. + */ +function stepKindI18nKey(kind: string): string | undefined { + return Object.prototype.hasOwnProperty.call(STEP_KIND_I18N_KEYS, kind) + ? STEP_KIND_I18N_KEYS[kind] + : undefined; +} + interface Props { threadId: string; proposal: WorkflowProposal; @@ -183,23 +227,22 @@ export const WorkflowProposalCard: React.FC = ({ threadId, proposal, onSa

{proposal.summary.steps.length > 0 ? (
    - {proposal.summary.steps.map((step, i) => ( -
  1. - - {step.kind} - - {step.name} - {step.config_hint ? ( + {proposal.summary.steps.map((step, i) => { + const kindI18nKey = stepKindI18nKey(step.kind); + const kindLabel = kindI18nKey + ? t(kindI18nKey) + : humanizeUnknownStepKind(step.kind); + return ( +
  2. - {step.config_hint} + data-testid="workflow-proposal-step-kind" + className="mr-1.5 inline-block rounded-full bg-ocean-100 px-1.5 py-0.5 text-[10px] font-medium text-ocean-700 dark:bg-ocean-500/15 dark:text-ocean-300"> + {kindLabel} - ) : null} -
  3. - ))} + {step.name} + + ); + })}
) : (

{t('chat.flowProposal.noSteps')}

diff --git a/app/src/lib/i18n/ar.ts b/app/src/lib/i18n/ar.ts index 145b79cbf..33b2e136d 100644 --- a/app/src/lib/i18n/ar.ts +++ b/app/src/lib/i18n/ar.ts @@ -3415,6 +3415,17 @@ const messages: TranslationMap = { 'chat.flowProposal.error': 'تعذّر حفظ سير العمل. حاول مرة أخرى.', 'chat.flowProposal.enableError': 'تم حفظ سير العمل، لكن تعذّر تفعيله. حاول مرة أخرى، أو فعّله من صفحة سير العمل.', + 'chat.flowProposal.stepKind.agent': 'وكيل', + 'chat.flowProposal.stepKind.toolCall': 'إجراء', + 'chat.flowProposal.stepKind.httpRequest': 'طلب ويب', + 'chat.flowProposal.stepKind.code': 'تشغيل الكود', + 'chat.flowProposal.stepKind.condition': 'شرط', + 'chat.flowProposal.stepKind.switch': 'تبديل', + 'chat.flowProposal.stepKind.merge': 'دمج', + 'chat.flowProposal.stepKind.splitOut': 'تقسيم', + 'chat.flowProposal.stepKind.transform': 'تحويل', + 'chat.flowProposal.stepKind.outputParser': 'تحليل الإخراج', + 'chat.flowProposal.stepKind.subWorkflow': 'مسار عمل فرعي', 'channels.authMode.managed_dm': 'قم بتسجيل الدخول باستخدام OpenHuman', 'channels.authMode.oauth': 'OAuth تسجيل الدخول', 'channels.authMode.bot_token': 'استخدم رمز الروبوت الخاص بك', diff --git a/app/src/lib/i18n/bn.ts b/app/src/lib/i18n/bn.ts index 62f87ff14..917a5e74c 100644 --- a/app/src/lib/i18n/bn.ts +++ b/app/src/lib/i18n/bn.ts @@ -3494,6 +3494,17 @@ const messages: TranslationMap = { 'chat.flowProposal.error': 'ওয়ার্কফ্লো সংরক্ষণ করা যায়নি। আবার চেষ্টা করুন।', 'chat.flowProposal.enableError': 'ওয়ার্কফ্লো সংরক্ষিত হয়েছে, কিন্তু সক্ষম করা যায়নি। আবার চেষ্টা করুন, বা Workflows পৃষ্ঠা থেকে সক্ষম করুন।', + 'chat.flowProposal.stepKind.agent': 'এজেন্ট', + 'chat.flowProposal.stepKind.toolCall': 'কার্যক্রম', + 'chat.flowProposal.stepKind.httpRequest': 'ওয়েব অনুরোধ', + 'chat.flowProposal.stepKind.code': 'কোড চালান', + 'chat.flowProposal.stepKind.condition': 'শর্ত', + 'chat.flowProposal.stepKind.switch': 'সুইচ', + 'chat.flowProposal.stepKind.merge': 'একত্রিত করুন', + 'chat.flowProposal.stepKind.splitOut': 'বিভক্ত করুন', + 'chat.flowProposal.stepKind.transform': 'রূপান্তর করুন', + 'chat.flowProposal.stepKind.outputParser': 'আউটপুট পার্স করুন', + 'chat.flowProposal.stepKind.subWorkflow': 'সাব-ওয়ার্কফ্লো', 'channels.authMode.managed_dm': 'OpenHuman দিয়ে লগইন করুন', 'channels.authMode.oauth': 'OAuth সাইন-ইন করুন', 'channels.authMode.bot_token': 'আপনার নিজের বট টোকেন ব্যবহার করুন', diff --git a/app/src/lib/i18n/de.ts b/app/src/lib/i18n/de.ts index 630b63ddf..aedf03a3c 100644 --- a/app/src/lib/i18n/de.ts +++ b/app/src/lib/i18n/de.ts @@ -3596,6 +3596,17 @@ const messages: TranslationMap = { 'Der Workflow konnte nicht gespeichert werden. Bitte versuchen Sie es erneut.', 'chat.flowProposal.enableError': 'Workflow gespeichert, konnte aber nicht aktiviert werden. Versuchen Sie es erneut oder aktivieren Sie ihn auf der Workflows-Seite.', + 'chat.flowProposal.stepKind.agent': 'Agent', + 'chat.flowProposal.stepKind.toolCall': 'Aktion', + 'chat.flowProposal.stepKind.httpRequest': 'Webanfrage', + 'chat.flowProposal.stepKind.code': 'Code ausführen', + 'chat.flowProposal.stepKind.condition': 'Bedingung', + 'chat.flowProposal.stepKind.switch': 'Weiche', + 'chat.flowProposal.stepKind.merge': 'Zusammenführen', + 'chat.flowProposal.stepKind.splitOut': 'Aufteilen', + 'chat.flowProposal.stepKind.transform': 'Transformieren', + 'chat.flowProposal.stepKind.outputParser': 'Ausgabe auswerten', + 'chat.flowProposal.stepKind.subWorkflow': 'Unter-Workflow', 'channels.authMode.managed_dm': 'Mit OpenHuman anmelden', 'channels.authMode.oauth': 'OAuth-Anmeldung', 'channels.authMode.bot_token': 'Eigenen Bot-Token verwenden', diff --git a/app/src/lib/i18n/en.ts b/app/src/lib/i18n/en.ts index 036908c71..32241d06c 100644 --- a/app/src/lib/i18n/en.ts +++ b/app/src/lib/i18n/en.ts @@ -3899,6 +3899,20 @@ const en: TranslationMap = { 'chat.flowProposal.error': 'Could not save the workflow. Please try again.', 'chat.flowProposal.enableError': 'Workflow saved, but could not enable it. Try again, or enable it from the Workflows page.', + // Plain-language labels for each `tinyflows` node kind, shown as the badge + // next to each step in the proposal card's step list. Keep names short: + // they render as small pill badges. + 'chat.flowProposal.stepKind.agent': 'Agent', + 'chat.flowProposal.stepKind.toolCall': 'Action', + 'chat.flowProposal.stepKind.httpRequest': 'Web request', + 'chat.flowProposal.stepKind.code': 'Run code', + 'chat.flowProposal.stepKind.condition': 'Condition', + 'chat.flowProposal.stepKind.switch': 'Switch', + 'chat.flowProposal.stepKind.merge': 'Merge', + 'chat.flowProposal.stepKind.splitOut': 'Split', + 'chat.flowProposal.stepKind.transform': 'Transform', + 'chat.flowProposal.stepKind.outputParser': 'Parse output', + 'chat.flowProposal.stepKind.subWorkflow': 'Sub-workflow', // Auth mode labels 'channels.authMode.managed_dm': 'Login with OpenHuman', diff --git a/app/src/lib/i18n/es.ts b/app/src/lib/i18n/es.ts index 7254c56c3..8da92e799 100644 --- a/app/src/lib/i18n/es.ts +++ b/app/src/lib/i18n/es.ts @@ -3558,6 +3558,17 @@ const messages: TranslationMap = { 'chat.flowProposal.error': 'No se pudo guardar el flujo de trabajo. Inténtalo de nuevo.', 'chat.flowProposal.enableError': 'Flujo de trabajo guardado, pero no se pudo activar. Inténtalo de nuevo o actívalo desde la página de Workflows.', + 'chat.flowProposal.stepKind.agent': 'Agente', + 'chat.flowProposal.stepKind.toolCall': 'Acción', + 'chat.flowProposal.stepKind.httpRequest': 'Solicitud web', + 'chat.flowProposal.stepKind.code': 'Ejecutar código', + 'chat.flowProposal.stepKind.condition': 'Condición', + 'chat.flowProposal.stepKind.switch': 'Selector', + 'chat.flowProposal.stepKind.merge': 'Combinar', + 'chat.flowProposal.stepKind.splitOut': 'Dividir', + 'chat.flowProposal.stepKind.transform': 'Transformar', + 'chat.flowProposal.stepKind.outputParser': 'Interpretar resultado', + 'chat.flowProposal.stepKind.subWorkflow': 'Subflujo de trabajo', 'channels.authMode.managed_dm': 'Iniciar sesión con OpenHuman', 'channels.authMode.oauth': 'OAuth Iniciar sesión', 'channels.authMode.bot_token': 'Utilice su propio token de bot', diff --git a/app/src/lib/i18n/fr.ts b/app/src/lib/i18n/fr.ts index 41e7d09a0..8ce9af17f 100644 --- a/app/src/lib/i18n/fr.ts +++ b/app/src/lib/i18n/fr.ts @@ -3581,6 +3581,17 @@ const messages: TranslationMap = { 'chat.flowProposal.error': "Impossible d'enregistrer le workflow. Veuillez réessayer.", 'chat.flowProposal.enableError': "Workflow enregistré, mais impossible de l'activer. Réessayez, ou activez-le depuis la page Workflows.", + 'chat.flowProposal.stepKind.agent': 'Agent', + 'chat.flowProposal.stepKind.toolCall': 'Action', + 'chat.flowProposal.stepKind.httpRequest': 'Requête web', + 'chat.flowProposal.stepKind.code': 'Exécuter du code', + 'chat.flowProposal.stepKind.condition': 'Condition', + 'chat.flowProposal.stepKind.switch': 'Sélecteur', + 'chat.flowProposal.stepKind.merge': 'Fusionner', + 'chat.flowProposal.stepKind.splitOut': 'Diviser', + 'chat.flowProposal.stepKind.transform': 'Transformer', + 'chat.flowProposal.stepKind.outputParser': 'Analyser le résultat', + 'chat.flowProposal.stepKind.subWorkflow': 'Sous-workflow', 'channels.authMode.managed_dm': 'Connectez-vous avec OpenHuman', 'channels.authMode.oauth': 'OAuth Connectez-vous', 'channels.authMode.bot_token': 'Utiliser votre propre jeton de robot', diff --git a/app/src/lib/i18n/hi.ts b/app/src/lib/i18n/hi.ts index 79138ea39..df6772c6f 100644 --- a/app/src/lib/i18n/hi.ts +++ b/app/src/lib/i18n/hi.ts @@ -3493,6 +3493,17 @@ const messages: TranslationMap = { 'chat.flowProposal.error': 'वर्कफ़्लो सहेजा नहीं जा सका। कृपया फिर से प्रयास करें।', 'chat.flowProposal.enableError': 'वर्कफ़्लो सहेजा गया, लेकिन सक्षम नहीं किया जा सका। फिर से प्रयास करें, या Workflows पेज से इसे सक्षम करें।', + 'chat.flowProposal.stepKind.agent': 'एजेंट', + 'chat.flowProposal.stepKind.toolCall': 'कार्रवाई', + 'chat.flowProposal.stepKind.httpRequest': 'वेब अनुरोध', + 'chat.flowProposal.stepKind.code': 'कोड चलाएं', + 'chat.flowProposal.stepKind.condition': 'शर्त', + 'chat.flowProposal.stepKind.switch': 'स्विच', + 'chat.flowProposal.stepKind.merge': 'मर्ज करें', + 'chat.flowProposal.stepKind.splitOut': 'विभाजित करें', + 'chat.flowProposal.stepKind.transform': 'रूपांतरित करें', + 'chat.flowProposal.stepKind.outputParser': 'आउटपुट पार्स करें', + 'chat.flowProposal.stepKind.subWorkflow': 'सब-वर्कफ़्लो', 'channels.authMode.managed_dm': 'OpenHuman से लॉगिन करें', 'channels.authMode.oauth': 'OAuth साइन-इन करें', 'channels.authMode.bot_token': 'अपने स्वयं के बॉट टोकन का उपयोग करें', diff --git a/app/src/lib/i18n/id.ts b/app/src/lib/i18n/id.ts index 46b4fb742..d16a94f35 100644 --- a/app/src/lib/i18n/id.ts +++ b/app/src/lib/i18n/id.ts @@ -3510,6 +3510,17 @@ const messages: TranslationMap = { 'chat.flowProposal.error': 'Alur kerja tidak dapat disimpan. Silakan coba lagi.', 'chat.flowProposal.enableError': 'Alur kerja disimpan, tetapi tidak dapat diaktifkan. Coba lagi, atau aktifkan dari halaman Workflows.', + 'chat.flowProposal.stepKind.agent': 'Agen', + 'chat.flowProposal.stepKind.toolCall': 'Tindakan', + 'chat.flowProposal.stepKind.httpRequest': 'Permintaan web', + 'chat.flowProposal.stepKind.code': 'Jalankan kode', + 'chat.flowProposal.stepKind.condition': 'Kondisi', + 'chat.flowProposal.stepKind.switch': 'Pengalih', + 'chat.flowProposal.stepKind.merge': 'Gabungkan', + 'chat.flowProposal.stepKind.splitOut': 'Pisahkan', + 'chat.flowProposal.stepKind.transform': 'Transformasikan', + 'chat.flowProposal.stepKind.outputParser': 'Uraikan output', + 'chat.flowProposal.stepKind.subWorkflow': 'Sub-alur kerja', 'channels.authMode.managed_dm': 'Masuk dengan OpenHuman', 'channels.authMode.oauth': 'OAuth Masuk', 'channels.authMode.bot_token': 'Gunakan Token Bot Anda sendiri', diff --git a/app/src/lib/i18n/it.ts b/app/src/lib/i18n/it.ts index 9a86d5e14..9196f50b3 100644 --- a/app/src/lib/i18n/it.ts +++ b/app/src/lib/i18n/it.ts @@ -3557,6 +3557,17 @@ const messages: TranslationMap = { 'chat.flowProposal.error': 'Impossibile salvare il workflow. Riprova.', 'chat.flowProposal.enableError': 'Workflow salvato, ma non è stato possibile attivarlo. Riprova, oppure attivalo dalla pagina Workflows.', + 'chat.flowProposal.stepKind.agent': 'Agente', + 'chat.flowProposal.stepKind.toolCall': 'Azione', + 'chat.flowProposal.stepKind.httpRequest': 'Richiesta web', + 'chat.flowProposal.stepKind.code': 'Esegui codice', + 'chat.flowProposal.stepKind.condition': 'Condizione', + 'chat.flowProposal.stepKind.switch': 'Selettore', + 'chat.flowProposal.stepKind.merge': 'Unisci', + 'chat.flowProposal.stepKind.splitOut': 'Dividi', + 'chat.flowProposal.stepKind.transform': 'Trasforma', + 'chat.flowProposal.stepKind.outputParser': 'Analizza risultato', + 'chat.flowProposal.stepKind.subWorkflow': 'Sotto-workflow', 'channels.authMode.managed_dm': 'Accedi con OpenHuman', 'channels.authMode.oauth': 'OAuth Accedi', 'channels.authMode.bot_token': 'Usa il tuo token Bot', diff --git a/app/src/lib/i18n/ko.ts b/app/src/lib/i18n/ko.ts index 1620ecf3d..7af3e8c14 100644 --- a/app/src/lib/i18n/ko.ts +++ b/app/src/lib/i18n/ko.ts @@ -3458,6 +3458,17 @@ const messages: TranslationMap = { 'chat.flowProposal.error': '워크플로를 저장할 수 없습니다. 다시 시도하세요.', 'chat.flowProposal.enableError': '워크플로는 저장되었지만 활성화할 수 없습니다. 다시 시도하거나 Workflows 페이지에서 활성화하세요.', + 'chat.flowProposal.stepKind.agent': '에이전트', + 'chat.flowProposal.stepKind.toolCall': '작업', + 'chat.flowProposal.stepKind.httpRequest': '웹 요청', + 'chat.flowProposal.stepKind.code': '코드 실행', + 'chat.flowProposal.stepKind.condition': '조건', + 'chat.flowProposal.stepKind.switch': '스위치', + 'chat.flowProposal.stepKind.merge': '병합', + 'chat.flowProposal.stepKind.splitOut': '분할', + 'chat.flowProposal.stepKind.transform': '변환', + 'chat.flowProposal.stepKind.outputParser': '출력 파싱', + 'chat.flowProposal.stepKind.subWorkflow': '하위 워크플로', 'channels.authMode.managed_dm': 'OpenHuman로 로그인', 'channels.authMode.oauth': 'OAuth 로그인', 'channels.authMode.bot_token': '자체 봇 토큰 사용', diff --git a/app/src/lib/i18n/pl.ts b/app/src/lib/i18n/pl.ts index 4a5dda9f2..c67e7cea0 100644 --- a/app/src/lib/i18n/pl.ts +++ b/app/src/lib/i18n/pl.ts @@ -3538,6 +3538,17 @@ const messages: TranslationMap = { 'chat.flowProposal.error': 'Nie udało się zapisać przepływu pracy. Spróbuj ponownie.', 'chat.flowProposal.enableError': 'Przepływ pracy zapisany, ale nie udało się go włączyć. Spróbuj ponownie lub włącz go na stronie Workflows.', + 'chat.flowProposal.stepKind.agent': 'Agent', + 'chat.flowProposal.stepKind.toolCall': 'Akcja', + 'chat.flowProposal.stepKind.httpRequest': 'Żądanie sieciowe', + 'chat.flowProposal.stepKind.code': 'Uruchom kod', + 'chat.flowProposal.stepKind.condition': 'Warunek', + 'chat.flowProposal.stepKind.switch': 'Przełącznik', + 'chat.flowProposal.stepKind.merge': 'Scal', + 'chat.flowProposal.stepKind.splitOut': 'Podziel', + 'chat.flowProposal.stepKind.transform': 'Przekształć', + 'chat.flowProposal.stepKind.outputParser': 'Przetwórz wynik', + 'chat.flowProposal.stepKind.subWorkflow': 'Podprzepływ pracy', 'channels.authMode.managed_dm': 'Zaloguj się z OpenHuman', 'channels.authMode.oauth': 'Logowanie OAuth', 'channels.authMode.bot_token': 'Użyj własnego tokena bota', diff --git a/app/src/lib/i18n/pt.ts b/app/src/lib/i18n/pt.ts index 712be4fbb..7c7ebeeeb 100644 --- a/app/src/lib/i18n/pt.ts +++ b/app/src/lib/i18n/pt.ts @@ -3550,6 +3550,17 @@ const messages: TranslationMap = { 'chat.flowProposal.error': 'Não foi possível salvar o fluxo de trabalho. Tente novamente.', 'chat.flowProposal.enableError': 'Fluxo de trabalho salvo, mas não foi possível ativá-lo. Tente novamente ou ative-o na página Workflows.', + 'chat.flowProposal.stepKind.agent': 'Agente', + 'chat.flowProposal.stepKind.toolCall': 'Ação', + 'chat.flowProposal.stepKind.httpRequest': 'Pedido web', + 'chat.flowProposal.stepKind.code': 'Executar código', + 'chat.flowProposal.stepKind.condition': 'Condição', + 'chat.flowProposal.stepKind.switch': 'Seletor', + 'chat.flowProposal.stepKind.merge': 'Mesclar', + 'chat.flowProposal.stepKind.splitOut': 'Dividir', + 'chat.flowProposal.stepKind.transform': 'Transformar', + 'chat.flowProposal.stepKind.outputParser': 'Analisar resultado', + 'chat.flowProposal.stepKind.subWorkflow': 'Subfluxo de trabalho', 'channels.authMode.managed_dm': 'Faça login com OpenHuman', 'channels.authMode.oauth': 'OAuth Faça login', 'channels.authMode.bot_token': 'Use seu próprio token de bot', diff --git a/app/src/lib/i18n/ru.ts b/app/src/lib/i18n/ru.ts index 5bf1c48d9..9d382dee4 100644 --- a/app/src/lib/i18n/ru.ts +++ b/app/src/lib/i18n/ru.ts @@ -3522,6 +3522,17 @@ const messages: TranslationMap = { 'chat.flowProposal.error': 'Не удалось сохранить рабочий процесс. Попробуйте еще раз.', 'chat.flowProposal.enableError': 'Рабочий процесс сохранён, но не удалось его включить. Попробуйте ещё раз или включите его на странице Workflows.', + 'chat.flowProposal.stepKind.agent': 'Агент', + 'chat.flowProposal.stepKind.toolCall': 'Действие', + 'chat.flowProposal.stepKind.httpRequest': 'Веб-запрос', + 'chat.flowProposal.stepKind.code': 'Выполнить код', + 'chat.flowProposal.stepKind.condition': 'Условие', + 'chat.flowProposal.stepKind.switch': 'Переключатель', + 'chat.flowProposal.stepKind.merge': 'Объединить', + 'chat.flowProposal.stepKind.splitOut': 'Разделить', + 'chat.flowProposal.stepKind.transform': 'Преобразовать', + 'chat.flowProposal.stepKind.outputParser': 'Обработать вывод', + 'chat.flowProposal.stepKind.subWorkflow': 'Подпроцесс', 'channels.authMode.managed_dm': 'Войдите с помощью OpenHuman', 'channels.authMode.oauth': 'OAuth Вход в систему', 'channels.authMode.bot_token': 'Используйте свой собственный токен бота', diff --git a/app/src/lib/i18n/zh-CN.ts b/app/src/lib/i18n/zh-CN.ts index 4861f5a83..a7c7a1030 100644 --- a/app/src/lib/i18n/zh-CN.ts +++ b/app/src/lib/i18n/zh-CN.ts @@ -3313,6 +3313,17 @@ const messages: TranslationMap = { 'chat.flowProposal.dismiss': '忽略', 'chat.flowProposal.error': '无法保存该工作流。请重试。', 'chat.flowProposal.enableError': '工作流已保存,但无法启用。请重试,或在“工作流”页面手动启用。', + 'chat.flowProposal.stepKind.agent': '智能体', + 'chat.flowProposal.stepKind.toolCall': '操作', + 'chat.flowProposal.stepKind.httpRequest': '网络请求', + 'chat.flowProposal.stepKind.code': '运行代码', + 'chat.flowProposal.stepKind.condition': '条件', + 'chat.flowProposal.stepKind.switch': '分支选择', + 'chat.flowProposal.stepKind.merge': '合并', + 'chat.flowProposal.stepKind.splitOut': '拆分', + 'chat.flowProposal.stepKind.transform': '转换', + 'chat.flowProposal.stepKind.outputParser': '解析输出', + 'chat.flowProposal.stepKind.subWorkflow': '子工作流', 'channels.authMode.managed_dm': '使用 OpenHuman 登录', 'channels.authMode.oauth': 'OAuth 登录', 'channels.authMode.bot_token': '使用你自己的 Bot Token',