@memberjunction/task-graph 6.1.0-edge.1 → 6.1.0-edge.3
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/LICENSE +180 -4
- package/README.md +214 -0
- package/dist/TaskClaimStore.d.ts +387 -4
- package/dist/TaskClaimStore.d.ts.map +1 -1
- package/dist/TaskClaimStore.js +605 -20
- package/dist/TaskClaimStore.js.map +1 -1
- package/dist/TaskGraphDispatcher.d.ts +668 -5
- package/dist/TaskGraphDispatcher.d.ts.map +1 -1
- package/dist/TaskGraphDispatcher.js +2942 -127
- package/dist/TaskGraphDispatcher.js.map +1 -1
- package/dist/TaskGraphService.d.ts +364 -5
- package/dist/TaskGraphService.d.ts.map +1 -1
- package/dist/TaskGraphService.js +1039 -43
- package/dist/TaskGraphService.js.map +1 -1
- package/dist/TaskGraphSubmitterImpl.d.ts.map +1 -1
- package/dist/TaskGraphSubmitterImpl.js +5 -0
- package/dist/TaskGraphSubmitterImpl.js.map +1 -1
- package/dist/TaskLoopExecutor.d.ts +62 -0
- package/dist/TaskLoopExecutor.d.ts.map +1 -0
- package/dist/TaskLoopExecutor.js +248 -0
- package/dist/TaskLoopExecutor.js.map +1 -0
- package/dist/WorkflowSpecSync.d.ts +28 -2
- package/dist/WorkflowSpecSync.d.ts.map +1 -1
- package/dist/WorkflowSpecSync.js +83 -2
- package/dist/WorkflowSpecSync.js.map +1 -1
- package/dist/condition-gate.d.ts +128 -0
- package/dist/condition-gate.d.ts.map +1 -0
- package/dist/condition-gate.js +257 -0
- package/dist/condition-gate.js.map +1 -0
- package/dist/debug-state.d.ts +102 -0
- package/dist/debug-state.d.ts.map +1 -0
- package/dist/debug-state.js +135 -0
- package/dist/debug-state.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/operations/TaskGraphDebugOperations.d.ts +99 -0
- package/dist/operations/TaskGraphDebugOperations.d.ts.map +1 -0
- package/dist/operations/TaskGraphDebugOperations.js +310 -0
- package/dist/operations/TaskGraphDebugOperations.js.map +1 -0
- package/dist/operations/TaskGraphOperations.d.ts +20 -2
- package/dist/operations/TaskGraphOperations.d.ts.map +1 -1
- package/dist/operations/TaskGraphOperations.js +51 -8
- package/dist/operations/TaskGraphOperations.js.map +1 -1
- package/dist/operations/WorkflowDraftOperation.d.ts +37 -0
- package/dist/operations/WorkflowDraftOperation.d.ts.map +1 -0
- package/dist/operations/WorkflowDraftOperation.js +141 -0
- package/dist/operations/WorkflowDraftOperation.js.map +1 -0
- package/dist/settlement-rescue.d.ts +85 -0
- package/dist/settlement-rescue.d.ts.map +1 -0
- package/dist/settlement-rescue.js +119 -0
- package/dist/settlement-rescue.js.map +1 -0
- package/dist/task-graph-kick.d.ts +3 -0
- package/dist/task-graph-kick.d.ts.map +1 -0
- package/dist/task-graph-kick.js +17 -0
- package/dist/task-graph-kick.js.map +1 -0
- package/dist/task-predicates.d.ts +77 -0
- package/dist/task-predicates.d.ts.map +1 -0
- package/dist/task-predicates.js +75 -0
- package/dist/task-predicates.js.map +1 -0
- package/dist/types.d.ts +224 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +12 -8
|
@@ -6,9 +6,25 @@ import { TaskGraphSubmitOperation, TaskGraphCancelOperation, TaskGraphRetryTaskO
|
|
|
6
6
|
* Returning before execution is the point: the caller is freed the moment the work is safe, and the
|
|
7
7
|
* dispatcher owns it from there. That is what lets an agent submit a graph over MCP without holding
|
|
8
8
|
* anything open.
|
|
9
|
+
*
|
|
10
|
+
* **REMAINING LIMITATION (C5/D1): a remote submission does not bind to an agent run.**
|
|
11
|
+
* `TaskGraphSubmitContext` carries `AgentRunID`, and this input deliberately has no field for it —
|
|
12
|
+
* whether a remote caller's graph should BIND to an agent run (cost rollup, `reinvoke` routing) is
|
|
13
|
+
* the D1 execution-identity design question, to be decided rather than defaulted. Until then a
|
|
14
|
+
* remote submission records `submittedByAgentRunID: null`: no cost rollup, and `reinvoke` degrades
|
|
15
|
+
* to a message. The other two fields the in-process path carries DO ride this operation now —
|
|
16
|
+
* `reinvokeDepth` (clamped; see below) so the runaway-loop cap counts remote hops, and the R3-3
|
|
17
|
+
* `invocation` envelope so `data.*`/`context.*` conditions evaluate against the invocation instead
|
|
18
|
+
* of nothing.
|
|
9
19
|
*/
|
|
10
20
|
export declare class TaskGraphSubmitServerOperation extends TaskGraphSubmitOperation {
|
|
11
|
-
protected InternalExecute(input: TaskGraphSubmitInput
|
|
21
|
+
protected InternalExecute(input: TaskGraphSubmitInput & {
|
|
22
|
+
reinvokeDepth?: number;
|
|
23
|
+
invocation?: {
|
|
24
|
+
data?: unknown;
|
|
25
|
+
context?: unknown;
|
|
26
|
+
};
|
|
27
|
+
}, provider: IMetadataProvider, user: UserInfo): Promise<TaskGraphSubmitOutput>;
|
|
12
28
|
}
|
|
13
29
|
/** `TaskGraph.Cancel` — cancel a graph and every task in it that has not already settled. */
|
|
14
30
|
export declare class TaskGraphCancelServerOperation extends TaskGraphCancelOperation {
|
|
@@ -21,7 +37,9 @@ export declare class TaskGraphCancelServerOperation extends TaskGraphCancelOpera
|
|
|
21
37
|
* exactly as stuck as before, because nothing downstream ever becomes eligible again.
|
|
22
38
|
*/
|
|
23
39
|
export declare class TaskGraphRetryTaskServerOperation extends TaskGraphRetryTaskOperation {
|
|
24
|
-
protected InternalExecute(input: TaskGraphRetryInput
|
|
40
|
+
protected InternalExecute(input: TaskGraphRetryInput & {
|
|
41
|
+
inputPayload?: Record<string, unknown> | string;
|
|
42
|
+
}, provider: IMetadataProvider, user: UserInfo): Promise<TaskGraphControlOutput>;
|
|
25
43
|
}
|
|
26
44
|
/**
|
|
27
45
|
* `TaskGraph.GetStatus` — snapshot a graph's progress without waiting for anything.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskGraphOperations.d.ts","sourceRoot":"","sources":["../../src/operations/TaskGraphOperations.ts"],"names":[],"mappings":"AAqBA,OAAO,EAA0B,iBAAiB,EAAW,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACpG,OAAO,EAEH,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,2BAA2B,EAC3B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC7B,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"TaskGraphOperations.d.ts","sourceRoot":"","sources":["../../src/operations/TaskGraphOperations.ts"],"names":[],"mappings":"AAqBA,OAAO,EAA0B,iBAAiB,EAAW,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACpG,OAAO,EAEH,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,2BAA2B,EAC3B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC7B,MAAM,+BAA+B,CAAC;AAwCvC;;;;;;;;;;;;;;;;GAgBG;AACH,qBACa,8BAA+B,SAAQ,wBAAwB;cACxD,eAAe,CAQ3B,KAAK,EAAE,oBAAoB,GAAG;QAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,UAAU,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,OAAO,CAAC;YAAC,OAAO,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC;KACtD,EACD,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GACf,OAAO,CAAC,qBAAqB,CAAC;CAyBpC;AAED,6FAA6F;AAC7F,qBACa,8BAA+B,SAAQ,wBAAwB;cACxD,eAAe,CAC3B,KAAK,EAAE,qBAAqB,EAC5B,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GACf,OAAO,CAAC,sBAAsB,CAAC;CAgBrC;AAED;;;;;GAKG;AACH,qBACa,iCAAkC,SAAQ,2BAA2B;cAC9D,eAAe,CAI3B,KAAK,EAAE,mBAAmB,GAAG;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAA;KAAE,EAChF,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GACf,OAAO,CAAC,sBAAsB,CAAC;CAUrC;AAED;;;;;;;GAOG;AACH,qBACa,iCAAkC,SAAQ,2BAA2B;cAC9D,eAAe,CAC3B,KAAK,EAAE,qBAAqB,EAC5B,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GACf,OAAO,CAAC,qBAAqB,CAAC;CAkCpC;AAED,iEAAiE;AACjE,wBAAgB,uBAAuB,IAAI,IAAI,CAY9C"}
|
|
@@ -28,7 +28,9 @@ import { RegisterClass } from '@memberjunction/global';
|
|
|
28
28
|
import { BaseRemotableOperation, RunView } from '@memberjunction/core';
|
|
29
29
|
import { TaskGraphSubmitOperation, TaskGraphCancelOperation, TaskGraphRetryTaskOperation, TaskGraphGetStatusOperation, } from '@memberjunction/core-entities';
|
|
30
30
|
import { ComputeParentRollup } from '@memberjunction/ai-core-plus';
|
|
31
|
-
import { TaskGraphService } from '../TaskGraphService.js';
|
|
31
|
+
import { ClampReinvokeDepth, TaskGraphService } from '../TaskGraphService.js';
|
|
32
|
+
import { LoadWorkflowDraftOperation } from './WorkflowDraftOperation.js';
|
|
33
|
+
import { LoadTaskGraphDebugOperations } from './TaskGraphDebugOperations.js';
|
|
32
34
|
/**
|
|
33
35
|
* Builds the service context from the operation's provider + user.
|
|
34
36
|
*
|
|
@@ -50,15 +52,42 @@ function submitContext(provider, user, environmentID, conversationDetailID) {
|
|
|
50
52
|
* Returning before execution is the point: the caller is freed the moment the work is safe, and the
|
|
51
53
|
* dispatcher owns it from there. That is what lets an agent submit a graph over MCP without holding
|
|
52
54
|
* anything open.
|
|
55
|
+
*
|
|
56
|
+
* **REMAINING LIMITATION (C5/D1): a remote submission does not bind to an agent run.**
|
|
57
|
+
* `TaskGraphSubmitContext` carries `AgentRunID`, and this input deliberately has no field for it —
|
|
58
|
+
* whether a remote caller's graph should BIND to an agent run (cost rollup, `reinvoke` routing) is
|
|
59
|
+
* the D1 execution-identity design question, to be decided rather than defaulted. Until then a
|
|
60
|
+
* remote submission records `submittedByAgentRunID: null`: no cost rollup, and `reinvoke` degrades
|
|
61
|
+
* to a message. The other two fields the in-process path carries DO ride this operation now —
|
|
62
|
+
* `reinvokeDepth` (clamped; see below) so the runaway-loop cap counts remote hops, and the R3-3
|
|
63
|
+
* `invocation` envelope so `data.*`/`context.*` conditions evaluate against the invocation instead
|
|
64
|
+
* of nothing.
|
|
53
65
|
*/
|
|
54
66
|
let TaskGraphSubmitServerOperation = class TaskGraphSubmitServerOperation extends TaskGraphSubmitOperation {
|
|
55
|
-
async InternalExecute(
|
|
67
|
+
async InternalExecute(
|
|
68
|
+
// Widened locally until CodeGen re-emits the base from the updated metadata row, the
|
|
69
|
+
// RetryTask precedent. Two of the three fields the in-process path carries now ride the
|
|
70
|
+
// remote one too: `reinvokeDepth`, because the runaway-loop cap is a safety bound that
|
|
71
|
+
// must count remote hops the same as local ones, and `invocation`, because a flow graph's
|
|
72
|
+
// documented `data.*`/`context.*` conditions (R3-3) are dead on arrival without it.
|
|
73
|
+
// `AgentRunID` stays deliberately absent — whether a remote caller's graph should BIND to
|
|
74
|
+
// an agent run is the D1 execution-identity design question, not a dropped field.
|
|
75
|
+
input, provider, user) {
|
|
56
76
|
if (!input?.spec)
|
|
57
77
|
throw new Error('spec is required');
|
|
58
78
|
if (!input?.environmentID)
|
|
59
79
|
throw new Error('environmentID is required');
|
|
60
80
|
const spec = input.spec;
|
|
61
|
-
const
|
|
81
|
+
const invocation = input.invocation && (input.invocation.data !== undefined || input.invocation.context !== undefined)
|
|
82
|
+
? { Data: input.invocation.data, Context: input.invocation.context }
|
|
83
|
+
: undefined;
|
|
84
|
+
const result = await new TaskGraphService().Submit(spec, {
|
|
85
|
+
...submitContext(provider, user, input.environmentID, input.conversationDetailID),
|
|
86
|
+
// CLAMPED, not merely finite — see ClampReinvokeDepth: a negative caller-supplied
|
|
87
|
+
// seed would buy hops against the runaway-loop cap.
|
|
88
|
+
ReinvokeDepth: ClampReinvokeDepth(input.reinvokeDepth),
|
|
89
|
+
Invocation: invocation,
|
|
90
|
+
});
|
|
62
91
|
return {
|
|
63
92
|
success: result.Success,
|
|
64
93
|
parentTaskID: result.ParentTaskID,
|
|
@@ -77,9 +106,12 @@ let TaskGraphCancelServerOperation = class TaskGraphCancelServerOperation extend
|
|
|
77
106
|
throw new Error('parentTaskID is required');
|
|
78
107
|
// EnvironmentID is unused on the cancel path — the graph already exists, so nothing new is
|
|
79
108
|
// created that would need one.
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
109
|
+
const result = await new TaskGraphService().Cancel(input.parentTaskID, submitContext(provider, user, ''));
|
|
110
|
+
// The verdict names what survived, so the caller can tell the user which parts of their
|
|
111
|
+
// workflow are still running rather than reporting a success the graph does not reflect.
|
|
112
|
+
if (!result.Success) {
|
|
113
|
+
return { success: false, errorMessage: result.ErrorMessage ?? 'Cancel failed; see the server log for detail.' };
|
|
114
|
+
}
|
|
83
115
|
const parent = await provider.GetEntityObject('MJ: Tasks', user);
|
|
84
116
|
const loaded = await parent.Load(input.parentTaskID);
|
|
85
117
|
return { success: true, status: loaded ? parent.Status : undefined };
|
|
@@ -96,10 +128,14 @@ export { TaskGraphCancelServerOperation };
|
|
|
96
128
|
* exactly as stuck as before, because nothing downstream ever becomes eligible again.
|
|
97
129
|
*/
|
|
98
130
|
let TaskGraphRetryTaskServerOperation = class TaskGraphRetryTaskServerOperation extends TaskGraphRetryTaskOperation {
|
|
99
|
-
async InternalExecute(
|
|
131
|
+
async InternalExecute(
|
|
132
|
+
// Widened locally until CodeGen re-emits the base from the updated metadata row: the
|
|
133
|
+
// optional edited input rides the retry so an operator can correct the brief they watched
|
|
134
|
+
// fail. See the InputTypeDefinition on the `TaskGraph.RetryTask` metadata record.
|
|
135
|
+
input, provider, user) {
|
|
100
136
|
if (!input?.taskID)
|
|
101
137
|
throw new Error('taskID is required');
|
|
102
|
-
const ok = await new TaskGraphService().Retry(input.taskID, submitContext(provider, user, ''));
|
|
138
|
+
const ok = await new TaskGraphService().Retry(input.taskID, submitContext(provider, user, ''), input.inputPayload);
|
|
103
139
|
if (!ok)
|
|
104
140
|
return { success: false, errorMessage: 'Retry failed; the task may not be in a Failed state.' };
|
|
105
141
|
const task = await provider.GetEntityObject('MJ: Tasks', user);
|
|
@@ -160,5 +196,12 @@ export function LoadTaskGraphOperations() {
|
|
|
160
196
|
void TaskGraphCancelServerOperation;
|
|
161
197
|
void TaskGraphRetryTaskServerOperation;
|
|
162
198
|
void TaskGraphGetStatusServerOperation;
|
|
199
|
+
// Workflow authoring rides the same loader: a host that starts the dispatcher but never
|
|
200
|
+
// registered these would accept a draft request and route it to the contract-only base.
|
|
201
|
+
LoadWorkflowDraftOperation();
|
|
202
|
+
// The debug/runner control plane (pause, step, breakpoints, interventions) rides it too, for
|
|
203
|
+
// the same reason — a host with the dispatcher but no debug verbs would accept a console's
|
|
204
|
+
// pause request and route it to the throwing base.
|
|
205
|
+
LoadTaskGraphDebugOperations();
|
|
163
206
|
}
|
|
164
207
|
//# sourceMappingURL=TaskGraphOperations.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskGraphOperations.js","sourceRoot":"","sources":["../../src/operations/TaskGraphOperations.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAqB,OAAO,EAAY,MAAM,sBAAsB,CAAC;AACpG,OAAO,EAEH,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,2BAA2B,GAO9B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"TaskGraphOperations.js","sourceRoot":"","sources":["../../src/operations/TaskGraphOperations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
2
|
+
import { WorkflowDraftOperation, type WorkflowDraftInput, type WorkflowDraftOutput } from '@memberjunction/core-entities';
|
|
3
|
+
import { type TaskGraphSpec } from '@memberjunction/ai-core-plus';
|
|
4
|
+
/** The seeded prompt that does the drafting. */
|
|
5
|
+
export declare const WORKFLOW_DRAFTING_PROMPT = "Workflow Drafting";
|
|
6
|
+
/**
|
|
7
|
+
* How many agent names the prompt is told about.
|
|
8
|
+
*
|
|
9
|
+
* Bounded because the list goes into a prompt: an instance with hundreds of agents would spend most
|
|
10
|
+
* of its context enumerating them, and a model choosing between 300 names chooses worse than one
|
|
11
|
+
* choosing between 40. Top-level agents come first — those are the ones a workflow step can actually
|
|
12
|
+
* be assigned to.
|
|
13
|
+
*/
|
|
14
|
+
export declare const MAX_AGENTS_OFFERED = 40;
|
|
15
|
+
/** `Workflow.Draft` — draft a workflow's steps from a description. Persists nothing. */
|
|
16
|
+
export declare class WorkflowDraftServerOperation extends WorkflowDraftOperation {
|
|
17
|
+
protected InternalExecute(input: WorkflowDraftInput, provider: IMetadataProvider, user: UserInfo): Promise<WorkflowDraftOutput>;
|
|
18
|
+
/**
|
|
19
|
+
* Checks the model's output against the SAME validator the canvas and `Workflow.Save` run.
|
|
20
|
+
*
|
|
21
|
+
* A draft that comes back must be savable. Returning something that only fails later — on the
|
|
22
|
+
* canvas, or worse at save time — would put the author in the position of debugging a graph they
|
|
23
|
+
* did not write, which is precisely the work this operation was meant to save them.
|
|
24
|
+
*/
|
|
25
|
+
protected acceptDraft(draft: TaskGraphSpec, workflowName: string): WorkflowDraftOutput;
|
|
26
|
+
/**
|
|
27
|
+
* Agent names a step may be assigned to.
|
|
28
|
+
*
|
|
29
|
+
* Top-level agents only. A sub-agent exists to be called by its parent, so offering one as a
|
|
30
|
+
* workflow step would produce a draft that looks fine and assigns work to something that was
|
|
31
|
+
* never meant to be entered directly.
|
|
32
|
+
*/
|
|
33
|
+
protected resolveAssignableAgents(provider: IMetadataProvider, user: UserInfo): Promise<string[]>;
|
|
34
|
+
}
|
|
35
|
+
/** Keeps the registration from being tree-shaken out of a bundled host. */
|
|
36
|
+
export declare function LoadWorkflowDraftOperation(): void;
|
|
37
|
+
//# sourceMappingURL=WorkflowDraftOperation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkflowDraftOperation.d.ts","sourceRoot":"","sources":["../../src/operations/WorkflowDraftOperation.ts"],"names":[],"mappings":"AAoBA,OAAO,EAA0B,iBAAiB,EAAqB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC9G,OAAO,EACH,sBAAsB,EACtB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAIH,KAAK,aAAa,EACrB,MAAM,8BAA8B,CAAC;AAItC,gDAAgD;AAChD,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAE5D;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,wFAAwF;AACxF,qBACa,4BAA6B,SAAQ,sBAAsB;cACpD,eAAe,CAC3B,KAAK,EAAE,kBAAkB,EACzB,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GACf,OAAO,CAAC,mBAAmB,CAAC;IAgD/B;;;;;;OAMG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,GAAG,mBAAmB;IAetF;;;;;;OAMG;cACa,uBAAuB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAiB1G;AAED,2EAA2E;AAC3E,wBAAgB,0BAA0B,IAAI,IAAI,CAGjD"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* @fileoverview `Workflow.Draft` — turn a description into a workflow's steps.
|
|
9
|
+
*
|
|
10
|
+
* **Why this exists.** The Create Workflow front door offers three doors, and the middle one says
|
|
11
|
+
* *"Say what you want done. We draft the steps; you refine them on the canvas."* Without this
|
|
12
|
+
* operation that sentence is a promise the product does not keep — the author types a brief and
|
|
13
|
+
* lands on an empty canvas, which is worse than not offering the door at all.
|
|
14
|
+
*
|
|
15
|
+
* **It persists nothing.** The draft goes back to the caller and onto the canvas; `Workflow.Save` is
|
|
16
|
+
* what commits. That split is what makes the tile's other promise — *"Nothing is saved until you
|
|
17
|
+
* approve it"* — true rather than merely stated, and it is the same draft-then-confirm shape dry-run
|
|
18
|
+
* and Plan Mode already established.
|
|
19
|
+
*
|
|
20
|
+
* **A Remote Operation, per the program's standing rule**, so drafting is reachable from MCP, an
|
|
21
|
+
* Action wrapper and the editor by the same typed call — not a mutation only the Explorer client can
|
|
22
|
+
* make.
|
|
23
|
+
*
|
|
24
|
+
* @module @memberjunction/task-graph
|
|
25
|
+
*/
|
|
26
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
27
|
+
import { BaseRemotableOperation, LogError, RunView } from '@memberjunction/core';
|
|
28
|
+
import { WorkflowDraftOperation, } from '@memberjunction/core-entities';
|
|
29
|
+
import { AIPromptParams, FormatValidationErrors, ValidateTaskGraphSpec, } from '@memberjunction/ai-core-plus';
|
|
30
|
+
import { AIEngine } from '@memberjunction/aiengine';
|
|
31
|
+
import { AIPromptRunner } from '@memberjunction/ai-prompts';
|
|
32
|
+
/** The seeded prompt that does the drafting. */
|
|
33
|
+
export const WORKFLOW_DRAFTING_PROMPT = 'Workflow Drafting';
|
|
34
|
+
/**
|
|
35
|
+
* How many agent names the prompt is told about.
|
|
36
|
+
*
|
|
37
|
+
* Bounded because the list goes into a prompt: an instance with hundreds of agents would spend most
|
|
38
|
+
* of its context enumerating them, and a model choosing between 300 names chooses worse than one
|
|
39
|
+
* choosing between 40. Top-level agents come first — those are the ones a workflow step can actually
|
|
40
|
+
* be assigned to.
|
|
41
|
+
*/
|
|
42
|
+
export const MAX_AGENTS_OFFERED = 40;
|
|
43
|
+
/** `Workflow.Draft` — draft a workflow's steps from a description. Persists nothing. */
|
|
44
|
+
let WorkflowDraftServerOperation = class WorkflowDraftServerOperation extends WorkflowDraftOperation {
|
|
45
|
+
async InternalExecute(input, provider, user) {
|
|
46
|
+
const description = input?.description?.trim();
|
|
47
|
+
const workflowName = input?.workflowName?.trim();
|
|
48
|
+
if (!description)
|
|
49
|
+
return { success: false, errorMessage: 'A description is required to draft a workflow.' };
|
|
50
|
+
if (!workflowName)
|
|
51
|
+
return { success: false, errorMessage: 'A workflow name is required.' };
|
|
52
|
+
try {
|
|
53
|
+
await AIEngine.Instance.Config(false, user, provider);
|
|
54
|
+
const prompt = AIEngine.Instance.Prompts.find((p) => p.Name === WORKFLOW_DRAFTING_PROMPT);
|
|
55
|
+
if (!prompt) {
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
errorMessage: `The '${WORKFLOW_DRAFTING_PROMPT}' prompt is not present — has the metadata seed been pushed?`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const agentNames = await this.resolveAssignableAgents(provider, user);
|
|
62
|
+
if (agentNames.length === 0) {
|
|
63
|
+
// Stated rather than drafted around: every step needs an assignment, so a draft
|
|
64
|
+
// produced with no agents to assign would be invalid the moment it was validated.
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
errorMessage: 'No agents are available to run workflow steps on this instance, so there is nothing to draft with.',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const params = new AIPromptParams();
|
|
71
|
+
params.prompt = prompt;
|
|
72
|
+
params.contextUser = user;
|
|
73
|
+
params.data = {
|
|
74
|
+
description,
|
|
75
|
+
workflowName,
|
|
76
|
+
availableAgents: agentNames.join('\n'),
|
|
77
|
+
};
|
|
78
|
+
const result = await new AIPromptRunner().ExecutePrompt(params);
|
|
79
|
+
if (!result.success || !result.result) {
|
|
80
|
+
return { success: false, errorMessage: result.errorMessage ?? 'The workflow could not be drafted.' };
|
|
81
|
+
}
|
|
82
|
+
return this.acceptDraft(result.result, workflowName);
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
86
|
+
LogError(`[Workflow.Draft] Drafting failed for "${workflowName}": ${message}`);
|
|
87
|
+
return { success: false, errorMessage: message };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Checks the model's output against the SAME validator the canvas and `Workflow.Save` run.
|
|
92
|
+
*
|
|
93
|
+
* A draft that comes back must be savable. Returning something that only fails later — on the
|
|
94
|
+
* canvas, or worse at save time — would put the author in the position of debugging a graph they
|
|
95
|
+
* did not write, which is precisely the work this operation was meant to save them.
|
|
96
|
+
*/
|
|
97
|
+
acceptDraft(draft, workflowName) {
|
|
98
|
+
// The name is the author's, not the model's: they typed it on the front door, and a model
|
|
99
|
+
// quietly renaming their workflow is a small betrayal of a field they filled in themselves.
|
|
100
|
+
const graph = { ...draft, workflowName };
|
|
101
|
+
const validation = ValidateTaskGraphSpec(graph);
|
|
102
|
+
if (!validation.Valid) {
|
|
103
|
+
return {
|
|
104
|
+
success: false,
|
|
105
|
+
errorMessage: `The drafted workflow was not usable:\n${FormatValidationErrors(validation.Errors)}`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return { success: true, graph };
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Agent names a step may be assigned to.
|
|
112
|
+
*
|
|
113
|
+
* Top-level agents only. A sub-agent exists to be called by its parent, so offering one as a
|
|
114
|
+
* workflow step would produce a draft that looks fine and assigns work to something that was
|
|
115
|
+
* never meant to be entered directly.
|
|
116
|
+
*/
|
|
117
|
+
async resolveAssignableAgents(provider, user) {
|
|
118
|
+
const result = await RunView.FromMetadataProvider(provider).RunView({
|
|
119
|
+
EntityName: 'MJ: AI Agents',
|
|
120
|
+
ExtraFilter: `Status='Active' AND ParentID IS NULL`,
|
|
121
|
+
Fields: ['Name'],
|
|
122
|
+
OrderBy: 'Name ASC',
|
|
123
|
+
MaxRows: MAX_AGENTS_OFFERED,
|
|
124
|
+
ResultType: 'simple',
|
|
125
|
+
}, user);
|
|
126
|
+
if (!result.Success) {
|
|
127
|
+
throw new Error(result.ErrorMessage ?? 'The list of available agents could not be read.');
|
|
128
|
+
}
|
|
129
|
+
return (result.Results ?? []).map((a) => a.Name).filter((n) => !!n);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
WorkflowDraftServerOperation = __decorate([
|
|
133
|
+
RegisterClass(BaseRemotableOperation, 'Workflow.Draft')
|
|
134
|
+
], WorkflowDraftServerOperation);
|
|
135
|
+
export { WorkflowDraftServerOperation };
|
|
136
|
+
/** Keeps the registration from being tree-shaken out of a bundled host. */
|
|
137
|
+
export function LoadWorkflowDraftOperation() {
|
|
138
|
+
// Referencing the class is what the bundler needs.
|
|
139
|
+
void WorkflowDraftServerOperation;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=WorkflowDraftOperation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkflowDraftOperation.js","sourceRoot":"","sources":["../../src/operations/WorkflowDraftOperation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** How long after settling a graph is still eligible for a normal continuation delivery. */
|
|
2
|
+
export declare const UNSETTLED_SWEEP_WINDOW_HOURS = 24;
|
|
3
|
+
/**
|
|
4
|
+
* How far back the ONE startup sweep looks.
|
|
5
|
+
*
|
|
6
|
+
* Wider than the steady-state window because a deployment gap is exactly the case the rescue exists
|
|
7
|
+
* for: nothing was running, so nothing swept, and the graphs stranded by whatever took the process
|
|
8
|
+
* down are older than a day by the time it returns. Runs once at `Start()`, so the cost of the wider
|
|
9
|
+
* scan is paid once per process, not once per poll.
|
|
10
|
+
*/
|
|
11
|
+
export declare const UNSETTLED_STARTUP_WINDOW_HOURS: number;
|
|
12
|
+
/**
|
|
13
|
+
* How long a settled graph waits for its submitting run to park before giving up on it.
|
|
14
|
+
*
|
|
15
|
+
* `BaseAgent.finalizeAgentRun` parks the run within moments of the graph becoming dispatchable, so
|
|
16
|
+
* the honest window is seconds; anything beyond this means the submitting process is gone. Generous
|
|
17
|
+
* enough that a loaded machine does not trip it, short enough that a dead submitter cannot hold a
|
|
18
|
+
* completed workflow's announcement hostage for a day.
|
|
19
|
+
*/
|
|
20
|
+
export declare const SUBMITTER_PARK_GRACE_MS: number;
|
|
21
|
+
/**
|
|
22
|
+
* Whether this pass's writes to the submitting run will mean anything yet.
|
|
23
|
+
*
|
|
24
|
+
* **The `Running` case is the whole point.** A graph can settle before the run that submitted it has
|
|
25
|
+
* parked at all: `finalizeAgentRun` sets `Paused` *after* the graph is durable and dispatchable, so
|
|
26
|
+
* a fast graph finishes first. Both of the settled branch's writes then land wrong — the lifecycle
|
|
27
|
+
* write silently returns (its guard is `Status === 'Paused'`), and the cost write is overwritten
|
|
28
|
+
* moments later by finalize's own full-row save carrying the nulls it held before the dispatcher
|
|
29
|
+
* wrote anything. Neither failure is visible, and the pass then claims the delivery marker, making
|
|
30
|
+
* itself the last pass ever to look at the graph. The run stays `Paused` forever.
|
|
31
|
+
*
|
|
32
|
+
* Every other status proceeds: `Paused` is the case settlement exists for, and a run already
|
|
33
|
+
* `Completed`/`Failed`/`Cancelled` reached that for its own reasons — the lifecycle write's own
|
|
34
|
+
* guard declines it, which is correct, and delivery should not be held up by it.
|
|
35
|
+
*
|
|
36
|
+
* **Bounded, because "not parked yet" and "the submitter died before parking" look identical from
|
|
37
|
+
* here.** Waiting forever on the second loses the outcome of work that actually completed, which is
|
|
38
|
+
* strictly worse than announcing it late — so past the grace period the caller proceeds and says
|
|
39
|
+
* why. The run stays `Running`, which is visibly wrong and belongs to whatever reconciles abandoned
|
|
40
|
+
* runs, not to the graph that finished correctly.
|
|
41
|
+
*
|
|
42
|
+
* @param settledForMs how long ago the graph reached its terminal status
|
|
43
|
+
*/
|
|
44
|
+
export declare function IsSubmittingRunReady(runStatus: string, settledForMs: number, graceMs?: number): boolean;
|
|
45
|
+
/** The shape the third sweep arm selects — everything needed to judge "settled but undelivered". */
|
|
46
|
+
export type UnsettledCandidate = {
|
|
47
|
+
ID: string | null;
|
|
48
|
+
InputPayload: string | null;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* The oldest `__mj_UpdatedAt` still worth rescuing, as an ISO string for the SQL filter.
|
|
52
|
+
*
|
|
53
|
+
* The bound is on ABANDONMENT, not age: `__mj_UpdatedAt` advances on every settle attempt, so a
|
|
54
|
+
* graph something is still actively retrying keeps re-entering the window. What ages out is a graph
|
|
55
|
+
* nothing has touched — which is the only kind this sweep can help.
|
|
56
|
+
*/
|
|
57
|
+
export declare function SweepCutoff(now: Date, windowHours: number): string;
|
|
58
|
+
/**
|
|
59
|
+
* Picks the graphs that reached a terminal status without delivering their continuation.
|
|
60
|
+
*
|
|
61
|
+
* Filtered here rather than in SQL because the delivery marker lives inside the parent's
|
|
62
|
+
* `InputPayload` JSON, and it lives there deliberately: one representation means the writer
|
|
63
|
+
* (`TryClaimContinuation`) and the reader are pinned to each other, and a graph settled before any
|
|
64
|
+
* of this existed is judged by the same parser as one settled after — which a new column plus a
|
|
65
|
+
* backfill could not promise.
|
|
66
|
+
*
|
|
67
|
+
* **An unreadable payload counts as undelivered.** It is selected, the claim then refuses it
|
|
68
|
+
* (`ISJSON` guard), and it is selected again next pass until it ages out of the window. That is the
|
|
69
|
+
* intended shape: we cannot prove such a graph was delivered, so we must not assume it, and the
|
|
70
|
+
* window is what keeps "cannot prove" from meaning "retry forever".
|
|
71
|
+
*/
|
|
72
|
+
export declare function SelectUnsettledGraphIDs(rows: readonly UnsettledCandidate[]): string[];
|
|
73
|
+
/**
|
|
74
|
+
* Whether a settlement is too old to deliver as if it had just happened.
|
|
75
|
+
*
|
|
76
|
+
* A graph stranded by a crash and found days later should still settle its run and stop showing as
|
|
77
|
+
* `Paused` — but re-invoking the submitting agent on stale context, or messaging a conversation
|
|
78
|
+
* about work that finished last week, is worse than not delivering. So an expired settlement takes
|
|
79
|
+
* the same once-only claim and records itself as `expired`, which keeps the distinction visible
|
|
80
|
+
* afterwards instead of erasing it.
|
|
81
|
+
*
|
|
82
|
+
* A graph with no `CompletedAt` has not settled at all, so there is nothing to have expired.
|
|
83
|
+
*/
|
|
84
|
+
export declare function IsSettlementExpired(completedAt: Date | null | undefined, now: Date, windowHours?: number): boolean;
|
|
85
|
+
//# sourceMappingURL=settlement-rescue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlement-rescue.d.ts","sourceRoot":"","sources":["../src/settlement-rescue.ts"],"names":[],"mappings":"AAoBA,4FAA4F;AAC5F,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,QAAU,CAAC;AAEtD;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,QAAa,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAChC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,MAAgC,GAC1C,OAAO,CAGT;AAED,oGAAoG;AACpG,MAAM,MAAM,kBAAkB,GAAG;IAC7B,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,EAAE,CAQrF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAC/B,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,EACpC,GAAG,EAAE,IAAI,EACT,WAAW,GAAE,MAAqC,GACnD,OAAO,CAGT"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The decisions that rescue a graph whose settlement never finished.
|
|
3
|
+
*
|
|
4
|
+
* **Why these live here and not inside the dispatcher.** A graph settles in two steps that are not
|
|
5
|
+
* one transaction: the parent's terminal write, and then the post-settlement sequence — cost rollup,
|
|
6
|
+
* agent-run settlement, continuation delivery. A process that dies between them leaves a graph that
|
|
7
|
+
* is finished by every query the dispatcher runs and yet has delivered nothing, with the submitting
|
|
8
|
+
* agent run `Paused` forever. The third sweep arm exists to find exactly those.
|
|
9
|
+
*
|
|
10
|
+
* That makes this the one part of settlement whose correctness is a *predicate*, not a statement:
|
|
11
|
+
* which rows are unfinished, and when is an unfinished one too old to deliver normally. Left inside
|
|
12
|
+
* `TaskGraphDispatcher` they could only be exercised through a fake `RunView`, a fake entity object
|
|
13
|
+
* and a fake clock — a test that mostly asserts the shape of its own mocks. Pulled out, they are
|
|
14
|
+
* ordinary functions with ordinary tests, and the dispatcher keeps the I/O.
|
|
15
|
+
*
|
|
16
|
+
* The guarded WRITES stay in `TaskClaimStore`, where the statement is the guarantee. This module
|
|
17
|
+
* decides *whether* to attempt them; that module decides what happens when two instances both do.
|
|
18
|
+
*/
|
|
19
|
+
import { ParseTaskGraphParentMetadata } from './TaskGraphService.js';
|
|
20
|
+
/** How long after settling a graph is still eligible for a normal continuation delivery. */
|
|
21
|
+
export const UNSETTLED_SWEEP_WINDOW_HOURS = 24;
|
|
22
|
+
/**
|
|
23
|
+
* How far back the ONE startup sweep looks.
|
|
24
|
+
*
|
|
25
|
+
* Wider than the steady-state window because a deployment gap is exactly the case the rescue exists
|
|
26
|
+
* for: nothing was running, so nothing swept, and the graphs stranded by whatever took the process
|
|
27
|
+
* down are older than a day by the time it returns. Runs once at `Start()`, so the cost of the wider
|
|
28
|
+
* scan is paid once per process, not once per poll.
|
|
29
|
+
*/
|
|
30
|
+
export const UNSETTLED_STARTUP_WINDOW_HOURS = 24 * 30;
|
|
31
|
+
/**
|
|
32
|
+
* How long a settled graph waits for its submitting run to park before giving up on it.
|
|
33
|
+
*
|
|
34
|
+
* `BaseAgent.finalizeAgentRun` parks the run within moments of the graph becoming dispatchable, so
|
|
35
|
+
* the honest window is seconds; anything beyond this means the submitting process is gone. Generous
|
|
36
|
+
* enough that a loaded machine does not trip it, short enough that a dead submitter cannot hold a
|
|
37
|
+
* completed workflow's announcement hostage for a day.
|
|
38
|
+
*/
|
|
39
|
+
export const SUBMITTER_PARK_GRACE_MS = 5 * 60_000;
|
|
40
|
+
/**
|
|
41
|
+
* Whether this pass's writes to the submitting run will mean anything yet.
|
|
42
|
+
*
|
|
43
|
+
* **The `Running` case is the whole point.** A graph can settle before the run that submitted it has
|
|
44
|
+
* parked at all: `finalizeAgentRun` sets `Paused` *after* the graph is durable and dispatchable, so
|
|
45
|
+
* a fast graph finishes first. Both of the settled branch's writes then land wrong — the lifecycle
|
|
46
|
+
* write silently returns (its guard is `Status === 'Paused'`), and the cost write is overwritten
|
|
47
|
+
* moments later by finalize's own full-row save carrying the nulls it held before the dispatcher
|
|
48
|
+
* wrote anything. Neither failure is visible, and the pass then claims the delivery marker, making
|
|
49
|
+
* itself the last pass ever to look at the graph. The run stays `Paused` forever.
|
|
50
|
+
*
|
|
51
|
+
* Every other status proceeds: `Paused` is the case settlement exists for, and a run already
|
|
52
|
+
* `Completed`/`Failed`/`Cancelled` reached that for its own reasons — the lifecycle write's own
|
|
53
|
+
* guard declines it, which is correct, and delivery should not be held up by it.
|
|
54
|
+
*
|
|
55
|
+
* **Bounded, because "not parked yet" and "the submitter died before parking" look identical from
|
|
56
|
+
* here.** Waiting forever on the second loses the outcome of work that actually completed, which is
|
|
57
|
+
* strictly worse than announcing it late — so past the grace period the caller proceeds and says
|
|
58
|
+
* why. The run stays `Running`, which is visibly wrong and belongs to whatever reconciles abandoned
|
|
59
|
+
* runs, not to the graph that finished correctly.
|
|
60
|
+
*
|
|
61
|
+
* @param settledForMs how long ago the graph reached its terminal status
|
|
62
|
+
*/
|
|
63
|
+
export function IsSubmittingRunReady(runStatus, settledForMs, graceMs = SUBMITTER_PARK_GRACE_MS) {
|
|
64
|
+
if (runStatus !== 'Running')
|
|
65
|
+
return true;
|
|
66
|
+
return settledForMs > graceMs;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The oldest `__mj_UpdatedAt` still worth rescuing, as an ISO string for the SQL filter.
|
|
70
|
+
*
|
|
71
|
+
* The bound is on ABANDONMENT, not age: `__mj_UpdatedAt` advances on every settle attempt, so a
|
|
72
|
+
* graph something is still actively retrying keeps re-entering the window. What ages out is a graph
|
|
73
|
+
* nothing has touched — which is the only kind this sweep can help.
|
|
74
|
+
*/
|
|
75
|
+
export function SweepCutoff(now, windowHours) {
|
|
76
|
+
return new Date(now.getTime() - windowHours * 3600_000).toISOString();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Picks the graphs that reached a terminal status without delivering their continuation.
|
|
80
|
+
*
|
|
81
|
+
* Filtered here rather than in SQL because the delivery marker lives inside the parent's
|
|
82
|
+
* `InputPayload` JSON, and it lives there deliberately: one representation means the writer
|
|
83
|
+
* (`TryClaimContinuation`) and the reader are pinned to each other, and a graph settled before any
|
|
84
|
+
* of this existed is judged by the same parser as one settled after — which a new column plus a
|
|
85
|
+
* backfill could not promise.
|
|
86
|
+
*
|
|
87
|
+
* **An unreadable payload counts as undelivered.** It is selected, the claim then refuses it
|
|
88
|
+
* (`ISJSON` guard), and it is selected again next pass until it ages out of the window. That is the
|
|
89
|
+
* intended shape: we cannot prove such a graph was delivered, so we must not assume it, and the
|
|
90
|
+
* window is what keeps "cannot prove" from meaning "retry forever".
|
|
91
|
+
*/
|
|
92
|
+
export function SelectUnsettledGraphIDs(rows) {
|
|
93
|
+
const ids = [];
|
|
94
|
+
for (const row of rows) {
|
|
95
|
+
if (!row.ID)
|
|
96
|
+
continue;
|
|
97
|
+
if (ParseTaskGraphParentMetadata(row.InputPayload).continuationDeliveredAt)
|
|
98
|
+
continue;
|
|
99
|
+
ids.push(row.ID);
|
|
100
|
+
}
|
|
101
|
+
return ids;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Whether a settlement is too old to deliver as if it had just happened.
|
|
105
|
+
*
|
|
106
|
+
* A graph stranded by a crash and found days later should still settle its run and stop showing as
|
|
107
|
+
* `Paused` — but re-invoking the submitting agent on stale context, or messaging a conversation
|
|
108
|
+
* about work that finished last week, is worse than not delivering. So an expired settlement takes
|
|
109
|
+
* the same once-only claim and records itself as `expired`, which keeps the distinction visible
|
|
110
|
+
* afterwards instead of erasing it.
|
|
111
|
+
*
|
|
112
|
+
* A graph with no `CompletedAt` has not settled at all, so there is nothing to have expired.
|
|
113
|
+
*/
|
|
114
|
+
export function IsSettlementExpired(completedAt, now, windowHours = UNSETTLED_SWEEP_WINDOW_HOURS) {
|
|
115
|
+
if (!completedAt)
|
|
116
|
+
return false;
|
|
117
|
+
return now.getTime() - completedAt.getTime() > windowHours * 3600_000;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=settlement-rescue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlement-rescue.js","sourceRoot":"","sources":["../src/settlement-rescue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAElE,4FAA4F;AAC5F,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,CAAC;AAE/C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,EAAE,GAAG,EAAE,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,GAAG,MAAM,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,oBAAoB,CAChC,SAAiB,EACjB,YAAoB,EACpB,UAAkB,uBAAuB;IAEzC,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO,YAAY,GAAG,OAAO,CAAC;AAClC,CAAC;AAQD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,GAAS,EAAE,WAAmB;IACtD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,WAAW,GAAG,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;AAC1E,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAmC;IACvE,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,SAAS;QACtB,IAAI,4BAA4B,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,uBAAuB;YAAE,SAAS;QACrF,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAC/B,WAAoC,EACpC,GAAS,EACT,cAAsB,4BAA4B;IAElD,IAAI,CAAC,WAAW;QAAE,OAAO,KAAK,CAAC;IAC/B,OAAO,GAAG,CAAC,OAAO,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,GAAG,WAAW,GAAG,QAAQ,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-graph-kick.d.ts","sourceRoot":"","sources":["../src/task-graph-kick.ts"],"names":[],"mappings":"AASA,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAGlE;AAED,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wake running dispatchers the moment a graph is submitted.
|
|
3
|
+
*
|
|
4
|
+
* The poll timer is 5s — fine in production, a noticeable dead pause after Debug/Run. Submit
|
|
5
|
+
* cannot import the dispatcher instance (submit and execute are separate halves), so each
|
|
6
|
+
* started dispatcher registers a kick here and Submit pokes the set.
|
|
7
|
+
*/
|
|
8
|
+
const kicks = new Set();
|
|
9
|
+
export function RegisterTaskGraphKick(kick) {
|
|
10
|
+
kicks.add(kick);
|
|
11
|
+
return () => { kicks.delete(kick); };
|
|
12
|
+
}
|
|
13
|
+
export function KickTaskGraphDispatchers() {
|
|
14
|
+
for (const kick of kicks)
|
|
15
|
+
kick();
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=task-graph-kick.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-graph-kick.js","sourceRoot":"","sources":["../src/task-graph-kick.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,KAAK,GAAG,IAAI,GAAG,EAAc,CAAC;AAEpC,MAAM,UAAU,qBAAqB,CAAC,IAAgB;IAClD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChB,OAAO,GAAG,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,wBAAwB;IACpC,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,IAAI,EAAE,CAAC;AACrC,CAAC"}
|