mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-29 22:23:01 +00:00
feat(flows): frontend for the dedup node — palette, key config, i18n ×14 (#5264)
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Behavior tests for the `dedup` node config form (issue #5263). Covers the
|
||||
* single `key` field: it renders and emits a `config.key` patch as the
|
||||
* `=`-bindable expression is typed. `useT()` falls back to the bundled
|
||||
* English map with no provider mounted (same convention as the sibling
|
||||
* `memoryFields.test.tsx`).
|
||||
*/
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { DedupForm } from '../dedupFields';
|
||||
|
||||
function renderDedupForm(config: Record<string, unknown> = {}) {
|
||||
const onChange = vi.fn();
|
||||
render(<DedupForm config={config} onChange={onChange} />);
|
||||
return { onChange };
|
||||
}
|
||||
|
||||
describe('DedupForm', () => {
|
||||
it('renders the key field', () => {
|
||||
renderDedupForm();
|
||||
expect(screen.getByTestId('node-config-dedup-key')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('seeds the key field from the existing config', () => {
|
||||
renderDedupForm({ key: '=item.id' });
|
||||
expect(screen.getByTestId('node-config-dedup-key')).toHaveValue('=item.id');
|
||||
});
|
||||
|
||||
it('emits a key patch as the expression is typed', () => {
|
||||
const { onChange } = renderDedupForm();
|
||||
fireEvent.change(screen.getByTestId('node-config-dedup-key'), {
|
||||
target: { value: '=item.id' },
|
||||
});
|
||||
expect(onChange).toHaveBeenLastCalledWith({ key: '=item.id' });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* `dedup` node config form (issue #5263 — 14th tinyflows `NodeKind`). Skips
|
||||
* items already seen, keyed by a stable per-item `=`-expression evaluated
|
||||
* against each item (e.g. `=item.id`) — the engine tracks which keys have
|
||||
* already passed through this node and drops repeats.
|
||||
*
|
||||
* Field keys mirror what the engine actually reads at runtime:
|
||||
* - `key` — `=`-bindable, required. The only config field this node has.
|
||||
*/
|
||||
import { useT } from '../../../../lib/i18n/I18nContext';
|
||||
import { configString, ExpressionField } from './nodeConfigFields';
|
||||
import type { UpstreamExpressionOption } from './upstreamOptions';
|
||||
|
||||
/**
|
||||
* Deliberately narrower than `NodeConfigFormProps` (`nodeConfigForms.tsx`) —
|
||||
* this form needs no `connections` (dedup nodes don't use the credential
|
||||
* picker), so it isn't imported here just to keep the shape identical. A
|
||||
* component typed against this subset is still assignable into
|
||||
* `NODE_CONFIG_FORMS`'s `NodeConfigForm` slot (the fuller prop type has
|
||||
* every property this one requires).
|
||||
*/
|
||||
export interface DedupFormProps {
|
||||
config: Record<string, unknown>;
|
||||
onChange: (patch: Record<string, unknown>) => void;
|
||||
upstreamOptions?: UpstreamExpressionOption[];
|
||||
}
|
||||
|
||||
export function DedupForm({ config, onChange, upstreamOptions }: DedupFormProps) {
|
||||
const { t } = useT();
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<ExpressionField
|
||||
label={t('flows.nodeConfig.dedup.keyLabel')}
|
||||
hint={t('flows.nodeConfig.dedup.keyHint')}
|
||||
value={configString(config, 'key')}
|
||||
onChange={v => onChange({ key: v })}
|
||||
placeholder="=item.id"
|
||||
upstreamOptions={upstreamOptions}
|
||||
testId="node-config-dedup-key"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
* - `trigger` → `trigger_kind` + kind-specific (`schedule`, `toolkit`/`trigger_slug`)
|
||||
* - `memory` → `operation` + operation-specific (`scope`/`query`/`flavour`/`key`/`value`/
|
||||
* `limit`/`min_score`), see `memoryFields.tsx`
|
||||
* - `dedup` → `key` (an `=`-bindable per-item id expression), see `dedupFields.tsx`
|
||||
*/
|
||||
import createDebug from 'debug';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -32,6 +33,7 @@ import {
|
||||
ComposioTriggerField,
|
||||
fetchActionSchema,
|
||||
} from './composioFields';
|
||||
import { DedupForm } from './dedupFields';
|
||||
import { MemoryForm } from './memoryFields';
|
||||
import { NATIVE_TOOL_PREFIX, NativeToolField } from './nativeToolFields';
|
||||
import {
|
||||
@@ -496,4 +498,5 @@ export const NODE_CONFIG_FORMS: Partial<Record<NodeKind, NodeConfigForm>> = {
|
||||
transform: TransformForm,
|
||||
code: CodeForm,
|
||||
memory: MemoryForm,
|
||||
dedup: DedupForm,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Per-kind visual metadata for the 13 tinyflows `NodeKind`s, shared by the
|
||||
* Per-kind visual metadata for the 14 tinyflows `NodeKind`s, shared by the
|
||||
* canvas node renderer (`FlowNodeComponent`) and the editable canvas's node
|
||||
* palette (`NodePalette`). Kept dependency-free (no React) so both a rendered
|
||||
* `<Handle>`-bearing card and a plain palette button can pull the same
|
||||
@@ -8,7 +8,7 @@
|
||||
* Colors cycle through the four CSS-variable-backed semantic ramps
|
||||
* (primary/sage/amber/coral) that support Tailwind's `/opacity` modifiers in
|
||||
* this codebase (see `tailwind.config.js`) so light/dark theming comes for
|
||||
* free; with 13 kinds and 4 ramps some kinds share a color family — the emoji
|
||||
* free; with 14 kinds and 4 ramps some kinds share a color family — the emoji
|
||||
* + name remain the primary distinguishers.
|
||||
*/
|
||||
import type { NodeKind } from './types';
|
||||
@@ -29,12 +29,16 @@ interface NodeKindMeta {
|
||||
}
|
||||
|
||||
/**
|
||||
* The 13 `NodeKind`s in the order they should appear in the palette. Trigger
|
||||
* The 14 `NodeKind`s in the order they should appear in the palette. Trigger
|
||||
* leads (every graph needs exactly one); the rest follow the logical grouping
|
||||
* of the `tinyflows::model::NodeKind` enum. `memory` (issue #5226) is
|
||||
* appended last — the design doc (`08-memory-node.md`) sequences it as the
|
||||
* 13th kind deliberately, so it trails `sub_workflow` here too rather than
|
||||
* being interleaved with the other `actions`-group kinds.
|
||||
* appended after `sub_workflow` — the design doc (`08-memory-node.md`)
|
||||
* sequences it as the 13th kind deliberately, so it trails `sub_workflow`
|
||||
* here too rather than being interleaved with the other `actions`-group
|
||||
* kinds. `dedup` (issue #5263) is the 14th kind and is appended last in turn
|
||||
* — it renders in the `logic` group (alongside `condition`/`split_out`/
|
||||
* `merge`) regardless of its position here, since {@link PALETTE_ENTRIES_BY_GROUP}
|
||||
* filters by group rather than relying on interleaved array order.
|
||||
*/
|
||||
const NODE_KINDS: NodeKind[] = [
|
||||
'trigger',
|
||||
@@ -50,6 +54,7 @@ const NODE_KINDS: NodeKind[] = [
|
||||
'output_parser',
|
||||
'sub_workflow',
|
||||
'memory',
|
||||
'dedup',
|
||||
];
|
||||
|
||||
/** Per-kind emoji + border/chip color + palette group. See the module doc. */
|
||||
@@ -70,6 +75,10 @@ const NODE_KIND_META: Record<NodeKind, NodeKindMeta> = {
|
||||
split_out: { emoji: '📤', color: 'sage', group: 'logic' },
|
||||
transform: { emoji: '♻️', color: 'primary', group: 'logic' },
|
||||
output_parser: { emoji: '📋', color: 'amber', group: 'logic' },
|
||||
// Skips items already seen, keyed by a stable per-item `=`-expression — a
|
||||
// "logic" node like its neighbours (`condition`/`split_out`/`merge`): it
|
||||
// routes/filters the item stream rather than calling out or reading state.
|
||||
dedup: { emoji: '🪪', color: 'coral', group: 'logic' },
|
||||
};
|
||||
|
||||
/** Palette group render order. */
|
||||
|
||||
@@ -72,4 +72,9 @@ describe('describeNode', () => {
|
||||
);
|
||||
expect(describeNode('memory', { operation: 'search' })).toBe('Searches memory');
|
||||
});
|
||||
|
||||
it('describes dedup by its key expression, and falls back generically when unset', () => {
|
||||
expect(describeNode('dedup', { key: '=item.id' })).toBe('Skips items already seen by =item.id');
|
||||
expect(describeNode('dedup', {})).toBe('Skips items already processed');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -104,6 +104,12 @@ export function describeNode(
|
||||
// recall
|
||||
return `Recalls memory${scoped}`;
|
||||
}
|
||||
case 'dedup': {
|
||||
const key = str(config, 'key');
|
||||
return key
|
||||
? `Skips items already seen by ${truncate(key, 40)}`
|
||||
: 'Skips items already processed';
|
||||
}
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export interface Position {
|
||||
}
|
||||
|
||||
/**
|
||||
* The 13 node kinds `tinyflows` currently defines (`tinyflows::model::NodeKind`).
|
||||
* The 14 node kinds `tinyflows` currently defines (`tinyflows::model::NodeKind`).
|
||||
* Wire values are `snake_case` (`#[serde(rename_all = "snake_case")]`).
|
||||
*
|
||||
* `memory` (issue #5226) is the 13th kind — declarative, in-graph memory
|
||||
@@ -48,6 +48,11 @@ export interface Position {
|
||||
* (`nodeConfig/memoryFields.tsx`) reads/writes the known keys
|
||||
* (`operation`, `scope`, `query`, `flavour`, `key`, `value`, `limit`,
|
||||
* `min_score`) directly off that bag, same as `condition`/`switch`/etc.
|
||||
*
|
||||
* `dedup` (issue #5263) is the 14th kind — skips items already seen, keyed
|
||||
* by a stable per-item `=`-expression (e.g. `=item.id`). Same free-form
|
||||
* config bag pattern: its one field, `key`, is read/written directly by
|
||||
* `nodeConfig/dedupFields.tsx`.
|
||||
*/
|
||||
export type NodeKind =
|
||||
| 'trigger'
|
||||
@@ -62,7 +67,8 @@ export type NodeKind =
|
||||
| 'transform'
|
||||
| 'output_parser'
|
||||
| 'sub_workflow'
|
||||
| 'memory';
|
||||
| 'memory'
|
||||
| 'dedup';
|
||||
|
||||
/**
|
||||
* A named connection point on a node. Mirrors `tinyflows::model::Port`.
|
||||
|
||||
@@ -4093,6 +4093,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'محلل المخرجات',
|
||||
'flows.nodeKind.sub_workflow': 'سير عمل فرعي',
|
||||
'flows.nodeKind.memory': 'الذاكرة',
|
||||
'flows.nodeKind.dedup': 'إزالة التكرار',
|
||||
'flows.palette.title': 'العقد',
|
||||
'flows.palette.addNode': 'إضافة عقدة {kind}',
|
||||
'flows.editor.save': 'حفظ',
|
||||
@@ -4258,6 +4259,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'أقصى عدد من النتائج.',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'الحد الأدنى للنتيجة',
|
||||
'flows.nodeConfig.memory.minScoreHint': 'عتبة الصلة من 0 إلى 1.',
|
||||
'flows.nodeConfig.dedup.keyLabel': 'المفتاح',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'تعبير معرف ثابت لكل عنصر، مثل =item.id. يتم تخطي العناصر التي شوهد مفتاحها من قبل.',
|
||||
|
||||
'flows.enableApproval.title': 'هل تسمح لسير العمل هذا بالتنفيذ؟',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -4195,6 +4195,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'আউটপুট পার্সার',
|
||||
'flows.nodeKind.sub_workflow': 'সাব-ওয়ার্কফ্লো',
|
||||
'flows.nodeKind.memory': 'মেমরি',
|
||||
'flows.nodeKind.dedup': 'ডুপ্লিকেট অপসারণ',
|
||||
'flows.palette.title': 'নোড',
|
||||
'flows.palette.addNode': '{kind} নোড যোগ করুন',
|
||||
'flows.editor.save': 'সংরক্ষণ করুন',
|
||||
@@ -4365,6 +4366,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'সর্বোচ্চ ফলাফল সংখ্যা।',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'সর্বনিম্ন স্কোর',
|
||||
'flows.nodeConfig.memory.minScoreHint': '০ থেকে ১ পর্যন্ত প্রাসঙ্গিকতার থ্রেশহোল্ড।',
|
||||
'flows.nodeConfig.dedup.keyLabel': 'কী',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'প্রতিটি আইটেমের জন্য একটি স্থিতিশীল আইডি এক্সপ্রেশন, যেমন =item.id। যেসব আইটেমের কী আগে দেখা গেছে সেগুলো এড়িয়ে যাওয়া হয়।',
|
||||
|
||||
'flows.enableApproval.title': 'এই ওয়ার্কফ্লোকে কাজ করার অনুমতি দেবেন?',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -4313,6 +4313,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'Ausgabe-Parser',
|
||||
'flows.nodeKind.sub_workflow': 'Unter-Workflow',
|
||||
'flows.nodeKind.memory': 'Gedächtnis',
|
||||
'flows.nodeKind.dedup': 'Deduplizierung',
|
||||
'flows.palette.title': 'Knoten',
|
||||
'flows.palette.addNode': '{kind}-Knoten hinzufügen',
|
||||
'flows.editor.save': 'Speichern',
|
||||
@@ -4488,6 +4489,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'Maximale Anzahl an Ergebnissen.',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'Mindestbewertung',
|
||||
'flows.nodeConfig.memory.minScoreHint': 'Relevanzschwelle von 0 bis 1.',
|
||||
'flows.nodeConfig.dedup.keyLabel': 'Schlüssel',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'Ein stabiler Id-Ausdruck pro Element, z. B. =item.id. Elemente mit einem bereits gesehenen Schlüssel werden übersprungen.',
|
||||
|
||||
'flows.enableApproval.title': 'Darf dieser Workflow Aktionen ausführen?',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -4767,6 +4767,7 @@ const en: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'Output parser',
|
||||
'flows.nodeKind.sub_workflow': 'Sub-workflow',
|
||||
'flows.nodeKind.memory': 'Memory',
|
||||
'flows.nodeKind.dedup': 'Dedup',
|
||||
|
||||
// ── Editable Workflow Canvas (issue B5b.2 / Phase 3a): the node palette
|
||||
// and editor toolbar layered on top of the read-only canvas above.
|
||||
@@ -4950,6 +4951,10 @@ const en: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'Maximum number of results.',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'Minimum score',
|
||||
'flows.nodeConfig.memory.minScoreHint': 'Relevance threshold from 0 to 1.',
|
||||
// `dedup` node (issue #5263): skips items already seen by a stable per-item key.
|
||||
'flows.nodeConfig.dedup.keyLabel': 'Key',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'A stable per-item id expression, e.g. =item.id. Items with a key already seen are skipped.',
|
||||
|
||||
// Phase 4a "New workflow" chooser + Phase 4c templates gallery. The chooser
|
||||
// offers scratch / template / describe; the gallery lists the curated
|
||||
|
||||
@@ -4264,6 +4264,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'Analizador de salida',
|
||||
'flows.nodeKind.sub_workflow': 'Subflujo de trabajo',
|
||||
'flows.nodeKind.memory': 'Memoria',
|
||||
'flows.nodeKind.dedup': 'Deduplicación',
|
||||
'flows.palette.title': 'Nodos',
|
||||
'flows.palette.addNode': 'Añadir nodo {kind}',
|
||||
'flows.editor.save': 'Guardar',
|
||||
@@ -4438,6 +4439,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'Número máximo de resultados.',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'Puntuación mínima',
|
||||
'flows.nodeConfig.memory.minScoreHint': 'Umbral de relevancia de 0 a 1.',
|
||||
'flows.nodeConfig.dedup.keyLabel': 'Clave',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'Una expresión de id estable por elemento, p. ej. =item.id. Los elementos con una clave ya vista se omiten.',
|
||||
|
||||
'flows.enableApproval.title': '¿Permitir que este flujo de trabajo actúe?',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -4292,6 +4292,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'Analyseur de sortie',
|
||||
'flows.nodeKind.sub_workflow': 'Sous-workflow',
|
||||
'flows.nodeKind.memory': 'Mémoire',
|
||||
'flows.nodeKind.dedup': 'Déduplication',
|
||||
'flows.palette.title': 'Nœuds',
|
||||
'flows.palette.addNode': 'Ajouter un nœud {kind}',
|
||||
'flows.editor.save': 'Enregistrer',
|
||||
@@ -4468,6 +4469,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'Nombre maximal de résultats.',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'Score minimal',
|
||||
'flows.nodeConfig.memory.minScoreHint': 'Seuil de pertinence de 0 à 1.',
|
||||
'flows.nodeConfig.dedup.keyLabel': 'Clé',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
"Une expression d'identifiant stable par élément, ex. =item.id. Les éléments dont la clé a déjà été vue sont ignorés.",
|
||||
|
||||
'flows.enableApproval.title': 'Autoriser ce workflow à agir ?',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -4192,6 +4192,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'आउटपुट पार्सर',
|
||||
'flows.nodeKind.sub_workflow': 'सब-वर्कफ़्लो',
|
||||
'flows.nodeKind.memory': 'मेमोरी',
|
||||
'flows.nodeKind.dedup': 'डुप्लिकेट हटाएं',
|
||||
'flows.palette.title': 'नोड',
|
||||
'flows.palette.addNode': '{kind} नोड जोड़ें',
|
||||
'flows.editor.save': 'सहेजें',
|
||||
@@ -4362,6 +4363,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'अधिकतम परिणामों की संख्या।',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'न्यूनतम स्कोर',
|
||||
'flows.nodeConfig.memory.minScoreHint': '0 से 1 तक की प्रासंगिकता सीमा।',
|
||||
'flows.nodeConfig.dedup.keyLabel': 'कुंजी',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'प्रति आइटम एक स्थिर आईडी एक्सप्रेशन, जैसे =item.id। जिन आइटम की कुंजी पहले देखी जा चुकी है उन्हें छोड़ दिया जाता है।',
|
||||
|
||||
'flows.enableApproval.title': 'क्या इस वर्कफ़्लो को काम करने की अनुमति दें?',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -4208,6 +4208,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'Pengurai keluaran',
|
||||
'flows.nodeKind.sub_workflow': 'Sub-alur kerja',
|
||||
'flows.nodeKind.memory': 'Memori',
|
||||
'flows.nodeKind.dedup': 'Hapus duplikat',
|
||||
'flows.palette.title': 'Simpul',
|
||||
'flows.palette.addNode': 'Tambah simpul {kind}',
|
||||
'flows.editor.save': 'Simpan',
|
||||
@@ -4380,6 +4381,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'Jumlah maksimum hasil.',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'Skor minimum',
|
||||
'flows.nodeConfig.memory.minScoreHint': 'Ambang batas relevansi dari 0 hingga 1.',
|
||||
'flows.nodeConfig.dedup.keyLabel': 'Kunci',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'Ekspresi id stabil per item, mis. =item.id. Item dengan kunci yang sudah pernah dilihat akan dilewati.',
|
||||
|
||||
'flows.enableApproval.title': 'Izinkan alur kerja ini bertindak?',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -4260,6 +4260,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'Analizzatore di output',
|
||||
'flows.nodeKind.sub_workflow': 'Sotto-flusso di lavoro',
|
||||
'flows.nodeKind.memory': 'Memoria',
|
||||
'flows.nodeKind.dedup': 'Deduplicazione',
|
||||
'flows.palette.title': 'Nodi',
|
||||
'flows.palette.addNode': 'Aggiungi nodo {kind}',
|
||||
'flows.editor.save': 'Salva',
|
||||
@@ -4436,6 +4437,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'Numero massimo di risultati.',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'Punteggio minimo',
|
||||
'flows.nodeConfig.memory.minScoreHint': 'Soglia di rilevanza da 0 a 1.',
|
||||
'flows.nodeConfig.dedup.keyLabel': 'Chiave',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
"Un'espressione id stabile per elemento, es. =item.id. Gli elementi con una chiave già vista vengono ignorati.",
|
||||
|
||||
'flows.enableApproval.title': 'Consentire a questo workflow di agire?',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -4145,6 +4145,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': '출력 파서',
|
||||
'flows.nodeKind.sub_workflow': '하위 워크플로',
|
||||
'flows.nodeKind.memory': '메모리',
|
||||
'flows.nodeKind.dedup': '중복 제거',
|
||||
'flows.palette.title': '노드',
|
||||
'flows.palette.addNode': '{kind} 노드 추가',
|
||||
'flows.editor.save': '저장',
|
||||
@@ -4313,6 +4314,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': '최대 결과 수입니다.',
|
||||
'flows.nodeConfig.memory.minScoreLabel': '최소 점수',
|
||||
'flows.nodeConfig.memory.minScoreHint': '0에서 1 사이의 관련성 임곗값입니다.',
|
||||
'flows.nodeConfig.dedup.keyLabel': '키',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'항목별 안정적인 id 표현식입니다. 예: =item.id. 이미 본 키를 가진 항목은 건너뜁니다.',
|
||||
|
||||
'flows.enableApproval.title': '이 워크플로가 작업을 수행하도록 허용할까요?',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -4249,6 +4249,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'Parser wyjścia',
|
||||
'flows.nodeKind.sub_workflow': 'Podprzepływ pracy',
|
||||
'flows.nodeKind.memory': 'Pamięć',
|
||||
'flows.nodeKind.dedup': 'Deduplikacja',
|
||||
'flows.palette.title': 'Węzły',
|
||||
'flows.palette.addNode': 'Dodaj węzeł {kind}',
|
||||
'flows.editor.save': 'Zapisz',
|
||||
@@ -4422,6 +4423,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'Maksymalna liczba wyników.',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'Minimalny wynik',
|
||||
'flows.nodeConfig.memory.minScoreHint': 'Próg trafności od 0 do 1.',
|
||||
'flows.nodeConfig.dedup.keyLabel': 'Klucz',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'Stabilne wyrażenie identyfikatora dla każdego elementu, np. =item.id. Elementy z już widzianym kluczem są pomijane.',
|
||||
|
||||
'flows.enableApproval.title': 'Zezwolić temu przepływowi pracy na działanie?',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -4253,6 +4253,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'Analisador de saída',
|
||||
'flows.nodeKind.sub_workflow': 'Subfluxo de trabalho',
|
||||
'flows.nodeKind.memory': 'Memória',
|
||||
'flows.nodeKind.dedup': 'Deduplicação',
|
||||
'flows.palette.title': 'Nós',
|
||||
'flows.palette.addNode': 'Adicionar nó {kind}',
|
||||
'flows.editor.save': 'Salvar',
|
||||
@@ -4426,6 +4427,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'Número máximo de resultados.',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'Pontuação mínima',
|
||||
'flows.nodeConfig.memory.minScoreHint': 'Limite de relevância de 0 a 1.',
|
||||
'flows.nodeConfig.dedup.keyLabel': 'Chave',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'Uma expressão de id estável por item, ex.: =item.id. Itens com uma chave já vista são ignorados.',
|
||||
|
||||
'flows.enableApproval.title': 'Permitir que este fluxo de trabalho aja?',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -4231,6 +4231,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': 'Парсер вывода',
|
||||
'flows.nodeKind.sub_workflow': 'Подпроцесс',
|
||||
'flows.nodeKind.memory': 'Память',
|
||||
'flows.nodeKind.dedup': 'Дедупликация',
|
||||
'flows.palette.title': 'Узлы',
|
||||
'flows.palette.addNode': 'Добавить узел {kind}',
|
||||
'flows.editor.save': 'Сохранить',
|
||||
@@ -4406,6 +4407,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': 'Максимальное количество результатов.',
|
||||
'flows.nodeConfig.memory.minScoreLabel': 'Минимальная оценка',
|
||||
'flows.nodeConfig.memory.minScoreHint': 'Порог релевантности от 0 до 1.',
|
||||
'flows.nodeConfig.dedup.keyLabel': 'Ключ',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'Стабильное выражение id для каждого элемента, напр. =item.id. Элементы с уже встреченным ключом пропускаются.',
|
||||
|
||||
'flows.enableApproval.title': 'Разрешить этому рабочему процессу действовать?',
|
||||
'flows.enableApproval.intro':
|
||||
|
||||
@@ -3973,6 +3973,7 @@ const messages: TranslationMap = {
|
||||
'flows.nodeKind.output_parser': '输出解析器',
|
||||
'flows.nodeKind.sub_workflow': '子工作流',
|
||||
'flows.nodeKind.memory': '记忆',
|
||||
'flows.nodeKind.dedup': '去重',
|
||||
'flows.palette.title': '节点',
|
||||
'flows.palette.addNode': '添加{kind}节点',
|
||||
'flows.editor.save': '保存',
|
||||
@@ -4134,6 +4135,9 @@ const messages: TranslationMap = {
|
||||
'flows.nodeConfig.memory.limitHint': '返回结果的最大数量。',
|
||||
'flows.nodeConfig.memory.minScoreLabel': '最低分数',
|
||||
'flows.nodeConfig.memory.minScoreHint': '相关性阈值,范围为 0 到 1。',
|
||||
'flows.nodeConfig.dedup.keyLabel': '键',
|
||||
'flows.nodeConfig.dedup.keyHint':
|
||||
'每个项目的稳定 id 表达式,例如 =item.id。已出现过该键的项目将被跳过。',
|
||||
|
||||
'flows.enableApproval.title': '允许此工作流执行操作吗?',
|
||||
'flows.enableApproval.intro': '此工作流需要您对以下操作的许可。批准仅适用于此工作流。',
|
||||
|
||||
Reference in New Issue
Block a user