mirror of
https://github.com/langgenius/dify.git
synced 2026-05-10 14:14:17 +08:00
Merge branch 'main' into deploy/dev
This commit is contained in:
commit
93f9004898
82
.github/scripts/generate-i18n-changes.mjs
vendored
Normal file
82
.github/scripts/generate-i18n-changes.mjs
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
const repoRoot = process.cwd()
|
||||
const baseSha = process.env.BASE_SHA || ''
|
||||
const headSha = process.env.HEAD_SHA || ''
|
||||
const files = (process.env.CHANGED_FILES || '').split(/\s+/).filter(Boolean)
|
||||
const outputPath = process.env.I18N_CHANGES_OUTPUT_PATH || '/tmp/i18n-changes.json'
|
||||
|
||||
const englishPath = fileStem => path.join(repoRoot, 'web', 'i18n', 'en-US', `${fileStem}.json`)
|
||||
|
||||
const readCurrentJson = (fileStem) => {
|
||||
const filePath = englishPath(fileStem)
|
||||
if (!fs.existsSync(filePath))
|
||||
return null
|
||||
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
||||
}
|
||||
|
||||
const readBaseJson = (fileStem) => {
|
||||
if (!baseSha)
|
||||
return null
|
||||
|
||||
try {
|
||||
const relativePath = `web/i18n/en-US/${fileStem}.json`
|
||||
const content = execFileSync('git', ['show', `${baseSha}:${relativePath}`], { encoding: 'utf8' })
|
||||
return JSON.parse(content)
|
||||
}
|
||||
catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const compareJson = (beforeValue, afterValue) => JSON.stringify(beforeValue) === JSON.stringify(afterValue)
|
||||
|
||||
const changes = {}
|
||||
|
||||
for (const fileStem of files) {
|
||||
const currentJson = readCurrentJson(fileStem)
|
||||
const beforeJson = readBaseJson(fileStem) || {}
|
||||
const afterJson = currentJson || {}
|
||||
const added = {}
|
||||
const updated = {}
|
||||
const deleted = []
|
||||
|
||||
for (const [key, value] of Object.entries(afterJson)) {
|
||||
if (!(key in beforeJson)) {
|
||||
added[key] = value
|
||||
continue
|
||||
}
|
||||
|
||||
if (!compareJson(beforeJson[key], value)) {
|
||||
updated[key] = {
|
||||
before: beforeJson[key],
|
||||
after: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of Object.keys(beforeJson)) {
|
||||
if (!(key in afterJson))
|
||||
deleted.push(key)
|
||||
}
|
||||
|
||||
changes[fileStem] = {
|
||||
fileDeleted: currentJson === null,
|
||||
added,
|
||||
updated,
|
||||
deleted,
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
outputPath,
|
||||
JSON.stringify({
|
||||
baseSha,
|
||||
headSha,
|
||||
files,
|
||||
changes,
|
||||
})
|
||||
)
|
||||
101
.github/workflows/translate-i18n-claude.yml
vendored
101
.github/workflows/translate-i18n-claude.yml
vendored
@ -68,89 +68,7 @@ jobs:
|
||||
" web/i18n-config/languages.ts | sed 's/[[:space:]]*$//')
|
||||
|
||||
generate_changes_json() {
|
||||
node <<'NODE'
|
||||
const { execFileSync } = require('node:child_process')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
|
||||
const repoRoot = process.cwd()
|
||||
const baseSha = process.env.BASE_SHA || ''
|
||||
const headSha = process.env.HEAD_SHA || ''
|
||||
const files = (process.env.CHANGED_FILES || '').split(/\s+/).filter(Boolean)
|
||||
|
||||
const englishPath = fileStem => path.join(repoRoot, 'web', 'i18n', 'en-US', `${fileStem}.json`)
|
||||
|
||||
const readCurrentJson = (fileStem) => {
|
||||
const filePath = englishPath(fileStem)
|
||||
if (!fs.existsSync(filePath))
|
||||
return null
|
||||
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
||||
}
|
||||
|
||||
const readBaseJson = (fileStem) => {
|
||||
if (!baseSha)
|
||||
return null
|
||||
|
||||
try {
|
||||
const relativePath = `web/i18n/en-US/${fileStem}.json`
|
||||
const content = execFileSync('git', ['show', `${baseSha}:${relativePath}`], { encoding: 'utf8' })
|
||||
return JSON.parse(content)
|
||||
}
|
||||
catch (error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const compareJson = (beforeValue, afterValue) => JSON.stringify(beforeValue) === JSON.stringify(afterValue)
|
||||
|
||||
const changes = {}
|
||||
|
||||
for (const fileStem of files) {
|
||||
const currentJson = readCurrentJson(fileStem)
|
||||
const beforeJson = readBaseJson(fileStem) || {}
|
||||
const afterJson = currentJson || {}
|
||||
const added = {}
|
||||
const updated = {}
|
||||
const deleted = []
|
||||
|
||||
for (const [key, value] of Object.entries(afterJson)) {
|
||||
if (!(key in beforeJson)) {
|
||||
added[key] = value
|
||||
continue
|
||||
}
|
||||
|
||||
if (!compareJson(beforeJson[key], value)) {
|
||||
updated[key] = {
|
||||
before: beforeJson[key],
|
||||
after: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of Object.keys(beforeJson)) {
|
||||
if (!(key in afterJson))
|
||||
deleted.push(key)
|
||||
}
|
||||
|
||||
changes[fileStem] = {
|
||||
fileDeleted: currentJson === null,
|
||||
added,
|
||||
updated,
|
||||
deleted,
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
'/tmp/i18n-changes.json',
|
||||
JSON.stringify({
|
||||
baseSha,
|
||||
headSha,
|
||||
files,
|
||||
changes,
|
||||
})
|
||||
)
|
||||
NODE
|
||||
node .github/scripts/generate-i18n-changes.mjs
|
||||
}
|
||||
|
||||
if [ "${{ github.event_name }}" = "repository_dispatch" ]; then
|
||||
@ -270,7 +188,7 @@ jobs:
|
||||
Tool rules:
|
||||
- Use Read for repository files.
|
||||
- Use Edit for JSON updates.
|
||||
- Use Bash only for `pnpm`.
|
||||
- Use Bash only for `vp`.
|
||||
- Do not use Bash for `git`, `gh`, or branch management.
|
||||
|
||||
Required execution plan:
|
||||
@ -292,7 +210,7 @@ jobs:
|
||||
- Read the current English JSON file for any file that still exists so wording, placeholders, and surrounding terminology stay accurate.
|
||||
- If `Structured change set available` is `false`, treat this as a scoped full sync and use the current English files plus scoped checks as the source of truth.
|
||||
4. Run a scoped pre-check before editing:
|
||||
- `pnpm --dir ${{ github.workspace }}/web run i18n:check ${{ steps.context.outputs.FILE_ARGS }} ${{ steps.context.outputs.LANG_ARGS }}`
|
||||
- `vp run dify-web#i18n:check ${{ steps.context.outputs.FILE_ARGS }} ${{ steps.context.outputs.LANG_ARGS }}`
|
||||
- Use this command as the source of truth for missing and extra keys inside the current scope.
|
||||
5. Apply translations.
|
||||
- For every target language and scoped file:
|
||||
@ -300,19 +218,19 @@ jobs:
|
||||
- If the locale file does not exist yet, create it with `Write` and then continue with `Edit` as needed.
|
||||
- ADD missing keys.
|
||||
- UPDATE stale translations when the English value changed.
|
||||
- DELETE removed keys. Prefer `pnpm --dir ${{ github.workspace }}/web run i18n:check ${{ steps.context.outputs.FILE_ARGS }} ${{ steps.context.outputs.LANG_ARGS }} --auto-remove` for extra keys so deletions stay in scope.
|
||||
- DELETE removed keys. Prefer `vp run dify-web#i18n:check ${{ steps.context.outputs.FILE_ARGS }} ${{ steps.context.outputs.LANG_ARGS }} --auto-remove` for extra keys so deletions stay in scope.
|
||||
- Preserve placeholders exactly: `{{variable}}`, `${variable}`, HTML tags, component tags, and variable names.
|
||||
- Match the existing terminology and register used by each locale.
|
||||
- Prefer one Edit per file when stable, but prioritize correctness over batching.
|
||||
6. Verify only the edited files.
|
||||
- Run `pnpm --dir ${{ github.workspace }}/web lint:fix --quiet -- <relative edited i18n file paths>`
|
||||
- Run `pnpm --dir ${{ github.workspace }}/web run i18n:check ${{ steps.context.outputs.FILE_ARGS }} ${{ steps.context.outputs.LANG_ARGS }}`
|
||||
- Run `vp run dify-web#lint:fix --quiet -- <relative edited i18n file paths under web/>`
|
||||
- Run `vp run dify-web#i18n:check ${{ steps.context.outputs.FILE_ARGS }} ${{ steps.context.outputs.LANG_ARGS }}`
|
||||
- If verification fails, fix the remaining problems before continuing.
|
||||
7. Stop after the scoped locale files are updated and verification passes.
|
||||
- Do not create branches, commits, or pull requests.
|
||||
claude_args: |
|
||||
--max-turns 120
|
||||
--allowedTools "Read,Write,Edit,Bash(pnpm *),Bash(pnpm:*),Glob,Grep"
|
||||
--allowedTools "Read,Write,Edit,Bash(vp *),Bash(vp:*),Glob,Grep"
|
||||
|
||||
- name: Prepare branch metadata
|
||||
id: pr_meta
|
||||
@ -354,6 +272,7 @@ jobs:
|
||||
- name: Create or update translation PR
|
||||
if: steps.pr_meta.outputs.has_changes == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH_NAME: ${{ steps.pr_meta.outputs.branch_name }}
|
||||
FILES_IN_SCOPE: ${{ steps.context.outputs.CHANGED_FILES }}
|
||||
TARGET_LANGS: ${{ steps.context.outputs.TARGET_LANGS }}
|
||||
@ -402,8 +321,8 @@ jobs:
|
||||
'',
|
||||
'## Verification',
|
||||
'',
|
||||
`- \`pnpm --dir web run i18n:check --file ${process.env.FILES_IN_SCOPE} --lang ${process.env.TARGET_LANGS}\``,
|
||||
`- \`pnpm --dir web lint:fix --quiet -- <edited i18n files>\``,
|
||||
`- \`vp run dify-web#i18n:check --file ${process.env.FILES_IN_SCOPE} --lang ${process.env.TARGET_LANGS}\``,
|
||||
`- \`vp run dify-web#lint:fix --quiet -- <edited i18n files under web/>\``,
|
||||
'',
|
||||
'## Notes',
|
||||
'',
|
||||
|
||||
83
.github/workflows/trigger-i18n-sync.yml
vendored
83
.github/workflows/trigger-i18n-sync.yml
vendored
@ -42,88 +42,7 @@ jobs:
|
||||
fi
|
||||
|
||||
export BASE_SHA HEAD_SHA CHANGED_FILES
|
||||
node <<'NODE'
|
||||
const { execFileSync } = require('node:child_process')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
|
||||
const repoRoot = process.cwd()
|
||||
const baseSha = process.env.BASE_SHA || ''
|
||||
const headSha = process.env.HEAD_SHA || ''
|
||||
const files = (process.env.CHANGED_FILES || '').split(/\s+/).filter(Boolean)
|
||||
|
||||
const englishPath = fileStem => path.join(repoRoot, 'web', 'i18n', 'en-US', `${fileStem}.json`)
|
||||
|
||||
const readCurrentJson = (fileStem) => {
|
||||
const filePath = englishPath(fileStem)
|
||||
if (!fs.existsSync(filePath))
|
||||
return null
|
||||
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
||||
}
|
||||
|
||||
const readBaseJson = (fileStem) => {
|
||||
if (!baseSha)
|
||||
return null
|
||||
|
||||
try {
|
||||
const relativePath = `web/i18n/en-US/${fileStem}.json`
|
||||
const content = execFileSync('git', ['show', `${baseSha}:${relativePath}`], { encoding: 'utf8' })
|
||||
return JSON.parse(content)
|
||||
}
|
||||
catch (error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const compareJson = (beforeValue, afterValue) => JSON.stringify(beforeValue) === JSON.stringify(afterValue)
|
||||
|
||||
const changes = {}
|
||||
|
||||
for (const fileStem of files) {
|
||||
const beforeJson = readBaseJson(fileStem) || {}
|
||||
const afterJson = readCurrentJson(fileStem) || {}
|
||||
const added = {}
|
||||
const updated = {}
|
||||
const deleted = []
|
||||
|
||||
for (const [key, value] of Object.entries(afterJson)) {
|
||||
if (!(key in beforeJson)) {
|
||||
added[key] = value
|
||||
continue
|
||||
}
|
||||
|
||||
if (!compareJson(beforeJson[key], value)) {
|
||||
updated[key] = {
|
||||
before: beforeJson[key],
|
||||
after: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of Object.keys(beforeJson)) {
|
||||
if (!(key in afterJson))
|
||||
deleted.push(key)
|
||||
}
|
||||
|
||||
changes[fileStem] = {
|
||||
fileDeleted: readCurrentJson(fileStem) === null,
|
||||
added,
|
||||
updated,
|
||||
deleted,
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
'/tmp/i18n-changes.json',
|
||||
JSON.stringify({
|
||||
baseSha,
|
||||
headSha,
|
||||
files,
|
||||
changes,
|
||||
})
|
||||
)
|
||||
NODE
|
||||
node .github/scripts/generate-i18n-changes.mjs
|
||||
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo "has_changes=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
@ -81,8 +81,8 @@ if $web_modified; then
|
||||
|
||||
if $web_ts_modified; then
|
||||
echo "Running TypeScript type-check:tsgo"
|
||||
if ! pnpm run type-check:tsgo; then
|
||||
echo "Type check failed. Please run 'pnpm run type-check:tsgo' to fix the errors."
|
||||
if ! npm run type-check:tsgo; then
|
||||
echo "Type check failed. Please run 'npm run type-check:tsgo' to fix the errors."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
@ -90,8 +90,8 @@ if $web_modified; then
|
||||
fi
|
||||
|
||||
echo "Running knip"
|
||||
if ! pnpm run knip; then
|
||||
echo "Knip check failed. Please run 'pnpm run knip' to fix the errors."
|
||||
if ! npm run knip; then
|
||||
echo "Knip check failed. Please run 'npm run knip' to fix the errors."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@ -209,7 +209,10 @@ class PluginInstaller(BasePluginClient):
|
||||
"GET",
|
||||
f"plugin/{tenant_id}/management/decode/from_identifier",
|
||||
PluginDecodeResponse,
|
||||
params={"plugin_unique_identifier": plugin_unique_identifier},
|
||||
params={
|
||||
"plugin_unique_identifier": plugin_unique_identifier,
|
||||
"PluginUniqueIdentifier": plugin_unique_identifier, # compat with daemon <= 0.5.4
|
||||
},
|
||||
)
|
||||
|
||||
def fetch_plugin_installation_by_ids(
|
||||
|
||||
@ -4,7 +4,7 @@ from graphon.entities.base_node_data import BaseNodeData
|
||||
from graphon.enums import NodeType
|
||||
from pydantic import BaseModel
|
||||
|
||||
from core.rag.entities import WeightedScoreConfig
|
||||
from core.rag.entities.retrieval_settings import WeightedScoreConfig
|
||||
from core.rag.index_processor.index_processor_base import SummaryIndexSettingDict
|
||||
from core.rag.retrieval.retrieval_methods import RetrievalMethod
|
||||
from core.workflow.nodes.knowledge_index import KNOWLEDGE_INDEX_NODE_TYPE
|
||||
|
||||
@ -120,7 +120,10 @@ describe('HITLInputBlock', () => {
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(onWorkflowMapUpdate).toHaveBeenCalledWith(workflowNodesMap)
|
||||
expect(onWorkflowMapUpdate).toHaveBeenCalledWith({
|
||||
workflowNodesMap,
|
||||
availableVariables: [],
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -148,7 +148,10 @@ describe('HITLInputVariableBlockComponent', () => {
|
||||
editor!.update(() => {
|
||||
$getRoot().selectEnd()
|
||||
})
|
||||
handled = editor!.dispatchCommand(UPDATE_WORKFLOW_NODES_MAP, createWorkflowNodesMap())
|
||||
handled = editor!.dispatchCommand(UPDATE_WORKFLOW_NODES_MAP, {
|
||||
workflowNodesMap: createWorkflowNodesMap(),
|
||||
availableVariables: [],
|
||||
})
|
||||
})
|
||||
|
||||
expect(handled).toBe(true)
|
||||
|
||||
@ -22,7 +22,7 @@ const HITLInputReplacementBlock = ({
|
||||
onFormInputsChange,
|
||||
onFormInputItemRename,
|
||||
onFormInputItemRemove,
|
||||
workflowNodesMap,
|
||||
workflowNodesMap = {},
|
||||
getVarType,
|
||||
variables,
|
||||
readonly,
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
useEffect,
|
||||
} from 'react'
|
||||
import { CustomTextNode } from '../custom-text/node'
|
||||
import { UPDATE_WORKFLOW_NODES_MAP as WORKFLOW_UPDATE_WORKFLOW_NODES_MAP } from '../workflow-variable-block'
|
||||
import {
|
||||
$createHITLInputNode,
|
||||
HITLInputNode,
|
||||
@ -21,11 +22,13 @@ import {
|
||||
|
||||
export const INSERT_HITL_INPUT_BLOCK_COMMAND = createCommand('INSERT_HITL_INPUT_BLOCK_COMMAND')
|
||||
export const DELETE_HITL_INPUT_BLOCK_COMMAND = createCommand('DELETE_HITL_INPUT_BLOCK_COMMAND')
|
||||
export const UPDATE_WORKFLOW_NODES_MAP = createCommand('UPDATE_WORKFLOW_NODES_MAP')
|
||||
export const UPDATE_WORKFLOW_NODES_MAP = WORKFLOW_UPDATE_WORKFLOW_NODES_MAP
|
||||
|
||||
const HITLInputBlock = memo(({
|
||||
onInsert,
|
||||
onDelete,
|
||||
workflowNodesMap,
|
||||
workflowNodesMap = {},
|
||||
variables: workflowAvailableVariables,
|
||||
getVarType,
|
||||
readonly,
|
||||
}: HITLInputBlockType) => {
|
||||
@ -33,9 +36,12 @@ const HITLInputBlock = memo(({
|
||||
|
||||
useEffect(() => {
|
||||
editor.update(() => {
|
||||
editor.dispatchCommand(UPDATE_WORKFLOW_NODES_MAP, workflowNodesMap)
|
||||
editor.dispatchCommand(UPDATE_WORKFLOW_NODES_MAP, {
|
||||
workflowNodesMap: workflowNodesMap || {},
|
||||
availableVariables: workflowAvailableVariables || [],
|
||||
})
|
||||
})
|
||||
}, [editor, workflowNodesMap])
|
||||
}, [editor, workflowNodesMap, workflowAvailableVariables])
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor.hasNodes([HITLInputNode]))
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import type { UpdateWorkflowNodesMapPayload } from '../workflow-variable-block'
|
||||
import type { WorkflowNodesMap } from '../workflow-variable-block/node'
|
||||
import type { ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
@ -98,9 +99,8 @@ const HITLInputVariableBlockComponent = ({
|
||||
return mergeRegister(
|
||||
editor.registerCommand(
|
||||
UPDATE_WORKFLOW_NODES_MAP,
|
||||
(workflowNodesMap: WorkflowNodesMap) => {
|
||||
setLocalWorkflowNodesMap(workflowNodesMap)
|
||||
|
||||
(payload: UpdateWorkflowNodesMapPayload) => {
|
||||
setLocalWorkflowNodesMap(payload.workflowNodesMap)
|
||||
return true
|
||||
},
|
||||
COMMAND_PRIORITY_EDITOR,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import type { LexicalEditor } from 'lexical'
|
||||
import type { UpdateWorkflowNodesMapPayload } from '../index'
|
||||
import type { ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import { mergeRegister } from '@lexical/utils'
|
||||
@ -216,7 +217,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should mark env variable invalid when not found in environmentVariables', () => {
|
||||
it('should treat env variable as valid regardless of environmentVariables contents', () => {
|
||||
const environmentVariables: Var[] = [{ variable: 'env.valid_key', type: VarType.string }]
|
||||
|
||||
render(
|
||||
@ -229,7 +230,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
)
|
||||
|
||||
expect(mockVarLabel).toHaveBeenCalledWith(expect.objectContaining({
|
||||
errorMsg: expect.any(String),
|
||||
errorMsg: undefined,
|
||||
}))
|
||||
})
|
||||
|
||||
@ -281,7 +282,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
}))
|
||||
})
|
||||
|
||||
it('should evaluate env fallback selector tokens when classifier is forced', () => {
|
||||
it('should mark forced env branch invalid when selector prefix is missing', () => {
|
||||
mockForcedVariableKind.value = 'env'
|
||||
const environmentVariables: Var[] = [{ variable: '.', type: VarType.string }]
|
||||
|
||||
@ -295,7 +296,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
)
|
||||
|
||||
expect(mockVarLabel).toHaveBeenCalledWith(expect.objectContaining({
|
||||
errorMsg: undefined,
|
||||
errorMsg: expect.any(String),
|
||||
}))
|
||||
})
|
||||
|
||||
@ -330,7 +331,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
}))
|
||||
})
|
||||
|
||||
it('should mark conversation variable invalid when not found in conversationVariables', () => {
|
||||
it('should treat conversation variable as valid regardless of conversationVariables contents', () => {
|
||||
const conversationVariables: Var[] = [{ variable: 'conversation.other', type: VarType.string }]
|
||||
|
||||
render(
|
||||
@ -343,7 +344,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
)
|
||||
|
||||
expect(mockVarLabel).toHaveBeenCalledWith(expect.objectContaining({
|
||||
errorMsg: expect.any(String),
|
||||
errorMsg: undefined,
|
||||
}))
|
||||
})
|
||||
|
||||
@ -364,7 +365,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
}))
|
||||
})
|
||||
|
||||
it('should evaluate conversation fallback selector tokens when classifier is forced', () => {
|
||||
it('should mark forced conversation branch invalid when selector prefix is missing', () => {
|
||||
mockForcedVariableKind.value = 'conversation'
|
||||
const conversationVariables: Var[] = [{ variable: '.', type: VarType.string }]
|
||||
|
||||
@ -378,7 +379,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
)
|
||||
|
||||
expect(mockVarLabel).toHaveBeenCalledWith(expect.objectContaining({
|
||||
errorMsg: undefined,
|
||||
errorMsg: expect.any(String),
|
||||
}))
|
||||
})
|
||||
|
||||
@ -427,7 +428,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
}))
|
||||
})
|
||||
|
||||
it('should mark rag variable invalid when not found in ragVariables', () => {
|
||||
it('should treat rag variable as valid regardless of ragVariables contents', () => {
|
||||
const ragVariables: Var[] = [{ variable: 'rag.shared.other', type: VarType.string }]
|
||||
|
||||
render(
|
||||
@ -440,7 +441,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
)
|
||||
|
||||
expect(mockVarLabel).toHaveBeenCalledWith(expect.objectContaining({
|
||||
errorMsg: expect.any(String),
|
||||
errorMsg: undefined,
|
||||
}))
|
||||
})
|
||||
|
||||
@ -461,7 +462,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
}))
|
||||
})
|
||||
|
||||
it('should evaluate rag fallback selector tokens when classifier is forced', () => {
|
||||
it('should mark forced rag branch invalid when selector prefix is missing', () => {
|
||||
mockForcedVariableKind.value = 'rag'
|
||||
const ragVariables: Var[] = [{ variable: '..', type: VarType.string }]
|
||||
|
||||
@ -475,7 +476,7 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
)
|
||||
|
||||
expect(mockVarLabel).toHaveBeenCalledWith(expect.objectContaining({
|
||||
errorMsg: undefined,
|
||||
errorMsg: expect.any(String),
|
||||
}))
|
||||
})
|
||||
|
||||
@ -488,20 +489,81 @@ describe('WorkflowVariableBlockComponent', () => {
|
||||
/>,
|
||||
)
|
||||
|
||||
const updateHandler = mockRegisterCommand.mock.calls[0][1] as (map: Record<string, unknown>) => boolean
|
||||
const updateHandler = mockRegisterCommand.mock.calls[0][1] as (payload: UpdateWorkflowNodesMapPayload) => boolean
|
||||
let result = false
|
||||
act(() => {
|
||||
result = updateHandler({
|
||||
'node-1': {
|
||||
title: 'Updated',
|
||||
type: BlockEnum.LLM,
|
||||
width: 100,
|
||||
height: 50,
|
||||
position: { x: 0, y: 0 },
|
||||
workflowNodesMap: {
|
||||
'node-1': {
|
||||
title: 'Updated',
|
||||
type: BlockEnum.LLM,
|
||||
width: 100,
|
||||
height: 50,
|
||||
position: { x: 0, y: 0 },
|
||||
},
|
||||
},
|
||||
availableVariables: [],
|
||||
})
|
||||
})
|
||||
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
|
||||
it('should mark non-special variable invalid when source key is missing in availableVariables', () => {
|
||||
render(
|
||||
<WorkflowVariableBlockComponent
|
||||
nodeKey="k"
|
||||
variables={['node-1', 'missing_key']}
|
||||
workflowNodesMap={{
|
||||
'node-1': {
|
||||
title: 'Node A',
|
||||
type: BlockEnum.LLM,
|
||||
width: 200,
|
||||
height: 100,
|
||||
position: { x: 0, y: 0 },
|
||||
},
|
||||
}}
|
||||
availableVariables={[
|
||||
{
|
||||
nodeId: 'node-1',
|
||||
title: 'Node A',
|
||||
vars: [{ variable: 'existing_key', type: VarType.string }],
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(mockVarLabel).toHaveBeenCalledWith(expect.objectContaining({
|
||||
errorMsg: expect.any(String),
|
||||
}))
|
||||
})
|
||||
|
||||
it('should keep non-special variable valid when source key exists in availableVariables', () => {
|
||||
render(
|
||||
<WorkflowVariableBlockComponent
|
||||
nodeKey="k"
|
||||
variables={['node-1', 'existing_key']}
|
||||
workflowNodesMap={{
|
||||
'node-1': {
|
||||
title: 'Node A',
|
||||
type: BlockEnum.LLM,
|
||||
width: 200,
|
||||
height: 100,
|
||||
position: { x: 0, y: 0 },
|
||||
},
|
||||
}}
|
||||
availableVariables={[
|
||||
{
|
||||
nodeId: 'node-1',
|
||||
title: 'Node A',
|
||||
vars: [{ variable: 'existing_key', type: VarType.string }],
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(mockVarLabel).toHaveBeenCalledWith(expect.objectContaining({
|
||||
errorMsg: undefined,
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
@ -105,7 +105,10 @@ describe('WorkflowVariableBlock', () => {
|
||||
)
|
||||
|
||||
expect(mockUpdate).toHaveBeenCalled()
|
||||
expect(mockDispatchCommand).toHaveBeenCalledWith(UPDATE_WORKFLOW_NODES_MAP, workflowNodesMap)
|
||||
expect(mockDispatchCommand).toHaveBeenCalledWith(UPDATE_WORKFLOW_NODES_MAP, {
|
||||
workflowNodesMap,
|
||||
availableVariables: [],
|
||||
})
|
||||
})
|
||||
|
||||
it('should throw when WorkflowVariableBlockNode is not registered', () => {
|
||||
@ -137,6 +140,7 @@ describe('WorkflowVariableBlock', () => {
|
||||
['node-1', 'answer'],
|
||||
workflowNodesMap,
|
||||
getVarType,
|
||||
[],
|
||||
)
|
||||
expect($insertNodes).toHaveBeenCalledWith([{ id: 'workflow-node' }])
|
||||
expect(onInsert).toHaveBeenCalledTimes(1)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { Klass, LexicalEditor, LexicalNode } from 'lexical'
|
||||
import type { Var } from '@/app/components/workflow/types'
|
||||
import type { NodeOutPutVar } from '@/app/components/workflow/types'
|
||||
import { createEditor } from 'lexical'
|
||||
import { Type } from '@/app/components/workflow/nodes/llm/types'
|
||||
import { BlockEnum, VarType } from '@/app/components/workflow/types'
|
||||
@ -57,45 +57,43 @@ describe('WorkflowVariableBlockNode', () => {
|
||||
it('should decorate with component props from node state', () => {
|
||||
runInEditor(() => {
|
||||
const getVarType = vi.fn(() => Type.number)
|
||||
const environmentVariables: Var[] = [{ variable: 'env.key', type: VarType.string }]
|
||||
const conversationVariables: Var[] = [{ variable: 'conversation.topic', type: VarType.string }]
|
||||
const ragVariables: Var[] = [{ variable: 'rag.shared.answer', type: VarType.string }]
|
||||
const availableVariables: NodeOutPutVar[] = [{
|
||||
nodeId: 'node-1',
|
||||
title: 'Node A',
|
||||
vars: [{ variable: 'answer', type: VarType.string }],
|
||||
}]
|
||||
|
||||
const node = new WorkflowVariableBlockNode(
|
||||
['node-1', 'answer'],
|
||||
{ 'node-1': { title: 'A', type: BlockEnum.LLM } },
|
||||
getVarType,
|
||||
'decorator-key',
|
||||
environmentVariables,
|
||||
conversationVariables,
|
||||
ragVariables,
|
||||
availableVariables,
|
||||
)
|
||||
|
||||
const decorated = node.decorate()
|
||||
expect(decorated.props.nodeKey).toBe('decorator-key')
|
||||
expect(decorated.props.variables).toEqual(['node-1', 'answer'])
|
||||
expect(decorated.props.workflowNodesMap).toEqual({ 'node-1': { title: 'A', type: BlockEnum.LLM } })
|
||||
expect(decorated.props.environmentVariables).toEqual(environmentVariables)
|
||||
expect(decorated.props.conversationVariables).toEqual(conversationVariables)
|
||||
expect(decorated.props.ragVariables).toEqual(ragVariables)
|
||||
expect(decorated.props.availableVariables).toEqual(availableVariables)
|
||||
})
|
||||
})
|
||||
|
||||
it('should export and import json with full payload', () => {
|
||||
it('should export and import json with available variables payload', () => {
|
||||
runInEditor(() => {
|
||||
const getVarType = vi.fn(() => Type.string)
|
||||
const environmentVariables: Var[] = [{ variable: 'env.key', type: VarType.string }]
|
||||
const conversationVariables: Var[] = [{ variable: 'conversation.topic', type: VarType.string }]
|
||||
const ragVariables: Var[] = [{ variable: 'rag.shared.answer', type: VarType.string }]
|
||||
const availableVariables: NodeOutPutVar[] = [{
|
||||
nodeId: 'node-1',
|
||||
title: 'Node A',
|
||||
vars: [{ variable: 'answer', type: VarType.string }],
|
||||
}]
|
||||
|
||||
const node = new WorkflowVariableBlockNode(
|
||||
['node-1', 'answer'],
|
||||
{ 'node-1': { title: 'A', type: BlockEnum.LLM } },
|
||||
getVarType,
|
||||
undefined,
|
||||
environmentVariables,
|
||||
conversationVariables,
|
||||
ragVariables,
|
||||
availableVariables,
|
||||
)
|
||||
|
||||
expect(node.exportJSON()).toEqual({
|
||||
@ -104,9 +102,7 @@ describe('WorkflowVariableBlockNode', () => {
|
||||
variables: ['node-1', 'answer'],
|
||||
workflowNodesMap: { 'node-1': { title: 'A', type: BlockEnum.LLM } },
|
||||
getVarType,
|
||||
environmentVariables,
|
||||
conversationVariables,
|
||||
ragVariables,
|
||||
availableVariables,
|
||||
})
|
||||
|
||||
const imported = WorkflowVariableBlockNode.importJSON({
|
||||
@ -115,48 +111,51 @@ describe('WorkflowVariableBlockNode', () => {
|
||||
variables: ['node-2', 'result'],
|
||||
workflowNodesMap: { 'node-2': { title: 'B', type: BlockEnum.Tool } },
|
||||
getVarType,
|
||||
environmentVariables,
|
||||
conversationVariables,
|
||||
ragVariables,
|
||||
availableVariables,
|
||||
})
|
||||
|
||||
expect(imported).toBeInstanceOf(WorkflowVariableBlockNode)
|
||||
expect(imported.getVariables()).toEqual(['node-2', 'result'])
|
||||
expect(imported.getWorkflowNodesMap()).toEqual({ 'node-2': { title: 'B', type: BlockEnum.Tool } })
|
||||
expect(imported.getAvailableVariables()).toEqual(availableVariables)
|
||||
})
|
||||
})
|
||||
|
||||
it('should return getters and text content in expected format', () => {
|
||||
runInEditor(() => {
|
||||
const getVarType = vi.fn(() => Type.string)
|
||||
const environmentVariables: Var[] = [{ variable: 'env.key', type: VarType.string }]
|
||||
const conversationVariables: Var[] = [{ variable: 'conversation.topic', type: VarType.string }]
|
||||
const ragVariables: Var[] = [{ variable: 'rag.shared.answer', type: VarType.string }]
|
||||
const availableVariables: NodeOutPutVar[] = [{
|
||||
nodeId: 'node-1',
|
||||
title: 'Node A',
|
||||
vars: [{ variable: 'answer', type: VarType.string }],
|
||||
}]
|
||||
const node = new WorkflowVariableBlockNode(
|
||||
['node-1', 'answer'],
|
||||
{ 'node-1': { title: 'A', type: BlockEnum.LLM } },
|
||||
getVarType,
|
||||
undefined,
|
||||
environmentVariables,
|
||||
conversationVariables,
|
||||
ragVariables,
|
||||
availableVariables,
|
||||
)
|
||||
|
||||
expect(node.getVariables()).toEqual(['node-1', 'answer'])
|
||||
expect(node.getWorkflowNodesMap()).toEqual({ 'node-1': { title: 'A', type: BlockEnum.LLM } })
|
||||
expect(node.getVarType()).toBe(getVarType)
|
||||
expect(node.getEnvironmentVariables()).toEqual(environmentVariables)
|
||||
expect(node.getConversationVariables()).toEqual(conversationVariables)
|
||||
expect(node.getRagVariables()).toEqual(ragVariables)
|
||||
expect(node.getAvailableVariables()).toEqual(availableVariables)
|
||||
expect(node.getTextContent()).toBe('{{#node-1.answer#}}')
|
||||
})
|
||||
})
|
||||
|
||||
it('should create node helper and type guard checks', () => {
|
||||
runInEditor(() => {
|
||||
const node = $createWorkflowVariableBlockNode(['node-1', 'answer'], {}, undefined)
|
||||
const availableVariables: NodeOutPutVar[] = [{
|
||||
nodeId: 'node-1',
|
||||
title: 'Node A',
|
||||
vars: [{ variable: 'answer', type: VarType.string }],
|
||||
}]
|
||||
const node = $createWorkflowVariableBlockNode(['node-1', 'answer'], {}, undefined, availableVariables)
|
||||
|
||||
expect(node).toBeInstanceOf(WorkflowVariableBlockNode)
|
||||
expect(node.getAvailableVariables()).toEqual(availableVariables)
|
||||
expect($isWorkflowVariableBlockNode(node)).toBe(true)
|
||||
expect($isWorkflowVariableBlockNode(null)).toBe(false)
|
||||
expect($isWorkflowVariableBlockNode(undefined)).toBe(false)
|
||||
|
||||
@ -183,12 +183,7 @@ describe('WorkflowVariableBlockReplacementBlock', () => {
|
||||
['node-1', 'output'],
|
||||
workflowNodesMap,
|
||||
getVarType,
|
||||
variables[0].vars,
|
||||
variables[1].vars,
|
||||
[
|
||||
{ variable: 'ragVarA', type: VarType.string, isRagVariable: true },
|
||||
{ variable: 'rag.shared.answer', type: VarType.string, isRagVariable: true },
|
||||
],
|
||||
variables,
|
||||
)
|
||||
expect($applyNodeReplacement).toHaveBeenCalledWith({ type: 'workflow-node' })
|
||||
expect(created).toEqual({ type: 'workflow-node' })
|
||||
@ -214,8 +209,6 @@ describe('WorkflowVariableBlockReplacementBlock', () => {
|
||||
workflowNodesMap,
|
||||
undefined,
|
||||
[],
|
||||
[],
|
||||
undefined,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import type {
|
||||
UpdateWorkflowNodesMapPayload,
|
||||
} from './index'
|
||||
import type { WorkflowNodesMap } from './node'
|
||||
import type { ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import { mergeRegister } from '@lexical/utils'
|
||||
import {
|
||||
@ -15,7 +18,7 @@ import {
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useReactFlow, useStoreApi } from 'reactflow'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/app/components/base/ui/tooltip'
|
||||
import { isConversationVar, isENV, isGlobalVar, isRagVariableVar, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
|
||||
import { isRagVariableVar, isSpecialVar, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
|
||||
import VarFullPathPanel from '@/app/components/workflow/nodes/_base/components/variable/var-full-path-panel'
|
||||
import {
|
||||
VariableLabelInEditor,
|
||||
@ -34,6 +37,7 @@ type WorkflowVariableBlockComponentProps = {
|
||||
nodeKey: string
|
||||
variables: string[]
|
||||
workflowNodesMap: WorkflowNodesMap
|
||||
availableVariables?: NodeOutPutVar[]
|
||||
environmentVariables?: Var[]
|
||||
conversationVariables?: Var[]
|
||||
ragVariables?: Var[]
|
||||
@ -47,10 +51,8 @@ const WorkflowVariableBlockComponent = ({
|
||||
nodeKey,
|
||||
variables,
|
||||
workflowNodesMap = {},
|
||||
availableVariables,
|
||||
getVarType,
|
||||
environmentVariables,
|
||||
conversationVariables,
|
||||
ragVariables,
|
||||
}: WorkflowVariableBlockComponentProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [editor] = useLexicalComposerContext()
|
||||
@ -66,36 +68,25 @@ const WorkflowVariableBlockComponent = ({
|
||||
}
|
||||
)()
|
||||
const [localWorkflowNodesMap, setLocalWorkflowNodesMap] = useState<WorkflowNodesMap>(workflowNodesMap)
|
||||
const [localAvailableVariables, setLocalAvailableVariables] = useState<NodeOutPutVar[]>(availableVariables || [])
|
||||
const node = localWorkflowNodesMap![variables[isRagVar ? 1 : 0]]
|
||||
|
||||
const isException = isExceptionVariable(varName, node?.type)
|
||||
const sourceNodeId = variables[isRagVar ? 1 : 0]
|
||||
const isLlmModelInstalled = useLlmModelPluginInstalled(sourceNodeId, localWorkflowNodesMap)
|
||||
const variableValid = useMemo(() => {
|
||||
let variableValid = true
|
||||
const isEnv = isENV(variables)
|
||||
const isChatVar = isConversationVar(variables)
|
||||
const isGlobal = isGlobalVar(variables)
|
||||
if (isGlobal)
|
||||
if (isSpecialVar(variables[0] ?? ''))
|
||||
return true
|
||||
|
||||
if (isEnv) {
|
||||
if (environmentVariables)
|
||||
variableValid = environmentVariables.some(v => v.variable === `${variables?.[0] ?? ''}.${variables?.[1] ?? ''}`)
|
||||
}
|
||||
else if (isChatVar) {
|
||||
if (conversationVariables)
|
||||
variableValid = conversationVariables.some(v => v.variable === `${variables?.[0] ?? ''}.${variables?.[1] ?? ''}`)
|
||||
}
|
||||
else if (isRagVar) {
|
||||
if (ragVariables)
|
||||
variableValid = ragVariables.some(v => v.variable === `${variables?.[0] ?? ''}.${variables?.[1] ?? ''}.${variables?.[2] ?? ''}`)
|
||||
}
|
||||
else {
|
||||
variableValid = !!node
|
||||
}
|
||||
return variableValid
|
||||
}, [variables, node, environmentVariables, conversationVariables, isRagVar, ragVariables])
|
||||
if (!variables[1])
|
||||
return false
|
||||
|
||||
const sourceNode = localAvailableVariables.find(v => v.nodeId === variables[0])
|
||||
if (!sourceNode)
|
||||
return false
|
||||
|
||||
return sourceNode.vars.some(v => v.variable === variables[1])
|
||||
}, [localAvailableVariables, variables])
|
||||
|
||||
const reactflow = useReactFlow()
|
||||
const store = useStoreApi()
|
||||
@ -107,9 +98,9 @@ const WorkflowVariableBlockComponent = ({
|
||||
return mergeRegister(
|
||||
editor.registerCommand(
|
||||
UPDATE_WORKFLOW_NODES_MAP,
|
||||
(workflowNodesMap: WorkflowNodesMap) => {
|
||||
setLocalWorkflowNodesMap(workflowNodesMap)
|
||||
|
||||
(payload: UpdateWorkflowNodesMapPayload) => {
|
||||
setLocalWorkflowNodesMap(payload.workflowNodesMap)
|
||||
setLocalAvailableVariables(payload.availableVariables)
|
||||
return true
|
||||
},
|
||||
COMMAND_PRIORITY_EDITOR,
|
||||
|
||||
@ -17,9 +17,14 @@ import {
|
||||
|
||||
export const INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND = createCommand('INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND')
|
||||
export const DELETE_WORKFLOW_VARIABLE_BLOCK_COMMAND = createCommand('DELETE_WORKFLOW_VARIABLE_BLOCK_COMMAND')
|
||||
export const UPDATE_WORKFLOW_NODES_MAP = createCommand('UPDATE_WORKFLOW_NODES_MAP')
|
||||
export type UpdateWorkflowNodesMapPayload = {
|
||||
workflowNodesMap: NonNullable<WorkflowVariableBlockType['workflowNodesMap']>
|
||||
availableVariables: NonNullable<WorkflowVariableBlockType['variables']>
|
||||
}
|
||||
export const UPDATE_WORKFLOW_NODES_MAP = createCommand<UpdateWorkflowNodesMapPayload>('UPDATE_WORKFLOW_NODES_MAP')
|
||||
const WorkflowVariableBlock = memo(({
|
||||
workflowNodesMap,
|
||||
workflowNodesMap = {},
|
||||
variables: workflowAvailableVariables,
|
||||
onInsert,
|
||||
onDelete,
|
||||
getVarType,
|
||||
@ -28,9 +33,12 @@ const WorkflowVariableBlock = memo(({
|
||||
|
||||
useEffect(() => {
|
||||
editor.update(() => {
|
||||
editor.dispatchCommand(UPDATE_WORKFLOW_NODES_MAP, workflowNodesMap)
|
||||
editor.dispatchCommand(UPDATE_WORKFLOW_NODES_MAP, {
|
||||
workflowNodesMap: workflowNodesMap || {},
|
||||
availableVariables: workflowAvailableVariables || [],
|
||||
})
|
||||
})
|
||||
}, [editor, workflowNodesMap])
|
||||
}, [editor, workflowNodesMap, workflowAvailableVariables])
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor.hasNodes([WorkflowVariableBlockNode]))
|
||||
@ -40,7 +48,12 @@ const WorkflowVariableBlock = memo(({
|
||||
editor.registerCommand(
|
||||
INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND,
|
||||
(variables: string[]) => {
|
||||
const workflowVariableBlockNode = $createWorkflowVariableBlockNode(variables, workflowNodesMap, getVarType)
|
||||
const workflowVariableBlockNode = $createWorkflowVariableBlockNode(
|
||||
variables,
|
||||
workflowNodesMap,
|
||||
getVarType,
|
||||
workflowAvailableVariables || [],
|
||||
)
|
||||
|
||||
$insertNodes([workflowVariableBlockNode])
|
||||
if (onInsert)
|
||||
@ -61,7 +74,7 @@ const WorkflowVariableBlock = memo(({
|
||||
COMMAND_PRIORITY_EDITOR,
|
||||
),
|
||||
)
|
||||
}, [editor, onInsert, onDelete, workflowNodesMap, getVarType])
|
||||
}, [editor, onInsert, onDelete, workflowNodesMap, getVarType, workflowAvailableVariables])
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
@ -1,49 +1,55 @@
|
||||
import type { LexicalNode, NodeKey, SerializedLexicalNode } from 'lexical'
|
||||
import type { GetVarType, WorkflowVariableBlockType } from '../../types'
|
||||
import type { Var } from '@/app/components/workflow/types'
|
||||
import type { NodeOutPutVar } from '@/app/components/workflow/types'
|
||||
import { DecoratorNode } from 'lexical'
|
||||
import WorkflowVariableBlockComponent from './component'
|
||||
|
||||
export type WorkflowNodesMap = WorkflowVariableBlockType['workflowNodesMap']
|
||||
export type WorkflowNodesMap = NonNullable<WorkflowVariableBlockType['workflowNodesMap']>
|
||||
|
||||
type SerializedNode = SerializedLexicalNode & {
|
||||
variables: string[]
|
||||
workflowNodesMap: WorkflowNodesMap
|
||||
getVarType?: GetVarType
|
||||
environmentVariables?: Var[]
|
||||
conversationVariables?: Var[]
|
||||
ragVariables?: Var[]
|
||||
availableVariables?: NodeOutPutVar[]
|
||||
}
|
||||
|
||||
export class WorkflowVariableBlockNode extends DecoratorNode<React.JSX.Element> {
|
||||
__variables: string[]
|
||||
__workflowNodesMap: WorkflowNodesMap
|
||||
__getVarType?: GetVarType
|
||||
__environmentVariables?: Var[]
|
||||
__conversationVariables?: Var[]
|
||||
__ragVariables?: Var[]
|
||||
__availableVariables?: NodeOutPutVar[]
|
||||
|
||||
static getType(): string {
|
||||
return 'workflow-variable-block'
|
||||
}
|
||||
|
||||
static clone(node: WorkflowVariableBlockNode): WorkflowVariableBlockNode {
|
||||
return new WorkflowVariableBlockNode(node.__variables, node.__workflowNodesMap, node.__getVarType, node.__key, node.__environmentVariables, node.__conversationVariables, node.__ragVariables)
|
||||
return new WorkflowVariableBlockNode(
|
||||
node.__variables,
|
||||
node.__workflowNodesMap,
|
||||
node.__getVarType,
|
||||
node.__key,
|
||||
node.__availableVariables,
|
||||
)
|
||||
}
|
||||
|
||||
isInline(): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
constructor(variables: string[], workflowNodesMap: WorkflowNodesMap, getVarType: any, key?: NodeKey, environmentVariables?: Var[], conversationVariables?: Var[], ragVariables?: Var[]) {
|
||||
constructor(
|
||||
variables: string[],
|
||||
workflowNodesMap: WorkflowNodesMap,
|
||||
getVarType: any,
|
||||
key?: NodeKey,
|
||||
availableVariables?: NodeOutPutVar[],
|
||||
) {
|
||||
super(key)
|
||||
|
||||
this.__variables = variables
|
||||
this.__workflowNodesMap = workflowNodesMap
|
||||
this.__getVarType = getVarType
|
||||
this.__environmentVariables = environmentVariables
|
||||
this.__conversationVariables = conversationVariables
|
||||
this.__ragVariables = ragVariables
|
||||
this.__availableVariables = availableVariables
|
||||
}
|
||||
|
||||
createDOM(): HTMLElement {
|
||||
@ -63,30 +69,34 @@ export class WorkflowVariableBlockNode extends DecoratorNode<React.JSX.Element>
|
||||
variables={this.__variables}
|
||||
workflowNodesMap={this.__workflowNodesMap}
|
||||
getVarType={this.__getVarType!}
|
||||
environmentVariables={this.__environmentVariables}
|
||||
conversationVariables={this.__conversationVariables}
|
||||
ragVariables={this.__ragVariables}
|
||||
availableVariables={this.__availableVariables}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
static importJSON(serializedNode: SerializedNode): WorkflowVariableBlockNode {
|
||||
const node = $createWorkflowVariableBlockNode(serializedNode.variables, serializedNode.workflowNodesMap, serializedNode.getVarType, serializedNode.environmentVariables, serializedNode.conversationVariables, serializedNode.ragVariables)
|
||||
const node = $createWorkflowVariableBlockNode(
|
||||
serializedNode.variables,
|
||||
serializedNode.workflowNodesMap,
|
||||
serializedNode.getVarType,
|
||||
serializedNode.availableVariables,
|
||||
)
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
exportJSON(): SerializedNode {
|
||||
return {
|
||||
const json: SerializedNode = {
|
||||
type: 'workflow-variable-block',
|
||||
version: 1,
|
||||
variables: this.getVariables(),
|
||||
workflowNodesMap: this.getWorkflowNodesMap(),
|
||||
getVarType: this.getVarType(),
|
||||
environmentVariables: this.getEnvironmentVariables(),
|
||||
conversationVariables: this.getConversationVariables(),
|
||||
ragVariables: this.getRagVariables(),
|
||||
}
|
||||
if (this.getAvailableVariables())
|
||||
json.availableVariables = this.getAvailableVariables()
|
||||
|
||||
return json
|
||||
}
|
||||
|
||||
getVariables(): string[] {
|
||||
@ -104,27 +114,28 @@ export class WorkflowVariableBlockNode extends DecoratorNode<React.JSX.Element>
|
||||
return self.__getVarType
|
||||
}
|
||||
|
||||
getEnvironmentVariables(): any {
|
||||
getAvailableVariables(): NodeOutPutVar[] | undefined {
|
||||
const self = this.getLatest()
|
||||
return self.__environmentVariables
|
||||
}
|
||||
|
||||
getConversationVariables(): any {
|
||||
const self = this.getLatest()
|
||||
return self.__conversationVariables
|
||||
}
|
||||
|
||||
getRagVariables(): any {
|
||||
const self = this.getLatest()
|
||||
return self.__ragVariables
|
||||
return self.__availableVariables
|
||||
}
|
||||
|
||||
getTextContent(): string {
|
||||
return `{{#${this.getVariables().join('.')}#}}`
|
||||
}
|
||||
}
|
||||
export function $createWorkflowVariableBlockNode(variables: string[], workflowNodesMap: WorkflowNodesMap, getVarType?: GetVarType, environmentVariables?: Var[], conversationVariables?: Var[], ragVariables?: Var[]): WorkflowVariableBlockNode {
|
||||
return new WorkflowVariableBlockNode(variables, workflowNodesMap, getVarType, undefined, environmentVariables, conversationVariables, ragVariables)
|
||||
export function $createWorkflowVariableBlockNode(
|
||||
variables: string[],
|
||||
workflowNodesMap: WorkflowNodesMap,
|
||||
getVarType?: GetVarType,
|
||||
availableVariables?: NodeOutPutVar[],
|
||||
): WorkflowVariableBlockNode {
|
||||
return new WorkflowVariableBlockNode(
|
||||
variables,
|
||||
workflowNodesMap,
|
||||
getVarType,
|
||||
undefined,
|
||||
availableVariables,
|
||||
)
|
||||
}
|
||||
|
||||
export function $isWorkflowVariableBlockNode(
|
||||
|
||||
@ -15,19 +15,12 @@ import { WorkflowVariableBlockNode } from './index'
|
||||
import { $createWorkflowVariableBlockNode } from './node'
|
||||
|
||||
const WorkflowVariableBlockReplacementBlock = ({
|
||||
workflowNodesMap,
|
||||
workflowNodesMap = {},
|
||||
getVarType,
|
||||
onInsert,
|
||||
variables,
|
||||
}: WorkflowVariableBlockType) => {
|
||||
const [editor] = useLexicalComposerContext()
|
||||
const ragVariables = variables?.reduce<any[]>((acc, curr) => {
|
||||
if (curr.nodeId === 'rag')
|
||||
acc.push(...curr.vars)
|
||||
else
|
||||
acc.push(...curr.vars.filter(v => v.isRagVariable))
|
||||
return acc
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor.hasNodes([WorkflowVariableBlockNode]))
|
||||
@ -39,8 +32,13 @@ const WorkflowVariableBlockReplacementBlock = ({
|
||||
onInsert()
|
||||
|
||||
const nodePathString = textNode.getTextContent().slice(3, -3)
|
||||
return $applyNodeReplacement($createWorkflowVariableBlockNode(nodePathString.split('.'), workflowNodesMap, getVarType, variables?.find(o => o.nodeId === 'env')?.vars || [], variables?.find(o => o.nodeId === 'conversation')?.vars || [], ragVariables))
|
||||
}, [onInsert, workflowNodesMap, getVarType, variables, ragVariables])
|
||||
return $applyNodeReplacement($createWorkflowVariableBlockNode(
|
||||
nodePathString.split('.'),
|
||||
workflowNodesMap,
|
||||
getVarType,
|
||||
variables || [],
|
||||
))
|
||||
}, [onInsert, workflowNodesMap, getVarType, variables])
|
||||
|
||||
const getMatch = useCallback((text: string) => {
|
||||
const matchArr = REGEX.exec(text)
|
||||
|
||||
@ -22,6 +22,9 @@ import Panel from '../panel'
|
||||
import { ParamType, ReasoningModeType } from '../types'
|
||||
import useConfig from '../use-config'
|
||||
|
||||
const reasoningModeFunctionToolCallingLabel = 'workflow.nodes.parameterExtractor.reasoningModeFunctionToolCalling'
|
||||
const reasoningModePromptLabel = 'workflow.nodes.parameterExtractor.reasoningModePrompt'
|
||||
|
||||
type MockToolCollection = {
|
||||
id: string
|
||||
tools: Array<{
|
||||
@ -735,8 +738,8 @@ describe('parameter-extractor path', () => {
|
||||
/>,
|
||||
)
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Function/Tool Calling' }))
|
||||
await user.click(screen.getByRole('button', { name: 'Prompt' }))
|
||||
await user.click(screen.getByRole('button', { name: reasoningModeFunctionToolCallingLabel }))
|
||||
await user.click(screen.getByRole('button', { name: reasoningModePromptLabel }))
|
||||
|
||||
expect(onChange).toHaveBeenNthCalledWith(1, ReasoningModeType.functionCall)
|
||||
expect(onChange).toHaveBeenNthCalledWith(2, ReasoningModeType.prompt)
|
||||
@ -826,7 +829,7 @@ describe('parameter-extractor path', () => {
|
||||
target: { value: 'Extract city, budget, and due date' },
|
||||
})
|
||||
await user.click(screen.getByRole('button', { name: 'memory-config' }))
|
||||
await user.click(screen.getByRole('button', { name: 'Function/Tool Calling' }))
|
||||
await user.click(screen.getByRole('button', { name: reasoningModeFunctionToolCallingLabel }))
|
||||
|
||||
expect(handleModelChanged).toHaveBeenCalledWith({
|
||||
provider: 'anthropic',
|
||||
|
||||
@ -33,12 +33,12 @@ const ReasoningModePicker: FC<Props> = ({
|
||||
>
|
||||
<div className="grid grid-cols-2 gap-x-1">
|
||||
<OptionCard
|
||||
title="Function/Tool Calling"
|
||||
title={t(`${i18nPrefix}.reasoningModeFunctionToolCalling`, { ns: 'workflow' })}
|
||||
onSelect={handleChange(ReasoningModeType.functionCall)}
|
||||
selected={type === ReasoningModeType.functionCall}
|
||||
/>
|
||||
<OptionCard
|
||||
title="Prompt"
|
||||
title={t(`${i18nPrefix}.reasoningModePrompt`, { ns: 'workflow' })}
|
||||
selected={type === ReasoningModeType.prompt}
|
||||
onSelect={handleChange(ReasoningModeType.prompt)}
|
||||
/>
|
||||
|
||||
@ -3385,7 +3385,7 @@
|
||||
"count": 3
|
||||
},
|
||||
"react-refresh/only-export-components": {
|
||||
"count": 3
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"app/components/base/prompt-editor/plugins/hitl-input-block/input-field.tsx": {
|
||||
@ -3485,12 +3485,7 @@
|
||||
},
|
||||
"app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx": {
|
||||
"ts/no-explicit-any": {
|
||||
"count": 5
|
||||
}
|
||||
},
|
||||
"app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx": {
|
||||
"ts/no-explicit-any": {
|
||||
"count": 1
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"app/components/base/prompt-log-modal/card.tsx": {
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "الصفحات المصرح بها",
|
||||
"dataSource.notion.remove": "إزالة",
|
||||
"dataSource.notion.selector.addPages": "إضافة صفحات",
|
||||
"dataSource.notion.selector.configure": "تكوين Notion",
|
||||
"dataSource.notion.selector.docs": "وثائق Notion",
|
||||
"dataSource.notion.selector.headerTitle": "اختر صفحات Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "لا توجد نتائج بحث",
|
||||
"dataSource.notion.selector.pageSelected": "الصفحات المحددة",
|
||||
"dataSource.notion.selector.preview": "معاينة",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "هو نجاح. عند النجاح تكون القيمة 1، عند الفشل تكون القيمة 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "معلومات استخدام النموذج",
|
||||
"nodes.parameterExtractor.reasoningMode": "وضع التفكير",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "استدعاء دالة/أداة",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "موجّه",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "يمكنك اختيار وضع التفكير المناسب بناءً على قدرة النموذج على الاستجابة للتعليمات لاستدعاء الوظيفة أو المطالبات.",
|
||||
"nodes.questionClassifiers.addClass": "إضافة فئة",
|
||||
"nodes.questionClassifiers.advancedSetting": "إعدادات متقدمة",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Autorisierte Seiten",
|
||||
"dataSource.notion.remove": "Entfernen",
|
||||
"dataSource.notion.selector.addPages": "Seiten hinzufügen",
|
||||
"dataSource.notion.selector.configure": "Notion konfigurieren",
|
||||
"dataSource.notion.selector.docs": "Notion-Dokumentation",
|
||||
"dataSource.notion.selector.headerTitle": "Notion-Seiten auswählen",
|
||||
"dataSource.notion.selector.noSearchResult": "Keine Suchergebnisse",
|
||||
"dataSource.notion.selector.pageSelected": "Ausgewählte Seiten",
|
||||
"dataSource.notion.selector.preview": "VORSCHAU",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Ist Erfolg. Bei Erfolg beträgt der Wert 1, bei Misserfolg beträgt der Wert 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Nutzungsinformationen des Modells",
|
||||
"nodes.parameterExtractor.reasoningMode": "Schlussfolgerungsmodus",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Funktion/Tool-Aufruf",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Eingabeaufforderung",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Sie können den entsprechenden Schlussfolgerungsmodus basierend auf der Fähigkeit des Modells wählen, auf Anweisungen zur Funktionsaufruf- oder Eingabeaufforderungen zu reagieren.",
|
||||
"nodes.questionClassifiers.addClass": "Klasse hinzufügen",
|
||||
"nodes.questionClassifiers.advancedSetting": "Erweiterte Einstellung",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Is Success.On success the value is 1, on failure the value is 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Model Usage Information",
|
||||
"nodes.parameterExtractor.reasoningMode": "Reasoning Mode",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Function/Tool Calling",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Prompt",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "You can choose the appropriate reasoning mode based on the model's ability to respond to instructions for function calling or prompts.",
|
||||
"nodes.questionClassifiers.addClass": "Add Class",
|
||||
"nodes.questionClassifiers.advancedSetting": "Advanced Setting",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Páginas autorizadas",
|
||||
"dataSource.notion.remove": "Eliminar",
|
||||
"dataSource.notion.selector.addPages": "Agregar páginas",
|
||||
"dataSource.notion.selector.configure": "Configurar Notion",
|
||||
"dataSource.notion.selector.docs": "Documentación de Notion",
|
||||
"dataSource.notion.selector.headerTitle": "Elegir páginas de Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "No hay resultados de búsqueda",
|
||||
"dataSource.notion.selector.pageSelected": "Páginas seleccionadas",
|
||||
"dataSource.notion.selector.preview": "VISTA PREVIA",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Es éxito. En caso de éxito el valor es 1, en caso de fallo el valor es 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Información de uso del modelo",
|
||||
"nodes.parameterExtractor.reasoningMode": "Modo de razonamiento",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Función/Llamada de herramienta",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Prompt",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Puede elegir el modo de razonamiento apropiado basado en la capacidad del modelo para responder a instrucciones para llamadas de funciones o indicaciones.",
|
||||
"nodes.questionClassifiers.addClass": "Agregar clase",
|
||||
"nodes.questionClassifiers.advancedSetting": "Configuración avanzada",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "صفحات مجاز",
|
||||
"dataSource.notion.remove": "حذف",
|
||||
"dataSource.notion.selector.addPages": "افزودن صفحات",
|
||||
"dataSource.notion.selector.configure": "پیکربندی Notion",
|
||||
"dataSource.notion.selector.docs": "مستندات Notion",
|
||||
"dataSource.notion.selector.headerTitle": "صفحات Notion را انتخاب کنید",
|
||||
"dataSource.notion.selector.noSearchResult": "نتیجه جستجویی یافت نشد",
|
||||
"dataSource.notion.selector.pageSelected": "صفحات انتخاب شده",
|
||||
"dataSource.notion.selector.preview": "پیشنمایش",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "موفقیت (۱=موفق، ۰=ناموفق)",
|
||||
"nodes.parameterExtractor.outputVars.usage": "اطلاعات مصرف مدل",
|
||||
"nodes.parameterExtractor.reasoningMode": "حالت استدلال",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "فراخوانی تابع/ابزار",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "پیام",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "حالت استدلال مناسب را بر اساس توانایی مدل (Function Call یا Prompt) انتخاب کنید.",
|
||||
"nodes.questionClassifiers.addClass": "افزودن کلاس",
|
||||
"nodes.questionClassifiers.advancedSetting": "تنظیمات پیشرفته",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Pages autorisées",
|
||||
"dataSource.notion.remove": "Supprimer",
|
||||
"dataSource.notion.selector.addPages": "Ajouter des pages",
|
||||
"dataSource.notion.selector.configure": "Configurer Notion",
|
||||
"dataSource.notion.selector.docs": "Documentation Notion",
|
||||
"dataSource.notion.selector.headerTitle": "Choisir des pages Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "Aucun résultat de recherche",
|
||||
"dataSource.notion.selector.pageSelected": "Pages Sélectionnées",
|
||||
"dataSource.notion.selector.preview": "APERÇU",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Est réussi. En cas de succès, la valeur est 1, en cas d'échec, la valeur est 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Informations sur l'utilisation du modèle",
|
||||
"nodes.parameterExtractor.reasoningMode": "Mode de raisonnement",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Fonction/Appel d'outil",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Invite",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Vous pouvez choisir le mode de raisonnement approprié en fonction de la capacité du modèle à répondre aux instructions pour les appels de fonction ou les invites.",
|
||||
"nodes.questionClassifiers.addClass": "Ajouter une classe",
|
||||
"nodes.questionClassifiers.advancedSetting": "Paramètre avancé",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "अधिकृत पृष्ठ",
|
||||
"dataSource.notion.remove": "हटाएं",
|
||||
"dataSource.notion.selector.addPages": "पृष्ठ जोड़ें",
|
||||
"dataSource.notion.selector.configure": "Notion कॉन्फ़िगर करें",
|
||||
"dataSource.notion.selector.docs": "Notion दस्तावेज़",
|
||||
"dataSource.notion.selector.headerTitle": "Notion पृष्ठ चुनें",
|
||||
"dataSource.notion.selector.noSearchResult": "कोई खोज परिणाम नहीं",
|
||||
"dataSource.notion.selector.pageSelected": "चयनित पृष्ठ",
|
||||
"dataSource.notion.selector.preview": "पूर्वावलोकन",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "सफलता है। सफलता पर मान 1 है, असफलता पर मान 0 है।",
|
||||
"nodes.parameterExtractor.outputVars.usage": "मॉडल उपयोग जानकारी",
|
||||
"nodes.parameterExtractor.reasoningMode": "रीज़निंग मोड",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "फ़ंक्शन/टूल कॉलिंग",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "प्रॉम्प्ट",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "फ़ंक्शन कॉलिंग या प्रॉम्प्ट्स के लिए निर्देशों का जवाब देने की मॉडल की क्षमता के आधार पर उपयुक्त रीज़निंग मोड चुन सकते हैं।",
|
||||
"nodes.questionClassifiers.addClass": "क्लास जोड़ें",
|
||||
"nodes.questionClassifiers.advancedSetting": "उन्नत सेटिंग",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Halaman yang disahkan",
|
||||
"dataSource.notion.remove": "Hapus",
|
||||
"dataSource.notion.selector.addPages": "Tambahkan halaman",
|
||||
"dataSource.notion.selector.configure": "Konfigurasi Notion",
|
||||
"dataSource.notion.selector.docs": "Dokumentasi Notion",
|
||||
"dataSource.notion.selector.headerTitle": "Pilih halaman Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "Tidak ada hasil pencarian",
|
||||
"dataSource.notion.selector.pageSelected": "Halaman yang Dipilih",
|
||||
"dataSource.notion.selector.preview": "PRATAYANG",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Apakah Success.Pada keberhasilan nilainya adalah 1, pada kegagalan nilainya adalah 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Informasi Penggunaan Model",
|
||||
"nodes.parameterExtractor.reasoningMode": "Mode Penalaran",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Fungsi/Pemanggilan Alat",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Prompt",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Anda dapat memilih mode penalaran yang sesuai berdasarkan kemampuan model untuk menanggapi instruksi untuk pemanggilan fungsi atau perintah.",
|
||||
"nodes.questionClassifiers.addClass": "Tambahkan Kelas",
|
||||
"nodes.questionClassifiers.advancedSetting": "Pengaturan Lanjutan",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Pagine autorizzate",
|
||||
"dataSource.notion.remove": "Rimuovi",
|
||||
"dataSource.notion.selector.addPages": "Aggiungi pagine",
|
||||
"dataSource.notion.selector.configure": "Configura Notion",
|
||||
"dataSource.notion.selector.docs": "Documentazione Notion",
|
||||
"dataSource.notion.selector.headerTitle": "Scegli le pagine Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "Nessun risultato di ricerca",
|
||||
"dataSource.notion.selector.pageSelected": "Pagine selezionate",
|
||||
"dataSource.notion.selector.preview": "ANTEPRIMA",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "È successo. In caso di successo il valore è 1, in caso di fallimento il valore è 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Informazioni sull'utilizzo del modello",
|
||||
"nodes.parameterExtractor.reasoningMode": "Modalità di ragionamento",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Funzione/Chiamata strumento",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Prompt",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Puoi scegliere la modalità di ragionamento appropriata in base alla capacità del modello di rispondere alle istruzioni per la chiamata delle funzioni o i prompt.",
|
||||
"nodes.questionClassifiers.addClass": "Aggiungi Classe",
|
||||
"nodes.questionClassifiers.advancedSetting": "Impostazione Avanzata",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "認証済みページ",
|
||||
"dataSource.notion.remove": "削除",
|
||||
"dataSource.notion.selector.addPages": "ページの追加",
|
||||
"dataSource.notion.selector.configure": "Notionを設定する",
|
||||
"dataSource.notion.selector.docs": "Notionドキュメント",
|
||||
"dataSource.notion.selector.headerTitle": "Notionページを選択",
|
||||
"dataSource.notion.selector.noSearchResult": "検索結果なし",
|
||||
"dataSource.notion.selector.pageSelected": "選択済みページ",
|
||||
"dataSource.notion.selector.preview": "プレビュー",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "成功。成功した場合の値は 1、失敗した場合の値は 0 です。",
|
||||
"nodes.parameterExtractor.outputVars.usage": "モデル使用量",
|
||||
"nodes.parameterExtractor.reasoningMode": "推論モード",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "関数/ツール呼び出し",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "プロンプト",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "関数呼び出しやプロンプトの指示に応答するモデルの能力に基づいて、適切な推論モードを選択できます。",
|
||||
"nodes.questionClassifiers.addClass": "クラスを追加",
|
||||
"nodes.questionClassifiers.advancedSetting": "高度な設定",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "페이지가 허가됨",
|
||||
"dataSource.notion.remove": "제거하기",
|
||||
"dataSource.notion.selector.addPages": "페이지 추가하기",
|
||||
"dataSource.notion.selector.configure": "Notion 구성",
|
||||
"dataSource.notion.selector.docs": "Notion 문서",
|
||||
"dataSource.notion.selector.headerTitle": "Notion 페이지 선택",
|
||||
"dataSource.notion.selector.noSearchResult": "검색 결과 없음",
|
||||
"dataSource.notion.selector.pageSelected": "페이지 선택됨",
|
||||
"dataSource.notion.selector.preview": "미리보기",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "성공 여부. 성공 시 값은 1 이고, 실패 시 값은 0 입니다.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "모델 사용 정보",
|
||||
"nodes.parameterExtractor.reasoningMode": "추론 모드",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "함수/도구 호출",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "프롬프트",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "모델의 함수 호출 또는 프롬프트에 대한 지시 응답 능력을 기반으로 적절한 추론 모드를 선택할 수 있습니다.",
|
||||
"nodes.questionClassifiers.addClass": "클래스 추가",
|
||||
"nodes.questionClassifiers.advancedSetting": "고급 설정",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Pages authorized",
|
||||
"dataSource.notion.remove": "Remove",
|
||||
"dataSource.notion.selector.addPages": "Add pages",
|
||||
"dataSource.notion.selector.configure": "Notion configureren",
|
||||
"dataSource.notion.selector.docs": "Notion-documentatie",
|
||||
"dataSource.notion.selector.headerTitle": "Notion-pagina's kiezen",
|
||||
"dataSource.notion.selector.noSearchResult": "No search results",
|
||||
"dataSource.notion.selector.pageSelected": "Pages Selected",
|
||||
"dataSource.notion.selector.preview": "PREVIEW",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Is Success.On success the value is 1, on failure the value is 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Model Usage Information",
|
||||
"nodes.parameterExtractor.reasoningMode": "Reasoning Mode",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Functie/Tool-aanroep",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Prompt",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "You can choose the appropriate reasoning mode based on the model's ability to respond to instructions for function calling or prompts.",
|
||||
"nodes.questionClassifiers.addClass": "Add Class",
|
||||
"nodes.questionClassifiers.advancedSetting": "Advanced Setting",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Strony autoryzowane",
|
||||
"dataSource.notion.remove": "Usuń",
|
||||
"dataSource.notion.selector.addPages": "Dodaj strony",
|
||||
"dataSource.notion.selector.configure": "Skonfiguruj Notion",
|
||||
"dataSource.notion.selector.docs": "Dokumentacja Notion",
|
||||
"dataSource.notion.selector.headerTitle": "Wybierz strony Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "Brak wyników wyszukiwania",
|
||||
"dataSource.notion.selector.pageSelected": "Zaznaczone strony",
|
||||
"dataSource.notion.selector.preview": "PODGLĄD",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Czy się udało. W przypadku sukcesu wartość wynosi 1, w przypadku niepowodzenia wartość wynosi 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Informacje o użyciu modelu",
|
||||
"nodes.parameterExtractor.reasoningMode": "Tryb wnioskowania",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Funkcja/Wywołanie narzędzia",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Prompt",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Możesz wybrać odpowiedni tryb wnioskowania w zależności od zdolności modelu do reagowania na instrukcje dotyczące wywoływania funkcji lub zapytań.",
|
||||
"nodes.questionClassifiers.addClass": "Dodaj klasę",
|
||||
"nodes.questionClassifiers.advancedSetting": "Zaawansowane ustawienia",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Páginas autorizadas",
|
||||
"dataSource.notion.remove": "Remover",
|
||||
"dataSource.notion.selector.addPages": "Adicionar páginas",
|
||||
"dataSource.notion.selector.configure": "Configurar Notion",
|
||||
"dataSource.notion.selector.docs": "Documentação do Notion",
|
||||
"dataSource.notion.selector.headerTitle": "Escolher páginas do Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "Nenhum resultado de pesquisa",
|
||||
"dataSource.notion.selector.pageSelected": "Páginas Selecionadas",
|
||||
"dataSource.notion.selector.preview": "PRÉ-VISUALIZAÇÃO",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "É sucesso. Em caso de sucesso, o valor é 1, em caso de falha, o valor é 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Informações de uso do modelo",
|
||||
"nodes.parameterExtractor.reasoningMode": "Modo de raciocínio",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Função/Chamada de Ferramenta",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Prompt",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Você pode escolher o modo de raciocínio apropriado com base na capacidade do modelo de responder a instruções para chamadas de função ou prompts.",
|
||||
"nodes.questionClassifiers.addClass": "Adicionar classe",
|
||||
"nodes.questionClassifiers.advancedSetting": "Configuração avançada",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Pagini autorizate",
|
||||
"dataSource.notion.remove": "Elimină",
|
||||
"dataSource.notion.selector.addPages": "Adăugați pagini",
|
||||
"dataSource.notion.selector.configure": "Configurare Notion",
|
||||
"dataSource.notion.selector.docs": "Documentație Notion",
|
||||
"dataSource.notion.selector.headerTitle": "Alegeți paginile Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "Niciun rezultat la căutare",
|
||||
"dataSource.notion.selector.pageSelected": "Pagini selectate",
|
||||
"dataSource.notion.selector.preview": "PREVIZUALIZARE",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Este succes. În caz de succes valoarea este 1, în caz de eșec valoarea este 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Informații de utilizare a modelului",
|
||||
"nodes.parameterExtractor.reasoningMode": "Mod de raționament",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Funcție/Apel instrument",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Prompt",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Puteți alege modul de raționament potrivit în funcție de capacitatea modelului de a răspunde la instrucțiuni pentru apelarea funcțiilor sau prompturi.",
|
||||
"nodes.questionClassifiers.addClass": "Adăugați clasă",
|
||||
"nodes.questionClassifiers.advancedSetting": "Setare avansată",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Авторизованные страницы",
|
||||
"dataSource.notion.remove": "Удалить",
|
||||
"dataSource.notion.selector.addPages": "Добавить страницы",
|
||||
"dataSource.notion.selector.configure": "Настроить Notion",
|
||||
"dataSource.notion.selector.docs": "Документация Notion",
|
||||
"dataSource.notion.selector.headerTitle": "Выберите страницы Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "Нет результатов поиска",
|
||||
"dataSource.notion.selector.pageSelected": "Выбранные страницы",
|
||||
"dataSource.notion.selector.preview": "ПРЕДПРОСМОТР",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Успешно. В случае успеха значение равно 1, в случае сбоя - 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Информация об использовании модели",
|
||||
"nodes.parameterExtractor.reasoningMode": "Режим рассуждения",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Вызов функции/инструмента",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Подсказка",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Вы можете выбрать соответствующий режим рассуждения, основываясь на способности модели реагировать на инструкции для вызова функций или подсказки.",
|
||||
"nodes.questionClassifiers.addClass": "Добавить класс",
|
||||
"nodes.questionClassifiers.advancedSetting": "Расширенные настройки",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Dovoljene strani",
|
||||
"dataSource.notion.remove": "Odstrani",
|
||||
"dataSource.notion.selector.addPages": "Dodajanje strani",
|
||||
"dataSource.notion.selector.configure": "Konfiguriraj Notion",
|
||||
"dataSource.notion.selector.docs": "Dokumentacija Notion",
|
||||
"dataSource.notion.selector.headerTitle": "Izberite strani Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "Ni rezultatov iskanja",
|
||||
"dataSource.notion.selector.pageSelected": "Izbrane strani",
|
||||
"dataSource.notion.selector.preview": "PREDOGLED",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Ali je uspeh. Na uspehu je vrednost 1, na neuspehu je vrednost 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Informacije o uporabi modela",
|
||||
"nodes.parameterExtractor.reasoningMode": "Način razmišljanja",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Klic funkcije/orodja",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Poziv",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Lahko izberete ustrezen način razmišljanja glede na sposobnost modela, da se odzove na navodila za klic funkcij ali pozive.",
|
||||
"nodes.questionClassifiers.addClass": "Dodaj razred",
|
||||
"nodes.questionClassifiers.advancedSetting": "Napredno nastavitev",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "เพจที่ได้รับอนุญาต",
|
||||
"dataSource.notion.remove": "ถอด",
|
||||
"dataSource.notion.selector.addPages": "เพิ่มหน้า",
|
||||
"dataSource.notion.selector.configure": "กำหนดค่า Notion",
|
||||
"dataSource.notion.selector.docs": "เอกสาร Notion",
|
||||
"dataSource.notion.selector.headerTitle": "เลือกหน้า Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "ไม่มีผลการค้นหา",
|
||||
"dataSource.notion.selector.pageSelected": "หน้าที่เลือก",
|
||||
"dataSource.notion.selector.preview": "ดูตัวอย่าง",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "คือ Success เมื่อสําเร็จค่าคือ 1 เมื่อล้มเหลวค่าเป็น 0",
|
||||
"nodes.parameterExtractor.outputVars.usage": "ข้อมูลการใช้งานรุ่น",
|
||||
"nodes.parameterExtractor.reasoningMode": "โหมดการให้เหตุผล",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "ฟังก์ชัน/การเรียกใช้เครื่องมือ",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "พรอมต์",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "คุณสามารถเลือกโหมดการให้เหตุผลที่เหมาะสมตามความสามารถของโมเดลในการตอบสนองต่อคําแนะนําสําหรับการเรียกใช้ฟังก์ชันหรือข้อความแจ้ง",
|
||||
"nodes.questionClassifiers.addClass": "เพิ่มชั้นเรียน",
|
||||
"nodes.questionClassifiers.advancedSetting": "การตั้งค่าขั้นสูง",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Yetkilendirilen sayfalar",
|
||||
"dataSource.notion.remove": "Kaldır",
|
||||
"dataSource.notion.selector.addPages": "Sayfa ekle",
|
||||
"dataSource.notion.selector.configure": "Notion'ı Yapılandır",
|
||||
"dataSource.notion.selector.docs": "Notion belgeleri",
|
||||
"dataSource.notion.selector.headerTitle": "Notion sayfalarını seçin",
|
||||
"dataSource.notion.selector.noSearchResult": "Arama sonucu yok",
|
||||
"dataSource.notion.selector.pageSelected": "Seçilen Sayfalar",
|
||||
"dataSource.notion.selector.preview": "ÖNİZLEME",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Başarılı mı. Başarılı olduğunda değer 1, başarısız olduğunda değer 0'dır.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Model Kullanım Bilgileri",
|
||||
"nodes.parameterExtractor.reasoningMode": "Akıl Yürütme Modu",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Fonksiyon/Araç Çağrısı",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Prompt",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Modelin fonksiyon çağırma veya istemler için talimatlara yanıt verme yeteneğine bağlı olarak uygun akıl yürütme modunu seçebilirsiniz.",
|
||||
"nodes.questionClassifiers.addClass": "Sınıf Ekle",
|
||||
"nodes.questionClassifiers.advancedSetting": "Gelişmiş Ayarlar",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Авторизовані сторінки",
|
||||
"dataSource.notion.remove": "Видалити",
|
||||
"dataSource.notion.selector.addPages": "Додати сторінки",
|
||||
"dataSource.notion.selector.configure": "Налаштувати Notion",
|
||||
"dataSource.notion.selector.docs": "Документація Notion",
|
||||
"dataSource.notion.selector.headerTitle": "Виберіть сторінки Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "Результатів пошуку немає",
|
||||
"dataSource.notion.selector.pageSelected": "Сторінки вибрано",
|
||||
"dataSource.notion.selector.preview": "ПЕРЕДПЕРЕГЛЯД",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Є успіх. У разі успіху значення 1, у разі невдачі значення 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Інформація про використання моделі",
|
||||
"nodes.parameterExtractor.reasoningMode": "Режим інференції",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Виклик функції/інструменту",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Підказка",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Ви можете вибрати відповідний режим інференції залежно від здатності моделі реагувати на інструкції щодо викликів функцій або запитів.",
|
||||
"nodes.questionClassifiers.addClass": "Додати клас",
|
||||
"nodes.questionClassifiers.advancedSetting": "Розширене налаштування",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "Các trang được ủy quyền",
|
||||
"dataSource.notion.remove": "Xóa",
|
||||
"dataSource.notion.selector.addPages": "Thêm trang",
|
||||
"dataSource.notion.selector.configure": "Cấu hình Notion",
|
||||
"dataSource.notion.selector.docs": "Tài liệu Notion",
|
||||
"dataSource.notion.selector.headerTitle": "Chọn các trang Notion",
|
||||
"dataSource.notion.selector.noSearchResult": "Không có kết quả tìm kiếm",
|
||||
"dataSource.notion.selector.pageSelected": "Các trang đã chọn",
|
||||
"dataSource.notion.selector.preview": "Xem trước",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "Thành công. Khi thành công giá trị là 1, khi thất bại giá trị là 0.",
|
||||
"nodes.parameterExtractor.outputVars.usage": "Thông tin sử dụng mô hình",
|
||||
"nodes.parameterExtractor.reasoningMode": "Chế độ suy luận",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Hàm/Gọi công cụ",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Prompt",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Bạn có thể chọn chế độ suy luận phù hợp dựa trên khả năng của mô hình để phản hồi các hướng dẫn về việc gọi hàm hoặc prompt.",
|
||||
"nodes.questionClassifiers.addClass": "Thêm lớp",
|
||||
"nodes.questionClassifiers.advancedSetting": "Cài đặt nâng cao",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "已授权页面",
|
||||
"dataSource.notion.remove": "删除",
|
||||
"dataSource.notion.selector.addPages": "添加页面",
|
||||
"dataSource.notion.selector.configure": "配置 Notion",
|
||||
"dataSource.notion.selector.docs": "Notion 文档",
|
||||
"dataSource.notion.selector.headerTitle": "选择 Notion 页面",
|
||||
"dataSource.notion.selector.noSearchResult": "无搜索结果",
|
||||
"dataSource.notion.selector.pageSelected": "已选页面",
|
||||
"dataSource.notion.selector.preview": "预览",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "是否成功。成功时值为 1,失败时值为 0。",
|
||||
"nodes.parameterExtractor.outputVars.usage": "模型用量信息",
|
||||
"nodes.parameterExtractor.reasoningMode": "推理模式",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "函数/工具调用",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "提示词",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "你可以根据模型对于 Function calling 或 Prompt 的指令响应能力选择合适的推理模式",
|
||||
"nodes.questionClassifiers.addClass": "添加分类",
|
||||
"nodes.questionClassifiers.advancedSetting": "高级设置",
|
||||
|
||||
@ -135,6 +135,9 @@
|
||||
"dataSource.notion.pagesAuthorized": "已授權頁面",
|
||||
"dataSource.notion.remove": "刪除",
|
||||
"dataSource.notion.selector.addPages": "新增頁面",
|
||||
"dataSource.notion.selector.configure": "配置 Notion",
|
||||
"dataSource.notion.selector.docs": "Notion 文件",
|
||||
"dataSource.notion.selector.headerTitle": "選擇 Notion 頁面",
|
||||
"dataSource.notion.selector.noSearchResult": "無搜尋結果",
|
||||
"dataSource.notion.selector.pageSelected": "已選頁面",
|
||||
"dataSource.notion.selector.preview": "預覽",
|
||||
|
||||
@ -856,6 +856,8 @@
|
||||
"nodes.parameterExtractor.outputVars.isSuccess": "是否成功。成功時值為 1,失敗時值為 0。",
|
||||
"nodes.parameterExtractor.outputVars.usage": "模型用量信息",
|
||||
"nodes.parameterExtractor.reasoningMode": "推理模式",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "函數/工具調用",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "提示詞",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "你可以根據模型對於 Function calling 或 Prompt 的指令響應能力選擇合適的推理模式",
|
||||
"nodes.questionClassifiers.addClass": "新增分類",
|
||||
"nodes.questionClassifiers.advancedSetting": "高級設置",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user