@ai-setting/roy-agent-cli 1.6.1 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/roy-agent.js +140 -17
- package/dist/index.js +140 -17
- package/dist/roy-agent-linux-x64/bin/roy-agent +0 -0
- package/package.json +1 -1
package/dist/bin/roy-agent.js
CHANGED
|
@@ -7407,7 +7407,7 @@ var require_dist = __commonJS((exports) => {
|
|
|
7407
7407
|
var require_package = __commonJS((exports, module) => {
|
|
7408
7408
|
module.exports = {
|
|
7409
7409
|
name: "@ai-setting/roy-agent-cli",
|
|
7410
|
-
version: "1.6.
|
|
7410
|
+
version: "1.6.2",
|
|
7411
7411
|
type: "module",
|
|
7412
7412
|
description: "CLI for roy-agent - Non-interactive command execution",
|
|
7413
7413
|
main: "./dist/index.js",
|
|
@@ -9762,6 +9762,68 @@ function joinResolvedSystemPrompts(prompts) {
|
|
|
9762
9762
|
// src/commands/shared/ask-user-handler.ts
|
|
9763
9763
|
import * as readline from "readline";
|
|
9764
9764
|
import chalk3 from "chalk";
|
|
9765
|
+
|
|
9766
|
+
// src/commands/shared/ask-user-timeout.ts
|
|
9767
|
+
var ASK_USER_TIMEOUT_MS = 120000;
|
|
9768
|
+
var ASK_USER_TIMEOUT_SENTINEL_PREFIX = "__ASK_USER_TIMEOUT__:";
|
|
9769
|
+
function isAskUserTimeoutSentinel(value) {
|
|
9770
|
+
return typeof value === "string" && value.length > ASK_USER_TIMEOUT_SENTINEL_PREFIX.length && value.startsWith(ASK_USER_TIMEOUT_SENTINEL_PREFIX);
|
|
9771
|
+
}
|
|
9772
|
+
function createAskUserTimeoutSentinel(errorInfo, timeoutMs, extra) {
|
|
9773
|
+
const payload = {
|
|
9774
|
+
query: errorInfo?.query ?? extra?.question ?? "",
|
|
9775
|
+
sessionId: errorInfo?.sessionId,
|
|
9776
|
+
agentSessionId: errorInfo?.agentSessionId,
|
|
9777
|
+
nodeId: errorInfo?.nodeId,
|
|
9778
|
+
nodeType: errorInfo?.nodeType,
|
|
9779
|
+
timestamp: Date.now(),
|
|
9780
|
+
timeoutMs,
|
|
9781
|
+
source: extra?.source ?? "repl"
|
|
9782
|
+
};
|
|
9783
|
+
return ASK_USER_TIMEOUT_SENTINEL_PREFIX + JSON.stringify(payload);
|
|
9784
|
+
}
|
|
9785
|
+
function withAskUserTimeoutRace(opts) {
|
|
9786
|
+
const { rl, timeoutMs, onLine, onTimeout } = opts;
|
|
9787
|
+
let resolved = false;
|
|
9788
|
+
let timer = null;
|
|
9789
|
+
const handleLine = (input) => {
|
|
9790
|
+
if (resolved)
|
|
9791
|
+
return;
|
|
9792
|
+
resolved = true;
|
|
9793
|
+
rl.removeListener("line", handleLine);
|
|
9794
|
+
if (timer) {
|
|
9795
|
+
clearTimeout(timer);
|
|
9796
|
+
timer = null;
|
|
9797
|
+
}
|
|
9798
|
+
onLine(input);
|
|
9799
|
+
};
|
|
9800
|
+
rl.on("line", handleLine);
|
|
9801
|
+
timer = setTimeout(() => {
|
|
9802
|
+
if (resolved)
|
|
9803
|
+
return;
|
|
9804
|
+
resolved = true;
|
|
9805
|
+
rl.removeListener("line", handleLine);
|
|
9806
|
+
onTimeout();
|
|
9807
|
+
timer = null;
|
|
9808
|
+
}, timeoutMs);
|
|
9809
|
+
if (timer && typeof timer.unref === "function") {
|
|
9810
|
+
timer.unref();
|
|
9811
|
+
}
|
|
9812
|
+
return {
|
|
9813
|
+
cancel() {
|
|
9814
|
+
if (resolved)
|
|
9815
|
+
return;
|
|
9816
|
+
resolved = true;
|
|
9817
|
+
rl.removeListener("line", handleLine);
|
|
9818
|
+
if (timer) {
|
|
9819
|
+
clearTimeout(timer);
|
|
9820
|
+
timer = null;
|
|
9821
|
+
}
|
|
9822
|
+
}
|
|
9823
|
+
};
|
|
9824
|
+
}
|
|
9825
|
+
|
|
9826
|
+
// src/commands/shared/ask-user-handler.ts
|
|
9765
9827
|
function parseOptionsFromQuery(query) {
|
|
9766
9828
|
const optionsMatch = query.match(/\(选项:\s*(.+)\)/);
|
|
9767
9829
|
if (optionsMatch) {
|
|
@@ -9816,7 +9878,6 @@ function parseUserInput(input, options) {
|
|
|
9816
9878
|
}
|
|
9817
9879
|
return { type: "text", value: trimmedInput };
|
|
9818
9880
|
}
|
|
9819
|
-
|
|
9820
9881
|
// src/commands/interactive-shutdown.ts
|
|
9821
9882
|
import { TempFileManager as TempFileManager2 } from "@ai-setting/roy-agent-core/utils/temp-file-manager";
|
|
9822
9883
|
async function shutdownInteractiveSteps(deps) {
|
|
@@ -9963,6 +10024,7 @@ class REPL {
|
|
|
9963
10024
|
sessionComponent = null;
|
|
9964
10025
|
lastAttachPath = undefined;
|
|
9965
10026
|
lastUsage = null;
|
|
10027
|
+
askUserTimeoutMs = ASK_USER_TIMEOUT_MS;
|
|
9966
10028
|
setLastUsage(usage) {
|
|
9967
10029
|
this.lastUsage = usage;
|
|
9968
10030
|
}
|
|
@@ -10350,22 +10412,27 @@ ${COLORS.error("❌ 执行失败: " + error)}
|
|
|
10350
10412
|
async handleAskUserInteraction(errorInfo) {
|
|
10351
10413
|
const { question, options } = parseOptionsFromQuery(errorInfo.query);
|
|
10352
10414
|
console.log(formatAskUserOutput({ ...errorInfo, query: question, options }));
|
|
10353
|
-
const userResponse = await this.promptUser(question, options);
|
|
10415
|
+
const userResponse = await this.promptUser(question, options, errorInfo);
|
|
10416
|
+
if (isAskUserTimeoutSentinel(userResponse)) {
|
|
10417
|
+
console.log(chalk5.dim(`
|
|
10418
|
+
请直接输入新指令继续,或使用 /abort 中断当前工作流。`));
|
|
10419
|
+
return;
|
|
10420
|
+
}
|
|
10354
10421
|
console.log(COLORS.userInput(`❯ ${userResponse.replace(/\n/g, `
|
|
10355
10422
|
` + COLORS.userInput("❯ "))}`));
|
|
10356
10423
|
await this.executeInternal(userResponse, { showPrompt: false });
|
|
10357
10424
|
}
|
|
10358
|
-
promptUser(question, options) {
|
|
10425
|
+
promptUser(question, options, errorInfo, opts) {
|
|
10426
|
+
const timeoutMs = opts?.timeoutMs ?? this.askUserTimeoutMs ?? ASK_USER_TIMEOUT_MS;
|
|
10359
10427
|
return new Promise((resolve) => {
|
|
10360
10428
|
this.rl.setPrompt(COLORS.userInput("❯ "));
|
|
10361
10429
|
this.rl.prompt(true);
|
|
10362
|
-
const
|
|
10363
|
-
this.rl.removeListener("line", handleLine);
|
|
10430
|
+
const finishWithUserInput = (input) => {
|
|
10364
10431
|
const trimmedInput = input.trim();
|
|
10365
10432
|
if (!trimmedInput) {
|
|
10366
10433
|
console.log(chalk5.yellow(`⚠️ 输入不能为空,请重新输入
|
|
10367
10434
|
`));
|
|
10368
|
-
this.promptUser(question, options).then(resolve);
|
|
10435
|
+
this.promptUser(question, options, errorInfo, opts).then(resolve);
|
|
10369
10436
|
return;
|
|
10370
10437
|
}
|
|
10371
10438
|
const parsed = parseUserInput(trimmedInput, options);
|
|
@@ -10380,7 +10447,21 @@ ${COLORS.error("❌ 执行失败: " + error)}
|
|
|
10380
10447
|
resolve(parsed.value);
|
|
10381
10448
|
}
|
|
10382
10449
|
};
|
|
10383
|
-
|
|
10450
|
+
withAskUserTimeoutRace({
|
|
10451
|
+
rl: this.rl,
|
|
10452
|
+
timeoutMs,
|
|
10453
|
+
onLine: (input) => {
|
|
10454
|
+
finishWithUserInput(input);
|
|
10455
|
+
},
|
|
10456
|
+
onTimeout: () => {
|
|
10457
|
+
console.log(chalk5.yellow(`
|
|
10458
|
+
⏱ ask_user 超时:${timeoutMs}ms 内未收到回应,已自动解除等待。`));
|
|
10459
|
+
resolve(createAskUserTimeoutSentinel(errorInfo, timeoutMs, {
|
|
10460
|
+
source: "repl",
|
|
10461
|
+
question
|
|
10462
|
+
}));
|
|
10463
|
+
}
|
|
10464
|
+
});
|
|
10384
10465
|
});
|
|
10385
10466
|
}
|
|
10386
10467
|
handleSigint() {
|
|
@@ -18493,6 +18574,19 @@ function renderRunResult(result) {
|
|
|
18493
18574
|
} else if (result.status === "stopped") {
|
|
18494
18575
|
lines.push(chalk65.yellow(`
|
|
18495
18576
|
⚠️ Workflow stopped`));
|
|
18577
|
+
} else if (result.status === "paused") {
|
|
18578
|
+
lines.push(chalk65.yellow(`
|
|
18579
|
+
⏸️ Workflow paused`));
|
|
18580
|
+
if (result.pendingNodeId) {
|
|
18581
|
+
lines.push(chalk65.gray(` Pending node: ${result.pendingNodeId}`));
|
|
18582
|
+
}
|
|
18583
|
+
if (result.query) {
|
|
18584
|
+
lines.push("");
|
|
18585
|
+
lines.push(chalk65.bold("\uD83D\uDCAC Agent asked: ") + chalk65.white(result.query));
|
|
18586
|
+
}
|
|
18587
|
+
if (result.agentSessionId) {
|
|
18588
|
+
lines.push(chalk65.gray(` Agent sub-session: ${result.agentSessionId}`));
|
|
18589
|
+
}
|
|
18496
18590
|
} else {
|
|
18497
18591
|
lines.push(chalk65.blue(`
|
|
18498
18592
|
\uD83D\uDD04 Workflow ${result.status}`));
|
|
@@ -19971,6 +20065,20 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
|
|
|
19971
20065
|
input = args.session ? args.input : undefined;
|
|
19972
20066
|
}
|
|
19973
20067
|
}
|
|
20068
|
+
let nodeConfig;
|
|
20069
|
+
if (args.nodeConfig) {
|
|
20070
|
+
try {
|
|
20071
|
+
const parsed = JSON.parse(args.nodeConfig);
|
|
20072
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
20073
|
+
output.error(`Invalid --node-config: expected a JSON object mapping nodeId → overrides, got: ${args.nodeConfig}`);
|
|
20074
|
+
process.exit(1);
|
|
20075
|
+
}
|
|
20076
|
+
nodeConfig = parsed;
|
|
20077
|
+
} catch (err) {
|
|
20078
|
+
output.error(`Invalid --node-config JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
20079
|
+
process.exit(1);
|
|
20080
|
+
}
|
|
20081
|
+
}
|
|
19974
20082
|
if (args.session && !args.session.startsWith("workflow_")) {
|
|
19975
20083
|
output.error(`Invalid session ID: must start with 'workflow_' (got: ${args.session})`);
|
|
19976
20084
|
process.exit(1);
|
|
@@ -19978,7 +20086,8 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
|
|
|
19978
20086
|
const runOptions = {
|
|
19979
20087
|
debug: args.debug,
|
|
19980
20088
|
parallelLimit: args.parallelLimit,
|
|
19981
|
-
timeout: args.timeout
|
|
20089
|
+
timeout: args.timeout,
|
|
20090
|
+
...nodeConfig ? { nodeConfig } : {}
|
|
19982
20091
|
};
|
|
19983
20092
|
const rawEnvParentId = process.env["ROY_PARENT_SESSION_ID"];
|
|
19984
20093
|
if (typeof rawEnvParentId === "string" && rawEnvParentId.length > 0) {
|
|
@@ -20002,7 +20111,10 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
|
|
|
20002
20111
|
status: result.status,
|
|
20003
20112
|
output: result.output,
|
|
20004
20113
|
error: result.error,
|
|
20005
|
-
durationMs: result.durationMs
|
|
20114
|
+
durationMs: result.durationMs,
|
|
20115
|
+
...result.pendingNodeId ? { pendingNodeId: result.pendingNodeId } : {},
|
|
20116
|
+
...result.query ? { query: result.query } : {},
|
|
20117
|
+
...result.agentSessionId ? { agentSessionId: result.agentSessionId } : {}
|
|
20006
20118
|
}));
|
|
20007
20119
|
} catch (err) {
|
|
20008
20120
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -20044,24 +20156,29 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
|
|
|
20044
20156
|
process.exit(0);
|
|
20045
20157
|
}
|
|
20046
20158
|
output.log(chalk71.blue(`\uD83D\uDE80 Running workflow: ${workflow.name}`));
|
|
20047
|
-
const
|
|
20159
|
+
const fileBranchInput = typeof input === "string" ? undefined : input;
|
|
20160
|
+
const result = await service.runWorkflow(definition, fileBranchInput, runOptions);
|
|
20048
20161
|
output.log(renderRunResult({
|
|
20049
20162
|
runId: result.runId,
|
|
20050
20163
|
status: result.status,
|
|
20051
20164
|
output: result.output,
|
|
20052
20165
|
error: result.error,
|
|
20053
|
-
durationMs: result.durationMs
|
|
20166
|
+
durationMs: result.durationMs,
|
|
20167
|
+
...result.pendingNodeId ? { pendingNodeId: result.pendingNodeId } : {},
|
|
20168
|
+
...result.query ? { query: result.query } : {},
|
|
20169
|
+
...result.agentSessionId ? { agentSessionId: result.agentSessionId } : {}
|
|
20054
20170
|
}));
|
|
20055
20171
|
if (result.status === "paused") {
|
|
20056
20172
|
output.log(chalk71.gray(`
|
|
20057
|
-
\uD83D\uDCA1
|
|
20173
|
+
\uD83D\uDCA1 Resume with: roy-agent workflow run ${result.runId} --session ${result.runId} --input "<your answer>"`));
|
|
20058
20174
|
}
|
|
20059
20175
|
} else {
|
|
20060
20176
|
const tool = createRunWorkflowTool(service);
|
|
20061
20177
|
const toolResult = await tool.execute({
|
|
20062
20178
|
workflow_name: args.identifier,
|
|
20063
|
-
input: input || undefined,
|
|
20064
|
-
timeout: args.timeout
|
|
20179
|
+
input: typeof input === "string" ? undefined : input || undefined,
|
|
20180
|
+
timeout: args.timeout,
|
|
20181
|
+
...nodeConfig ? { node_config: nodeConfig } : {}
|
|
20065
20182
|
}, {});
|
|
20066
20183
|
if (!toolResult.success) {
|
|
20067
20184
|
const outAny = toolResult.output;
|
|
@@ -20080,11 +20197,14 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
|
|
|
20080
20197
|
status: runData.status,
|
|
20081
20198
|
output: runData.output,
|
|
20082
20199
|
error: runData.error,
|
|
20083
|
-
durationMs: runData.duration_ms
|
|
20200
|
+
durationMs: runData.duration_ms,
|
|
20201
|
+
...runData.pending_node_id ? { pendingNodeId: runData.pending_node_id } : {},
|
|
20202
|
+
...runData.query ? { query: runData.query } : {},
|
|
20203
|
+
...runData.agent_session_id ? { agentSessionId: runData.agent_session_id } : {}
|
|
20084
20204
|
}));
|
|
20085
20205
|
if (runData.status === "paused") {
|
|
20086
20206
|
output.log(chalk71.gray(`
|
|
20087
|
-
\uD83D\uDCA1
|
|
20207
|
+
\uD83D\uDCA1 Resume with: roy-agent workflow run ${args.identifier} --session ${runData.run_id} --input "<your answer>"`));
|
|
20088
20208
|
}
|
|
20089
20209
|
}
|
|
20090
20210
|
if (workflowSpan) {
|
|
@@ -20150,6 +20270,9 @@ var WorkflowRunCommand = {
|
|
|
20150
20270
|
alias: "s",
|
|
20151
20271
|
describe: "从已有 session 恢复运行(支持 workflow pause/interrupt 恢复;runId == sessionId,传 workflow run 的 runId 即可)",
|
|
20152
20272
|
type: "string"
|
|
20273
|
+
}).option("node-config", {
|
|
20274
|
+
describe: `Per-node runtime config overrides (Task #1974). JSON string: { "<nodeId>": { "timeout": 5000 } }. Shallow-merged into each node's effective config; input wins over nodeDef.config.`,
|
|
20275
|
+
type: "string"
|
|
20153
20276
|
}),
|
|
20154
20277
|
handler: runWorkflow
|
|
20155
20278
|
};
|
package/dist/index.js
CHANGED
|
@@ -7406,7 +7406,7 @@ var require_dist = __commonJS((exports) => {
|
|
|
7406
7406
|
var require_package = __commonJS((exports, module) => {
|
|
7407
7407
|
module.exports = {
|
|
7408
7408
|
name: "@ai-setting/roy-agent-cli",
|
|
7409
|
-
version: "1.6.
|
|
7409
|
+
version: "1.6.2",
|
|
7410
7410
|
type: "module",
|
|
7411
7411
|
description: "CLI for roy-agent - Non-interactive command execution",
|
|
7412
7412
|
main: "./dist/index.js",
|
|
@@ -9761,6 +9761,68 @@ function joinResolvedSystemPrompts(prompts) {
|
|
|
9761
9761
|
// src/commands/shared/ask-user-handler.ts
|
|
9762
9762
|
import * as readline from "readline";
|
|
9763
9763
|
import chalk3 from "chalk";
|
|
9764
|
+
|
|
9765
|
+
// src/commands/shared/ask-user-timeout.ts
|
|
9766
|
+
var ASK_USER_TIMEOUT_MS = 120000;
|
|
9767
|
+
var ASK_USER_TIMEOUT_SENTINEL_PREFIX = "__ASK_USER_TIMEOUT__:";
|
|
9768
|
+
function isAskUserTimeoutSentinel(value) {
|
|
9769
|
+
return typeof value === "string" && value.length > ASK_USER_TIMEOUT_SENTINEL_PREFIX.length && value.startsWith(ASK_USER_TIMEOUT_SENTINEL_PREFIX);
|
|
9770
|
+
}
|
|
9771
|
+
function createAskUserTimeoutSentinel(errorInfo, timeoutMs, extra) {
|
|
9772
|
+
const payload = {
|
|
9773
|
+
query: errorInfo?.query ?? extra?.question ?? "",
|
|
9774
|
+
sessionId: errorInfo?.sessionId,
|
|
9775
|
+
agentSessionId: errorInfo?.agentSessionId,
|
|
9776
|
+
nodeId: errorInfo?.nodeId,
|
|
9777
|
+
nodeType: errorInfo?.nodeType,
|
|
9778
|
+
timestamp: Date.now(),
|
|
9779
|
+
timeoutMs,
|
|
9780
|
+
source: extra?.source ?? "repl"
|
|
9781
|
+
};
|
|
9782
|
+
return ASK_USER_TIMEOUT_SENTINEL_PREFIX + JSON.stringify(payload);
|
|
9783
|
+
}
|
|
9784
|
+
function withAskUserTimeoutRace(opts) {
|
|
9785
|
+
const { rl, timeoutMs, onLine, onTimeout } = opts;
|
|
9786
|
+
let resolved = false;
|
|
9787
|
+
let timer = null;
|
|
9788
|
+
const handleLine = (input) => {
|
|
9789
|
+
if (resolved)
|
|
9790
|
+
return;
|
|
9791
|
+
resolved = true;
|
|
9792
|
+
rl.removeListener("line", handleLine);
|
|
9793
|
+
if (timer) {
|
|
9794
|
+
clearTimeout(timer);
|
|
9795
|
+
timer = null;
|
|
9796
|
+
}
|
|
9797
|
+
onLine(input);
|
|
9798
|
+
};
|
|
9799
|
+
rl.on("line", handleLine);
|
|
9800
|
+
timer = setTimeout(() => {
|
|
9801
|
+
if (resolved)
|
|
9802
|
+
return;
|
|
9803
|
+
resolved = true;
|
|
9804
|
+
rl.removeListener("line", handleLine);
|
|
9805
|
+
onTimeout();
|
|
9806
|
+
timer = null;
|
|
9807
|
+
}, timeoutMs);
|
|
9808
|
+
if (timer && typeof timer.unref === "function") {
|
|
9809
|
+
timer.unref();
|
|
9810
|
+
}
|
|
9811
|
+
return {
|
|
9812
|
+
cancel() {
|
|
9813
|
+
if (resolved)
|
|
9814
|
+
return;
|
|
9815
|
+
resolved = true;
|
|
9816
|
+
rl.removeListener("line", handleLine);
|
|
9817
|
+
if (timer) {
|
|
9818
|
+
clearTimeout(timer);
|
|
9819
|
+
timer = null;
|
|
9820
|
+
}
|
|
9821
|
+
}
|
|
9822
|
+
};
|
|
9823
|
+
}
|
|
9824
|
+
|
|
9825
|
+
// src/commands/shared/ask-user-handler.ts
|
|
9764
9826
|
function parseOptionsFromQuery(query) {
|
|
9765
9827
|
const optionsMatch = query.match(/\(选项:\s*(.+)\)/);
|
|
9766
9828
|
if (optionsMatch) {
|
|
@@ -9815,7 +9877,6 @@ function parseUserInput(input, options) {
|
|
|
9815
9877
|
}
|
|
9816
9878
|
return { type: "text", value: trimmedInput };
|
|
9817
9879
|
}
|
|
9818
|
-
|
|
9819
9880
|
// src/commands/interactive-shutdown.ts
|
|
9820
9881
|
import { TempFileManager as TempFileManager2 } from "@ai-setting/roy-agent-core/utils/temp-file-manager";
|
|
9821
9882
|
async function shutdownInteractiveSteps(deps) {
|
|
@@ -9962,6 +10023,7 @@ class REPL {
|
|
|
9962
10023
|
sessionComponent = null;
|
|
9963
10024
|
lastAttachPath = undefined;
|
|
9964
10025
|
lastUsage = null;
|
|
10026
|
+
askUserTimeoutMs = ASK_USER_TIMEOUT_MS;
|
|
9965
10027
|
setLastUsage(usage) {
|
|
9966
10028
|
this.lastUsage = usage;
|
|
9967
10029
|
}
|
|
@@ -10349,22 +10411,27 @@ ${COLORS.error("❌ 执行失败: " + error)}
|
|
|
10349
10411
|
async handleAskUserInteraction(errorInfo) {
|
|
10350
10412
|
const { question, options } = parseOptionsFromQuery(errorInfo.query);
|
|
10351
10413
|
console.log(formatAskUserOutput({ ...errorInfo, query: question, options }));
|
|
10352
|
-
const userResponse = await this.promptUser(question, options);
|
|
10414
|
+
const userResponse = await this.promptUser(question, options, errorInfo);
|
|
10415
|
+
if (isAskUserTimeoutSentinel(userResponse)) {
|
|
10416
|
+
console.log(chalk5.dim(`
|
|
10417
|
+
请直接输入新指令继续,或使用 /abort 中断当前工作流。`));
|
|
10418
|
+
return;
|
|
10419
|
+
}
|
|
10353
10420
|
console.log(COLORS.userInput(`❯ ${userResponse.replace(/\n/g, `
|
|
10354
10421
|
` + COLORS.userInput("❯ "))}`));
|
|
10355
10422
|
await this.executeInternal(userResponse, { showPrompt: false });
|
|
10356
10423
|
}
|
|
10357
|
-
promptUser(question, options) {
|
|
10424
|
+
promptUser(question, options, errorInfo, opts) {
|
|
10425
|
+
const timeoutMs = opts?.timeoutMs ?? this.askUserTimeoutMs ?? ASK_USER_TIMEOUT_MS;
|
|
10358
10426
|
return new Promise((resolve) => {
|
|
10359
10427
|
this.rl.setPrompt(COLORS.userInput("❯ "));
|
|
10360
10428
|
this.rl.prompt(true);
|
|
10361
|
-
const
|
|
10362
|
-
this.rl.removeListener("line", handleLine);
|
|
10429
|
+
const finishWithUserInput = (input) => {
|
|
10363
10430
|
const trimmedInput = input.trim();
|
|
10364
10431
|
if (!trimmedInput) {
|
|
10365
10432
|
console.log(chalk5.yellow(`⚠️ 输入不能为空,请重新输入
|
|
10366
10433
|
`));
|
|
10367
|
-
this.promptUser(question, options).then(resolve);
|
|
10434
|
+
this.promptUser(question, options, errorInfo, opts).then(resolve);
|
|
10368
10435
|
return;
|
|
10369
10436
|
}
|
|
10370
10437
|
const parsed = parseUserInput(trimmedInput, options);
|
|
@@ -10379,7 +10446,21 @@ ${COLORS.error("❌ 执行失败: " + error)}
|
|
|
10379
10446
|
resolve(parsed.value);
|
|
10380
10447
|
}
|
|
10381
10448
|
};
|
|
10382
|
-
|
|
10449
|
+
withAskUserTimeoutRace({
|
|
10450
|
+
rl: this.rl,
|
|
10451
|
+
timeoutMs,
|
|
10452
|
+
onLine: (input) => {
|
|
10453
|
+
finishWithUserInput(input);
|
|
10454
|
+
},
|
|
10455
|
+
onTimeout: () => {
|
|
10456
|
+
console.log(chalk5.yellow(`
|
|
10457
|
+
⏱ ask_user 超时:${timeoutMs}ms 内未收到回应,已自动解除等待。`));
|
|
10458
|
+
resolve(createAskUserTimeoutSentinel(errorInfo, timeoutMs, {
|
|
10459
|
+
source: "repl",
|
|
10460
|
+
question
|
|
10461
|
+
}));
|
|
10462
|
+
}
|
|
10463
|
+
});
|
|
10383
10464
|
});
|
|
10384
10465
|
}
|
|
10385
10466
|
handleSigint() {
|
|
@@ -18492,6 +18573,19 @@ function renderRunResult(result) {
|
|
|
18492
18573
|
} else if (result.status === "stopped") {
|
|
18493
18574
|
lines.push(chalk65.yellow(`
|
|
18494
18575
|
⚠️ Workflow stopped`));
|
|
18576
|
+
} else if (result.status === "paused") {
|
|
18577
|
+
lines.push(chalk65.yellow(`
|
|
18578
|
+
⏸️ Workflow paused`));
|
|
18579
|
+
if (result.pendingNodeId) {
|
|
18580
|
+
lines.push(chalk65.gray(` Pending node: ${result.pendingNodeId}`));
|
|
18581
|
+
}
|
|
18582
|
+
if (result.query) {
|
|
18583
|
+
lines.push("");
|
|
18584
|
+
lines.push(chalk65.bold("\uD83D\uDCAC Agent asked: ") + chalk65.white(result.query));
|
|
18585
|
+
}
|
|
18586
|
+
if (result.agentSessionId) {
|
|
18587
|
+
lines.push(chalk65.gray(` Agent sub-session: ${result.agentSessionId}`));
|
|
18588
|
+
}
|
|
18495
18589
|
} else {
|
|
18496
18590
|
lines.push(chalk65.blue(`
|
|
18497
18591
|
\uD83D\uDD04 Workflow ${result.status}`));
|
|
@@ -19970,6 +20064,20 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
|
|
|
19970
20064
|
input = args.session ? args.input : undefined;
|
|
19971
20065
|
}
|
|
19972
20066
|
}
|
|
20067
|
+
let nodeConfig;
|
|
20068
|
+
if (args.nodeConfig) {
|
|
20069
|
+
try {
|
|
20070
|
+
const parsed = JSON.parse(args.nodeConfig);
|
|
20071
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
20072
|
+
output.error(`Invalid --node-config: expected a JSON object mapping nodeId → overrides, got: ${args.nodeConfig}`);
|
|
20073
|
+
process.exit(1);
|
|
20074
|
+
}
|
|
20075
|
+
nodeConfig = parsed;
|
|
20076
|
+
} catch (err) {
|
|
20077
|
+
output.error(`Invalid --node-config JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
20078
|
+
process.exit(1);
|
|
20079
|
+
}
|
|
20080
|
+
}
|
|
19973
20081
|
if (args.session && !args.session.startsWith("workflow_")) {
|
|
19974
20082
|
output.error(`Invalid session ID: must start with 'workflow_' (got: ${args.session})`);
|
|
19975
20083
|
process.exit(1);
|
|
@@ -19977,7 +20085,8 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
|
|
|
19977
20085
|
const runOptions = {
|
|
19978
20086
|
debug: args.debug,
|
|
19979
20087
|
parallelLimit: args.parallelLimit,
|
|
19980
|
-
timeout: args.timeout
|
|
20088
|
+
timeout: args.timeout,
|
|
20089
|
+
...nodeConfig ? { nodeConfig } : {}
|
|
19981
20090
|
};
|
|
19982
20091
|
const rawEnvParentId = process.env["ROY_PARENT_SESSION_ID"];
|
|
19983
20092
|
if (typeof rawEnvParentId === "string" && rawEnvParentId.length > 0) {
|
|
@@ -20001,7 +20110,10 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
|
|
|
20001
20110
|
status: result.status,
|
|
20002
20111
|
output: result.output,
|
|
20003
20112
|
error: result.error,
|
|
20004
|
-
durationMs: result.durationMs
|
|
20113
|
+
durationMs: result.durationMs,
|
|
20114
|
+
...result.pendingNodeId ? { pendingNodeId: result.pendingNodeId } : {},
|
|
20115
|
+
...result.query ? { query: result.query } : {},
|
|
20116
|
+
...result.agentSessionId ? { agentSessionId: result.agentSessionId } : {}
|
|
20005
20117
|
}));
|
|
20006
20118
|
} catch (err) {
|
|
20007
20119
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -20043,24 +20155,29 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
|
|
|
20043
20155
|
process.exit(0);
|
|
20044
20156
|
}
|
|
20045
20157
|
output.log(chalk71.blue(`\uD83D\uDE80 Running workflow: ${workflow.name}`));
|
|
20046
|
-
const
|
|
20158
|
+
const fileBranchInput = typeof input === "string" ? undefined : input;
|
|
20159
|
+
const result = await service.runWorkflow(definition, fileBranchInput, runOptions);
|
|
20047
20160
|
output.log(renderRunResult({
|
|
20048
20161
|
runId: result.runId,
|
|
20049
20162
|
status: result.status,
|
|
20050
20163
|
output: result.output,
|
|
20051
20164
|
error: result.error,
|
|
20052
|
-
durationMs: result.durationMs
|
|
20165
|
+
durationMs: result.durationMs,
|
|
20166
|
+
...result.pendingNodeId ? { pendingNodeId: result.pendingNodeId } : {},
|
|
20167
|
+
...result.query ? { query: result.query } : {},
|
|
20168
|
+
...result.agentSessionId ? { agentSessionId: result.agentSessionId } : {}
|
|
20053
20169
|
}));
|
|
20054
20170
|
if (result.status === "paused") {
|
|
20055
20171
|
output.log(chalk71.gray(`
|
|
20056
|
-
\uD83D\uDCA1
|
|
20172
|
+
\uD83D\uDCA1 Resume with: roy-agent workflow run ${result.runId} --session ${result.runId} --input "<your answer>"`));
|
|
20057
20173
|
}
|
|
20058
20174
|
} else {
|
|
20059
20175
|
const tool = createRunWorkflowTool(service);
|
|
20060
20176
|
const toolResult = await tool.execute({
|
|
20061
20177
|
workflow_name: args.identifier,
|
|
20062
|
-
input: input || undefined,
|
|
20063
|
-
timeout: args.timeout
|
|
20178
|
+
input: typeof input === "string" ? undefined : input || undefined,
|
|
20179
|
+
timeout: args.timeout,
|
|
20180
|
+
...nodeConfig ? { node_config: nodeConfig } : {}
|
|
20064
20181
|
}, {});
|
|
20065
20182
|
if (!toolResult.success) {
|
|
20066
20183
|
const outAny = toolResult.output;
|
|
@@ -20079,11 +20196,14 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
|
|
|
20079
20196
|
status: runData.status,
|
|
20080
20197
|
output: runData.output,
|
|
20081
20198
|
error: runData.error,
|
|
20082
|
-
durationMs: runData.duration_ms
|
|
20199
|
+
durationMs: runData.duration_ms,
|
|
20200
|
+
...runData.pending_node_id ? { pendingNodeId: runData.pending_node_id } : {},
|
|
20201
|
+
...runData.query ? { query: runData.query } : {},
|
|
20202
|
+
...runData.agent_session_id ? { agentSessionId: runData.agent_session_id } : {}
|
|
20083
20203
|
}));
|
|
20084
20204
|
if (runData.status === "paused") {
|
|
20085
20205
|
output.log(chalk71.gray(`
|
|
20086
|
-
\uD83D\uDCA1
|
|
20206
|
+
\uD83D\uDCA1 Resume with: roy-agent workflow run ${args.identifier} --session ${runData.run_id} --input "<your answer>"`));
|
|
20087
20207
|
}
|
|
20088
20208
|
}
|
|
20089
20209
|
if (workflowSpan) {
|
|
@@ -20149,6 +20269,9 @@ var WorkflowRunCommand = {
|
|
|
20149
20269
|
alias: "s",
|
|
20150
20270
|
describe: "从已有 session 恢复运行(支持 workflow pause/interrupt 恢复;runId == sessionId,传 workflow run 的 runId 即可)",
|
|
20151
20271
|
type: "string"
|
|
20272
|
+
}).option("node-config", {
|
|
20273
|
+
describe: `Per-node runtime config overrides (Task #1974). JSON string: { "<nodeId>": { "timeout": 5000 } }. Shallow-merged into each node's effective config; input wins over nodeDef.config.`,
|
|
20274
|
+
type: "string"
|
|
20152
20275
|
}),
|
|
20153
20276
|
handler: runWorkflow
|
|
20154
20277
|
};
|
|
Binary file
|