@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,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nodetool app debug` as a service — the engine behind
|
|
3
|
+
* `POST /api/applications/debug` and the `debug_app` agent tool.
|
|
4
|
+
*
|
|
5
|
+
* The simulation itself is `simulateApp`, unchanged: this module supplies the
|
|
6
|
+
* three things it cannot get for itself — the target (an application row, or
|
|
7
|
+
* the document the caller posted inline), the workflow loader its operations
|
|
8
|
+
* resolve against, and a kernel runner for the runs.
|
|
9
|
+
*
|
|
10
|
+
* The inline `document` path is the one that matters for an editor assistant.
|
|
11
|
+
* A draft lives in the browser until the user saves, so anything keyed on
|
|
12
|
+
* `application_id` grades a stale row — a verdict that lies exactly when the
|
|
13
|
+
* assistant is mid-edit.
|
|
14
|
+
*
|
|
15
|
+
* A run with `run: true` executes real workflows, so it can take minutes:
|
|
16
|
+
* `poll: true` fronts it with the same session registry a build uses. A
|
|
17
|
+
* simulation parks no escalations, so its session only ever reports `running`
|
|
18
|
+
* or `done`.
|
|
19
|
+
*/
|
|
20
|
+
import { randomUUID } from "node:crypto";
|
|
21
|
+
import { createLogger } from "@nodetool-ai/config";
|
|
22
|
+
import { Application, Workflow, createJsScriptResolver } from "@nodetool-ai/models";
|
|
23
|
+
import { applicationTarget, inlineDocumentTarget, simulateApp, summarizeAppReport } from "../app-debug/index.js";
|
|
24
|
+
import { createAppServerRunner } from "./app-run-server.js";
|
|
25
|
+
import { debugSessions, InteractiveEscalationHandle } from "./debug-sessions.js";
|
|
26
|
+
import { isNonEmptyString, isPositiveFiniteNumber } from "../predicates.js";
|
|
27
|
+
const log = createLogger("nodetool.execution.app-debug");
|
|
28
|
+
/**
|
|
29
|
+
* A refusal the caller turns into its own transport error. `code` is the
|
|
30
|
+
* vocabulary the HTTP layer maps onto `ApiErrorCode`; nothing here knows about
|
|
31
|
+
* Fastify or tRPC.
|
|
32
|
+
*/
|
|
33
|
+
export class AppServiceError extends Error {
|
|
34
|
+
code;
|
|
35
|
+
constructor(code, message) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.code = code;
|
|
38
|
+
this.name = "AppServiceError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** A pinned script version the user owns, for a script operation. */
|
|
42
|
+
async function loadUserJsScript(userId, scriptId, scriptVersion) {
|
|
43
|
+
const resolved = await createJsScriptResolver().resolve({ id: scriptId, version: scriptVersion }, userId);
|
|
44
|
+
return resolved ? { name: resolved.name, document: resolved.document } : null;
|
|
45
|
+
}
|
|
46
|
+
/** A workflow the user can read, in the shape the simulator wants. */
|
|
47
|
+
async function loadUserWorkflow(userId, id) {
|
|
48
|
+
const workflow = await Workflow.find(userId, id);
|
|
49
|
+
const graph = workflow?.getGraph();
|
|
50
|
+
return graph ? { graph } : null;
|
|
51
|
+
}
|
|
52
|
+
/** An application the user owns, with its document still unparsed. */
|
|
53
|
+
async function loadUserApplication(userId, id) {
|
|
54
|
+
const application = await Application.findById(id);
|
|
55
|
+
if (!application || application.user_id !== userId)
|
|
56
|
+
return null;
|
|
57
|
+
return {
|
|
58
|
+
id: application.id,
|
|
59
|
+
name: application.name,
|
|
60
|
+
document: application.document
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** A body number that is a finite positive value, or undefined. */
|
|
64
|
+
function positive(value) {
|
|
65
|
+
return isPositiveFiniteNumber(value) ? value : undefined;
|
|
66
|
+
}
|
|
67
|
+
/** The simulation's payload while it is still running. */
|
|
68
|
+
function runningPayload(session, debugId) {
|
|
69
|
+
return {
|
|
70
|
+
status: "running",
|
|
71
|
+
session_id: session.id,
|
|
72
|
+
debug_id: debugId,
|
|
73
|
+
poll: `GET /api/debug/sessions/${session.id}`,
|
|
74
|
+
cancel: `POST /api/debug/sessions/${session.id}/cancel`
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The compacted report as the HTTP surface and the tool see it. The session
|
|
79
|
+
* fronts an untyped JSON payload, so the summary's own fields are spread
|
|
80
|
+
* through `Object.entries` rather than asserted into a dictionary.
|
|
81
|
+
*/
|
|
82
|
+
function debugPayload(report, debugId) {
|
|
83
|
+
return {
|
|
84
|
+
debug_id: debugId,
|
|
85
|
+
status: report.verdict.ok ? "completed" : "failed",
|
|
86
|
+
...Object.fromEntries(Object.entries(summarizeAppReport(report)))
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Resolve the request's target: an application row, or the document it carries.
|
|
91
|
+
* Exactly one of the two, so a caller never has to wonder which one was graded.
|
|
92
|
+
*/
|
|
93
|
+
async function resolveTarget(userId, body, deps) {
|
|
94
|
+
const hasId = isNonEmptyString(body.application_id);
|
|
95
|
+
const hasDocument = body.document !== undefined && body.document !== null;
|
|
96
|
+
if (hasId && hasDocument) {
|
|
97
|
+
throw new AppServiceError("invalid_input", "Pass either application_id or document, not both — a saved row and a " +
|
|
98
|
+
"live draft are different apps the moment the draft changes.");
|
|
99
|
+
}
|
|
100
|
+
const loadFromDb = (id) => (deps.loadWorkflow ?? loadUserWorkflow)(userId, id);
|
|
101
|
+
if (hasId) {
|
|
102
|
+
const id = body.application_id;
|
|
103
|
+
const application = await (deps.loadApplication ?? loadUserApplication)(userId, id);
|
|
104
|
+
if (!application) {
|
|
105
|
+
throw new AppServiceError("not_found", `No application found: ${id}`);
|
|
106
|
+
}
|
|
107
|
+
return applicationTarget(id, application, loadFromDb);
|
|
108
|
+
}
|
|
109
|
+
if (hasDocument) {
|
|
110
|
+
return inlineDocumentTarget(body.document, loadFromDb);
|
|
111
|
+
}
|
|
112
|
+
throw new AppServiceError("invalid_input", "An app debug run needs either an application_id or a document.");
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Debug an app. Resolves with the compacted report (plus the session id), or —
|
|
116
|
+
* with `poll: true` — with the session id as soon as the run is under way.
|
|
117
|
+
*/
|
|
118
|
+
export async function runApplicationDebug(userId, body, defaultRegistry, deps = {}) {
|
|
119
|
+
const debugId = `app-debug-${randomUUID()}`;
|
|
120
|
+
const resolved = await resolveTarget(userId, body, deps);
|
|
121
|
+
const registry = deps.registry ?? defaultRegistry;
|
|
122
|
+
const timeoutMs = positive(body.timeout_ms);
|
|
123
|
+
// Cancelling a simulation settles its session with a failed report; the runs
|
|
124
|
+
// already in flight finish in the background, since `simulateApp` takes no
|
|
125
|
+
// signal. Nothing they touch is persisted, so a finished orphan run is spend,
|
|
126
|
+
// not state.
|
|
127
|
+
let cancelled = null;
|
|
128
|
+
const abandoned = new Promise((resolve) => {
|
|
129
|
+
cancelled = resolve;
|
|
130
|
+
});
|
|
131
|
+
// The promise a session fronts must never reject: a rejected run would leave
|
|
132
|
+
// the session parked forever with no report to hand back.
|
|
133
|
+
const simulation = (async () => {
|
|
134
|
+
try {
|
|
135
|
+
const simulateOptions = {};
|
|
136
|
+
if (body.params) {
|
|
137
|
+
simulateOptions.params = body.params;
|
|
138
|
+
}
|
|
139
|
+
if (body.interact) {
|
|
140
|
+
simulateOptions.interact = body.interact;
|
|
141
|
+
}
|
|
142
|
+
if (body.run !== undefined) {
|
|
143
|
+
simulateOptions.run = body.run;
|
|
144
|
+
}
|
|
145
|
+
if (timeoutMs !== undefined) {
|
|
146
|
+
simulateOptions.timeoutMs = timeoutMs;
|
|
147
|
+
}
|
|
148
|
+
const simulateDeps = {
|
|
149
|
+
loadFromDb: (id) => (deps.loadWorkflow ?? loadUserWorkflow)(userId, id),
|
|
150
|
+
runOnServer: createAppServerRunner(userId, registry, {
|
|
151
|
+
jobPrefix: "app-debug-run",
|
|
152
|
+
assetStorage: deps.assetStorage ?? null
|
|
153
|
+
}),
|
|
154
|
+
loadScript: (scriptId, scriptVersion) => loadUserJsScript(userId, scriptId, scriptVersion)
|
|
155
|
+
};
|
|
156
|
+
if (deps.runScript) {
|
|
157
|
+
simulateDeps.runScript = deps.runScript;
|
|
158
|
+
}
|
|
159
|
+
const report = await simulateApp(resolved, simulateOptions, simulateDeps);
|
|
160
|
+
return debugPayload(report, debugId);
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
164
|
+
log.error("app debug failed outside the report", { debugId, message });
|
|
165
|
+
return {
|
|
166
|
+
debug_id: debugId,
|
|
167
|
+
status: "failed",
|
|
168
|
+
error: message,
|
|
169
|
+
verdict: {
|
|
170
|
+
ok: false,
|
|
171
|
+
headline: message,
|
|
172
|
+
issues: [message],
|
|
173
|
+
warnings: []
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
})();
|
|
178
|
+
const done = Promise.race([simulation, abandoned]);
|
|
179
|
+
const session = debugSessions.create({
|
|
180
|
+
userId,
|
|
181
|
+
workflowId: resolved.info.workflowId,
|
|
182
|
+
jobId: debugId,
|
|
183
|
+
handle: new InteractiveEscalationHandle(),
|
|
184
|
+
done,
|
|
185
|
+
cancel: () => cancelled?.({
|
|
186
|
+
debug_id: debugId,
|
|
187
|
+
status: "failed",
|
|
188
|
+
error: "cancelled",
|
|
189
|
+
verdict: {
|
|
190
|
+
ok: false,
|
|
191
|
+
headline: "App debug cancelled before it finished.",
|
|
192
|
+
issues: ["cancelled"],
|
|
193
|
+
warnings: []
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
});
|
|
197
|
+
if (body.poll === true)
|
|
198
|
+
return runningPayload(session, debugId);
|
|
199
|
+
return { ...(await done), session_id: session.id };
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=app-debug-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-debug-service.js","sourceRoot":"","sources":["../../src/service/app-debug-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kernel runner every server-side app simulation uses.
|
|
3
|
+
*
|
|
4
|
+
* `simulateApp` has exactly one contract with a kernel:
|
|
5
|
+
* `AppServerRunInput → AppServerRunOutcome`. This builds that closure — one
|
|
6
|
+
* `ExecutionSession` per run, over the graph the caller holds in memory,
|
|
7
|
+
* persisting nothing. A build's workflows have no rows until its bundle is
|
|
8
|
+
* imported, and a debugged draft may have none at all, so neither surface can
|
|
9
|
+
* run through the job machinery.
|
|
10
|
+
*
|
|
11
|
+
* Shared by the app build service (the Run stage) and the app debug service
|
|
12
|
+
* (`POST /api/applications/debug`), so a run means the same thing to both.
|
|
13
|
+
*/
|
|
14
|
+
import type { AppServerRunInput, AppServerRunOutcome } from "../app-debug/index.js";
|
|
15
|
+
import type { NodeRegistry } from "@nodetool-ai/node-sdk";
|
|
16
|
+
import { type StorageAdapter } from "@nodetool-ai/runtime";
|
|
17
|
+
export interface AppServerRunnerOptions {
|
|
18
|
+
/** Job-id prefix, so a run is attributable to the surface that started it. */
|
|
19
|
+
jobPrefix?: string;
|
|
20
|
+
/**
|
|
21
|
+
* The store `asset://<id>` inputs resolve through. Only the local assets dir
|
|
22
|
+
* on a `file` backend, so a host on S3/Supabase must pass its own or the
|
|
23
|
+
* run reads every uploaded input as empty.
|
|
24
|
+
*/
|
|
25
|
+
assetStorage?: StorageAdapter | null;
|
|
26
|
+
}
|
|
27
|
+
export declare function createAppServerRunner(userId: string, registry: NodeRegistry, options?: AppServerRunnerOptions): (input: AppServerRunInput) => Promise<AppServerRunOutcome>;
|
|
28
|
+
//# sourceMappingURL=app-run-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-run-server.d.ts","sourceRoot":"","sources":["../../src/service/app-run-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAQH,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG9E,MAAM,WAAW,sBAAsB;IACrC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;CACtC;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,YAAY,EACtB,OAAO,GAAE,sBAA2B,GACnC,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,mBAAmB,CAAC,CA8E5D"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kernel runner every server-side app simulation uses.
|
|
3
|
+
*
|
|
4
|
+
* `simulateApp` has exactly one contract with a kernel:
|
|
5
|
+
* `AppServerRunInput → AppServerRunOutcome`. This builds that closure — one
|
|
6
|
+
* `ExecutionSession` per run, over the graph the caller holds in memory,
|
|
7
|
+
* persisting nothing. A build's workflows have no rows until its bundle is
|
|
8
|
+
* imported, and a debugged draft may have none at all, so neither surface can
|
|
9
|
+
* run through the job machinery.
|
|
10
|
+
*
|
|
11
|
+
* Shared by the app build service (the Run stage) and the app debug service
|
|
12
|
+
* (`POST /api/applications/debug`), so a run means the same thing to both.
|
|
13
|
+
*/
|
|
14
|
+
import { randomUUID } from "node:crypto";
|
|
15
|
+
import { getDefaultAssetsPath } from "@nodetool-ai/config";
|
|
16
|
+
import { ExecutionSession } from "../session.js";
|
|
17
|
+
import { createFalGenerationLifecycleHooks } from "../generation-lifecycle.js";
|
|
18
|
+
import { isExecutionPreflightError } from "../preflight.js";
|
|
19
|
+
import { collectExecutionSummary } from "../debug/collector.js";
|
|
20
|
+
import { getSecret } from "@nodetool-ai/models";
|
|
21
|
+
import { ProcessingContext } from "@nodetool-ai/runtime";
|
|
22
|
+
import { FileStorageAdapter } from "@nodetool-ai/storage";
|
|
23
|
+
export function createAppServerRunner(userId, registry, options = {}) {
|
|
24
|
+
const jobPrefix = options.jobPrefix ?? "app-run";
|
|
25
|
+
return async (input) => {
|
|
26
|
+
const startedAt = Date.now();
|
|
27
|
+
const jobId = `${jobPrefix}-${randomUUID()}`;
|
|
28
|
+
const context = new ProcessingContext({
|
|
29
|
+
jobId,
|
|
30
|
+
workflowId: input.workflowId,
|
|
31
|
+
userId,
|
|
32
|
+
secretResolver: (key) => getSecret(key, userId),
|
|
33
|
+
storage: new FileStorageAdapter(getDefaultAssetsPath()),
|
|
34
|
+
assetStorage: options.assetStorage ?? null,
|
|
35
|
+
generationLifecycle: createFalGenerationLifecycleHooks({
|
|
36
|
+
userId,
|
|
37
|
+
jobId,
|
|
38
|
+
projectId: null,
|
|
39
|
+
publicUrl: process.env["NODETOOL_PUBLIC_URL"] ?? null
|
|
40
|
+
})
|
|
41
|
+
});
|
|
42
|
+
const sessionOptions = {
|
|
43
|
+
graph: input.graph,
|
|
44
|
+
registry,
|
|
45
|
+
jobId,
|
|
46
|
+
workflowId: input.workflowId,
|
|
47
|
+
params: input.params,
|
|
48
|
+
context
|
|
49
|
+
};
|
|
50
|
+
if (input.timeoutMs !== undefined) {
|
|
51
|
+
sessionOptions.limits = { runTimeoutMs: input.timeoutMs };
|
|
52
|
+
}
|
|
53
|
+
// A graph this runtime cannot honour is refused before the kernel starts.
|
|
54
|
+
// The simulator's contract is a report, so a refusal becomes a failed run
|
|
55
|
+
// it can complain about — not a throw out of the simulation.
|
|
56
|
+
let session;
|
|
57
|
+
try {
|
|
58
|
+
session = await ExecutionSession.create(sessionOptions);
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
if (!isExecutionPreflightError(err))
|
|
62
|
+
throw err;
|
|
63
|
+
const summary = collectExecutionSummary([]);
|
|
64
|
+
summary.status = "failed";
|
|
65
|
+
summary.error = err.message;
|
|
66
|
+
return {
|
|
67
|
+
report: {
|
|
68
|
+
surface: "server",
|
|
69
|
+
ok: false,
|
|
70
|
+
status: "failed",
|
|
71
|
+
error: err.message,
|
|
72
|
+
durationMs: Date.now() - startedAt,
|
|
73
|
+
summary,
|
|
74
|
+
trace: null
|
|
75
|
+
},
|
|
76
|
+
rawMessages: []
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// `session.result` never rejects: a kernel failure resolves as
|
|
80
|
+
// `status: "failed"`, which the simulator turns into a complaint.
|
|
81
|
+
const result = await session.result;
|
|
82
|
+
const messages = result.messages ?? [];
|
|
83
|
+
const summary = collectExecutionSummary(messages);
|
|
84
|
+
summary.status = result.status ?? summary.status;
|
|
85
|
+
const timedOut = session.cancelReason === "timeout";
|
|
86
|
+
const error = result.error ??
|
|
87
|
+
(timedOut ? `run exceeded timeout (${input.timeoutMs}ms)` : undefined);
|
|
88
|
+
if (error && !summary.error)
|
|
89
|
+
summary.error = error;
|
|
90
|
+
return {
|
|
91
|
+
report: {
|
|
92
|
+
surface: "server",
|
|
93
|
+
ok: result.status === "completed",
|
|
94
|
+
status: result.status ?? summary.status,
|
|
95
|
+
error: error ?? summary.error ?? null,
|
|
96
|
+
durationMs: Date.now() - startedAt,
|
|
97
|
+
summary,
|
|
98
|
+
trace: null
|
|
99
|
+
},
|
|
100
|
+
rawMessages: messages
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=app-run-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-run-server.js","sourceRoot":"","sources":["../../src/service/app-run-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,158 @@
|
|
|
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 type { DecisionOutcome, SupervisorHandle } from "@nodetool-ai/kernel";
|
|
22
|
+
import type { Escalation, Verdict } from "@nodetool-ai/protocol";
|
|
23
|
+
/** How long an agent gets to answer one escalation before it fails closed. */
|
|
24
|
+
export declare const INTERACTIVE_DECISION_TIMEOUT_MS: number;
|
|
25
|
+
/**
|
|
26
|
+
* Hard ceiling on a session's life. The TTL sweep only arms once a run
|
|
27
|
+
* settles, so a run whose `done` never resolves — a wedged bridge, a promise
|
|
28
|
+
* nobody rejects — used to hold its session (and the run behind it) forever.
|
|
29
|
+
*/
|
|
30
|
+
export declare const SESSION_MAX_LIFETIME_MS: number;
|
|
31
|
+
/** How long `cancel()` waits for the run to settle before answering anyway. */
|
|
32
|
+
export declare const CANCEL_SETTLE_TIMEOUT_MS = 30000;
|
|
33
|
+
/** Live (unsettled) sessions one user may hold at once. */
|
|
34
|
+
export declare const MAX_LIVE_SESSIONS_PER_USER = 8;
|
|
35
|
+
/** What escalation subscribers see: the record, never the settle handle. */
|
|
36
|
+
export interface ParkedEscalation {
|
|
37
|
+
id: string;
|
|
38
|
+
escalation: Escalation;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A `SupervisorHandle` that answers nothing itself: each `decide()` parks the
|
|
42
|
+
* escalation until `submit()` delivers a verdict (or the decision signal
|
|
43
|
+
* aborts, which fails closed). `BoundedHandle` serializes decisions, so at
|
|
44
|
+
* most one escalation is pending at a time.
|
|
45
|
+
*/
|
|
46
|
+
export declare class InteractiveEscalationHandle implements SupervisorHandle {
|
|
47
|
+
private _pending;
|
|
48
|
+
private _waiters;
|
|
49
|
+
private _counter;
|
|
50
|
+
private _closed;
|
|
51
|
+
decide(e: Escalation, signal: AbortSignal): Promise<DecisionOutcome>;
|
|
52
|
+
/** The escalation currently awaiting a verdict, if any. */
|
|
53
|
+
current(): {
|
|
54
|
+
id: string;
|
|
55
|
+
escalation: Escalation;
|
|
56
|
+
} | null;
|
|
57
|
+
/**
|
|
58
|
+
* Subscribe to the next parked escalation. Returns an unsubscribe so a
|
|
59
|
+
* caller racing this against run completion can withdraw when the run wins
|
|
60
|
+
* — otherwise every verdict round trip would strand one waiter until the
|
|
61
|
+
* session is swept.
|
|
62
|
+
*/
|
|
63
|
+
subscribe(waiter: (entry: ParkedEscalation) => void): () => void;
|
|
64
|
+
/**
|
|
65
|
+
* Deliver the agent's verdict for the parked escalation. Returns an error
|
|
66
|
+
* string instead of throwing so the HTTP layer can 400 with it; the verdict
|
|
67
|
+
* is checked against the escalation's `allowedActions` here so the agent can
|
|
68
|
+
* correct itself, and enforced again by the kernel regardless.
|
|
69
|
+
*
|
|
70
|
+
* A `substitute` payload is validated here too, against the same rules the
|
|
71
|
+
* actor applies. Accepting it and letting the kernel reject it fails the
|
|
72
|
+
* node with its *original* error and burns the decision — the agent never
|
|
73
|
+
* learns its repair was malformed. Rejecting here keeps the escalation
|
|
74
|
+
* parked, so it can answer again.
|
|
75
|
+
*/
|
|
76
|
+
submit(escalationId: string, verdict: Verdict): Promise<{
|
|
77
|
+
error: string;
|
|
78
|
+
} | null>;
|
|
79
|
+
close(): void;
|
|
80
|
+
}
|
|
81
|
+
export type DebugSessionEvent = {
|
|
82
|
+
kind: "escalated";
|
|
83
|
+
escalationId: string;
|
|
84
|
+
escalation: Escalation;
|
|
85
|
+
} | {
|
|
86
|
+
kind: "done";
|
|
87
|
+
report: Record<string, unknown>;
|
|
88
|
+
} | {
|
|
89
|
+
kind: "running";
|
|
90
|
+
};
|
|
91
|
+
export interface CreateDebugSessionOptions {
|
|
92
|
+
userId: string;
|
|
93
|
+
/** Null when the session fronts something other than a workflow run. */
|
|
94
|
+
workflowId: string | null;
|
|
95
|
+
jobId: string;
|
|
96
|
+
handle: InteractiveEscalationHandle;
|
|
97
|
+
/** Resolves with the final report once the run settles. Must never reject. */
|
|
98
|
+
done: Promise<Record<string, unknown>>;
|
|
99
|
+
cancel: () => void;
|
|
100
|
+
/** Overrides for tests; production uses the module constants. */
|
|
101
|
+
maxLifetimeMs?: number;
|
|
102
|
+
cancelWaitMs?: number;
|
|
103
|
+
}
|
|
104
|
+
export declare class DebugSession {
|
|
105
|
+
readonly id: string;
|
|
106
|
+
readonly userId: string;
|
|
107
|
+
readonly workflowId: string | null;
|
|
108
|
+
readonly jobId: string;
|
|
109
|
+
private readonly _handle;
|
|
110
|
+
/** The run's own completion, raced with a forced settle. Never rejects. */
|
|
111
|
+
private readonly _done;
|
|
112
|
+
private readonly _cancel;
|
|
113
|
+
private readonly _cancelWaitMs;
|
|
114
|
+
private _force;
|
|
115
|
+
private _report;
|
|
116
|
+
constructor(options: CreateDebugSessionOptions, onSettled: () => void);
|
|
117
|
+
/** True until the run (or a forced settle) has produced a final report. */
|
|
118
|
+
isLive(): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Settle the session without the run: cancel what can be cancelled, fail the
|
|
121
|
+
* parked escalation closed, and hand every waiter a failed report. Used by
|
|
122
|
+
* the lifetime ceiling and by a cancel the run does not answer.
|
|
123
|
+
*/
|
|
124
|
+
forceSettle(reason: string): void;
|
|
125
|
+
/**
|
|
126
|
+
* Wait until the run either parks an escalation or settles. There is no
|
|
127
|
+
* wait cap of its own: the non-interactive endpoint awaits the whole run
|
|
128
|
+
* too, a parked decision fails closed on its own timeout, and the session's
|
|
129
|
+
* lifetime ceiling settles anything that outlives both.
|
|
130
|
+
*/
|
|
131
|
+
waitForEvent(): Promise<DebugSessionEvent>;
|
|
132
|
+
/** Current state without waiting. */
|
|
133
|
+
peek(): DebugSessionEvent;
|
|
134
|
+
submitVerdict(escalationId: string, verdict: Verdict): Promise<{
|
|
135
|
+
error: string;
|
|
136
|
+
} | null>;
|
|
137
|
+
/**
|
|
138
|
+
* Cancel the run and return its final report. The wait is bounded: a run
|
|
139
|
+
* that ignores cancellation used to hang the cancel request itself, so past
|
|
140
|
+
* the deadline the session settles on its own and answers with that.
|
|
141
|
+
*/
|
|
142
|
+
cancel(): Promise<Record<string, unknown>>;
|
|
143
|
+
}
|
|
144
|
+
/** Thrown by `create()` when a user already holds the maximum live sessions. */
|
|
145
|
+
export declare class TooManyDebugSessionsError extends Error {
|
|
146
|
+
constructor(limit: number);
|
|
147
|
+
}
|
|
148
|
+
declare class DebugSessionRegistry {
|
|
149
|
+
private readonly _sessions;
|
|
150
|
+
/** Live sessions this user holds. */
|
|
151
|
+
liveCount(userId: string): number;
|
|
152
|
+
create(options: CreateDebugSessionOptions): DebugSession;
|
|
153
|
+
/** Ownership is part of the lookup: a foreign session id is a miss. */
|
|
154
|
+
get(sessionId: string, userId: string): DebugSession | null;
|
|
155
|
+
}
|
|
156
|
+
export declare const debugSessions: DebugSessionRegistry;
|
|
157
|
+
export {};
|
|
158
|
+
//# sourceMappingURL=debug-sessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-sessions.d.ts","sourceRoot":"","sources":["../../src/service/debug-sessions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAIjE,8EAA8E;AAC9E,eAAO,MAAM,+BAA+B,QAAc,CAAC;AAK3D;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,QAAc,CAAC;AAEnD,+EAA+E;AAC/E,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAE/C,2DAA2D;AAC3D,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAa5C,4EAA4E;AAC5E,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;;;;GAKG;AACH,qBAAa,2BAA4B,YAAW,gBAAgB;IAClE,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,QAAQ,CAAgD;IAChE,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,OAAO,CAAS;IAExB,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAsBnE;IAED,2DAA2D;IAC3D,OAAO,IAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE,GAAG,IAAI,CAGvD;IAED;;;;;OAKG;IACH,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI,CAM/D;IAED;;;;;;;;;;;OAWG;IACG,MAAM,CACV,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CA2CnC;IAED,KAAK,IAAI,IAAI,CAGZ;CACF;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAExB,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,2BAA2B,CAAC;IACpC,8EAA8E;IAC9E,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,YAAY;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;IACtD,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmC;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,MAAM,CAAuD;IACrE,OAAO,CAAC,OAAO,CAAwC;IAEvD,YAAY,OAAO,EAAE,yBAAyB,EAAE,SAAS,EAAE,MAAM,IAAI,EAmBpE;IAED,2EAA2E;IAC3E,MAAM,IAAI,OAAO,CAEhB;IAED;;;;OAIG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAiBhC;IAED;;;;;OAKG;IACG,YAAY,IAAI,OAAO,CAAC,iBAAiB,CAAC,CA4B/C;IAED,qCAAqC;IACrC,IAAI,IAAI,iBAAiB,CAWxB;IAEK,aAAa,CACjB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAKnC;IAED;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAwB/C;CACF;AAED,gFAAgF;AAChF,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,YAAY,KAAK,EAAE,MAAM,EAMxB;CACF;AAED,cAAM,oBAAoB;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmC;IAE7D,qCAAqC;IACrC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMhC;IAED,MAAM,CAAC,OAAO,EAAE,yBAAyB,GAAG,YAAY,CA4BvD;IAED,uEAAuE;IACvE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAI1D;CACF;AAED,eAAO,MAAM,aAAa,sBAA6B,CAAC"}
|