chore: initial commit

This commit is contained in:
2026-10-22 17:07:08 +08:00
commit 0acef64f48
200 changed files with 35546 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
import type {NodeHandler} from '../../../types/bot/workflow/runtime.ts';
import type {WorkflowNodeTemplate} from '../../../types/bot/workflow/metadata.ts';
import {describe, failure_port, output, port} from '../metadata.ts';
import {assert_json} from '../runtime/value.ts';
export const config_template: WorkflowNodeTemplate = {
name: 'goto', version: '1.0.0',
i18n: describe('重试跳转', '按当前节点的重试计数限制跳转次数,重试目标由 retry 出口连线指定。'),
config: [
{name: 'max_retries', type: 'number', required: true, default: 2, integer: true, min: 0, max: 10_000,
i18n: describe('最大重试次数', '允许经过 retry 出口的次数;0 表示直接进入次数耗尽分支,默认允许重试 2 次。')},
{name: 'delay_ms', type: 'number', required: true, default: 0, integer: true, min: 0, max: 2_147_483_647,
i18n: describe('重试间隔', '每次重试跳转前等待的毫秒数,0 表示不增加等待时长。')},
],
output: output('json', '上一节点输出', '重试或次数耗尽时均透传上一节点的 output,缺失时为 null。'),
ports: [port('retry', '重试', '未达到最大重试次数时增加计数、等待指定间隔,再以 success 状态跳转;必须连接重试目标。'),
port('exhausted', '次数耗尽', '已达到最大重试次数时以 failure 状态执行,错误代码为 RETRY_EXHAUSTED。'), failure_port],
};
export const execute: NodeHandler = async (node, state, signal, deps) => {
if (node.type !== 'goto') throw new Error('Expected a goto node');
signal.throwIfAborted();
const count = Object.hasOwn(state.retry_counts, node.id) ? state.retry_counts[node.id] : 0;
if (!Number.isSafeInteger(count) || count < 0 || !Number.isSafeInteger(node.config.max_retries)
|| node.config.max_retries < 0 || !Number.isFinite(node.config.delay_ms) || node.config.delay_ms < 0) {
throw Object.assign(new Error('Invalid retry configuration or count'), {code: 'INVALID_RETRY'});
}
if (count >= node.config.max_retries) {
return {port: 'exhausted', result: {status: 'failure', output: state.last_result?.output ?? null,
error: {code: 'RETRY_EXHAUSTED', message: 'Retry limit exhausted', node_id: node.id}}};
}
const retry_counts = {[node.id]: count + 1};
assert_json(retry_counts);
await deps.sleep('milliseconds', node.config.delay_ms, signal);
signal.throwIfAborted();
return {port: 'retry', result: {status: 'success', output: state.last_result?.output ?? null}, retry_counts};
};