mirror of
https://github.com/langgenius/dify.git
synced 2026-06-07 16:32:01 +08:00
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
116 lines
4.0 KiB
TypeScript
116 lines
4.0 KiB
TypeScript
import type { HitlPausePayload } from './sse-collector'
|
|
import { colorEnabled, colorScheme } from '@/sys/io/color'
|
|
|
|
export type HitlExitObject = {
|
|
status: 'paused'
|
|
app_id: string
|
|
task_id: string
|
|
workflow_run_id: string
|
|
form_id: string
|
|
node_id: string
|
|
node_title: string
|
|
form_token: string | null
|
|
form_content: string
|
|
inputs: unknown[]
|
|
actions: unknown[]
|
|
display_in_ui: boolean
|
|
resolved_default_values: Record<string, string>
|
|
expiration_time: number
|
|
}
|
|
|
|
export function buildHitlExitObject(appId: string, payload: HitlPausePayload): HitlExitObject {
|
|
const d = payload.data
|
|
return {
|
|
status: 'paused',
|
|
app_id: appId,
|
|
task_id: payload.task_id,
|
|
workflow_run_id: payload.workflow_run_id,
|
|
form_id: d.form_id,
|
|
node_id: d.node_id,
|
|
node_title: d.node_title,
|
|
form_token: d.form_token,
|
|
form_content: d.form_content,
|
|
inputs: d.inputs,
|
|
actions: d.actions,
|
|
display_in_ui: d.display_in_ui,
|
|
resolved_default_values: d.resolved_default_values,
|
|
expiration_time: d.expiration_time,
|
|
}
|
|
}
|
|
|
|
export function renderHitlExit(obj: HitlExitObject): string {
|
|
return JSON.stringify(obj, null, 2)
|
|
}
|
|
|
|
type ActionRecord = { id: string, title?: string, button_style?: string }
|
|
type InputRecord = { output_variable_name?: string, label?: string, type?: string, required?: boolean }
|
|
|
|
export function renderHitlBlock(_appId: string, payload: HitlPausePayload, isTTY: boolean): string {
|
|
const d = payload.data
|
|
const cs = colorScheme(colorEnabled(isTTY))
|
|
const lines: string[] = []
|
|
lines.push(`${cs.warningIcon()} ${cs.bold('Workflow paused')} ${cs.dim('— input required')}`)
|
|
lines.push(` ${cs.dim('Node:')} ${d.node_title}`)
|
|
const msgLines = d.form_content.split('\n')
|
|
if (msgLines.length === 1) {
|
|
lines.push(` ${cs.dim('Message:')} ${d.form_content}`)
|
|
}
|
|
else {
|
|
lines.push(` ${cs.dim('Message:')}`)
|
|
for (const ml of msgLines)
|
|
lines.push(` ${ml}`)
|
|
}
|
|
|
|
const actions = (Array.isArray(d.actions) ? d.actions : []) as ActionRecord[]
|
|
if (actions.length > 0) {
|
|
const inline = actions.map((a) => {
|
|
const title = a.title ?? ''
|
|
return `${cs.cyan(`[${a.id}]`)} ${title}`
|
|
}).join(' ')
|
|
lines.push(` ${cs.dim('Actions:')} ${inline}`)
|
|
}
|
|
|
|
const inputs = (Array.isArray(d.inputs) ? d.inputs : []) as InputRecord[]
|
|
if (inputs.length > 0) {
|
|
const inline = inputs.map((inp) => {
|
|
const name = inp.output_variable_name ?? '?'
|
|
const label = typeof inp.label === 'string' && inp.label !== '' ? ` ${cs.dim(`— ${inp.label}`)}` : ''
|
|
const req = inp.required === true ? ` ${cs.yellow('*')}` : ''
|
|
return `- ${cs.cyan(name)}${req}${label}`
|
|
}).join(' ')
|
|
lines.push(` ${cs.dim('Inputs:')} ${inline}`)
|
|
}
|
|
|
|
lines.push('')
|
|
return `${lines.join('\n')}\n`
|
|
}
|
|
|
|
export function renderHitlOutput(appId: string, payload: HitlPausePayload, isText: boolean, isOutTTY: boolean): string {
|
|
if (isText)
|
|
return renderHitlBlock(appId, payload, isOutTTY)
|
|
const obj = buildHitlExitObject(appId, payload)
|
|
return `${renderHitlExit(obj)}\n`
|
|
}
|
|
|
|
const EXTERNAL_CHANNEL_NOTE = 'form delivered via email/external channel — resume only from that channel'
|
|
|
|
export function renderHitlHint(appId: string, payload: HitlPausePayload, isErrTTY: boolean): string {
|
|
const d = payload.data
|
|
const cs = colorScheme(colorEnabled(isErrTTY))
|
|
if (d.form_token === null) {
|
|
if (!isErrTTY)
|
|
return `hint: workflow paused — ${EXTERNAL_CHANNEL_NOTE}\n`
|
|
return `${cs.warningIcon()} ${cs.bold('workflow paused')} — ${cs.dim(EXTERNAL_CHANNEL_NOTE)}\n`
|
|
}
|
|
const actions = (d.actions ?? []) as { id: string }[]
|
|
let cmd = `difyctl resume app ${appId} ${d.form_token} --workflow-run-id ${payload.workflow_run_id}`
|
|
if (actions.length > 1) {
|
|
const firstAction = actions[0]?.id
|
|
if (firstAction !== undefined)
|
|
cmd += ` --action ${firstAction}`
|
|
}
|
|
if (!isErrTTY)
|
|
return `hint: workflow paused — resume with: ${cmd}\n`
|
|
return `${cs.warningIcon()} ${cs.bold('workflow paused')} — resume with:\n ${cs.cyan(cmd)}\n`
|
|
}
|