@nodetool-ai/execution 0.8.1
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/README.md +129 -0
- package/dist/.nodetool-build-stamp +1 -0
- package/dist/app-debug/app-spec.d.ts +94 -0
- package/dist/app-debug/app-spec.d.ts.map +1 -0
- package/dist/app-debug/app-spec.js +710 -0
- package/dist/app-debug/app-spec.js.map +1 -0
- package/dist/app-debug/application-target.d.ts +53 -0
- package/dist/app-debug/application-target.d.ts.map +1 -0
- package/dist/app-debug/application-target.js +126 -0
- package/dist/app-debug/application-target.js.map +1 -0
- package/dist/app-debug/bundle-target.d.ts +21 -0
- package/dist/app-debug/bundle-target.d.ts.map +1 -0
- package/dist/app-debug/bundle-target.js +51 -0
- package/dist/app-debug/bundle-target.js.map +1 -0
- package/dist/app-debug/graph-shape.d.ts +14 -0
- package/dist/app-debug/graph-shape.d.ts.map +1 -0
- package/dist/app-debug/graph-shape.js +23 -0
- package/dist/app-debug/graph-shape.js.map +1 -0
- package/dist/app-debug/index.d.ts +26 -0
- package/dist/app-debug/index.d.ts.map +1 -0
- package/dist/app-debug/index.js +19 -0
- package/dist/app-debug/index.js.map +1 -0
- package/dist/app-debug/markdown.d.ts +6 -0
- package/dist/app-debug/markdown.d.ts.map +1 -0
- package/dist/app-debug/markdown.js +133 -0
- package/dist/app-debug/markdown.js.map +1 -0
- package/dist/app-debug/runtime.d.ts +267 -0
- package/dist/app-debug/runtime.d.ts.map +1 -0
- package/dist/app-debug/runtime.js +633 -0
- package/dist/app-debug/runtime.js.map +1 -0
- package/dist/app-debug/script-operation.d.ts +58 -0
- package/dist/app-debug/script-operation.d.ts.map +1 -0
- package/dist/app-debug/script-operation.js +44 -0
- package/dist/app-debug/script-operation.js.map +1 -0
- package/dist/app-debug/simulate.d.ts +85 -0
- package/dist/app-debug/simulate.d.ts.map +1 -0
- package/dist/app-debug/simulate.js +991 -0
- package/dist/app-debug/simulate.js.map +1 -0
- package/dist/app-debug/summarize.d.ts +64 -0
- package/dist/app-debug/summarize.d.ts.map +1 -0
- package/dist/app-debug/summarize.js +65 -0
- package/dist/app-debug/summarize.js.map +1 -0
- package/dist/app-debug/types.d.ts +343 -0
- package/dist/app-debug/types.d.ts.map +1 -0
- package/dist/app-debug/types.js +2 -0
- package/dist/app-debug/types.js.map +1 -0
- package/dist/cost-ledger.d.ts +147 -0
- package/dist/cost-ledger.d.ts.map +1 -0
- package/dist/cost-ledger.js +288 -0
- package/dist/cost-ledger.js.map +1 -0
- package/dist/debug/collector.d.ts +28 -0
- package/dist/debug/collector.d.ts.map +1 -0
- package/dist/debug/collector.js +284 -0
- package/dist/debug/collector.js.map +1 -0
- package/dist/debug/index.d.ts +15 -0
- package/dist/debug/index.d.ts.map +1 -0
- package/dist/debug/index.js +16 -0
- package/dist/debug/index.js.map +1 -0
- package/dist/debug/types.d.ts +179 -0
- package/dist/debug/types.d.ts.map +1 -0
- package/dist/debug/types.js +11 -0
- package/dist/debug/types.js.map +1 -0
- package/dist/debug/verdict.d.ts +27 -0
- package/dist/debug/verdict.d.ts.map +1 -0
- package/dist/debug/verdict.js +51 -0
- package/dist/debug/verdict.js.map +1 -0
- package/dist/executor-resolver.d.ts +13 -0
- package/dist/executor-resolver.d.ts.map +1 -0
- package/dist/executor-resolver.js +13 -0
- package/dist/executor-resolver.js.map +1 -0
- package/dist/fal-output-decoder.d.ts +36 -0
- package/dist/fal-output-decoder.d.ts.map +1 -0
- package/dist/fal-output-decoder.js +129 -0
- package/dist/fal-output-decoder.js.map +1 -0
- package/dist/generation-lifecycle.d.ts +54 -0
- package/dist/generation-lifecycle.d.ts.map +1 -0
- package/dist/generation-lifecycle.js +431 -0
- package/dist/generation-lifecycle.js.map +1 -0
- package/dist/generation-recovery-worker.d.ts +100 -0
- package/dist/generation-recovery-worker.d.ts.map +1 -0
- package/dist/generation-recovery-worker.js +995 -0
- package/dist/generation-recovery-worker.js.map +1 -0
- package/dist/generation-tracker.d.ts +83 -0
- package/dist/generation-tracker.d.ts.map +1 -0
- package/dist/generation-tracker.js +436 -0
- package/dist/generation-tracker.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/js-script-debug/index.d.ts +13 -0
- package/dist/js-script-debug/index.d.ts.map +1 -0
- package/dist/js-script-debug/index.js +12 -0
- package/dist/js-script-debug/index.js.map +1 -0
- package/dist/js-script-debug/markdown.d.ts +6 -0
- package/dist/js-script-debug/markdown.d.ts.map +1 -0
- package/dist/js-script-debug/markdown.js +62 -0
- package/dist/js-script-debug/markdown.js.map +1 -0
- package/dist/js-script-debug/outputs.d.ts +20 -0
- package/dist/js-script-debug/outputs.d.ts.map +1 -0
- package/dist/js-script-debug/outputs.js +30 -0
- package/dist/js-script-debug/outputs.js.map +1 -0
- package/dist/js-script-debug/report.d.ts +15 -0
- package/dist/js-script-debug/report.d.ts.map +1 -0
- package/dist/js-script-debug/report.js +90 -0
- package/dist/js-script-debug/report.js.map +1 -0
- package/dist/js-script-debug/types.d.ts +63 -0
- package/dist/js-script-debug/types.d.ts.map +1 -0
- package/dist/js-script-debug/types.js +10 -0
- package/dist/js-script-debug/types.js.map +1 -0
- package/dist/js-script-debug/validate.d.ts +38 -0
- package/dist/js-script-debug/validate.d.ts.map +1 -0
- package/dist/js-script-debug/validate.js +137 -0
- package/dist/js-script-debug/validate.js.map +1 -0
- package/dist/message-stream.d.ts +33 -0
- package/dist/message-stream.d.ts.map +1 -0
- package/dist/message-stream.js +58 -0
- package/dist/message-stream.js.map +1 -0
- package/dist/normalize-graph.d.ts +13 -0
- package/dist/normalize-graph.d.ts.map +1 -0
- package/dist/normalize-graph.js +63 -0
- package/dist/normalize-graph.js.map +1 -0
- package/dist/output-names.d.ts +13 -0
- package/dist/output-names.d.ts.map +1 -0
- package/dist/output-names.js +13 -0
- package/dist/output-names.js.map +1 -0
- package/dist/predicates.d.ts +6 -0
- package/dist/predicates.d.ts.map +1 -0
- package/dist/predicates.js +6 -0
- package/dist/predicates.js.map +1 -0
- package/dist/preflight.d.ts +87 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +139 -0
- package/dist/preflight.js.map +1 -0
- package/dist/provider-secret-key.d.ts +3 -0
- package/dist/provider-secret-key.d.ts.map +1 -0
- package/dist/provider-secret-key.js +7 -0
- package/dist/provider-secret-key.js.map +1 -0
- package/dist/service/app-debug-service.d.ts +78 -0
- package/dist/service/app-debug-service.d.ts.map +1 -0
- package/dist/service/app-debug-service.js +201 -0
- package/dist/service/app-debug-service.js.map +1 -0
- package/dist/service/app-run-server.d.ts +28 -0
- package/dist/service/app-run-server.d.ts.map +1 -0
- package/dist/service/app-run-server.js +104 -0
- package/dist/service/app-run-server.js.map +1 -0
- package/dist/service/debug-sessions.d.ts +158 -0
- package/dist/service/debug-sessions.d.ts.map +1 -0
- package/dist/service/debug-sessions.js +358 -0
- package/dist/service/debug-sessions.js.map +1 -0
- package/dist/service/index.d.ts +22 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/index.js +17 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/job-progress.d.ts +40 -0
- package/dist/service/job-progress.d.ts.map +1 -0
- package/dist/service/job-progress.js +53 -0
- package/dist/service/job-progress.js.map +1 -0
- package/dist/service/workflow-run.d.ts +279 -0
- package/dist/service/workflow-run.d.ts.map +1 -0
- package/dist/service/workflow-run.js +598 -0
- package/dist/service/workflow-run.js.map +1 -0
- package/dist/service/workflow-workspace.d.ts +89 -0
- package/dist/service/workflow-workspace.d.ts.map +1 -0
- package/dist/service/workflow-workspace.js +160 -0
- package/dist/service/workflow-workspace.js.map +1 -0
- package/dist/session.d.ts +62 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +353 -0
- package/dist/session.js.map +1 -0
- package/dist/sketch-debug/index.d.ts +11 -0
- package/dist/sketch-debug/index.d.ts.map +1 -0
- package/dist/sketch-debug/index.js +10 -0
- package/dist/sketch-debug/index.js.map +1 -0
- package/dist/sketch-debug/markdown.d.ts +6 -0
- package/dist/sketch-debug/markdown.d.ts.map +1 -0
- package/dist/sketch-debug/markdown.js +93 -0
- package/dist/sketch-debug/markdown.js.map +1 -0
- package/dist/sketch-debug/report.d.ts +15 -0
- package/dist/sketch-debug/report.d.ts.map +1 -0
- package/dist/sketch-debug/report.js +98 -0
- package/dist/sketch-debug/report.js.map +1 -0
- package/dist/sketch-debug/types.d.ts +62 -0
- package/dist/sketch-debug/types.d.ts.map +1 -0
- package/dist/sketch-debug/types.js +10 -0
- package/dist/sketch-debug/types.js.map +1 -0
- package/dist/sketch-debug/validate.d.ts +14 -0
- package/dist/sketch-debug/validate.d.ts.map +1 -0
- package/dist/sketch-debug/validate.js +478 -0
- package/dist/sketch-debug/validate.js.map +1 -0
- package/dist/supervisor.d.ts +45 -0
- package/dist/supervisor.d.ts.map +1 -0
- package/dist/supervisor.js +97 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/timeline-debug/index.d.ts +11 -0
- package/dist/timeline-debug/index.d.ts.map +1 -0
- package/dist/timeline-debug/index.js +10 -0
- package/dist/timeline-debug/index.js.map +1 -0
- package/dist/timeline-debug/legibility.d.ts +23 -0
- package/dist/timeline-debug/legibility.d.ts.map +1 -0
- package/dist/timeline-debug/legibility.js +240 -0
- package/dist/timeline-debug/legibility.js.map +1 -0
- package/dist/timeline-debug/markdown.d.ts +6 -0
- package/dist/timeline-debug/markdown.d.ts.map +1 -0
- package/dist/timeline-debug/markdown.js +103 -0
- package/dist/timeline-debug/markdown.js.map +1 -0
- package/dist/timeline-debug/motion.d.ts +20 -0
- package/dist/timeline-debug/motion.d.ts.map +1 -0
- package/dist/timeline-debug/motion.js +362 -0
- package/dist/timeline-debug/motion.js.map +1 -0
- package/dist/timeline-debug/report.d.ts +16 -0
- package/dist/timeline-debug/report.d.ts.map +1 -0
- package/dist/timeline-debug/report.js +100 -0
- package/dist/timeline-debug/report.js.map +1 -0
- package/dist/timeline-debug/showcase.d.ts +7 -0
- package/dist/timeline-debug/showcase.d.ts.map +1 -0
- package/dist/timeline-debug/showcase.js +347 -0
- package/dist/timeline-debug/showcase.js.map +1 -0
- package/dist/timeline-debug/types.d.ts +64 -0
- package/dist/timeline-debug/types.d.ts.map +1 -0
- package/dist/timeline-debug/types.js +10 -0
- package/dist/timeline-debug/types.js.map +1 -0
- package/dist/timeline-debug/validate.d.ts +24 -0
- package/dist/timeline-debug/validate.d.ts.map +1 -0
- package/dist/timeline-debug/validate.js +1432 -0
- package/dist/timeline-debug/validate.js.map +1 -0
- package/dist/types.d.ts +211 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive escalation sessions for the agent-facing run/debug endpoints.
|
|
3
|
+
*
|
|
4
|
+
* The supervisor design (docs/workflow-supervisor-design.md) puts an LLM agent
|
|
5
|
+
* on a run's failure path. This module puts the *calling* agent there instead:
|
|
6
|
+
* `InteractiveEscalationHandle` is a `SupervisorHandle` whose `decide()` parks
|
|
7
|
+
* the escalation until a verdict arrives over HTTP, so the tool that started
|
|
8
|
+
* the run gets the problem back as its result and answers with one of the
|
|
9
|
+
* same verdicts the supervisor vocabulary defines. The kernel's guarantees are
|
|
10
|
+
* untouched — the handle is wrapped in `BoundedHandle` (decision/retry caps,
|
|
11
|
+
* timeout, sticky verdicts) and the actor still enforces `allowedActions`.
|
|
12
|
+
*
|
|
13
|
+
* A session is one run: the parked escalations, the run's completion promise,
|
|
14
|
+
* and the final report. Sessions are owned by the user who started the run and
|
|
15
|
+
* are swept a few minutes after the run settles.
|
|
16
|
+
*
|
|
17
|
+
* Long-running work that is not a workflow run uses the same registry for its
|
|
18
|
+
* polling and cancel — `POST /api/applications/build` fronts a build this way,
|
|
19
|
+
* with a null `workflowId` and a handle nothing ever escalates to.
|
|
20
|
+
*/
|
|
21
|
+
import { randomUUID } from "node:crypto";
|
|
22
|
+
import { createLogger } from "@nodetool-ai/config";
|
|
23
|
+
import { validateSubstituteOutputs } from "@nodetool-ai/kernel";
|
|
24
|
+
const log = createLogger("nodetool.execution.debug-sessions");
|
|
25
|
+
/** How long an agent gets to answer one escalation before it fails closed. */
|
|
26
|
+
export const INTERACTIVE_DECISION_TIMEOUT_MS = 10 * 60_000;
|
|
27
|
+
/** How long a settled session's report stays fetchable. */
|
|
28
|
+
const SESSION_DONE_TTL_MS = 10 * 60_000;
|
|
29
|
+
/**
|
|
30
|
+
* Hard ceiling on a session's life. The TTL sweep only arms once a run
|
|
31
|
+
* settles, so a run whose `done` never resolves — a wedged bridge, a promise
|
|
32
|
+
* nobody rejects — used to hold its session (and the run behind it) forever.
|
|
33
|
+
*/
|
|
34
|
+
export const SESSION_MAX_LIFETIME_MS = 60 * 60_000;
|
|
35
|
+
/** How long `cancel()` waits for the run to settle before answering anyway. */
|
|
36
|
+
export const CANCEL_SETTLE_TIMEOUT_MS = 30_000;
|
|
37
|
+
/** Live (unsettled) sessions one user may hold at once. */
|
|
38
|
+
export const MAX_LIVE_SESSIONS_PER_USER = 8;
|
|
39
|
+
const FAIL_CLOSED = {
|
|
40
|
+
verdict: { action: "fail" },
|
|
41
|
+
decidedBy: "default"
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* A `SupervisorHandle` that answers nothing itself: each `decide()` parks the
|
|
45
|
+
* escalation until `submit()` delivers a verdict (or the decision signal
|
|
46
|
+
* aborts, which fails closed). `BoundedHandle` serializes decisions, so at
|
|
47
|
+
* most one escalation is pending at a time.
|
|
48
|
+
*/
|
|
49
|
+
export class InteractiveEscalationHandle {
|
|
50
|
+
_pending = null;
|
|
51
|
+
_waiters = [];
|
|
52
|
+
_counter = 0;
|
|
53
|
+
_closed = false;
|
|
54
|
+
decide(e, signal) {
|
|
55
|
+
if (this._closed || signal.aborted)
|
|
56
|
+
return Promise.resolve(FAIL_CLOSED);
|
|
57
|
+
return new Promise((resolve) => {
|
|
58
|
+
let settled = false;
|
|
59
|
+
const entry = {
|
|
60
|
+
id: `esc-${++this._counter}`,
|
|
61
|
+
escalation: e,
|
|
62
|
+
settle: (outcome) => {
|
|
63
|
+
if (settled)
|
|
64
|
+
return;
|
|
65
|
+
settled = true;
|
|
66
|
+
if (this._pending === entry)
|
|
67
|
+
this._pending = null;
|
|
68
|
+
signal.removeEventListener("abort", onAbort);
|
|
69
|
+
resolve(outcome);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const onAbort = () => entry.settle(FAIL_CLOSED);
|
|
73
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
74
|
+
this._pending = entry;
|
|
75
|
+
const waiters = this._waiters;
|
|
76
|
+
this._waiters = [];
|
|
77
|
+
for (const waiter of waiters)
|
|
78
|
+
waiter(entry);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/** The escalation currently awaiting a verdict, if any. */
|
|
82
|
+
current() {
|
|
83
|
+
if (!this._pending)
|
|
84
|
+
return null;
|
|
85
|
+
return { id: this._pending.id, escalation: this._pending.escalation };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Subscribe to the next parked escalation. Returns an unsubscribe so a
|
|
89
|
+
* caller racing this against run completion can withdraw when the run wins
|
|
90
|
+
* — otherwise every verdict round trip would strand one waiter until the
|
|
91
|
+
* session is swept.
|
|
92
|
+
*/
|
|
93
|
+
subscribe(waiter) {
|
|
94
|
+
this._waiters.push(waiter);
|
|
95
|
+
return () => {
|
|
96
|
+
const index = this._waiters.indexOf(waiter);
|
|
97
|
+
if (index !== -1)
|
|
98
|
+
this._waiters.splice(index, 1);
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Deliver the agent's verdict for the parked escalation. Returns an error
|
|
103
|
+
* string instead of throwing so the HTTP layer can 400 with it; the verdict
|
|
104
|
+
* is checked against the escalation's `allowedActions` here so the agent can
|
|
105
|
+
* correct itself, and enforced again by the kernel regardless.
|
|
106
|
+
*
|
|
107
|
+
* A `substitute` payload is validated here too, against the same rules the
|
|
108
|
+
* actor applies. Accepting it and letting the kernel reject it fails the
|
|
109
|
+
* node with its *original* error and burns the decision — the agent never
|
|
110
|
+
* learns its repair was malformed. Rejecting here keeps the escalation
|
|
111
|
+
* parked, so it can answer again.
|
|
112
|
+
*/
|
|
113
|
+
async submit(escalationId, verdict) {
|
|
114
|
+
const pending = this._pending;
|
|
115
|
+
if (!pending) {
|
|
116
|
+
return {
|
|
117
|
+
error: "No escalation is awaiting a verdict — the run may have moved on " +
|
|
118
|
+
"(a timed-out decision fails closed) or finished."
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (pending.id !== escalationId) {
|
|
122
|
+
return {
|
|
123
|
+
error: `Escalation ${escalationId} is not pending (current: ${pending.id}).`
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (!pending.escalation.allowedActions.includes(verdict.action)) {
|
|
127
|
+
return {
|
|
128
|
+
error: `Verdict "${verdict.action}" is not allowed for this escalation. ` +
|
|
129
|
+
`Allowed: ${pending.escalation.allowedActions.join(", ")}.`
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (verdict.action === "substitute") {
|
|
133
|
+
const result = await validateSubstituteOutputs(verdict.outputs, {
|
|
134
|
+
declaredOutputs: pending.escalation.declaredOutputs
|
|
135
|
+
});
|
|
136
|
+
if (!result.ok) {
|
|
137
|
+
return {
|
|
138
|
+
error: "Substituted outputs are invalid, so the escalation is still " +
|
|
139
|
+
`awaiting a verdict: ${result.issues.join("; ")}`
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// Validation is async; the escalation may have failed closed meanwhile.
|
|
143
|
+
if (this._pending !== pending) {
|
|
144
|
+
return {
|
|
145
|
+
error: "The escalation stopped awaiting a verdict while the substituted " +
|
|
146
|
+
"outputs were being validated."
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
pending.settle({ verdict, decidedBy: "agent" });
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
close() {
|
|
154
|
+
this._closed = true;
|
|
155
|
+
this._pending?.settle(FAIL_CLOSED);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export class DebugSession {
|
|
159
|
+
id;
|
|
160
|
+
userId;
|
|
161
|
+
workflowId;
|
|
162
|
+
jobId;
|
|
163
|
+
_handle;
|
|
164
|
+
/** The run's own completion, raced with a forced settle. Never rejects. */
|
|
165
|
+
_done;
|
|
166
|
+
_cancel;
|
|
167
|
+
_cancelWaitMs;
|
|
168
|
+
_force = () => { };
|
|
169
|
+
_report = null;
|
|
170
|
+
constructor(options, onSettled) {
|
|
171
|
+
this.id = randomUUID();
|
|
172
|
+
this.userId = options.userId;
|
|
173
|
+
this.workflowId = options.workflowId;
|
|
174
|
+
this.jobId = options.jobId;
|
|
175
|
+
this._handle = options.handle;
|
|
176
|
+
this._cancel = options.cancel;
|
|
177
|
+
this._cancelWaitMs = options.cancelWaitMs ?? CANCEL_SETTLE_TIMEOUT_MS;
|
|
178
|
+
// A run that never settles must not hold the session — or its waiters —
|
|
179
|
+
// open forever, so every wait goes through this race rather than through
|
|
180
|
+
// the run's own promise.
|
|
181
|
+
const forced = new Promise((resolve) => {
|
|
182
|
+
this._force = resolve;
|
|
183
|
+
});
|
|
184
|
+
this._done = Promise.race([options.done, forced]);
|
|
185
|
+
void this._done.then((report) => {
|
|
186
|
+
this._report = report;
|
|
187
|
+
onSettled();
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/** True until the run (or a forced settle) has produced a final report. */
|
|
191
|
+
isLive() {
|
|
192
|
+
return this._report === null;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Settle the session without the run: cancel what can be cancelled, fail the
|
|
196
|
+
* parked escalation closed, and hand every waiter a failed report. Used by
|
|
197
|
+
* the lifetime ceiling and by a cancel the run does not answer.
|
|
198
|
+
*/
|
|
199
|
+
forceSettle(reason) {
|
|
200
|
+
try {
|
|
201
|
+
this._cancel();
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
log.warn("cancel threw while force-settling a debug session", {
|
|
205
|
+
sessionId: this.id,
|
|
206
|
+
error: String(error)
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
this._handle.close();
|
|
210
|
+
this._force({
|
|
211
|
+
status: "failed",
|
|
212
|
+
error: reason,
|
|
213
|
+
job_id: this.jobId,
|
|
214
|
+
workflow_id: this.workflowId,
|
|
215
|
+
outputs: {}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Wait until the run either parks an escalation or settles. There is no
|
|
220
|
+
* wait cap of its own: the non-interactive endpoint awaits the whole run
|
|
221
|
+
* too, a parked decision fails closed on its own timeout, and the session's
|
|
222
|
+
* lifetime ceiling settles anything that outlives both.
|
|
223
|
+
*/
|
|
224
|
+
async waitForEvent() {
|
|
225
|
+
const pending = this._handle.current();
|
|
226
|
+
if (pending) {
|
|
227
|
+
return {
|
|
228
|
+
kind: "escalated",
|
|
229
|
+
escalationId: pending.id,
|
|
230
|
+
escalation: pending.escalation
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
let unsubscribe = () => { };
|
|
234
|
+
try {
|
|
235
|
+
return await Promise.race([
|
|
236
|
+
this._done.then((report) => ({ kind: "done", report })),
|
|
237
|
+
new Promise((resolve) => {
|
|
238
|
+
unsubscribe = this._handle.subscribe((entry) => resolve({
|
|
239
|
+
kind: "escalated",
|
|
240
|
+
escalationId: entry.id,
|
|
241
|
+
escalation: entry.escalation
|
|
242
|
+
}));
|
|
243
|
+
})
|
|
244
|
+
]);
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
unsubscribe();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/** Current state without waiting. */
|
|
251
|
+
peek() {
|
|
252
|
+
if (this._report)
|
|
253
|
+
return { kind: "done", report: this._report };
|
|
254
|
+
const pending = this._handle.current();
|
|
255
|
+
if (pending) {
|
|
256
|
+
return {
|
|
257
|
+
kind: "escalated",
|
|
258
|
+
escalationId: pending.id,
|
|
259
|
+
escalation: pending.escalation
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
return { kind: "running" };
|
|
263
|
+
}
|
|
264
|
+
async submitVerdict(escalationId, verdict) {
|
|
265
|
+
if (this._report) {
|
|
266
|
+
return { error: "The run has already finished." };
|
|
267
|
+
}
|
|
268
|
+
return this._handle.submit(escalationId, verdict);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Cancel the run and return its final report. The wait is bounded: a run
|
|
272
|
+
* that ignores cancellation used to hang the cancel request itself, so past
|
|
273
|
+
* the deadline the session settles on its own and answers with that.
|
|
274
|
+
*/
|
|
275
|
+
async cancel() {
|
|
276
|
+
try {
|
|
277
|
+
this._cancel();
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
log.warn("cancel threw for a debug session", {
|
|
281
|
+
sessionId: this.id,
|
|
282
|
+
error: String(error)
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
let timer;
|
|
286
|
+
const deadline = new Promise((resolve) => {
|
|
287
|
+
timer = setTimeout(() => resolve("timeout"), this._cancelWaitMs);
|
|
288
|
+
timer.unref?.();
|
|
289
|
+
});
|
|
290
|
+
try {
|
|
291
|
+
const outcome = await Promise.race([this._done, deadline]);
|
|
292
|
+
if (outcome !== "timeout")
|
|
293
|
+
return outcome;
|
|
294
|
+
}
|
|
295
|
+
finally {
|
|
296
|
+
if (timer)
|
|
297
|
+
clearTimeout(timer);
|
|
298
|
+
}
|
|
299
|
+
this.forceSettle(`Cancel requested, but the run did not settle within ${this._cancelWaitMs}ms.`);
|
|
300
|
+
return this._done;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/** Thrown by `create()` when a user already holds the maximum live sessions. */
|
|
304
|
+
export class TooManyDebugSessionsError extends Error {
|
|
305
|
+
constructor(limit) {
|
|
306
|
+
super(`Too many active debug sessions (limit ${limit}). Cancel or finish one ` +
|
|
307
|
+
"with POST /api/debug/sessions/:id/cancel before starting another.");
|
|
308
|
+
this.name = "TooManyDebugSessionsError";
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
class DebugSessionRegistry {
|
|
312
|
+
_sessions = new Map();
|
|
313
|
+
/** Live sessions this user holds. */
|
|
314
|
+
liveCount(userId) {
|
|
315
|
+
let count = 0;
|
|
316
|
+
for (const session of this._sessions.values()) {
|
|
317
|
+
if (session.userId === userId && session.isLive())
|
|
318
|
+
count += 1;
|
|
319
|
+
}
|
|
320
|
+
return count;
|
|
321
|
+
}
|
|
322
|
+
create(options) {
|
|
323
|
+
if (this.liveCount(options.userId) >= MAX_LIVE_SESSIONS_PER_USER) {
|
|
324
|
+
throw new TooManyDebugSessionsError(MAX_LIVE_SESSIONS_PER_USER);
|
|
325
|
+
}
|
|
326
|
+
const session = new DebugSession(options, () => {
|
|
327
|
+
clearTimeout(lifetime);
|
|
328
|
+
const timer = setTimeout(() => {
|
|
329
|
+
this._sessions.delete(session.id);
|
|
330
|
+
}, SESSION_DONE_TTL_MS);
|
|
331
|
+
timer.unref?.();
|
|
332
|
+
});
|
|
333
|
+
const lifetime = setTimeout(() => {
|
|
334
|
+
log.warn("debug session hit its lifetime ceiling", {
|
|
335
|
+
sessionId: session.id,
|
|
336
|
+
jobId: options.jobId
|
|
337
|
+
});
|
|
338
|
+
session.forceSettle("The run exceeded the maximum session lifetime and was force-settled.");
|
|
339
|
+
}, options.maxLifetimeMs ?? SESSION_MAX_LIFETIME_MS);
|
|
340
|
+
lifetime.unref?.();
|
|
341
|
+
this._sessions.set(session.id, session);
|
|
342
|
+
log.info("interactive debug session opened", {
|
|
343
|
+
sessionId: session.id,
|
|
344
|
+
jobId: options.jobId,
|
|
345
|
+
workflowId: options.workflowId
|
|
346
|
+
});
|
|
347
|
+
return session;
|
|
348
|
+
}
|
|
349
|
+
/** Ownership is part of the lookup: a foreign session id is a miss. */
|
|
350
|
+
get(sessionId, userId) {
|
|
351
|
+
const session = this._sessions.get(sessionId);
|
|
352
|
+
if (!session || session.userId !== userId)
|
|
353
|
+
return null;
|
|
354
|
+
return session;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
export const debugSessions = new DebugSessionRegistry();
|
|
358
|
+
//# sourceMappingURL=debug-sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-sessions.js","sourceRoot":"","sources":["../../src/service/debug-sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nodetool-ai/execution/service` — workflow execution as a service.
|
|
3
|
+
*
|
|
4
|
+
* Everything the HTTP surface does *except* parse a Request and write a
|
|
5
|
+
* Response: running a saved workflow (plain, debug, or interactive), the
|
|
6
|
+
* in-memory escalation-session registry those interactive runs park in, the
|
|
7
|
+
* kernel runner every app simulation shares, and the app-debug engine.
|
|
8
|
+
*
|
|
9
|
+
* The websocket package keeps the Fastify routes and calls this. So do the
|
|
10
|
+
* agent tools — an agent runs a workflow in-process, never over HTTP.
|
|
11
|
+
*/
|
|
12
|
+
export { debugSessions, DebugSession, InteractiveEscalationHandle, TooManyDebugSessionsError, INTERACTIVE_DECISION_TIMEOUT_MS, SESSION_MAX_LIFETIME_MS, CANCEL_SETTLE_TIMEOUT_MS, MAX_LIVE_SESSIONS_PER_USER } from "./debug-sessions.js";
|
|
13
|
+
export type { CreateDebugSessionOptions, DebugSessionEvent, ParkedEscalation } from "./debug-sessions.js";
|
|
14
|
+
export { resolveWorkflowWorkspace, resolveWorkflowWorkspaceDir, workspaceFromRow, setWorkspaceCloudStorage, setWorkspaceChangeNotifier, usesCloudWorkspaces, buildWorkspaceExecutionContext } from "./workflow-workspace.js";
|
|
15
|
+
export type { WorkspaceFileChange } from "./workflow-workspace.js";
|
|
16
|
+
export { createAppServerRunner } from "./app-run-server.js";
|
|
17
|
+
export type { AppServerRunnerOptions } from "./app-run-server.js";
|
|
18
|
+
export { runWorkflow, peekDebugSession, submitEscalationVerdict, cancelDebugSession, buildWorkflowRunPayload, debugSessionEventPayload, boundedRunOption, persistableOutputs, withoutInlineAssetBytes, modelSelectionErrors, MAX_INTERACTIVE_DECISIONS, MAX_INTERACTIVE_RETRIES_PER_NODE, MAX_INTERACTIVE_DECISION_TIMEOUT_MS } from "./workflow-run.js";
|
|
19
|
+
export type { RunModelCatalogs, RunWorkflowOptions, RunWorkflowOutcome, WorkflowRunEnvironment } from "./workflow-run.js";
|
|
20
|
+
export { runApplicationDebug, AppServiceError } from "./app-debug-service.js";
|
|
21
|
+
export type { AppDebugDeps, AppDebugRequest } from "./app-debug-service.js";
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,aAAa,EACb,YAAY,EACZ,2BAA2B,EAC3B,yBAAyB,EACzB,+BAA+B,EAC/B,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,gBAAgB,EAChB,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACnB,8BAA8B,EAC/B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,EACxB,gBAAgB,EAChB,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,yBAAyB,EACzB,gCAAgC,EAChC,mCAAmC,EACpC,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,mBAAmB,EACnB,eAAe,EAChB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nodetool-ai/execution/service` — workflow execution as a service.
|
|
3
|
+
*
|
|
4
|
+
* Everything the HTTP surface does *except* parse a Request and write a
|
|
5
|
+
* Response: running a saved workflow (plain, debug, or interactive), the
|
|
6
|
+
* in-memory escalation-session registry those interactive runs park in, the
|
|
7
|
+
* kernel runner every app simulation shares, and the app-debug engine.
|
|
8
|
+
*
|
|
9
|
+
* The websocket package keeps the Fastify routes and calls this. So do the
|
|
10
|
+
* agent tools — an agent runs a workflow in-process, never over HTTP.
|
|
11
|
+
*/
|
|
12
|
+
export { debugSessions, DebugSession, InteractiveEscalationHandle, TooManyDebugSessionsError, INTERACTIVE_DECISION_TIMEOUT_MS, SESSION_MAX_LIFETIME_MS, CANCEL_SETTLE_TIMEOUT_MS, MAX_LIVE_SESSIONS_PER_USER } from "./debug-sessions.js";
|
|
13
|
+
export { resolveWorkflowWorkspace, resolveWorkflowWorkspaceDir, workspaceFromRow, setWorkspaceCloudStorage, setWorkspaceChangeNotifier, usesCloudWorkspaces, buildWorkspaceExecutionContext } from "./workflow-workspace.js";
|
|
14
|
+
export { createAppServerRunner } from "./app-run-server.js";
|
|
15
|
+
export { runWorkflow, peekDebugSession, submitEscalationVerdict, cancelDebugSession, buildWorkflowRunPayload, debugSessionEventPayload, boundedRunOption, persistableOutputs, withoutInlineAssetBytes, modelSelectionErrors, MAX_INTERACTIVE_DECISIONS, MAX_INTERACTIVE_RETRIES_PER_NODE, MAX_INTERACTIVE_DECISION_TIMEOUT_MS } from "./workflow-run.js";
|
|
16
|
+
export { runApplicationDebug, AppServiceError } from "./app-debug-service.js";
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,aAAa,EACb,YAAY,EACZ,2BAA2B,EAC3B,yBAAyB,EACzB,+BAA+B,EAC/B,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;AAO7B,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,gBAAgB,EAChB,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACnB,8BAA8B,EAC/B,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,EACxB,gBAAgB,EAChB,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,yBAAyB,EACzB,gCAAgC,EAChC,mCAAmC,EACpC,MAAM,mBAAmB,CAAC;AAQ3B,OAAO,EACL,mBAAmB,EACnB,eAAe,EAChB,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ProcessingMessage } from "@nodetool-ai/protocol";
|
|
2
|
+
/**
|
|
3
|
+
* Job progress on the job row.
|
|
4
|
+
*
|
|
5
|
+
* A node posts `node_progress` while it works — a render posts one per frame —
|
|
6
|
+
* and until now that message reached only the debug collector, which exists
|
|
7
|
+
* for a finished run. So `get_job` on a background render in its third minute
|
|
8
|
+
* answered "running" and nothing else, which is exactly the moment the caller
|
|
9
|
+
* needs a number. This folds the latest message onto the row.
|
|
10
|
+
*
|
|
11
|
+
* Throttled, because a 25fps two-minute render posts three thousand of them
|
|
12
|
+
* and each write is a database round trip: at most one write every
|
|
13
|
+
* `minIntervalMs`, with a jump of `minPercentStep` or the final frame going
|
|
14
|
+
* through immediately.
|
|
15
|
+
*/
|
|
16
|
+
/** The shape read off a `node_progress` message. */
|
|
17
|
+
export interface JobProgress {
|
|
18
|
+
node_id: string;
|
|
19
|
+
progress: number;
|
|
20
|
+
total: number;
|
|
21
|
+
updated_at: string;
|
|
22
|
+
}
|
|
23
|
+
export interface JobProgressRecorderOptions {
|
|
24
|
+
/** Persist one progress value. Rejections are swallowed, not thrown. */
|
|
25
|
+
write: (progress: JobProgress) => Promise<void>;
|
|
26
|
+
/** Injected so the throttle is tested against a clock rather than a wait. */
|
|
27
|
+
now?: () => number;
|
|
28
|
+
minIntervalMs?: number;
|
|
29
|
+
/** Percent of `total` that goes through regardless of the interval. */
|
|
30
|
+
minPercentStep?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A message listener that keeps the job row's progress current.
|
|
34
|
+
*
|
|
35
|
+
* Synchronous on purpose: it is called from the message bus, so it starts the
|
|
36
|
+
* write and returns. A write that fails is dropped — progress is a courtesy,
|
|
37
|
+
* and a database blip must not fail the run it is reporting on.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createJobProgressRecorder(options: JobProgressRecorderOptions): (message: ProcessingMessage) => void;
|
|
40
|
+
//# sourceMappingURL=job-progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job-progress.d.ts","sourceRoot":"","sources":["../../src/service/job-progress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D;;;;;;;;;;;;;GAaG;AAEH,oDAAoD;AACpD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,wEAAwE;IACxE,KAAK,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AASD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,0BAA0B,GAClC,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CA0CtC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const DEFAULT_MIN_INTERVAL_MS = 2000;
|
|
2
|
+
const DEFAULT_MIN_PERCENT_STEP = 5;
|
|
3
|
+
function num(value) {
|
|
4
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* A message listener that keeps the job row's progress current.
|
|
8
|
+
*
|
|
9
|
+
* Synchronous on purpose: it is called from the message bus, so it starts the
|
|
10
|
+
* write and returns. A write that fails is dropped — progress is a courtesy,
|
|
11
|
+
* and a database blip must not fail the run it is reporting on.
|
|
12
|
+
*/
|
|
13
|
+
export function createJobProgressRecorder(options) {
|
|
14
|
+
const now = options.now ?? Date.now;
|
|
15
|
+
const minIntervalMs = options.minIntervalMs ?? DEFAULT_MIN_INTERVAL_MS;
|
|
16
|
+
const minPercentStep = options.minPercentStep ?? DEFAULT_MIN_PERCENT_STEP;
|
|
17
|
+
let lastWriteAt = Number.NEGATIVE_INFINITY;
|
|
18
|
+
let lastProgress = null;
|
|
19
|
+
return (message) => {
|
|
20
|
+
if (message.type !== "node_progress")
|
|
21
|
+
return;
|
|
22
|
+
const nodeId = message.node_id;
|
|
23
|
+
const progress = num(message.progress);
|
|
24
|
+
const total = num(message.total);
|
|
25
|
+
if (typeof nodeId !== "string" || progress === null || total === null) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const at = now();
|
|
29
|
+
const stepPercent = total > 0 && lastProgress !== null
|
|
30
|
+
? ((progress - lastProgress) / total) * 100
|
|
31
|
+
: Number.POSITIVE_INFINITY;
|
|
32
|
+
const finished = total > 0 && progress >= total;
|
|
33
|
+
const due = lastProgress === null ||
|
|
34
|
+
finished ||
|
|
35
|
+
at - lastWriteAt >= minIntervalMs ||
|
|
36
|
+
stepPercent >= minPercentStep;
|
|
37
|
+
if (!due)
|
|
38
|
+
return;
|
|
39
|
+
lastWriteAt = at;
|
|
40
|
+
lastProgress = progress;
|
|
41
|
+
void options
|
|
42
|
+
.write({
|
|
43
|
+
node_id: nodeId,
|
|
44
|
+
progress,
|
|
45
|
+
total,
|
|
46
|
+
updated_at: new Date(at).toISOString()
|
|
47
|
+
})
|
|
48
|
+
.catch(() => {
|
|
49
|
+
// Progress is a courtesy: a failed write must not fail the run.
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=job-progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job-progress.js","sourceRoot":"","sources":["../../src/service/job-progress.ts"],"names":[],"mappings":"AAmCA,MAAM,uBAAuB,GAAG,IAAI,CAAC;AACrC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAEnC,SAAS,GAAG,CAAC,KAAc;IACzB,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CACvC,OAAmC;IAEnC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,uBAAuB,CAAC;IACvE,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,wBAAwB,CAAC;IAC1E,IAAI,WAAW,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAC3C,IAAI,YAAY,GAAkB,IAAI,CAAC;IAEvC,OAAO,CAAC,OAA0B,EAAQ,EAAE;QAC1C,IAAI,OAAO,CAAC,IAAI,KAAK,eAAe;YAAE,OAAO;QAC7C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACtE,OAAO;QACT,CAAC;QAED,MAAM,EAAE,GAAG,GAAG,EAAE,CAAC;QACjB,MAAM,WAAW,GACf,KAAK,GAAG,CAAC,IAAI,YAAY,KAAK,IAAI;YAChC,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,YAAY,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG;YAC3C,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;QAC/B,MAAM,QAAQ,GAAG,KAAK,GAAG,CAAC,IAAI,QAAQ,IAAI,KAAK,CAAC;QAChD,MAAM,GAAG,GACP,YAAY,KAAK,IAAI;YACrB,QAAQ;YACR,EAAE,GAAG,WAAW,IAAI,aAAa;YACjC,WAAW,IAAI,cAAc,CAAC;QAChC,IAAI,CAAC,GAAG;YAAE,OAAO;QAEjB,WAAW,GAAG,EAAE,CAAC;QACjB,YAAY,GAAG,QAAQ,CAAC;QACxB,KAAK,OAAO;aACT,KAAK,CAAC;YACL,OAAO,EAAE,MAAM;YACf,QAAQ;YACR,KAAK;YACL,UAAU,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE;SACvC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,gEAAgE;QAClE,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;AACJ,CAAC"}
|