@agimon-ai/po-workflow 0.0.0-alpha.66 → 0.0.0-alpha.68
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/extensions/server.cjs +151 -150
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.mjs +151 -150
- package/dist/extensions/server.mjs.map +1 -1
- package/package.json +8 -8
|
@@ -409,7 +409,7 @@ function runBelongsToSession(run, sessionId) {
|
|
|
409
409
|
}
|
|
410
410
|
/** Whether the session handed this run to a workflow session of its own: it lists the run but does not own it. */
|
|
411
411
|
function runLaunchedBySession(run, sessionId) {
|
|
412
|
-
return run.launcherSessionId !== void 0 && run.launcherSessionId === sessionId && !runBelongsToSession(run, sessionId);
|
|
412
|
+
return run.piSessionId !== void 0 && run.launcherSessionId !== void 0 && run.launcherSessionId === sessionId && !runBelongsToSession(run, sessionId);
|
|
413
413
|
}
|
|
414
414
|
function parseTime(value) {
|
|
415
415
|
if (value === void 0) return 0;
|
|
@@ -2912,6 +2912,155 @@ const WORKFLOW_API_BASE_PATH = "workflow";
|
|
|
2912
2912
|
/** The SSE event name the screen stream writes. */
|
|
2913
2913
|
const WORKFLOW_SCREEN_EVENT = "screen";
|
|
2914
2914
|
//#endregion
|
|
2915
|
+
//#region src/services/piToolBridge/index.ts
|
|
2916
|
+
/**
|
|
2917
|
+
* Environment variable stamped onto every run launched from a Pi session.
|
|
2918
|
+
*
|
|
2919
|
+
* `RunWorkflowService` forwards `env` to the inner CLI invocation across the
|
|
2920
|
+
* `launch-command` delegation boundary and persists it on the run record, so
|
|
2921
|
+
* this survives backgrounding and identifies the launching session afterwards.
|
|
2922
|
+
*/
|
|
2923
|
+
const PO_SESSION_ENV = "PO_SESSION_ID";
|
|
2924
|
+
/** Operator override for the per-session launch ceiling. */
|
|
2925
|
+
const MAX_CONCURRENT_ENV = "WORKFLOW_MCP_MAX_CONCURRENT";
|
|
2926
|
+
const DEFAULT_MAX_CONCURRENT = 5;
|
|
2927
|
+
/** Resolve the per-session launch ceiling from the environment. */
|
|
2928
|
+
function resolveMaxConcurrent(env) {
|
|
2929
|
+
const parsed = Number(env[MAX_CONCURRENT_ENV]);
|
|
2930
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : DEFAULT_MAX_CONCURRENT;
|
|
2931
|
+
}
|
|
2932
|
+
/**
|
|
2933
|
+
* True when this session launched the run.
|
|
2934
|
+
*
|
|
2935
|
+
* Fails closed on a missing session id: an unstamped record (a CLI launch) and
|
|
2936
|
+
* a call arriving before the session id is known both match nothing, so no run
|
|
2937
|
+
* ever leaks across sessions through an undefined-equals-undefined comparison.
|
|
2938
|
+
*/
|
|
2939
|
+
function isSessionRun(record, sessionId) {
|
|
2940
|
+
return sessionId !== void 0 && record.env?.["PO_SESSION_ID"] === sessionId;
|
|
2941
|
+
}
|
|
2942
|
+
/** True when this session handed the run to a workflow session of its own: it is told, but does not own it. */
|
|
2943
|
+
function isLaunchedRun(record, sessionId) {
|
|
2944
|
+
const owner = record.env?.[PO_SESSION_ENV];
|
|
2945
|
+
return sessionId !== void 0 && typeof owner === "string" && owner !== "" && record.env?.["PO_WORKFLOW_LAUNCHER_SESSION_ID"] === sessionId && !isSessionRun(record, sessionId);
|
|
2946
|
+
}
|
|
2947
|
+
/** The line a launcher's finish notice adds: where the run lived, and where to take it up. */
|
|
2948
|
+
function launchedRunHint(record) {
|
|
2949
|
+
return `It ran in workflow session ${record.env?.["PO_SESSION_ID"] ?? "unknown"}; troubleshoot and recover it there.`;
|
|
2950
|
+
}
|
|
2951
|
+
/**
|
|
2952
|
+
* True when this session owns a run another session handed to it: it is the
|
|
2953
|
+
* run's workflow session, so a finished run is posted without starting a turn.
|
|
2954
|
+
*/
|
|
2955
|
+
function isOwnedDelegatedRun(record, sessionId) {
|
|
2956
|
+
const launcher = record.env?.[WORKFLOW_LAUNCHER_SESSION_ENV];
|
|
2957
|
+
return isSessionRun(record, sessionId) && typeof launcher === "string" && launcher !== "" && launcher !== sessionId;
|
|
2958
|
+
}
|
|
2959
|
+
/**
|
|
2960
|
+
* What the caller is told when the registry, not the launcher, acknowledged a
|
|
2961
|
+
* launch.
|
|
2962
|
+
*
|
|
2963
|
+
* Leads with the run key because it is the handle every other workflow action
|
|
2964
|
+
* takes, and it is no longer available any other way: the launcher's own output
|
|
2965
|
+
* is not waited for, so nothing else in this result carries it.
|
|
2966
|
+
*/
|
|
2967
|
+
function launchedRunSummary(record) {
|
|
2968
|
+
return [
|
|
2969
|
+
`Started ${record.displayName} in workspace ${record.workspace}.`,
|
|
2970
|
+
`Run key: ${record.runKey}`,
|
|
2971
|
+
"The run is registered and going. This call returned at that point rather than waiting for the launcher process to exit."
|
|
2972
|
+
].join("\n");
|
|
2973
|
+
}
|
|
2974
|
+
/**
|
|
2975
|
+
* What the caller is told when the launch was handed off but no run has
|
|
2976
|
+
* registered inside the acknowledgement budget.
|
|
2977
|
+
*
|
|
2978
|
+
* Deliberately not an error: the launcher is slow rather than broken often
|
|
2979
|
+
* enough that failing here would strand runs that go on to start normally.
|
|
2980
|
+
* There is no run key to offer yet, so it points at the surfaces that do not
|
|
2981
|
+
* need one.
|
|
2982
|
+
*/
|
|
2983
|
+
function launchHandoffSummary(workflowPath) {
|
|
2984
|
+
return [
|
|
2985
|
+
`Launch handed off for ${workflowPath}, but no run has registered yet.`,
|
|
2986
|
+
"Nothing was cancelled: the launcher is still starting, and a run that registers later still reports back here when it finishes.",
|
|
2987
|
+
"Do not launch it again. Ask the user to check the active workflow list if they need to see it sooner."
|
|
2988
|
+
].join("\n");
|
|
2989
|
+
}
|
|
2990
|
+
new RegExp([
|
|
2991
|
+
"\\u001B\\[[0-9;?]*[ -/]*[@-~]",
|
|
2992
|
+
"\\u001B\\][^\\u0007\\u001B]*(?:\\u0007|\\u001B\\\\)",
|
|
2993
|
+
"\\u001B[@-Z\\\\-_]"
|
|
2994
|
+
].join("|"), "g");
|
|
2995
|
+
/** Flatten MCP tool content to text for Pi. */
|
|
2996
|
+
function toolResultText(result) {
|
|
2997
|
+
return result.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n").trim();
|
|
2998
|
+
}
|
|
2999
|
+
/**
|
|
3000
|
+
* Attach a short menu of next steps to a problem.
|
|
3001
|
+
*
|
|
3002
|
+
* An error with no route forward is where an agent invents one: retrying a
|
|
3003
|
+
* capacity limit, relaunching a run that should be recovered, or silently
|
|
3004
|
+
* giving up on work the user is waiting for. Naming two or three real options
|
|
3005
|
+
* turns an error into a decision, and the decision belongs to the user.
|
|
3006
|
+
*/
|
|
3007
|
+
function withOptions(problem, options) {
|
|
3008
|
+
if (options.length === 0) return problem;
|
|
3009
|
+
return [
|
|
3010
|
+
problem,
|
|
3011
|
+
"",
|
|
3012
|
+
"Options, put these to the user rather than picking one yourself:",
|
|
3013
|
+
...options.map(bullet)
|
|
3014
|
+
].join("\n");
|
|
3015
|
+
}
|
|
3016
|
+
function bullet(option) {
|
|
3017
|
+
return `- ${option}`;
|
|
3018
|
+
}
|
|
3019
|
+
/** The job and step a run died on, preferring the progress log to the record. */
|
|
3020
|
+
function failurePosition(record, jobs) {
|
|
3021
|
+
const failedJob = jobs.find((job) => job.status === "failed");
|
|
3022
|
+
const failedStep = failedJob?.steps.find((step) => step.status === "failed");
|
|
3023
|
+
return {
|
|
3024
|
+
job: failedJob?.name ?? record.failedJob,
|
|
3025
|
+
step: failedStep?.name,
|
|
3026
|
+
reason: failedStep?.reason ?? failedJob?.reason
|
|
3027
|
+
};
|
|
3028
|
+
}
|
|
3029
|
+
/**
|
|
3030
|
+
* Describe a finished run for the agent that launched it.
|
|
3031
|
+
*
|
|
3032
|
+
* Carries the job identifiers back so a dispatching agent can match the run to
|
|
3033
|
+
* the work item it launched it for without another lookup. When the run failed,
|
|
3034
|
+
* carries the failing step and a set of options too: the agent is being told
|
|
3035
|
+
* about this out of band, with no user question in flight, so without them it
|
|
3036
|
+
* has to guess whether to recover, relaunch, or report.
|
|
3037
|
+
*/
|
|
3038
|
+
function finishedRunSummary(record, jobs = []) {
|
|
3039
|
+
const outcome = record.stage === "completed" ? "completed" : `ended in ${record.stage}`;
|
|
3040
|
+
const failure = failurePosition(record, jobs);
|
|
3041
|
+
const lines = [
|
|
3042
|
+
`Workflow run ${record.runKey} in workspace ${record.workspace} ${outcome}.`,
|
|
3043
|
+
record.workflowId ? `Workflow: ${record.workflowId}` : void 0,
|
|
3044
|
+
failure.job ? `Failed job: ${failure.job}${failure.step ? ` (step: ${failure.step})` : ""}` : void 0,
|
|
3045
|
+
record.errorMessage ? `Error: ${record.errorMessage}` : void 0,
|
|
3046
|
+
failure.reason && failure.reason !== record.errorMessage ? `Step reported: ${failure.reason}` : void 0
|
|
3047
|
+
];
|
|
3048
|
+
const jobId = record.env?.AGIFLOW_JOB_ID;
|
|
3049
|
+
if (jobId) lines.push(`Agiflow job: ${record.env?.AGIFLOW_JOB_KIND ?? "unknown"} ${jobId}`);
|
|
3050
|
+
const summary = lines.filter((line) => Boolean(line)).join("\n");
|
|
3051
|
+
if (record.stage === "completed") return summary;
|
|
3052
|
+
if (record.outcome === "interrupted") return withOptions(summary, [`workflow_run {"action":"recover","runKey":${JSON.stringify(record.runKey)}}: pick it up where it stopped.`, "Leave it stopped and move on."]);
|
|
3053
|
+
const diagnosticText = [record.errorMessage, failure.reason].filter(Boolean).join("\n");
|
|
3054
|
+
if (diagnosticText.includes("JOB_ALREADY_CLAIMED")) return withOptions(summary, ["Report contention: another worker owns this job. Do not unlock, release, or retry the claim automatically."]);
|
|
3055
|
+
if (diagnosticText.includes("WORKFLOW_NOT_OWNED") || /release failed/i.test(diagnosticText)) return withOptions(summary, ["Inspect the current workflow ownership and ask the user before any release or unlock. Never force another worker’s lock."]);
|
|
3056
|
+
if (/running workflow not found/i.test(diagnosticText)) return withOptions(summary, [`workflow_run {"action":"status","runKey":${JSON.stringify(record.runKey)}}: re-check current state before retrying.`, "Report the recorded terminal state when no running owner remains."]);
|
|
3057
|
+
return withOptions(summary, [
|
|
3058
|
+
`workflow_run {"action":"tail","runKey":${JSON.stringify(record.runKey)}}: read the run's own output first, when the error above does not explain the failure.`,
|
|
3059
|
+
`workflow_run {"action":"recover","runKey":${JSON.stringify(record.runKey)}}: resume from the failed job, keeping the work already done. Fits a transient or external cause.`,
|
|
3060
|
+
"Report the failure and stop, when it needs a code change or a decision you cannot make."
|
|
3061
|
+
]);
|
|
3062
|
+
}
|
|
3063
|
+
//#endregion
|
|
2915
3064
|
//#region src/schemas/workflowRenderGrid.ts
|
|
2916
3065
|
const renderGridStyleSchema = zod.z.object({
|
|
2917
3066
|
id: zod.z.number().int().nonnegative(),
|
|
@@ -3937,7 +4086,7 @@ function createWorkflowApi(runtime, launch) {
|
|
|
3937
4086
|
app = createWorkflowHubApi({
|
|
3938
4087
|
runtime,
|
|
3939
4088
|
registry: new require_RecoverWorkflowService.WorkflowRegistryService(runtime, homeDir),
|
|
3940
|
-
recordFilter: (record) => context.sessionId === void 0 || record
|
|
4089
|
+
recordFilter: (record) => context.sessionId === void 0 || isSessionRun(record, context.sessionId) || isLaunchedRun(record, context.sessionId),
|
|
3941
4090
|
...steer === void 0 ? {} : { steer: (sessionId, message) => steer(sessionId, message) },
|
|
3942
4091
|
...launch === void 0 ? {} : { launch }
|
|
3943
4092
|
});
|
|
@@ -4815,154 +4964,6 @@ function registerRunProvider(ctx) {
|
|
|
4815
4964
|
};
|
|
4816
4965
|
}
|
|
4817
4966
|
//#endregion
|
|
4818
|
-
//#region src/services/piToolBridge/index.ts
|
|
4819
|
-
/**
|
|
4820
|
-
* Environment variable stamped onto every run launched from a Pi session.
|
|
4821
|
-
*
|
|
4822
|
-
* `RunWorkflowService` forwards `env` to the inner CLI invocation across the
|
|
4823
|
-
* `launch-command` delegation boundary and persists it on the run record, so
|
|
4824
|
-
* this survives backgrounding and identifies the launching session afterwards.
|
|
4825
|
-
*/
|
|
4826
|
-
const PO_SESSION_ENV = "PO_SESSION_ID";
|
|
4827
|
-
/** Operator override for the per-session launch ceiling. */
|
|
4828
|
-
const MAX_CONCURRENT_ENV = "WORKFLOW_MCP_MAX_CONCURRENT";
|
|
4829
|
-
const DEFAULT_MAX_CONCURRENT = 5;
|
|
4830
|
-
/** Resolve the per-session launch ceiling from the environment. */
|
|
4831
|
-
function resolveMaxConcurrent(env) {
|
|
4832
|
-
const parsed = Number(env[MAX_CONCURRENT_ENV]);
|
|
4833
|
-
return Number.isInteger(parsed) && parsed > 0 ? parsed : DEFAULT_MAX_CONCURRENT;
|
|
4834
|
-
}
|
|
4835
|
-
/**
|
|
4836
|
-
* True when this session launched the run.
|
|
4837
|
-
*
|
|
4838
|
-
* Fails closed on a missing session id: an unstamped record (a CLI launch) and
|
|
4839
|
-
* a call arriving before the session id is known both match nothing, so no run
|
|
4840
|
-
* ever leaks across sessions through an undefined-equals-undefined comparison.
|
|
4841
|
-
*/
|
|
4842
|
-
function isSessionRun(record, sessionId) {
|
|
4843
|
-
return sessionId !== void 0 && record.env?.["PO_SESSION_ID"] === sessionId;
|
|
4844
|
-
}
|
|
4845
|
-
/** True when this session handed the run to a workflow session of its own: it is told, but does not own it. */
|
|
4846
|
-
function isLaunchedRun(record, sessionId) {
|
|
4847
|
-
return sessionId !== void 0 && record.env?.["PO_WORKFLOW_LAUNCHER_SESSION_ID"] === sessionId && !isSessionRun(record, sessionId);
|
|
4848
|
-
}
|
|
4849
|
-
/** The line a launcher's finish notice adds: where the run lived, and where to take it up. */
|
|
4850
|
-
function launchedRunHint(record) {
|
|
4851
|
-
return `It ran in workflow session ${record.env?.["PO_SESSION_ID"] ?? "unknown"}; troubleshoot and recover it there.`;
|
|
4852
|
-
}
|
|
4853
|
-
/**
|
|
4854
|
-
* True when this session owns a run another session handed to it: it is the
|
|
4855
|
-
* run's workflow session, so a finished run is posted without starting a turn.
|
|
4856
|
-
*/
|
|
4857
|
-
function isOwnedDelegatedRun(record, sessionId) {
|
|
4858
|
-
const launcher = record.env?.[WORKFLOW_LAUNCHER_SESSION_ENV];
|
|
4859
|
-
return isSessionRun(record, sessionId) && typeof launcher === "string" && launcher !== "" && launcher !== sessionId;
|
|
4860
|
-
}
|
|
4861
|
-
/**
|
|
4862
|
-
* What the caller is told when the registry, not the launcher, acknowledged a
|
|
4863
|
-
* launch.
|
|
4864
|
-
*
|
|
4865
|
-
* Leads with the run key because it is the handle every other workflow action
|
|
4866
|
-
* takes, and it is no longer available any other way: the launcher's own output
|
|
4867
|
-
* is not waited for, so nothing else in this result carries it.
|
|
4868
|
-
*/
|
|
4869
|
-
function launchedRunSummary(record) {
|
|
4870
|
-
return [
|
|
4871
|
-
`Started ${record.displayName} in workspace ${record.workspace}.`,
|
|
4872
|
-
`Run key: ${record.runKey}`,
|
|
4873
|
-
"The run is registered and going. This call returned at that point rather than waiting for the launcher process to exit."
|
|
4874
|
-
].join("\n");
|
|
4875
|
-
}
|
|
4876
|
-
/**
|
|
4877
|
-
* What the caller is told when the launch was handed off but no run has
|
|
4878
|
-
* registered inside the acknowledgement budget.
|
|
4879
|
-
*
|
|
4880
|
-
* Deliberately not an error: the launcher is slow rather than broken often
|
|
4881
|
-
* enough that failing here would strand runs that go on to start normally.
|
|
4882
|
-
* There is no run key to offer yet, so it points at the surfaces that do not
|
|
4883
|
-
* need one.
|
|
4884
|
-
*/
|
|
4885
|
-
function launchHandoffSummary(workflowPath) {
|
|
4886
|
-
return [
|
|
4887
|
-
`Launch handed off for ${workflowPath}, but no run has registered yet.`,
|
|
4888
|
-
"Nothing was cancelled: the launcher is still starting, and a run that registers later still reports back here when it finishes.",
|
|
4889
|
-
"Do not launch it again. Ask the user to check the active workflow list if they need to see it sooner."
|
|
4890
|
-
].join("\n");
|
|
4891
|
-
}
|
|
4892
|
-
new RegExp([
|
|
4893
|
-
"\\u001B\\[[0-9;?]*[ -/]*[@-~]",
|
|
4894
|
-
"\\u001B\\][^\\u0007\\u001B]*(?:\\u0007|\\u001B\\\\)",
|
|
4895
|
-
"\\u001B[@-Z\\\\-_]"
|
|
4896
|
-
].join("|"), "g");
|
|
4897
|
-
/** Flatten MCP tool content to text for Pi. */
|
|
4898
|
-
function toolResultText(result) {
|
|
4899
|
-
return result.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n").trim();
|
|
4900
|
-
}
|
|
4901
|
-
/**
|
|
4902
|
-
* Attach a short menu of next steps to a problem.
|
|
4903
|
-
*
|
|
4904
|
-
* An error with no route forward is where an agent invents one: retrying a
|
|
4905
|
-
* capacity limit, relaunching a run that should be recovered, or silently
|
|
4906
|
-
* giving up on work the user is waiting for. Naming two or three real options
|
|
4907
|
-
* turns an error into a decision, and the decision belongs to the user.
|
|
4908
|
-
*/
|
|
4909
|
-
function withOptions(problem, options) {
|
|
4910
|
-
if (options.length === 0) return problem;
|
|
4911
|
-
return [
|
|
4912
|
-
problem,
|
|
4913
|
-
"",
|
|
4914
|
-
"Options, put these to the user rather than picking one yourself:",
|
|
4915
|
-
...options.map(bullet)
|
|
4916
|
-
].join("\n");
|
|
4917
|
-
}
|
|
4918
|
-
function bullet(option) {
|
|
4919
|
-
return `- ${option}`;
|
|
4920
|
-
}
|
|
4921
|
-
/** The job and step a run died on, preferring the progress log to the record. */
|
|
4922
|
-
function failurePosition(record, jobs) {
|
|
4923
|
-
const failedJob = jobs.find((job) => job.status === "failed");
|
|
4924
|
-
const failedStep = failedJob?.steps.find((step) => step.status === "failed");
|
|
4925
|
-
return {
|
|
4926
|
-
job: failedJob?.name ?? record.failedJob,
|
|
4927
|
-
step: failedStep?.name,
|
|
4928
|
-
reason: failedStep?.reason ?? failedJob?.reason
|
|
4929
|
-
};
|
|
4930
|
-
}
|
|
4931
|
-
/**
|
|
4932
|
-
* Describe a finished run for the agent that launched it.
|
|
4933
|
-
*
|
|
4934
|
-
* Carries the job identifiers back so a dispatching agent can match the run to
|
|
4935
|
-
* the work item it launched it for without another lookup. When the run failed,
|
|
4936
|
-
* carries the failing step and a set of options too: the agent is being told
|
|
4937
|
-
* about this out of band, with no user question in flight, so without them it
|
|
4938
|
-
* has to guess whether to recover, relaunch, or report.
|
|
4939
|
-
*/
|
|
4940
|
-
function finishedRunSummary(record, jobs = []) {
|
|
4941
|
-
const outcome = record.stage === "completed" ? "completed" : `ended in ${record.stage}`;
|
|
4942
|
-
const failure = failurePosition(record, jobs);
|
|
4943
|
-
const lines = [
|
|
4944
|
-
`Workflow run ${record.runKey} in workspace ${record.workspace} ${outcome}.`,
|
|
4945
|
-
record.workflowId ? `Workflow: ${record.workflowId}` : void 0,
|
|
4946
|
-
failure.job ? `Failed job: ${failure.job}${failure.step ? ` (step: ${failure.step})` : ""}` : void 0,
|
|
4947
|
-
record.errorMessage ? `Error: ${record.errorMessage}` : void 0,
|
|
4948
|
-
failure.reason && failure.reason !== record.errorMessage ? `Step reported: ${failure.reason}` : void 0
|
|
4949
|
-
];
|
|
4950
|
-
const jobId = record.env?.AGIFLOW_JOB_ID;
|
|
4951
|
-
if (jobId) lines.push(`Agiflow job: ${record.env?.AGIFLOW_JOB_KIND ?? "unknown"} ${jobId}`);
|
|
4952
|
-
const summary = lines.filter((line) => Boolean(line)).join("\n");
|
|
4953
|
-
if (record.stage === "completed") return summary;
|
|
4954
|
-
if (record.outcome === "interrupted") return withOptions(summary, [`workflow_run {"action":"recover","runKey":${JSON.stringify(record.runKey)}}: pick it up where it stopped.`, "Leave it stopped and move on."]);
|
|
4955
|
-
const diagnosticText = [record.errorMessage, failure.reason].filter(Boolean).join("\n");
|
|
4956
|
-
if (diagnosticText.includes("JOB_ALREADY_CLAIMED")) return withOptions(summary, ["Report contention: another worker owns this job. Do not unlock, release, or retry the claim automatically."]);
|
|
4957
|
-
if (diagnosticText.includes("WORKFLOW_NOT_OWNED") || /release failed/i.test(diagnosticText)) return withOptions(summary, ["Inspect the current workflow ownership and ask the user before any release or unlock. Never force another worker’s lock."]);
|
|
4958
|
-
if (/running workflow not found/i.test(diagnosticText)) return withOptions(summary, [`workflow_run {"action":"status","runKey":${JSON.stringify(record.runKey)}}: re-check current state before retrying.`, "Report the recorded terminal state when no running owner remains."]);
|
|
4959
|
-
return withOptions(summary, [
|
|
4960
|
-
`workflow_run {"action":"tail","runKey":${JSON.stringify(record.runKey)}}: read the run's own output first, when the error above does not explain the failure.`,
|
|
4961
|
-
`workflow_run {"action":"recover","runKey":${JSON.stringify(record.runKey)}}: resume from the failed job, keeping the work already done. Fits a transient or external cause.`,
|
|
4962
|
-
"Report the failure and stop, when it needs a code change or a decision you cannot make."
|
|
4963
|
-
]);
|
|
4964
|
-
}
|
|
4965
|
-
//#endregion
|
|
4966
4967
|
//#region src/services/workflowExecution/index.ts
|
|
4967
4968
|
const AGIFLOW_JOB_ID_ENV = "AGIFLOW_JOB_ID";
|
|
4968
4969
|
const AGIFLOW_JOB_KIND_ENV = "AGIFLOW_JOB_KIND";
|