feat: run with params from logs (#26787)

Co-authored-by: lyzno1 <yuanyouhuilyz@gmail.com>
Co-authored-by: lyzno1 <92089059+lyzno1@users.noreply.github.com>
This commit is contained in:
wellCh4n
2025-10-16 11:01:11 +08:00
committed by GitHub
parent f295c7532c
commit 35011b810d
24 changed files with 119 additions and 4 deletions

View File

@@ -1,9 +1,11 @@
'use client'
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { RiCloseLine } from '@remixicon/react'
import { RiCloseLine, RiPlayLargeLine } from '@remixicon/react'
import Run from '@/app/components/workflow/run'
import { useStore } from '@/app/components/app/store'
import TooltipPlus from '@/app/components/base/tooltip'
import { useRouter } from 'next/navigation'
type ILogDetail = {
runID: string
@@ -13,13 +15,34 @@ type ILogDetail = {
const DetailPanel: FC<ILogDetail> = ({ runID, onClose }) => {
const { t } = useTranslation()
const appDetail = useStore(state => state.appDetail)
const router = useRouter()
const handleReplay = () => {
if (!appDetail?.id) return
router.push(`/app/${appDetail.id}/workflow?replayRunId=${runID}`)
}
return (
<div className='relative flex grow flex-col pt-3'>
<span className='absolute right-3 top-4 z-20 cursor-pointer p-1' onClick={onClose}>
<RiCloseLine className='h-4 w-4 text-text-tertiary' />
</span>
<h1 className='system-xl-semibold shrink-0 px-4 py-1 text-text-primary'>{t('appLog.runDetail.workflowTitle')}</h1>
<div className='flex items-center bg-components-panel-bg'>
<h1 className='system-xl-semibold shrink-0 px-4 py-1 text-text-primary'>{t('appLog.runDetail.workflowTitle')}</h1>
<TooltipPlus
popupContent={t('appLog.runDetail.testWithParams')}
popupClassName='rounded-xl'
>
<button
type='button'
className='mr-1 flex h-6 w-6 items-center justify-center rounded-md hover:bg-state-base-hover'
aria-label={t('appLog.runDetail.testWithParams')}
onClick={handleReplay}
>
<RiPlayLargeLine className='h-4 w-4 text-text-tertiary' />
</button>
</TooltipPlus>
</div>
<Run
runDetailUrl={runID ? `/apps/${appDetail?.id}/workflow-runs/${runID}` : ''}
tracingListUrl={runID ? `/apps/${appDetail?.id}/workflow-runs/${runID}/node-executions` : ''}

View File

@@ -1,6 +1,7 @@
'use client'
import {
useEffect,
useMemo,
} from 'react'
import {
@@ -23,8 +24,13 @@ import {
WorkflowContextProvider,
} from '@/app/components/workflow/context'
import type { InjectWorkflowStoreSliceFn } from '@/app/components/workflow/store'
import { useWorkflowStore } from '@/app/components/workflow/store'
import { createWorkflowSlice } from './store/workflow/workflow-slice'
import WorkflowAppMain from './components/workflow-main'
import { useSearchParams } from 'next/navigation'
import { fetchRunDetail } from '@/service/log'
import { useGetRunAndTraceUrl } from './hooks/use-get-run-and-trace-url'
const WorkflowAppWithAdditionalContext = () => {
const {
@@ -47,6 +53,71 @@ const WorkflowAppWithAdditionalContext = () => {
return []
}, [data])
const searchParams = useSearchParams()
const workflowStore = useWorkflowStore()
const { getWorkflowRunAndTraceUrl } = useGetRunAndTraceUrl()
const replayRunId = searchParams.get('replayRunId')
useEffect(() => {
if (!replayRunId)
return
const { runUrl } = getWorkflowRunAndTraceUrl(replayRunId)
if (!runUrl)
return
fetchRunDetail(runUrl).then((res) => {
const { setInputs, setShowInputsPanel, setShowDebugAndPreviewPanel } = workflowStore.getState()
const rawInputs = res.inputs
let parsedInputs: Record<string, unknown> | null = null
if (typeof rawInputs === 'string') {
try {
const maybeParsed = JSON.parse(rawInputs) as unknown
if (maybeParsed && typeof maybeParsed === 'object' && !Array.isArray(maybeParsed))
parsedInputs = maybeParsed as Record<string, unknown>
}
catch (error) {
console.error('Failed to parse workflow run inputs', error)
}
}
else if (rawInputs && typeof rawInputs === 'object' && !Array.isArray(rawInputs)) {
parsedInputs = rawInputs as Record<string, unknown>
}
if (!parsedInputs)
return
const userInputs: Record<string, string> = {}
Object.entries(parsedInputs).forEach(([key, value]) => {
if (key.startsWith('sys.'))
return
if (value == null) {
userInputs[key] = ''
return
}
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
userInputs[key] = value
return
}
try {
userInputs[key] = JSON.stringify(value)
}
catch {
userInputs[key] = String(value)
}
})
if (!Object.keys(userInputs).length)
return
setInputs(userInputs)
setShowInputsPanel(true)
setShowDebugAndPreviewPanel(true)
})
}, [replayRunId, workflowStore, getWorkflowRunAndTraceUrl])
if (!data || isLoading || isLoadingCurrentWorkspace || !currentWorkspace.id) {
return (
<div className='relative flex h-full w-full items-center justify-center'>

View File

@@ -4,8 +4,8 @@ import type {
} from '@/app/components/workflow/types'
export type FormSliceShape = {
inputs: Record<string, string>
setInputs: (inputs: Record<string, string>) => void
inputs: Record<string, string | number | boolean>
setInputs: (inputs: Record<string, string | number | boolean>) => void
files: RunFile[]
setFiles: (files: RunFile[]) => void
}

View File

@@ -83,6 +83,7 @@ const translation = {
workflowTitle: 'Protokolldetail',
fileListLabel: 'Details zur Datei',
fileListDetail: 'Detail',
testWithParams: 'Test mit Parametern',
},
promptLog: 'Prompt-Protokoll',
agentLog: 'Agentenprotokoll',

View File

@@ -83,6 +83,7 @@ const translation = {
workflowTitle: 'Log Detail',
fileListLabel: 'File Details',
fileListDetail: 'Detail',
testWithParams: 'Test With Params',
},
promptLog: 'Prompt Log',
agentLog: 'Agent Log',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: 'Detalle del Registro',
fileListLabel: 'Detalles del archivo',
fileListDetail: 'Detalle',
testWithParams: 'Prueba con parámetros',
},
promptLog: 'Registro de Indicación',
agentLog: 'Registro de Agente',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: 'جزئیات لاگ',
fileListLabel: 'جزئیات فایل',
fileListDetail: 'جزئیات',
testWithParams: 'تست با پارامترها',
},
promptLog: 'لاگ درخواست',
agentLog: 'لاگ عامل',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: 'Détail du journal',
fileListDetail: 'Détail',
fileListLabel: 'Détails du fichier',
testWithParams: 'Test avec paramètres',
},
promptLog: 'Journal de consigne',
agentLog: 'Journal des agents',

View File

@@ -84,6 +84,7 @@ const translation = {
workflowTitle: 'लॉग विवरण',
fileListDetail: 'विस्तार',
fileListLabel: 'फ़ाइल विवरण',
testWithParams: 'पैरामीटर्स के साथ परीक्षण',
},
promptLog: 'प्रॉम्प्ट लॉग',
agentLog: 'एजेंट लॉग',

View File

@@ -74,6 +74,7 @@ const translation = {
workflowTitle: 'Log Detail',
title: 'Log Percakapan',
fileListLabel: 'Rincian File',
testWithParams: 'Uji Dengan Param',
},
agentLogDetail: {
iterations: 'Iterasi',

View File

@@ -86,6 +86,7 @@ const translation = {
workflowTitle: 'Dettagli Registro',
fileListDetail: 'Dettaglio',
fileListLabel: 'Dettagli del file',
testWithParams: 'Test con parametri',
},
promptLog: 'Registro Prompt',
agentLog: 'Registro Agente',

View File

@@ -83,6 +83,7 @@ const translation = {
workflowTitle: 'ログの詳細',
fileListLabel: 'ファイルの詳細',
fileListDetail: '詳細',
testWithParams: 'パラメータ付きテスト',
},
promptLog: 'プロンプトログ',
agentLog: 'エージェントログ',

View File

@@ -83,6 +83,7 @@ const translation = {
workflowTitle: '로그 세부 정보',
fileListDetail: '세부',
fileListLabel: '파일 세부 정보',
testWithParams: '매개변수로 테스트',
},
promptLog: '프롬프트 로그',
agentLog: '에이전트 로그',

View File

@@ -86,6 +86,7 @@ const translation = {
workflowTitle: 'Szczegół dziennika',
fileListDetail: 'Detal',
fileListLabel: 'Szczegóły pliku',
testWithParams: 'Test z parametrami',
},
promptLog: 'Dziennik monitów',
agentLog: 'Dziennik agenta',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: 'Detalhes do Registro',
fileListLabel: 'Detalhes do arquivo',
fileListDetail: 'Detalhe',
testWithParams: 'Teste com parâmetros',
},
promptLog: 'Registro de Prompt',
agentLog: 'Registro do agente',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: 'Detalii jurnal',
fileListDetail: 'Amănunt',
fileListLabel: 'Detalii fișier',
testWithParams: 'Test cu parametri',
},
promptLog: 'Jurnal prompt',
agentLog: 'Jurnal agent',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: 'Подробная информация о журнале',
fileListLabel: 'Сведения о файле',
fileListDetail: 'Подробность',
testWithParams: 'Тест с параметрами',
},
promptLog: 'Журнал подсказок',
agentLog: 'Журнал агента',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: 'Podrobnosti dnevnika',
fileListDetail: 'Podrobnosti',
fileListLabel: 'Podrobnosti o datoteki',
testWithParams: 'Preizkus s parametri',
},
promptLog: 'Dnevnik PROMPT-ov',
agentLog: 'Dnevnik pomočnika',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: 'รายละเอียดบันทึก',
fileListDetail: 'รายละเอียด',
fileListLabel: 'รายละเอียดไฟล์',
testWithParams: 'ทดสอบด้วยพารามิเตอร์',
},
promptLog: 'บันทึกพร้อมท์',
agentLog: 'บันทึกตัวแทน',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: 'Günlük Detayı',
fileListDetail: 'Ayrıntı',
fileListLabel: 'Dosya Detayları',
testWithParams: 'Parametrelerle Test',
},
promptLog: 'Prompt Günlüğü',
agentLog: 'Agent Günlüğü',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: 'Деталі Журналу',
fileListDetail: 'Деталь',
fileListLabel: 'Подробиці файлу',
testWithParams: 'Тест з параметрами',
},
promptLog: 'Журнал Запитань',
agentLog: 'Журнал агента',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: 'Chi tiết nhật ký',
fileListDetail: 'Chi tiết',
fileListLabel: 'Chi tiết tệp',
testWithParams: 'Kiểm tra với các tham số',
},
promptLog: 'Nhật ký lời nhắc',
viewLog: 'Xem nhật ký',

View File

@@ -83,6 +83,7 @@ const translation = {
workflowTitle: '日志详情',
fileListLabel: '文件详情',
fileListDetail: '详情',
testWithParams: '按此参数测试',
},
promptLog: 'Prompt 日志',
agentLog: 'Agent 日志',

View File

@@ -82,6 +82,7 @@ const translation = {
workflowTitle: '日誌詳情',
fileListDetail: '細節',
fileListLabel: '檔詳細資訊',
testWithParams: '使用參數測試',
},
promptLog: 'Prompt 日誌',
agentLog: 'Agent 日誌',