@memberjunction/task-graph 0.0.0 → 6.1.0-edge.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/LICENSE +7 -0
- package/README.md +167 -27
- package/dist/DispatcherConditionEvaluator.d.ts +10 -0
- package/dist/DispatcherConditionEvaluator.d.ts.map +1 -0
- package/dist/DispatcherConditionEvaluator.js +27 -0
- package/dist/DispatcherConditionEvaluator.js.map +1 -0
- package/dist/TaskClaimStore.d.ts +125 -0
- package/dist/TaskClaimStore.d.ts.map +1 -0
- package/dist/TaskClaimStore.js +223 -0
- package/dist/TaskClaimStore.js.map +1 -0
- package/dist/TaskGraphDispatcher.d.ts +548 -0
- package/dist/TaskGraphDispatcher.d.ts.map +1 -0
- package/dist/TaskGraphDispatcher.js +2232 -0
- package/dist/TaskGraphDispatcher.js.map +1 -0
- package/dist/TaskGraphService.d.ts +247 -0
- package/dist/TaskGraphService.d.ts.map +1 -0
- package/dist/TaskGraphService.js +753 -0
- package/dist/TaskGraphService.js.map +1 -0
- package/dist/TaskGraphSubmitterImpl.d.ts +7 -0
- package/dist/TaskGraphSubmitterImpl.d.ts.map +1 -0
- package/dist/TaskGraphSubmitterImpl.js +52 -0
- package/dist/TaskGraphSubmitterImpl.js.map +1 -0
- 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 +197 -0
- package/dist/WorkflowSpecSync.d.ts.map +1 -0
- package/dist/WorkflowSpecSync.js +474 -0
- package/dist/WorkflowSpecSync.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/operations/TaskGraphOperations.d.ts +39 -0
- package/dist/operations/TaskGraphOperations.d.ts.map +1 -0
- package/dist/operations/TaskGraphOperations.js +168 -0
- package/dist/operations/TaskGraphOperations.js.map +1 -0
- 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/operations/WorkflowOperations.d.ts +22 -0
- package/dist/operations/WorkflowOperations.d.ts.map +1 -0
- package/dist/operations/WorkflowOperations.js +99 -0
- package/dist/operations/WorkflowOperations.js.map +1 -0
- package/dist/types.d.ts +328 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +36 -8
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Persists a `WorkflowSpec` by **reconciling substrates that already exist**.
|
|
3
|
+
*
|
|
4
|
+
* **The central design constraint: no new storage.** There is no `Workflow` table and there will not
|
|
5
|
+
* be one. A workflow's WHAT is a Flow agent (the graph); its WHEN is a Scheduled Job or an Entity
|
|
6
|
+
* Action binding. Inventing a parallel `Workflow` row would create a second definition of "a
|
|
7
|
+
* scheduled thing", and the scheduler would then have two masters that can disagree — which is
|
|
8
|
+
* exactly the class of divergence this whole program has been removing.
|
|
9
|
+
*
|
|
10
|
+
* So this is a **reconciler**, not a writer. It follows the pattern
|
|
11
|
+
* `MJRecordProcessEntityServer.Save()` already proved: resolve the job type, find the rows this
|
|
12
|
+
* definition owns, then upsert or disable them so the substrate matches the spec. Rows are matched
|
|
13
|
+
* by a marker in their own `Configuration`, which is what makes ownership survive a rename.
|
|
14
|
+
*
|
|
15
|
+
* **Agent persistence crosses a seam.** Writing the Flow agent behind the graph is `AgentSpecSync`'s
|
|
16
|
+
* job — it already owns atomic multi-entity agent writes and the mutation audit. Importing it here
|
|
17
|
+
* would pull the agent-manager package into the execution substrate, so the host injects it instead.
|
|
18
|
+
* A caller with no agent writer still gets correct trigger reconciliation and an honest error rather
|
|
19
|
+
* than a half-persisted workflow.
|
|
20
|
+
*
|
|
21
|
+
* @module @memberjunction/task-graph
|
|
22
|
+
*/
|
|
23
|
+
import { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
24
|
+
import { type WorkflowSpec } from '@memberjunction/ai-core-plus';
|
|
25
|
+
/**
|
|
26
|
+
* Scheduled Job Type that runs a workflow's Flow agent.
|
|
27
|
+
*
|
|
28
|
+
* `'Agent'` is an existing seeded type backed by `AgentScheduledJobDriver` — a workflow's schedule
|
|
29
|
+
* reuses it rather than introducing a parallel one. `ScheduledJobType.DriverClass` is UNIQUE, so a
|
|
30
|
+
* second type for the same driver is not merely redundant, it is impossible; discovering that is
|
|
31
|
+
* what confirmed the substrate was already there and only the authoring surface was missing.
|
|
32
|
+
*/
|
|
33
|
+
export declare const RUN_WORKFLOW_JOB_TYPE = "Agent";
|
|
34
|
+
/** Marker written into an owned row's `Configuration`, so ownership survives a rename. */
|
|
35
|
+
export declare const WORKFLOW_OWNER_KEY = "WorkflowAgentID";
|
|
36
|
+
/**
|
|
37
|
+
* The Action an entity-change trigger dispatches to.
|
|
38
|
+
*
|
|
39
|
+
* `Execute Agent` already exists and was written for exactly this: "a concrete dispatch target for
|
|
40
|
+
* `AIAgent.ExposeAsAction`". Entity-action *invocation* is likewise already wired — the save pipeline
|
|
41
|
+
* fires validate / before-save / after-save / before-delete / after-delete through
|
|
42
|
+
* `HandleEntityActions`. So an entity-change trigger needs no new machinery at all; it needs a
|
|
43
|
+
* binding row, which is what this creates.
|
|
44
|
+
*/
|
|
45
|
+
export declare const EXECUTE_AGENT_ACTION = "Execute Agent";
|
|
46
|
+
/** Everything reconciliation needs beyond the spec itself. */
|
|
47
|
+
export type WorkflowSyncContext = {
|
|
48
|
+
ContextUser: UserInfo;
|
|
49
|
+
Provider: IMetadataProvider;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Persists the Flow agent behind a workflow's graph.
|
|
53
|
+
*
|
|
54
|
+
* Injected rather than imported so this package does not depend on the agent-manager. The host
|
|
55
|
+
* supplies an implementation backed by `AgentSpecSync`, which is the one place that writes an agent.
|
|
56
|
+
*/
|
|
57
|
+
export type WorkflowAgentWriter = {
|
|
58
|
+
/** Creates or updates the Flow agent for this workflow. Returns its ID. */
|
|
59
|
+
PersistFlowAgent(spec: WorkflowSpec, context: WorkflowSyncContext): Promise<string>;
|
|
60
|
+
};
|
|
61
|
+
export type WorkflowSyncResult = {
|
|
62
|
+
Success: boolean;
|
|
63
|
+
/** The Flow agent the workflow's graph persisted as — the handle for everything downstream. */
|
|
64
|
+
AgentID?: string;
|
|
65
|
+
/** Scheduled Jobs created, updated or disabled by this reconciliation. */
|
|
66
|
+
ScheduledJobIDs: string[];
|
|
67
|
+
/** Triggers the spec asked for that this build cannot yet reconcile, stated rather than dropped. */
|
|
68
|
+
Unreconciled: string[];
|
|
69
|
+
ErrorMessage?: string;
|
|
70
|
+
};
|
|
71
|
+
export declare class WorkflowSpecSync {
|
|
72
|
+
private readonly agentWriter;
|
|
73
|
+
constructor(agentWriter?: WorkflowAgentWriter | null);
|
|
74
|
+
/**
|
|
75
|
+
* Reconciles every substrate a workflow owns, so they match the spec.
|
|
76
|
+
*
|
|
77
|
+
* Order matters: the agent is persisted first because a Scheduled Job needs its ID to point at,
|
|
78
|
+
* and a job pointing at an agent that does not exist would be a scheduled no-op — the failure
|
|
79
|
+
* mode where everything looks configured and nothing ever runs.
|
|
80
|
+
*/
|
|
81
|
+
Persist(spec: WorkflowSpec, context: WorkflowSyncContext): Promise<WorkflowSyncResult>;
|
|
82
|
+
/**
|
|
83
|
+
* Brings the workflow's owned trigger rows in line with its spec.
|
|
84
|
+
*
|
|
85
|
+
* A trigger the spec no longer names has its owned row **disabled rather than deleted**. Deleting
|
|
86
|
+
* would destroy the run history attached to it, and a workflow whose schedule someone removed by
|
|
87
|
+
* mistake should be recoverable — the row carries counts, last-run and next-run that are the only
|
|
88
|
+
* record that it ever fired.
|
|
89
|
+
*/
|
|
90
|
+
private reconcileTriggers;
|
|
91
|
+
/** Identity of a schedule within a workflow — cron plus zone, matching `TriggerKey`. */
|
|
92
|
+
private scheduleKey;
|
|
93
|
+
/** The same identity, read back off a persisted job. */
|
|
94
|
+
private scheduleKeyOf;
|
|
95
|
+
/**
|
|
96
|
+
* Binds an entity-change trigger by creating the Entity Action rows the save pipeline already
|
|
97
|
+
* reads.
|
|
98
|
+
*
|
|
99
|
+
* Nothing here teaches the platform a new trick. `HandleEntityActions` has fired entity actions
|
|
100
|
+
* from the save pipeline all along; what was missing was a row saying "when an Invoice is
|
|
101
|
+
* updated, run Execute Agent with this agent". Three rows express that: the `EntityAction`
|
|
102
|
+
* (which entity, which action), the `EntityActionInvocation` (which change fires it), and an
|
|
103
|
+
* `EntityActionParam` carrying the agent to run.
|
|
104
|
+
*
|
|
105
|
+
* Idempotent by lookup rather than by delete-and-recreate: re-saving a workflow must not detach
|
|
106
|
+
* and re-attach a live trigger, because a change landing in that window would be missed.
|
|
107
|
+
*
|
|
108
|
+
* **Scope reconciles onto the binding's own `ScopeEntityID`/`ScopeRecordID`.** Those columns and
|
|
109
|
+
* the engine's scope resolver already exist for exactly this; leaving them unset while the spec
|
|
110
|
+
* declared a scope produced a workflow firing on every record of the entity while its author
|
|
111
|
+
* believed it was watching one. `filter` reconciles the same way — onto an `ActionFilter` bound
|
|
112
|
+
* through `EntityActionFilter`, the row the invocation path already consults.
|
|
113
|
+
*/
|
|
114
|
+
private reconcileEntityEvent;
|
|
115
|
+
/**
|
|
116
|
+
* Brings the binding's filter row in line with the trigger's predicate.
|
|
117
|
+
*
|
|
118
|
+
* The trigger's `filter` is an expression; what the platform evaluates is an `ActionFilter.Code`
|
|
119
|
+
* bound through `EntityActionFilter`. That indirection is what lets a workflow narrow *when* it
|
|
120
|
+
* fires without the workflow layer inventing an evaluator of its own — `RunSingleFilter` already
|
|
121
|
+
* compiles, caches and fail-closes this code, and the change context it hands the expression is
|
|
122
|
+
* the same one every other entity action sees.
|
|
123
|
+
*
|
|
124
|
+
* **Removing a filter disables the binding rather than deleting the row.** The `ActionFilter`
|
|
125
|
+
* survives with its code intact, so re-adding the predicate is recoverable and the audit trail of
|
|
126
|
+
* what this trigger used to be narrowed by does not evaporate on a save. A `Disabled` binding is
|
|
127
|
+
* genuinely inert — {@link EntityActionInvocationSingleRecord.ResolveFilters} skips it, which
|
|
128
|
+
* matters because filters fail closed, so a disabled-but-honored filter would not be a no-op, it
|
|
129
|
+
* would be a permanent block.
|
|
130
|
+
*/
|
|
131
|
+
private reconcileTriggerFilter;
|
|
132
|
+
/**
|
|
133
|
+
* Writes the filter row holding the generated predicate.
|
|
134
|
+
*
|
|
135
|
+
* Reuses the row the binding already points at, so editing a workflow's filter edits one row
|
|
136
|
+
* rather than accumulating an orphan per save. `UserDescription` keeps the author's expression
|
|
137
|
+
* verbatim next to the generated code — without it, reading the row back tells you what the
|
|
138
|
+
* machine produced but not what the person asked for.
|
|
139
|
+
*/
|
|
140
|
+
private upsertActionFilter;
|
|
141
|
+
/**
|
|
142
|
+
* Turn the spec's scope names into the IDs the binding stores.
|
|
143
|
+
*
|
|
144
|
+
* A scope that names an entity the instance does not have is an error rather than a silent
|
|
145
|
+
* widening: "watch this one invoice" degrading to "watch every invoice" is the failure the
|
|
146
|
+
* scope columns exist to prevent.
|
|
147
|
+
*/
|
|
148
|
+
private resolveScope;
|
|
149
|
+
/**
|
|
150
|
+
* Finds or creates the Entity Action binding this workflow needs.
|
|
151
|
+
*
|
|
152
|
+
* **Each workflow owns its own binding row.** `Execute Agent` is one shared action, so every
|
|
153
|
+
* workflow watching a given entity would otherwise land on the same `(EntityID, ActionID)` pair
|
|
154
|
+
* — and reusing that row means rewriting its `AgentID`, which silently repoints the first
|
|
155
|
+
* workflow's trigger at the second workflow's agent. Workflow A keeps looking configured, keeps
|
|
156
|
+
* showing its trigger, and never runs again.
|
|
157
|
+
*
|
|
158
|
+
* That shape was briefly impossible: `UQ_EntityAction_ActionID_EntityID`, added by the v5.37.x
|
|
159
|
+
* junction sweep, permitted one binding per (entity, action). The sweep's own stated scope was
|
|
160
|
+
* "pure junction tables ... with no other meaningful data columns", which `EntityAction` — with
|
|
161
|
+
* Status, Sequence, LoggingMode, scope columns and three owned child collections — never met.
|
|
162
|
+
* `V202608080100__v6.1.x__Drop_EntityAction_Uniqueness` removes it, which also unblocks the
|
|
163
|
+
* ordinary case of one action bound to one entity at two different events with different params.
|
|
164
|
+
*
|
|
165
|
+
* Ownership is therefore matched on the agent and the scope, not on entity + action alone.
|
|
166
|
+
*/
|
|
167
|
+
private upsertEntityAction;
|
|
168
|
+
/**
|
|
169
|
+
* This workflow's own binding at this scope, if it already has one.
|
|
170
|
+
*
|
|
171
|
+
* Ownership lives in the `AgentID` param rather than on the binding row, so candidates are
|
|
172
|
+
* narrowed in SQL by entity + action + scope and then matched on that param. Scope is part of
|
|
173
|
+
* the identity because narrowing a trigger to a different record is a *different* subscription,
|
|
174
|
+
* not an edit of the existing one — matching without it would silently re-point the old binding.
|
|
175
|
+
*/
|
|
176
|
+
private findOwnedEntityAction;
|
|
177
|
+
/** Finds or creates the invocation row that says which change fires the action. */
|
|
178
|
+
private upsertInvocation;
|
|
179
|
+
/**
|
|
180
|
+
* Finds or creates one Entity Action Param binding.
|
|
181
|
+
*
|
|
182
|
+
* `value` is null for value types the platform derives at invocation time (`Entity Object Data`,
|
|
183
|
+
* `Entity Object`, `Entity Field`) — for those the ValueType *is* the instruction.
|
|
184
|
+
*/
|
|
185
|
+
private upsertActionParam;
|
|
186
|
+
private resolveJobTypeID;
|
|
187
|
+
/**
|
|
188
|
+
* Finds the Scheduled Jobs this workflow owns.
|
|
189
|
+
*
|
|
190
|
+
* Matched on a marker inside `Configuration` rather than on name, so renaming a workflow does not
|
|
191
|
+
* orphan its schedule and leave a second one firing alongside the new row.
|
|
192
|
+
*/
|
|
193
|
+
private findOwnedJobs;
|
|
194
|
+
/** Creates or updates one owned Scheduled Job so it matches the trigger. */
|
|
195
|
+
private upsertScheduledJob;
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=WorkflowSpecSync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkflowSpecSync.d.ts","sourceRoot":"","sources":["../src/WorkflowSpecSync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,iBAAiB,EAAgC,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAejG,OAAO,EAOH,KAAK,YAAY,EACpB,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,UAAU,CAAC;AAE7C,0FAA0F;AAC1F,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AAEpD;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AAUpD,8DAA8D;AAC9D,MAAM,MAAM,mBAAmB,GAAG;IAC9B,WAAW,EAAE,QAAQ,CAAC;IACtB,QAAQ,EAAE,iBAAiB,CAAC;CAC/B,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAC9B,2EAA2E;IAC3E,gBAAgB,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACvF,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,oGAAoG;IACpG,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,qBAAa,gBAAgB;IACb,OAAO,CAAC,QAAQ,CAAC,WAAW;gBAAX,WAAW,GAAE,mBAAmB,GAAG,IAAW;IAE3E;;;;;;OAMG;IACU,OAAO,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAgCnG;;;;;;;OAOG;YACW,iBAAiB;IA+C/B,wFAAwF;IACxF,OAAO,CAAC,WAAW;IAInB,wDAAwD;IACxD,OAAO,CAAC,aAAa;IAIrB;;;;;;;;;;;;;;;;;;OAkBG;YACW,oBAAoB;IAmDlC;;;;;;;;;;;;;;;OAeG;YACW,sBAAsB;IA4CpC;;;;;;;OAOG;YACW,kBAAkB;IA4BhC;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;IASpB;;;;;;;;;;;;;;;;;OAiBG;YACW,kBAAkB;IA+BhC;;;;;;;OAOG;YACW,qBAAqB;IAoCnC,mFAAmF;YACrE,gBAAgB;IAgC9B;;;;;OAKG;YACW,iBAAiB;YA4CjB,gBAAgB;IAkB9B;;;;;OAKG;YACW,aAAa;IAkB3B,4EAA4E;YAC9D,kBAAkB;CAoCnC"}
|