@memberjunction/ai-agents 5.38.0 → 5.40.0

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.
Files changed (91) hide show
  1. package/dist/AgentRunner.d.ts +23 -0
  2. package/dist/AgentRunner.d.ts.map +1 -1
  3. package/dist/AgentRunner.js +81 -26
  4. package/dist/AgentRunner.js.map +1 -1
  5. package/dist/ArtifactToolManager.d.ts +13 -0
  6. package/dist/ArtifactToolManager.d.ts.map +1 -1
  7. package/dist/ArtifactToolManager.js +60 -1
  8. package/dist/ArtifactToolManager.js.map +1 -1
  9. package/dist/agent-run-watchdog.d.ts +109 -0
  10. package/dist/agent-run-watchdog.d.ts.map +1 -0
  11. package/dist/agent-run-watchdog.js +278 -0
  12. package/dist/agent-run-watchdog.js.map +1 -0
  13. package/dist/agent-types/loop-agent-prompt-params.d.ts +13 -0
  14. package/dist/agent-types/loop-agent-prompt-params.d.ts.map +1 -1
  15. package/dist/agent-types/loop-agent-prompt-params.js +3 -1
  16. package/dist/agent-types/loop-agent-prompt-params.js.map +1 -1
  17. package/dist/agent-types/loop-agent-response-type.d.ts +12 -3
  18. package/dist/agent-types/loop-agent-response-type.d.ts.map +1 -1
  19. package/dist/agent-types/loop-agent-response-type.js.map +1 -1
  20. package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
  21. package/dist/agent-types/loop-agent-type.js +41 -2
  22. package/dist/agent-types/loop-agent-type.js.map +1 -1
  23. package/dist/artifact-tools/DataSnapshotToolLibrary.js +2 -2
  24. package/dist/artifact-tools/JSONToolLibrary.d.ts.map +1 -1
  25. package/dist/artifact-tools/JSONToolLibrary.js +7 -1
  26. package/dist/artifact-tools/JSONToolLibrary.js.map +1 -1
  27. package/dist/base-agent.d.ts +69 -1
  28. package/dist/base-agent.d.ts.map +1 -1
  29. package/dist/base-agent.js +294 -24
  30. package/dist/base-agent.js.map +1 -1
  31. package/dist/index.d.ts +2 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +2 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/pipeline/coerce.d.ts +43 -0
  36. package/dist/pipeline/coerce.d.ts.map +1 -0
  37. package/dist/pipeline/coerce.js +92 -0
  38. package/dist/pipeline/coerce.js.map +1 -0
  39. package/dist/pipeline/index.d.ts +20 -0
  40. package/dist/pipeline/index.d.ts.map +1 -0
  41. package/dist/pipeline/index.js +20 -0
  42. package/dist/pipeline/index.js.map +1 -0
  43. package/dist/pipeline/jsonpath-eval.d.ts +29 -0
  44. package/dist/pipeline/jsonpath-eval.d.ts.map +1 -0
  45. package/dist/pipeline/jsonpath-eval.js +144 -0
  46. package/dist/pipeline/jsonpath-eval.js.map +1 -0
  47. package/dist/pipeline/operators.d.ts +15 -0
  48. package/dist/pipeline/operators.d.ts.map +1 -0
  49. package/dist/pipeline/operators.js +332 -0
  50. package/dist/pipeline/operators.js.map +1 -0
  51. package/dist/pipeline/path.d.ts +16 -0
  52. package/dist/pipeline/path.d.ts.map +1 -0
  53. package/dist/pipeline/path.js +34 -0
  54. package/dist/pipeline/path.js.map +1 -0
  55. package/dist/pipeline/pipeline-docs.d.ts +6 -0
  56. package/dist/pipeline/pipeline-docs.d.ts.map +1 -0
  57. package/dist/pipeline/pipeline-docs.js +137 -0
  58. package/dist/pipeline/pipeline-docs.js.map +1 -0
  59. package/dist/pipeline/pipeline-executor.d.ts +72 -0
  60. package/dist/pipeline/pipeline-executor.d.ts.map +1 -0
  61. package/dist/pipeline/pipeline-executor.js +326 -0
  62. package/dist/pipeline/pipeline-executor.js.map +1 -0
  63. package/dist/pipeline/pipeline-registry.d.ts +24 -0
  64. package/dist/pipeline/pipeline-registry.d.ts.map +1 -0
  65. package/dist/pipeline/pipeline-registry.js +28 -0
  66. package/dist/pipeline/pipeline-registry.js.map +1 -0
  67. package/dist/pipeline/pipeline.types.d.ts +89 -0
  68. package/dist/pipeline/pipeline.types.d.ts.map +1 -0
  69. package/dist/pipeline/pipeline.types.js +13 -0
  70. package/dist/pipeline/pipeline.types.js.map +1 -0
  71. package/dist/pipeline/predicate.d.ts +23 -0
  72. package/dist/pipeline/predicate.d.ts.map +1 -0
  73. package/dist/pipeline/predicate.js +306 -0
  74. package/dist/pipeline/predicate.js.map +1 -0
  75. package/dist/pipeline/providers/action-provider.d.ts +21 -0
  76. package/dist/pipeline/providers/action-provider.d.ts.map +1 -0
  77. package/dist/pipeline/providers/action-provider.js +24 -0
  78. package/dist/pipeline/providers/action-provider.js.map +1 -0
  79. package/dist/pipeline/providers/artifact-tool-provider.d.ts +20 -0
  80. package/dist/pipeline/providers/artifact-tool-provider.d.ts.map +1 -0
  81. package/dist/pipeline/providers/artifact-tool-provider.js +27 -0
  82. package/dist/pipeline/providers/artifact-tool-provider.js.map +1 -0
  83. package/dist/pipeline/providers/serialize.d.ts +23 -0
  84. package/dist/pipeline/providers/serialize.d.ts.map +1 -0
  85. package/dist/pipeline/providers/serialize.js +99 -0
  86. package/dist/pipeline/providers/serialize.js.map +1 -0
  87. package/dist/pipeline/template.d.ts +18 -0
  88. package/dist/pipeline/template.d.ts.map +1 -0
  89. package/dist/pipeline/template.js +47 -0
  90. package/dist/pipeline/template.js.map +1 -0
  91. package/package.json +19 -17
