feat(flow): 新增流式执行模式与SSE支持
新增流式执行模式,通过SSE实时推送节点执行事件与日志 重构HTTP执行器与中间件,提取通用HTTP客户端组件 优化前端测试面板,支持流式模式切换与实时日志展示 更新依赖版本并修复密码哈希的随机数生成器问题 修复前端节点类型映射问题,确保Code节点表单可用
This commit is contained in:
@ -14,9 +14,16 @@ import { Toast } from '@douyinfe/semi-ui';
|
||||
import { I18n } from '@flowgram.ai/free-layout-editor';
|
||||
import api, { type ApiResp } from '../../utils/axios';
|
||||
import { stringifyFlowDoc } from '../utils/yaml';
|
||||
import { postSSE } from '../../utils/sse';
|
||||
|
||||
interface RunResult { ok: boolean; ctx: any; logs: string[] }
|
||||
|
||||
// 与后端 StreamEvent 保持一致(serde(tag = "type"))
|
||||
export type StreamEvent =
|
||||
| { type: 'node'; node_id?: string; ctx?: any; logs?: string[] }
|
||||
| { type: 'done'; ok: boolean; ctx: any; logs: string[] }
|
||||
| { type: 'error'; message: string };
|
||||
|
||||
// 兼容 BrowserRouter 与 HashRouter:优先从 search 获取,若无则从 hash 的查询串中获取
|
||||
function getFlowIdFromUrl(): string {
|
||||
const searchId = new URLSearchParams(window.location.search).get('id');
|
||||
@ -116,4 +123,40 @@ export class CustomService {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:SSE 流式运行,返回取消函数与完成 Promise
|
||||
runStream(input: any = {}, handlers?: { onNode?: (e: StreamEvent & { type: 'node' }) => void; onDone?: (e: StreamEvent & { type: 'done' }) => void; onError?: (e: StreamEvent & { type: 'error' }) => void; onFatal?: (err: Error) => void; }) {
|
||||
const id = getFlowIdFromUrl();
|
||||
if (!id) {
|
||||
const err = new Error(I18n.t('Flow ID is missing, cannot run'));
|
||||
handlers?.onFatal?.(err);
|
||||
return { cancel: () => {}, done: Promise.resolve<RunResult | null>(null) } as const;
|
||||
}
|
||||
|
||||
const base = (api.defaults.baseURL || '') as string;
|
||||
const url = base ? `${base}/flows/${id}/run/stream` : `/flows/${id}/run/stream`;
|
||||
|
||||
const { cancel, done } = postSSE<RunResult | null>(url, { input }, {
|
||||
onMessage: (json: any) => {
|
||||
try {
|
||||
const evt = json as StreamEvent
|
||||
if (evt.type === 'node') {
|
||||
handlers?.onNode?.(evt as any)
|
||||
return undefined
|
||||
}
|
||||
if (evt.type === 'error') {
|
||||
handlers?.onError?.(evt as any)
|
||||
return undefined
|
||||
}
|
||||
if (evt.type === 'done') {
|
||||
handlers?.onDone?.(evt as any)
|
||||
return { ok: evt.ok, ctx: evt.ctx, logs: evt.logs }
|
||||
}
|
||||
} catch (_) {}
|
||||
return undefined
|
||||
},
|
||||
onFatal: (e) => handlers?.onFatal?.(e),
|
||||
})
|
||||
return { cancel, done } as const;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user