@@ -0,0 +1,109 @@
1
+ import { BaseSingleton, IShutdownable } from '@memberjunction/global';
2
+ import { DatabaseProviderBase, UserInfo } from '@memberjunction/core';
3
+ /**
4
+ * Tuning for the agent-run watchdog. All durations are in their named units. Defaults are
5
+ * deliberately conservative: the stale threshold is many heartbeat intervals wide, so a
6
+ * momentarily-slow-but-alive process is never mistaken for a dead one.
7
+ */
8
+ export interface AgentRunWatchdogConfig {
9
+ /** How often the owning process stamps a liveness heartbeat for its in-flight runs. */
10
+ heartbeatIntervalMs: number;
11
+ /** How often this process re-scans for orphaned runs (mid-life, without waiting for a restart). */
12
+ sweepIntervalMs: number;
13
+ /** A Running run whose heartbeat is older than this (or NULL with an older StartedAt) is force-failed. */
14
+ staleThresholdMinutes: number;
15
+ }
16
+ /**
17
+ * Process-wide watchdog that guarantees no `AIAgentRun` is left stuck in `Status='Running'`
18
+ * after the owning process dies (restart, crash, OOM) or its terminal-state write fails.
19
+ *
20
+ * Three cooperating mechanisms, all anchored to the **database clock** so they remain correct
21
+ * across multiple MJAPI instances behind a load balancer (no instance trusts its own clock):
22
+ *
23
+ * 1. **Heartbeat** — while a run is in flight, the owning process stamps `LastHeartbeatAt`
24
+ * every {@link AgentRunWatchdogConfig.heartbeatIntervalMs} via {@link SP_HEARTBEAT}.
25
+ * 2. **Sweep** — {@link SweepOrphanedRuns} force-fails any `Running` run whose heartbeat has
26
+ * gone stale, via {@link SP_SWEEP} (one atomic, set-based `UPDATE … WHERE Status='Running'
27
+ * AND <stale>` inside the proc — so concurrent sweeps from multiple instances are harmless
28
+ * and a run another instance is still heart-beating can't be caught mid-sweep). Run once on
29
+ * boot (closes restart-orphans) and on a timer (closes mid-life orphans).
30
+ * 3. **Graceful shutdown** — on SIGTERM/SIGINT (via {@link ShutdownRegistry}) this process marks
31
+ * the runs *it* owns `Cancelled` via {@link SP_CANCEL}, closing the deploy case instantly.
32
+ *
33
+ * Every proc filters `Status='Running'` only — `Paused` and `AwaitingFeedback` are
34
+ * legitimately-not-progressing states and are never touched. The watchdog accesses the DB only
35
+ * through these stored procedures (writes) and the base view (reads) — never the base table —
36
+ * so it works as the regular runtime DB user, not just the elevated CodeGen user. Proc calls are
37
+ * built through the provider's {@link Dialect.ProcedureCallSyntax}, so they run on SQL Server and
38
+ * PostgreSQL unchanged.
39
+ */
40
+ export declare class AgentRunWatchdog extends BaseSingleton<AgentRunWatchdog> implements IShutdownable {
41
+ private _config;
42
+ private _trackedRuns;
43
+ private _provider;
44
+ private _contextUser;
45
+ private _heartbeatTimer;
46
+ private _sweepTimer;
47
+ private _registered;
48
+ protected constructor();
49
+ static get Instance(): AgentRunWatchdog;
50
+ readonly ShutdownName = "AgentRunWatchdog";
51
+ /** Overrides the default tuning. Safe to call before or after runs start tracking. */
52
+ Configure(config: Partial<AgentRunWatchdogConfig>): void;
53
+ /**
54
+ * Begin guarding a run. The owning agent calls this immediately after the run row is saved
55
+ * (so it has a stable ID). Idempotent per run ID. Capturing the provider/user lets the
56
+ * central heartbeat + shutdown statements run without each run re-supplying them.
57
+ */
58
+ Track(runID: string, provider: DatabaseProviderBase, contextUser: UserInfo): void;
59
+ /** Stop guarding a run. Optional — the periodic prune drops terminal runs automatically — but
60
+ * callers may invoke it for prompt cleanup right after writing a terminal state. */
61
+ Untrack(runID: string): void;
62
+ /** Number of runs this process is currently guarding (primarily for tests/diagnostics). */
63
+ get TrackedCount(): number;
64
+ /**
65
+ * IShutdownable: on graceful shutdown, mark every run this process still owns as `Cancelled`
66
+ * (via {@link SP_CANCEL}) so it doesn't linger as a phantom `Running` row until the next sweep.
67
+ * Idempotent and never throws — a failed cancel just falls through to the staleness sweep later.
68
+ */
69
+ Shutdown(): Promise<void>;
70
+ /**
71
+ * Force-fail any `Running` agent run whose liveness heartbeat has gone stale (or that never
72
+ * beat and was started long ago), via the dedicated {@link SP_SWEEP} proc. The proc does the
73
+ * whole thing as one atomic, set-based `UPDATE` and returns the count, so it's safe to run on
74
+ * every boot and on a timer, on every instance: the predicate is staleness-based (never "fail
75
+ * all Running") and re-evaluated at write time, so it cannot touch a run a healthy instance is
76
+ * still heart-beating. Returns the number of rows failed.
77
+ */
78
+ static SweepOrphanedRuns(provider: DatabaseProviderBase, contextUser: UserInfo, config?: Partial<AgentRunWatchdogConfig>): Promise<number>;
79
+ /** Start the heartbeat + sweep timers and register for graceful shutdown, exactly once. */
80
+ private ensureStarted;
81
+ private stopTimers;
82
+ /** Stamp LastHeartbeatAt for every run this process is guarding, via {@link SP_HEARTBEAT}.
83
+ * Never throws (runs on a timer); a per-run failure is logged and the rest still beat. */
84
+ private heartbeat;
85
+ /** Periodic tick: force-fail orphans, then prune any terminal runs out of the tracked set. */
86
+ private periodicSweep;
87
+ /**
88
+ * Drop any tracked run that is no longer `Running` so the in-memory set can't grow unbounded
89
+ * over a long-lived process. A single SELECT (against the base VIEW — the runtime user has no
90
+ * table access) of the still-running subset; the rest are pruned.
91
+ */
92
+ private pruneTerminalRuns;
93
+ /** Validated, lowercased UUIDs this process is guarding (for per-run proc calls). */
94
+ private trackedIds;
95
+ /**
96
+ * Build a single batched SQL string of one proc call per id, newline-separated, so a set of
97
+ * per-run writes goes to the DB as one round-trip instead of N. Each id is already a validated
98
+ * UUID and is quoted as a string literal before interpolation. Runs unchanged on SQL Server and
99
+ * PostgreSQL because the call form comes from {@link Dialect.ProcedureCallSyntax}.
100
+ */
101
+ private static buildProcBatch;
102
+ /** Comma-joined, quoted, validated UUID list for an `ID IN (...)` clause, or '' if none. */
103
+ private trackedIdList;
104
+ /** Schema that owns the AIAgentRun objects (for qualifying proc calls), or null if unresolved. */
105
+ private static schemaOf;
106
+ /** Fully-qualified, dialect-quoted base VIEW for AIAgentRun reads, or null if unresolved. */
107
+ private static viewOf;
108
+ }
109
+ //# sourceMappingURL=agent-run-watchdog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-run-watchdog.d.ts","sourceRoot":"","sources":["../src/agent-run-watchdog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAoB,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAuB,MAAM,sBAAsB,CAAC;AAM3F;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACnC,uFAAuF;IACvF,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mGAAmG;IACnG,eAAe,EAAE,MAAM,CAAC;IACxB,0GAA0G;IAC1G,qBAAqB,EAAE,MAAM,CAAC;CACjC;AAsBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,gBAAiB,SAAQ,aAAa,CAAC,gBAAgB,CAAE,YAAW,aAAa;IAC1F,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,WAAW,CAA+C;IAClE,OAAO,CAAC,WAAW,CAAS;IAE5B,SAAS;IAIT,WAAkB,QAAQ,IAAI,gBAAgB,CAE7C;IAED,SAAgB,YAAY,sBAAsB;IAElD,sFAAsF;IAC/E,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,sBAAsB,CAAC,GAAG,IAAI;IAI/D;;;;OAIG;IACI,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,EAAE,WAAW,EAAE,QAAQ,GAAG,IAAI;IAUxF;yFACqF;IAC9E,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAMnC,2FAA2F;IAC3F,IAAW,YAAY,IAAI,MAAM,CAEhC;IAED;;;;OAIG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBtC;;;;;;;OAOG;WACiB,iBAAiB,CACjC,QAAQ,EAAE,oBAAoB,EAC9B,WAAW,EAAE,QAAQ,EACrB,MAAM,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,GACzC,OAAO,CAAC,MAAM,CAAC;IA0BlB,2FAA2F;IAC3F,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,UAAU;IAWlB;+FAC2F;YAC7E,SAAS;IAsBvB,8FAA8F;YAChF,aAAa;IAQ3B;;;;OAIG;YACW,iBAAiB;IAiC/B,qFAAqF;IACrF,OAAO,CAAC,UAAU;IAIlB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAI7B,4FAA4F;IAC5F,OAAO,CAAC,aAAa;IAIrB,kGAAkG;IAClG,OAAO,CAAC,MAAM,CAAC,QAAQ;IAKvB,6FAA6F;IAC7F,OAAO,CAAC,MAAM,CAAC,MAAM;CAQxB"}
@@ -0,0 +1,278 @@
1
+ import { BaseSingleton, ShutdownRegistry } from '@memberjunction/global';
2
+ import { LogError, LogStatus } from '@memberjunction/core';
3
+ const DEFAULT_CONFIG = {
4
+ heartbeatIntervalMs: 30_000,
5
+ sweepIntervalMs: 5 * 60_000,
6
+ staleThresholdMinutes: 5,
7
+ };
8
+ /** Matches a canonical UUID. Tracked IDs come from provider-generated PKs, but we validate
9
+ * before ever interpolating into SQL so a proc argument can never become an injection vector. */
10
+ const UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
11
+ /** The one MJ entity whose runs this watchdog guards. */
12
+ const AGENT_RUN_ENTITY = 'MJ: AI Agent Runs';
13
+ /** Dedicated maintenance stored procedures (see the watchdog sprocs migration). The runtime DB
14
+ * user has EXECUTE on these + SELECT on the base view, but no direct table access — so all of
15
+ * the watchdog's writes go through these procs and its reads go through the view. */
16
+ const SP_HEARTBEAT = 'spStampAIAgentRunHeartbeat';
17
+ const SP_SWEEP = 'spSweepStaleAIAgentRuns';
18
+ const SP_CANCEL = 'spCancelAIAgentRun';
19
+ /**
20
+ * Process-wide watchdog that guarantees no `AIAgentRun` is left stuck in `Status='Running'`
21
+ * after the owning process dies (restart, crash, OOM) or its terminal-state write fails.
22
+ *
23
+ * Three cooperating mechanisms, all anchored to the **database clock** so they remain correct
24
+ * across multiple MJAPI instances behind a load balancer (no instance trusts its own clock):
25
+ *
26
+ * 1. **Heartbeat** — while a run is in flight, the owning process stamps `LastHeartbeatAt`
27
+ * every {@link AgentRunWatchdogConfig.heartbeatIntervalMs} via {@link SP_HEARTBEAT}.
28
+ * 2. **Sweep** — {@link SweepOrphanedRuns} force-fails any `Running` run whose heartbeat has
29
+ * gone stale, via {@link SP_SWEEP} (one atomic, set-based `UPDATE … WHERE Status='Running'
30
+ * AND <stale>` inside the proc — so concurrent sweeps from multiple instances are harmless
31
+ * and a run another instance is still heart-beating can't be caught mid-sweep). Run once on
32
+ * boot (closes restart-orphans) and on a timer (closes mid-life orphans).
33
+ * 3. **Graceful shutdown** — on SIGTERM/SIGINT (via {@link ShutdownRegistry}) this process marks
34
+ * the runs *it* owns `Cancelled` via {@link SP_CANCEL}, closing the deploy case instantly.
35
+ *
36
+ * Every proc filters `Status='Running'` only — `Paused` and `AwaitingFeedback` are
37
+ * legitimately-not-progressing states and are never touched. The watchdog accesses the DB only
38
+ * through these stored procedures (writes) and the base view (reads) — never the base table —
39
+ * so it works as the regular runtime DB user, not just the elevated CodeGen user. Proc calls are
40
+ * built through the provider's {@link Dialect.ProcedureCallSyntax}, so they run on SQL Server and
41
+ * PostgreSQL unchanged.
42
+ */
43
+ export class AgentRunWatchdog extends BaseSingleton {
44
+ constructor() {
45
+ super();
46
+ this._config = DEFAULT_CONFIG;
47
+ this._trackedRuns = new Set();
48
+ this._provider = null;
49
+ this._contextUser = null;
50
+ this._heartbeatTimer = null;
51
+ this._sweepTimer = null;
52
+ this._registered = false;
53
+ this.ShutdownName = 'AgentRunWatchdog';
54
+ }
55
+ static get Instance() {
56
+ return super.getInstance();
57
+ }
58
+ /** Overrides the default tuning. Safe to call before or after runs start tracking. */
59
+ Configure(config) {
60
+ this._config = { ...this._config, ...config };
61
+ }
62
+ /**
63
+ * Begin guarding a run. The owning agent calls this immediately after the run row is saved
64
+ * (so it has a stable ID). Idempotent per run ID. Capturing the provider/user lets the
65
+ * central heartbeat + shutdown statements run without each run re-supplying them.
66
+ */
67
+ Track(runID, provider, contextUser) {
68
+ if (!runID || !UUID_RE.test(runID)) {
69
+ return;
70
+ }
71
+ this._provider = provider;
72
+ this._contextUser = contextUser;
73
+ this._trackedRuns.add(runID.toLowerCase());
74
+ this.ensureStarted();
75
+ }
76
+ /** Stop guarding a run. Optional — the periodic prune drops terminal runs automatically — but
77
+ * callers may invoke it for prompt cleanup right after writing a terminal state. */
78
+ Untrack(runID) {
79
+ if (runID) {
80
+ this._trackedRuns.delete(runID.toLowerCase());
81
+ }
82
+ }
83
+ /** Number of runs this process is currently guarding (primarily for tests/diagnostics). */
84
+ get TrackedCount() {
85
+ return this._trackedRuns.size;
86
+ }
87
+ /**
88
+ * IShutdownable: on graceful shutdown, mark every run this process still owns as `Cancelled`
89
+ * (via {@link SP_CANCEL}) so it doesn't linger as a phantom `Running` row until the next sweep.
90
+ * Idempotent and never throws — a failed cancel just falls through to the staleness sweep later.
91
+ */
92
+ async Shutdown() {
93
+ this.stopTimers();
94
+ const ids = this.trackedIds();
95
+ this._trackedRuns.clear();
96
+ if (!ids.length || !this._provider) {
97
+ return;
98
+ }
99
+ const schema = AgentRunWatchdog.schemaOf(this._provider);
100
+ if (!schema) {
101
+ return;
102
+ }
103
+ const d = this._provider.Dialect;
104
+ // One batched round-trip (one EXEC per id, newline-separated) rather than a call per run.
105
+ const sql = AgentRunWatchdog.buildProcBatch(d, schema, SP_CANCEL, ids);
106
+ try {
107
+ await this._provider.ExecuteSQL(sql, undefined, { isMutation: true, description: 'AgentRunWatchdog graceful-shutdown cancel' }, this._contextUser ?? undefined);
108
+ }
109
+ catch (err) {
110
+ LogError(`AgentRunWatchdog.Shutdown failed to cancel runs [${ids.join(', ')}]: ${err instanceof Error ? err.message : String(err)}`);
111
+ }
112
+ }
113
+ /**
114
+ * Force-fail any `Running` agent run whose liveness heartbeat has gone stale (or that never
115
+ * beat and was started long ago), via the dedicated {@link SP_SWEEP} proc. The proc does the
116
+ * whole thing as one atomic, set-based `UPDATE` and returns the count, so it's safe to run on
117
+ * every boot and on a timer, on every instance: the predicate is staleness-based (never "fail
118
+ * all Running") and re-evaluated at write time, so it cannot touch a run a healthy instance is
119
+ * still heart-beating. Returns the number of rows failed.
120
+ */
121
+ static async SweepOrphanedRuns(provider, contextUser, config) {
122
+ const threshold = config?.staleThresholdMinutes ?? DEFAULT_CONFIG.staleThresholdMinutes;
123
+ const schema = AgentRunWatchdog.schemaOf(provider);
124
+ if (!schema) {
125
+ LogError('AgentRunWatchdog.SweepOrphanedRuns: could not resolve the AIAgentRun schema from metadata; skipping sweep');
126
+ return 0;
127
+ }
128
+ const d = provider.Dialect;
129
+ try {
130
+ // The proc runs the atomic UPDATE on the DB clock and returns RunsFailed.
131
+ const sql = d.ProcedureCallSyntax(schema, SP_SWEEP, [String(Math.trunc(threshold))]) + ';';
132
+ const rows = await provider.ExecuteSQL(sql, undefined, { isMutation: true, description: 'AgentRunWatchdog stale-run sweep' }, contextUser);
133
+ const failCount = (Array.isArray(rows) && rows[0] && typeof rows[0].RunsFailed === 'number') ? rows[0].RunsFailed : 0;
134
+ if (failCount > 0) {
135
+ LogStatus(`[AgentRunWatchdog] Swept ${failCount} orphaned agent run(s) -> Failed (no heartbeat for >${threshold}m)`);
136
+ }
137
+ return failCount;
138
+ }
139
+ catch (err) {
140
+ LogError(`AgentRunWatchdog.SweepOrphanedRuns failed: ${err instanceof Error ? err.message : String(err)}`);
141
+ return 0;
142
+ }
143
+ }
144
+ // ----- internals -------------------------------------------------------------------------
145
+ /** Start the heartbeat + sweep timers and register for graceful shutdown, exactly once. */
146
+ ensureStarted() {
147
+ if (!this._registered) {
148
+ ShutdownRegistry.Instance.Register(this);
149
+ this._registered = true;
150
+ }
151
+ if (!this._heartbeatTimer) {
152
+ this._heartbeatTimer = setInterval(() => void this.heartbeat(), this._config.heartbeatIntervalMs);
153
+ // Don't keep the event loop alive solely for the watchdog.
154
+ this._heartbeatTimer.unref?.();
155
+ }
156
+ if (!this._sweepTimer) {
157
+ // The periodic sweep is an always-on in-process timer rather than an MJ Scheduled Job
158
+ // (MJ: Scheduled Jobs / SchedulingEngine) on purpose. This is a reliability floor for
159
+ // orphaned runs, and ScheduledJobsService is gated by `scheduledJobs.enabled` in config
160
+ // — moving the sweep there would silently disable it in any deployment that runs with
161
+ // scheduled jobs off, exactly where the safety net still needs to work. A Scheduled Job
162
+ // could be added on top later as an observability/audit layer (it would call the same
163
+ // idempotent SweepOrphanedRuns), but it must not be the only thing that runs it.
164
+ this._sweepTimer = setInterval(() => void this.periodicSweep(), this._config.sweepIntervalMs);
165
+ this._sweepTimer.unref?.();
166
+ }
167
+ }
168
+ stopTimers() {
169
+ if (this._heartbeatTimer) {
170
+ clearInterval(this._heartbeatTimer);
171
+ this._heartbeatTimer = null;
172
+ }
173
+ if (this._sweepTimer) {
174
+ clearInterval(this._sweepTimer);
175
+ this._sweepTimer = null;
176
+ }
177
+ }
178
+ /** Stamp LastHeartbeatAt for every run this process is guarding, via {@link SP_HEARTBEAT}.
179
+ * Never throws (runs on a timer); a per-run failure is logged and the rest still beat. */
180
+ async heartbeat() {
181
+ if (!this._provider) {
182
+ return;
183
+ }
184
+ const ids = this.trackedIds();
185
+ if (!ids.length) {
186
+ return;
187
+ }
188
+ const schema = AgentRunWatchdog.schemaOf(this._provider);
189
+ if (!schema) {
190
+ return;
191
+ }
192
+ const d = this._provider.Dialect;
193
+ // One batched round-trip (one EXEC per id, newline-separated) rather than a call per run.
194
+ const sql = AgentRunWatchdog.buildProcBatch(d, schema, SP_HEARTBEAT, ids);
195
+ try {
196
+ await this._provider.ExecuteSQL(sql, undefined, { isMutation: true, ignoreLogging: true, description: 'AgentRunWatchdog heartbeat' }, this._contextUser ?? undefined);
197
+ }
198
+ catch (err) {
199
+ LogError(`AgentRunWatchdog heartbeat failed for runs [${ids.join(', ')}]: ${err instanceof Error ? err.message : String(err)}`);
200
+ }
201
+ }
202
+ /** Periodic tick: force-fail orphans, then prune any terminal runs out of the tracked set. */
203
+ async periodicSweep() {
204
+ if (!this._provider || !this._contextUser) {
205
+ return;
206
+ }
207
+ await AgentRunWatchdog.SweepOrphanedRuns(this._provider, this._contextUser, this._config);
208
+ await this.pruneTerminalRuns();
209
+ }
210
+ /**
211
+ * Drop any tracked run that is no longer `Running` so the in-memory set can't grow unbounded
212
+ * over a long-lived process. A single SELECT (against the base VIEW — the runtime user has no
213
+ * table access) of the still-running subset; the rest are pruned.
214
+ */
215
+ async pruneTerminalRuns() {
216
+ const ids = this.trackedIdList();
217
+ if (!ids || !this._provider) {
218
+ return;
219
+ }
220
+ const view = AgentRunWatchdog.viewOf(this._provider);
221
+ if (!view) {
222
+ return;
223
+ }
224
+ const d = this._provider.Dialect;
225
+ try {
226
+ const rows = await this._provider.ExecuteSQL(`SELECT ${d.QuoteIdentifier('ID')} FROM ${view} ` +
227
+ `WHERE ${d.QuoteIdentifier('Status')} = 'Running' AND ${d.QuoteIdentifier('ID')} IN (${ids});`, undefined, { ignoreLogging: true, description: 'AgentRunWatchdog tracked-set prune' }, this._contextUser ?? undefined);
228
+ const stillRunning = new Set();
229
+ if (Array.isArray(rows)) {
230
+ for (const row of rows) {
231
+ if (typeof row?.ID === 'string') {
232
+ stillRunning.add(row.ID.toLowerCase());
233
+ }
234
+ }
235
+ }
236
+ for (const tracked of Array.from(this._trackedRuns)) {
237
+ if (!stillRunning.has(tracked)) {
238
+ this._trackedRuns.delete(tracked);
239
+ }
240
+ }
241
+ }
242
+ catch (err) {
243
+ LogError(`AgentRunWatchdog prune failed: ${err instanceof Error ? err.message : String(err)}`);
244
+ }
245
+ }
246
+ /** Validated, lowercased UUIDs this process is guarding (for per-run proc calls). */
247
+ trackedIds() {
248
+ return Array.from(this._trackedRuns).filter(id => UUID_RE.test(id));
249
+ }
250
+ /**
251
+ * Build a single batched SQL string of one proc call per id, newline-separated, so a set of
252
+ * per-run writes goes to the DB as one round-trip instead of N. Each id is already a validated
253
+ * UUID and is quoted as a string literal before interpolation. Runs unchanged on SQL Server and
254
+ * PostgreSQL because the call form comes from {@link Dialect.ProcedureCallSyntax}.
255
+ */
256
+ static buildProcBatch(d, schema, proc, ids) {
257
+ return ids.map(id => d.ProcedureCallSyntax(schema, proc, [d.QuoteStringLiteral(id)]) + ';').join('\n');
258
+ }
259
+ /** Comma-joined, quoted, validated UUID list for an `ID IN (...)` clause, or '' if none. */
260
+ trackedIdList() {
261
+ return this.trackedIds().map(id => `'${id}'`).join(',');
262
+ }
263
+ /** Schema that owns the AIAgentRun objects (for qualifying proc calls), or null if unresolved. */
264
+ static schemaOf(provider) {
265
+ const entity = provider.EntityByName(AGENT_RUN_ENTITY);
266
+ return entity?.SchemaName || null;
267
+ }
268
+ /** Fully-qualified, dialect-quoted base VIEW for AIAgentRun reads, or null if unresolved. */
269
+ static viewOf(provider) {
270
+ const entity = provider.EntityByName(AGENT_RUN_ENTITY);
271
+ if (!entity || !entity.BaseView) {
272
+ return null;
273
+ }
274
+ const d = provider.Dialect;
275
+ return entity.SchemaName ? d.QuoteSchema(entity.SchemaName, entity.BaseView) : d.QuoteIdentifier(entity.BaseView);
276
+ }
277
+ }
278
+ //# sourceMappingURL=agent-run-watchdog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-run-watchdog.js","sourceRoot":"","sources":["../src/agent-run-watchdog.ts"],"names":[],"mappings":"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"}
@@ -79,6 +79,12 @@ export interface ResponseTypeInclusionRules {
79
79
  * @default true
80
80
  */
81
81
  artifactToolCalls?: boolean;
82
+ /**
83
+ * Include the pipeline field in the response interface.
84
+ * Auto-aligns with includePipelineDocs unless explicitly set.
85
+ * @default true
86
+ */
87
+ pipeline?: boolean;
82
88
  }
83
89
  /**
84
90
  * Default values for ResponseTypeInclusionRules.
@@ -237,6 +243,13 @@ export interface LoopAgentTypePromptParams {
237
243
  * @default true
238
244
  */
239
245
  includeArtifactToolsDocs?: boolean;
246
+ /**
247
+ * Include tool-pipeline documentation in the prompt (the `_PIPELINE_TOOLS` block).
248
+ * Only emitted when at least one pipeline source — an Action or artifact tool — is available.
249
+ * Disable for agents that should never compose pipelines.
250
+ * @default true
251
+ */
252
+ includePipelineDocs?: boolean;
240
253
  /**
241
254
  * Maximum number of sub-agents to include in prompt details.
242
255
  * -1 = include all (default)
@@ -1 +1 @@
1
- {"version":3,"file":"loop-agent-prompt-params.d.ts","sourceRoot":"","sources":["../../src/agent-types/loop-agent-prompt-params.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;GAGG;AACH,eAAO,MAAM,qCAAqC,EAAE,QAAQ,CAAC,0BAA0B,CAQtF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,MAAM,WAAW,yBAAyB;IAGtC;;;;;;;;;OASG;IACH,6BAA6B,CAAC,EAAE,0BAA0B,CAAC;IAE3D;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;;;;OAOG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;IAEtC;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;;;OAMG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAInC;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,eAAO,MAAM,gCAAgC,EAAE,QAAQ,CAAC,yBAAyB,CAehF,CAAC"}
1
+ {"version":3,"file":"loop-agent-prompt-params.d.ts","sourceRoot":"","sources":["../../src/agent-types/loop-agent-prompt-params.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,qCAAqC,EAAE,QAAQ,CAAC,0BAA0B,CAStF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,MAAM,WAAW,yBAAyB;IAGtC;;;;;;;;;OASG;IACH,6BAA6B,CAAC,EAAE,0BAA0B,CAAC;IAE3D;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;;;;OAOG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;IAEtC;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;;;OAMG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAEnC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAI9B;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,eAAO,MAAM,gCAAgC,EAAE,QAAQ,CAAC,yBAAyB,CAgBhF,CAAC"}
@@ -30,7 +30,8 @@ export const DEFAULT_RESPONSE_TYPE_INCLUSION_RULES = {
30
30
  forEach: true,
31
31
  while: true,
32
32
  scratchpad: true,
33
- artifactToolCalls: true
33
+ artifactToolCalls: true,
34
+ pipeline: true
34
35
  };
35
36
  /**
36
37
  * Default values for LoopAgentTypePromptParams.
@@ -49,6 +50,7 @@ export const DEFAULT_LOOP_AGENT_PROMPT_PARAMS = {
49
50
  includeScratchpadDocs: true,
50
51
  scratchpadMaxTasks: 50,
51
52
  includeArtifactToolsDocs: true,
53
+ includePipelineDocs: true,
52
54
  maxSubAgentsInPrompt: -1,
53
55
  maxActionsInPrompt: -1
54
56
  };
@@ -1 +1 @@
1
- {"version":3,"file":"loop-agent-prompt-params.js","sourceRoot":"","sources":["../../src/agent-types/loop-agent-prompt-params.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAwEH;;;GAGG;AACH,MAAM,CAAC,MAAM,qCAAqC,GAAyC;IACvF,OAAO,EAAE,IAAI;IACb,aAAa,EAAE,IAAI;IACnB,QAAQ,EAAE,IAAI;IACd,OAAO,EAAE,IAAI;IACb,KAAK,EAAE,IAAI;IACX,UAAU,EAAE,IAAI;IAChB,iBAAiB,EAAE,IAAI;CAC1B,CAAC;AA+LF;;;GAGG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAwC;IACjF,6BAA6B,EAAE,EAAE,GAAG,qCAAqC,EAAE;IAC3E,kBAAkB,EAAE,IAAI;IACxB,gBAAgB,EAAE,IAAI;IACtB,uBAAuB,EAAE,IAAI;IAC7B,kBAAkB,EAAE,IAAI;IACxB,2BAA2B,EAAE,IAAI;IACjC,uBAAuB,EAAE,IAAI;IAC7B,sBAAsB,EAAE,IAAI;IAC5B,uBAAuB,EAAE,IAAI;IAC7B,qBAAqB,EAAE,IAAI;IAC3B,kBAAkB,EAAE,EAAE;IACtB,wBAAwB,EAAE,IAAI;IAC9B,oBAAoB,EAAE,CAAC,CAAC;IACxB,kBAAkB,EAAE,CAAC,CAAC;CACzB,CAAC"}
1
+ {"version":3,"file":"loop-agent-prompt-params.js","sourceRoot":"","sources":["../../src/agent-types/loop-agent-prompt-params.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AA+EH;;;GAGG;AACH,MAAM,CAAC,MAAM,qCAAqC,GAAyC;IACvF,OAAO,EAAE,IAAI;IACb,aAAa,EAAE,IAAI;IACnB,QAAQ,EAAE,IAAI;IACd,OAAO,EAAE,IAAI;IACb,KAAK,EAAE,IAAI;IACX,UAAU,EAAE,IAAI;IAChB,iBAAiB,EAAE,IAAI;IACvB,QAAQ,EAAE,IAAI;CACjB,CAAC;AAuMF;;;GAGG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAwC;IACjF,6BAA6B,EAAE,EAAE,GAAG,qCAAqC,EAAE;IAC3E,kBAAkB,EAAE,IAAI;IACxB,gBAAgB,EAAE,IAAI;IACtB,uBAAuB,EAAE,IAAI;IAC7B,kBAAkB,EAAE,IAAI;IACxB,2BAA2B,EAAE,IAAI;IACjC,uBAAuB,EAAE,IAAI;IAC7B,sBAAsB,EAAE,IAAI;IAC5B,uBAAuB,EAAE,IAAI;IAC7B,qBAAqB,EAAE,IAAI;IAC3B,kBAAkB,EAAE,EAAE;IACtB,wBAAwB,EAAE,IAAI;IAC9B,mBAAmB,EAAE,IAAI;IACzB,oBAAoB,EAAE,CAAC,CAAC;IACxB,kBAAkB,EAAE,CAAC,CAAC;CACzB,CAAC"}
@@ -1,4 +1,4 @@
1
- import { AgentPayloadChangeRequest, ForEachOperation, WhileOperation, AgentResponseForm, ActionableCommand, AutomaticCommand, AgentScratchpad } from "@memberjunction/ai-core-plus";
1
+ import { AgentPayloadChangeRequest, ForEachOperation, WhileOperation, AgentResponseForm, ActionableCommand, AutomaticCommand, AgentScratchpad, AgentPipelineRequest } from "@memberjunction/ai-core-plus";
2
2
  import { ArtifactToolCall } from "../ArtifactToolManager.js";
3
3
  export type { ForEachOperation, WhileOperation, ArtifactToolCall };
4
4
  /**
@@ -62,9 +62,9 @@ export interface LoopAgentResponse<P = any> {
62
62
  */
63
63
  nextStep?: {
64
64
  /**
65
- * Operation type: 'Actions' | 'ClientTools' | 'Sub-Agent' | 'Chat' | 'Retry' | 'ForEach' | 'While'
65
+ * Operation type: 'Actions' | 'ClientTools' | 'Sub-Agent' | 'Chat' | 'Retry' | 'ForEach' | 'While' | 'Pipeline'
66
66
  */
67
- type: 'Actions' | 'ClientTools' | 'Sub-Agent' | 'Chat' | 'Retry' | 'ForEach' | 'While';
67
+ type: 'Actions' | 'ClientTools' | 'Sub-Agent' | 'Chat' | 'Retry' | 'ForEach' | 'While' | 'Pipeline';
68
68
  /**
69
69
  * Actions to execute (when type='Actions')
70
70
  */
@@ -72,6 +72,15 @@ export interface LoopAgentResponse<P = any> {
72
72
  name: string;
73
73
  params: Record<string, unknown>;
74
74
  }>;
75
+ /**
76
+ * Tool pipeline to run server-side (when type='Pipeline'). Like client tools, it is a
77
+ * yield/await action: the agent cannot know the result until it executes, so the loop runs
78
+ * the pipeline inline, injects the final output, and forces one more turn. Only the final
79
+ * step's output enters the context window. Modeling it as a `nextStep.type` (rather than a
80
+ * top-level field) makes it structurally mutually exclusive with Actions/Chat/etc. — the LLM
81
+ * cannot accidentally request a pipeline AND another step in the same turn.
82
+ */
83
+ pipeline?: AgentPipelineRequest;
75
84
  /**
76
85
  * Index of a compacted message to expand (when type='Retry').
77
86
  * The message is restored to full content and the prompt re-runs.
@@ -1 +1 @@
1
- {"version":3,"file":"loop-agent-response-type.d.ts","sourceRoot":"","sources":["../../src/agent-types/loop-agent-response-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpL,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAG1D,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC,GAAG,GAAG;IACtC;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,iBAAiB,CAAC;IAEjC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAEzC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAEvC;;OAEG;IACH,oBAAoB,CAAC,EAAE,yBAAyB,CAAC,CAAC,CAAC,CAAC;IAEpD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAE7B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAEvC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,QAAQ,CAAC,EAAE;QACP;;WAEG;QACH,IAAI,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;QAEvF;;WAEG;QACH,OAAO,CAAC,EAAE,KAAK,CAAC;YACZ,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACnC,CAAC,CAAC;QAEH;;;WAGG;QACH,YAAY,CAAC,EAAE,MAAM,CAAC;QAEtB;;WAEG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;QAEhB;;WAEG;QACH,QAAQ,CAAC,EAAE;YACP,IAAI,EAAE,MAAM,CAAC;YAEb;;eAEG;YACH,OAAO,EAAE,MAAM,CAAC;YAEhB;;;;eAIG;YACH,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAEzC;;eAEG;YACH,cAAc,EAAE,OAAO,CAAC;SAC3B,CAAC;QAEF;;WAEG;QACH,SAAS,CAAC,EAAE,KAAK,CAAC;YACd,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;YAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YACzC,cAAc,EAAE,OAAO,CAAC;SAC3B,CAAC,CAAC;QAEH;;;WAGG;QACH,WAAW,CAAC,EAAE,KAAK,CAAC;YAChB,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACjC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACjC,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,WAAW,CAAC,EAAE,MAAM,CAAC;YACrB,WAAW,CAAC,EAAE,MAAM,CAAC;SACxB,CAAC,CAAC;QAEH;;WAEG;QACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;QAE3B;;WAEG;QACH,KAAK,CAAC,EAAE,cAAc,CAAC;KAC1B,CAAC;CACL"}
1
+ {"version":3,"file":"loop-agent-response-type.d.ts","sourceRoot":"","sources":["../../src/agent-types/loop-agent-response-type.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"loop-agent-response-type.js","sourceRoot":"","sources":["../../src/agent-types/loop-agent-response-type.ts"],"names":[],"mappings":";AAiKA,oEAAoE;AACpE,sDAAsD"}
1
+ {"version":3,"file":"loop-agent-response-type.js","sourceRoot":"","sources":["../../src/agent-types/loop-agent-response-type.ts"],"names":[],"mappings":";AA2KA,oEAAoE;AACpE,sDAAsD"}
@@ -1 +1 @@
1
- {"version":3,"file":"loop-agent-type.d.ts","sourceRoot":"","sources":["../../src/agent-types/loop-agent-type.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,cAAc,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,WAAW,EAA6B,MAAM,8BAA8B,CAAC;AAEpL,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAIxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBACa,aAAc,SAAQ,aAAa;IAC5C,OAAO,CAAC,UAAU,CAAiC;IAEtC,wBAAwB,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAM3G;;;;;;;;;;;OAWG;IACU,iBAAiB,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAC7C,YAAY,EAAE,iBAAiB,GAAG,IAAI,EACtC,MAAM,EAAE,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,EAClC,OAAO,EAAE,CAAC,EACV,cAAc,EAAE,GAAG,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAoLhC;;;;;;;OAOG;IACH,SAAS,CAAC,mBAAmB,CAAC,cAAc,EAAE,OAAO,GAAG;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAC;IAsI5F;;;;;;;OAOG;IACU,aAAa,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EACzC,OAAO,EAAE,CAAC,EACV,cAAc,EAAE,GAAG,EACnB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GACpD,OAAO,CAAC,IAAI,CAAC;IAShB;;;;;;;;;;OAUG;IACU,oBAAoB,CAAC,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAK/G;;;;;;;;;;;OAWG;IACU,kBAAkB,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAC9C,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC7B,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC1B,OAAO,EAAE,CAAC,EACV,cAAc,EAAE,GAAG,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAKvC;;;;;;;;;;;OAWG;IACU,gBAAgB,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAC5C,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,CAAC,EACV,cAAc,EAAE,GAAG,EACnB,gBAAgB,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI,GAC/C,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC;IAK3C;;;;;;;;;;;;;;;;;OAiBG;IACU,oBAAoB,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAChD,OAAO,EAAE,WAAW,EAAE,EACtB,cAAc,EAAE,CAAC,EACjB,cAAc,EAAE,GAAG,EACnB,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC,EACjC,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC;IAShB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,6BAA6B;CAyBxC"}
1
+ {"version":3,"file":"loop-agent-type.d.ts","sourceRoot":"","sources":["../../src/agent-types/loop-agent-type.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,cAAc,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,WAAW,EAA6B,MAAM,8BAA8B,CAAC;AAEpL,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAIxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBACa,aAAc,SAAQ,aAAa;IAC5C,OAAO,CAAC,UAAU,CAAiC;IAEtC,wBAAwB,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAM3G;;;;;;;;;;;OAWG;IACU,iBAAiB,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAC7C,YAAY,EAAE,iBAAiB,GAAG,IAAI,EACtC,MAAM,EAAE,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,EAClC,OAAO,EAAE,CAAC,EACV,cAAc,EAAE,GAAG,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IA0NhC;;;;;;;OAOG;IACH,SAAS,CAAC,mBAAmB,CAAC,cAAc,EAAE,OAAO,GAAG;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAC;IAyI5F;;;;;;;OAOG;IACU,aAAa,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EACzC,OAAO,EAAE,CAAC,EACV,cAAc,EAAE,GAAG,EACnB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GACpD,OAAO,CAAC,IAAI,CAAC;IAShB;;;;;;;;;;OAUG;IACU,oBAAoB,CAAC,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAK/G;;;;;;;;;;;OAWG;IACU,kBAAkB,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAC9C,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC7B,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC1B,OAAO,EAAE,CAAC,EACV,cAAc,EAAE,GAAG,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAKvC;;;;;;;;;;;OAWG;IACU,gBAAgB,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAC5C,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,CAAC,EACV,cAAc,EAAE,GAAG,EACnB,gBAAgB,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI,GAC/C,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC;IAK3C;;;;;;;;;;;;;;;;;OAiBG;IACU,oBAAoB,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAChD,OAAO,EAAE,WAAW,EAAE,EACtB,cAAc,EAAE,CAAC,EACjB,cAAc,EAAE,GAAG,EACnB,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC,EACjC,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC;IAShB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,6BAA6B;CAyBxC"}
@@ -86,13 +86,41 @@ let LoopAgentType = class LoopAgentType extends BaseAgentType {
86
86
  // Parse the response using the base class utility
87
87
  const response = this.parseJSONResponse(promptResult);
88
88
  if (!response) {
89
- return this.createRetryStep('Failed to parse JSON response');
89
+ // Strong, specific corrective directive. The common failure mode here is the model
90
+ // drifting into conversational prose (e.g. "I'm executing the X action with
91
+ // parameters: ...") instead of emitting the JSON envelope. A terse "couldn't parse"
92
+ // message gives the model nothing to correct against, so we spell out exactly what
93
+ // to do and what NOT to do. This is the retry-feedback half of the prose-drift fix;
94
+ // the other half re-roles framework action records so they stop reading as prose
95
+ // assistant exemplars.
96
+ return this.createRetryStep('Your previous message was not valid JSON and could not be parsed. Respond with ONLY a ' +
97
+ 'single raw JSON object conforming to the LoopAgentResponse interface — no prose, no ' +
98
+ 'markdown code fences, and no natural-language narration such as "I\'m executing the ... ' +
99
+ 'action". Do not describe your action in text; express it inside the JSON (e.g. via ' +
100
+ 'nextStep). Output the JSON object and nothing else.');
90
101
  }
91
102
  // Validate the response structure
92
103
  const validationResult = this.isValidLoopResponse(response);
93
104
  if (!validationResult.success) {
94
105
  return this.createRetryStep(validationResult.message);
95
106
  }
107
+ // A tool pipeline is a yield/await action (like client tools): the agent can't know
108
+ // its result until it runs. Handle it BEFORE Chat/taskComplete/nextStep-switch checks —
109
+ // the loop executes the pipeline inline, injects the final output, and we force one
110
+ // more turn (Retry, non-terminal) so the LLM can use the result. Pipeline is a singular
111
+ // `nextStep.type`, so the model cannot also request Actions/Chat/etc. this turn; checking
112
+ // it here preserves yield/await semantics (it pre-empts taskComplete, like client tools).
113
+ if (response.nextStep?.type === 'Pipeline' && response.nextStep.pipeline?.steps?.length) {
114
+ return this.createNextStep('Retry', {
115
+ pipeline: response.nextStep.pipeline,
116
+ terminate: false,
117
+ scratchpad: response.scratchpad,
118
+ artifactToolCalls: response.artifactToolCalls,
119
+ payloadChangeRequest: response.payloadChangeRequest,
120
+ reasoning: response.reasoning,
121
+ confidence: response.confidence
122
+ });
123
+ }
96
124
  // Check for Chat nextStep BEFORE checking taskComplete
97
125
  // This allows agents to ask for user clarification even when taskComplete=true
98
126
  if (response.nextStep?.type === 'Chat') {
@@ -238,6 +266,13 @@ let LoopAgentType = class LoopAgentType extends BaseAgentType {
238
266
  retVal.messageIndex = response.nextStep.messageIndex;
239
267
  retVal.expandReason = response.nextStep.reason;
240
268
  break;
269
+ case 'Pipeline':
270
+ // A well-formed pipeline is handled by the early return above; reaching the
271
+ // switch means type='Pipeline' was set with no (or empty) nextStep.pipeline.steps.
272
+ retVal.step = 'Retry';
273
+ retVal.message = 'When nextStep.type == "Pipeline", nextStep.pipeline.steps must contain 1 or more stages';
274
+ retVal.errorMessage = 'Pipeline steps not specified for Pipeline type';
275
+ break;
241
276
  default:
242
277
  retVal.step = 'Retry';
243
278
  retVal.errorMessage = `Unknown next step type: ${response.nextStep.type}`;
@@ -317,7 +352,7 @@ let LoopAgentType = class LoopAgentType extends BaseAgentType {
317
352
  }
318
353
  // Validate nextStep structure if present
319
354
  if (response.nextStep) {
320
- const validStepTypes = ['actions', 'sub-agent', 'chat', 'retry', 'foreach', 'while', 'clienttools'];
355
+ const validStepTypes = ['actions', 'sub-agent', 'chat', 'retry', 'foreach', 'while', 'clienttools', 'pipeline'];
321
356
  let lcaseType = response.nextStep.type?.toLowerCase().trim();
322
357
  // allow the AI to mess up the case, but we need to validate it
323
358
  // be smart/lenient about missing types. if type is missing but we have a nextStep.subAgent/subAgents, default to sub-agent and if type is missing and we have nextStep.actions, default to actions
@@ -341,6 +376,10 @@ let LoopAgentType = class LoopAgentType extends BaseAgentType {
341
376
  response.nextStep.type = 'While'; // update the data structure to have the correct type
342
377
  lcaseType = 'while';
343
378
  }
379
+ else if (!lcaseType && response.nextStep.pipeline?.steps?.length) {
380
+ response.nextStep.type = 'Pipeline'; // update the data structure to have the correct type
381
+ lcaseType = 'pipeline';
382
+ }
344
383
  if (!validStepTypes.includes(lcaseType)) {
345
384
  const message = `LoopAgentResponse has invalid nextStep.type: ${response.nextStep.type}`;
346
385
  LogError(message);