@anvia/studio 1.0.1 → 1.0.4
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 +45 -3
- package/dist/index.d.ts +56 -5
- package/dist/index.js +349 -41
- package/dist/index.js.map +1 -1
- package/dist/ui/assets/Check.es-DgvuCllR.js +2 -0
- package/dist/ui/assets/Check.es-DgvuCllR.js.map +1 -0
- package/dist/ui/assets/Copy.es-DV7tb_eC.js +2 -0
- package/dist/ui/assets/Copy.es-DV7tb_eC.js.map +1 -0
- package/dist/ui/assets/MagnifyingGlass.es-yzEp9c89.js +2 -0
- package/dist/ui/assets/MagnifyingGlass.es-yzEp9c89.js.map +1 -0
- package/dist/ui/assets/Wrench.es-rRuP3Mrh.js +2 -0
- package/dist/ui/assets/Wrench.es-rRuP3Mrh.js.map +1 -0
- package/dist/ui/assets/agents-page-ByhvVYOx.js +2 -0
- package/dist/ui/assets/agents-page-ByhvVYOx.js.map +1 -0
- package/dist/ui/assets/badge-C3fkxijh.js +2 -0
- package/dist/ui/assets/badge-C3fkxijh.js.map +1 -0
- package/dist/ui/assets/button-B_AoswCu.js +2 -0
- package/dist/ui/assets/button-B_AoswCu.js.map +1 -0
- package/dist/ui/assets/{dialog-DN8F1Aaq.js → dialog-BfKpnby4.js} +2 -2
- package/dist/ui/assets/{dialog-DN8F1Aaq.js.map → dialog-BfKpnby4.js.map} +1 -1
- package/dist/ui/assets/{dist-PrGeYMiK.js → dist-Dr6EWOhl.js} +2 -2
- package/dist/ui/assets/{dist-PrGeYMiK.js.map → dist-Dr6EWOhl.js.map} +1 -1
- package/dist/ui/assets/{es2015-Ck1KeeEx.js → es2015-DGcxtKLK.js} +2 -2
- package/dist/ui/assets/{es2015-Ck1KeeEx.js.map → es2015-DGcxtKLK.js.map} +1 -1
- package/dist/ui/assets/favicon-dark.svg +7 -0
- package/dist/ui/assets/favicon-light.svg +7 -0
- package/dist/ui/assets/favicon.svg +1 -1
- package/dist/ui/assets/graphs-page-ne3dJIrx.js +2 -0
- package/dist/ui/assets/graphs-page-ne3dJIrx.js.map +1 -0
- package/dist/ui/assets/index-BGl7eOVR.css +2 -0
- package/dist/ui/assets/index-DF9Ysm8q.js +75 -0
- package/dist/ui/assets/index-DF9Ysm8q.js.map +1 -0
- package/dist/ui/assets/{input-DHvac9Uq.js → input-DuERdYTl.js} +2 -2
- package/dist/ui/assets/{input-DHvac9Uq.js.map → input-DuERdYTl.js.map} +1 -1
- package/dist/ui/assets/knowledge-page-1WgvGV4f.js +2 -0
- package/dist/ui/assets/knowledge-page-1WgvGV4f.js.map +1 -0
- package/dist/ui/assets/{mcps-page-MSz67ifn.js → mcps-page-BV96jSfG.js} +2 -2
- package/dist/ui/assets/mcps-page-BV96jSfG.js.map +1 -0
- package/dist/ui/assets/memory-page-DxClkjRl.js +4 -0
- package/dist/ui/assets/{memory-page-2qr2eMrI.js.map → memory-page-DxClkjRl.js.map} +1 -1
- package/dist/ui/assets/pipelines-page-ClO_uXn1.js +2 -0
- package/dist/ui/assets/pipelines-page-ClO_uXn1.js.map +1 -0
- package/dist/ui/assets/{renderers-BIw5yJkg.js → renderers-Cf55u6J4.js} +3 -3
- package/dist/ui/assets/{renderers-BIw5yJkg.js.map → renderers-Cf55u6J4.js.map} +1 -1
- package/dist/ui/assets/{request-CnFL8L6p.js → request-DbgMKweq.js} +2 -2
- package/dist/ui/assets/{request-CnFL8L6p.js.map → request-DbgMKweq.js.map} +1 -1
- package/dist/ui/assets/{sandboxes-page-DWMtrKYJ.js → sandboxes-page-Bo4S4ILL.js} +2 -2
- package/dist/ui/assets/sandboxes-page-Bo4S4ILL.js.map +1 -0
- package/dist/ui/assets/select-BdCBnmXx.js +2 -0
- package/dist/ui/assets/{select-C1_9fsRu.js.map → select-BdCBnmXx.js.map} +1 -1
- package/dist/ui/assets/sessions-page-BMnR-r_F.js +2 -0
- package/dist/ui/assets/sessions-page-BMnR-r_F.js.map +1 -0
- package/dist/ui/assets/status-page-Ys5dQyMG.js +2 -0
- package/dist/ui/assets/status-page-Ys5dQyMG.js.map +1 -0
- package/dist/ui/assets/studio-DzEdCFsX.js +2 -0
- package/dist/ui/assets/studio-DzEdCFsX.js.map +1 -0
- package/dist/ui/assets/style-BstB0PNS.js +8 -0
- package/dist/ui/assets/style-BstB0PNS.js.map +1 -0
- package/dist/ui/assets/{textarea-CZvhTJxB.js → textarea-fAtCF2cf.js} +2 -2
- package/dist/ui/assets/{textarea-CZvhTJxB.js.map → textarea-fAtCF2cf.js.map} +1 -1
- package/dist/ui/assets/tool-runner-Cwfc3yY8.js +2 -0
- package/dist/ui/assets/tool-runner-Cwfc3yY8.js.map +1 -0
- package/dist/ui/assets/{tools-page-D1ewvG0D.js → tools-page-BSgFqVi2.js} +2 -2
- package/dist/ui/assets/tools-page-BSgFqVi2.js.map +1 -0
- package/dist/ui/assets/trace-browser-Co9iS9HR.js +4 -0
- package/dist/ui/assets/trace-browser-Co9iS9HR.js.map +1 -0
- package/dist/ui/assets/transcript-item-ChVGempt.js +3 -0
- package/dist/ui/assets/transcript-item-ChVGempt.js.map +1 -0
- package/dist/ui/index.html +28 -20
- package/package.json +12 -8
- package/dist/ui/assets/CaretDown.es-CXu4Fvbf.js +0 -2
- package/dist/ui/assets/CaretDown.es-CXu4Fvbf.js.map +0 -1
- package/dist/ui/assets/Check.es-DSXK9-8c.js +0 -2
- package/dist/ui/assets/Check.es-DSXK9-8c.js.map +0 -1
- package/dist/ui/assets/Wrench.es-Cl38Pi3C.js +0 -4
- package/dist/ui/assets/Wrench.es-Cl38Pi3C.js.map +0 -1
- package/dist/ui/assets/agents-page-h-83w9EN.js +0 -2
- package/dist/ui/assets/agents-page-h-83w9EN.js.map +0 -1
- package/dist/ui/assets/badge-O3YyUN3G.js +0 -2
- package/dist/ui/assets/badge-O3YyUN3G.js.map +0 -1
- package/dist/ui/assets/button-Dsqwey2_.js +0 -2
- package/dist/ui/assets/button-Dsqwey2_.js.map +0 -1
- package/dist/ui/assets/index-Dggzi3lZ.js +0 -75
- package/dist/ui/assets/index-Dggzi3lZ.js.map +0 -1
- package/dist/ui/assets/index-VCdJ2Rb4.css +0 -2
- package/dist/ui/assets/knowledge-page-DKnPrmhK.js +0 -2
- package/dist/ui/assets/knowledge-page-DKnPrmhK.js.map +0 -1
- package/dist/ui/assets/mcps-page-MSz67ifn.js.map +0 -1
- package/dist/ui/assets/memory-page-2qr2eMrI.js +0 -4
- package/dist/ui/assets/pipelines-page-D1IB1tw-.js +0 -8
- package/dist/ui/assets/pipelines-page-D1IB1tw-.js.map +0 -1
- package/dist/ui/assets/sandboxes-page-DWMtrKYJ.js.map +0 -1
- package/dist/ui/assets/select-C1_9fsRu.js +0 -2
- package/dist/ui/assets/sessions-page-BIk4q-L8.js +0 -2
- package/dist/ui/assets/sessions-page-BIk4q-L8.js.map +0 -1
- package/dist/ui/assets/status-page-jKTghmnz.js +0 -2
- package/dist/ui/assets/status-page-jKTghmnz.js.map +0 -1
- package/dist/ui/assets/studio-Bh00wIF1.js +0 -2
- package/dist/ui/assets/studio-Bh00wIF1.js.map +0 -1
- package/dist/ui/assets/tool-runner-BtaZqE3R.js +0 -2
- package/dist/ui/assets/tool-runner-BtaZqE3R.js.map +0 -1
- package/dist/ui/assets/tools-page-D1ewvG0D.js.map +0 -1
- package/dist/ui/assets/trace-browser-CwRUyCO6.js +0 -10
- package/dist/ui/assets/trace-browser-CwRUyCO6.js.map +0 -1
- package/dist/ui/assets/transcript-item-ChtaJvPe.js +0 -3
- package/dist/ui/assets/transcript-item-ChtaJvPe.js.map +0 -1
- /package/dist/ui/assets/{pipelines-page-DLioOiRN.css → style-DLioOiRN.css} +0 -0
package/dist/index.js
CHANGED
|
@@ -5,6 +5,9 @@ import { serve } from "@hono/node-server";
|
|
|
5
5
|
import { Hono as HonoApp } from "hono";
|
|
6
6
|
import { WebSocketServer } from "ws";
|
|
7
7
|
|
|
8
|
+
// src/traces/trace-observer.ts
|
|
9
|
+
import { AgentRunCancelledError } from "@anvia/core/agent";
|
|
10
|
+
|
|
8
11
|
// src/runtime/json.ts
|
|
9
12
|
function toJsonValue(value) {
|
|
10
13
|
return toJsonValueInternal(value, /* @__PURE__ */ new WeakSet());
|
|
@@ -213,7 +216,7 @@ var StudioRunTraceObserver = class {
|
|
|
213
216
|
});
|
|
214
217
|
}
|
|
215
218
|
async error(args) {
|
|
216
|
-
await this.save("error", {
|
|
219
|
+
await this.save(args.status === "cancelled" ? "cancelled" : "error", {
|
|
217
220
|
endedAt: /* @__PURE__ */ new Date(),
|
|
218
221
|
error: serializeUnknown(args.error),
|
|
219
222
|
usage: args.usage,
|
|
@@ -355,11 +358,12 @@ var ChildAgentToolTraceAccumulator = class {
|
|
|
355
358
|
if (child.type === "error") {
|
|
356
359
|
const metadata = this.childMetadata(agentId, agentName, childTurn);
|
|
357
360
|
if (isRecord(child.usage)) metadata.usage = toJsonValue(child.usage);
|
|
361
|
+
const status = child.error instanceof AgentRunCancelledError ? "cancelled" : "error";
|
|
358
362
|
this.completedObservations.push(
|
|
359
363
|
traceObservation({
|
|
360
364
|
kind: "tool",
|
|
361
365
|
name: `${agentLabel(agentId, agentName)}.error`,
|
|
362
|
-
status
|
|
366
|
+
status,
|
|
363
367
|
turn: this.parent.turn,
|
|
364
368
|
startedAt: /* @__PURE__ */ new Date(),
|
|
365
369
|
error: serializeUnknown(child.error),
|
|
@@ -385,7 +389,7 @@ var ChildAgentToolTraceAccumulator = class {
|
|
|
385
389
|
parentObservationId,
|
|
386
390
|
kind: "agent",
|
|
387
391
|
name: `${agentLabel(agentStart.agentId, agentStart.agentName)}.run`,
|
|
388
|
-
status: agentChildren.some((observation) => observation.status === "error") ? "error" : "success",
|
|
392
|
+
status: agentChildren.some((observation) => observation.status === "error") ? "error" : agentChildren.some((observation) => observation.status === "cancelled") ? "cancelled" : "success",
|
|
389
393
|
turn: this.parent.turn,
|
|
390
394
|
startedAt,
|
|
391
395
|
endedAt,
|
|
@@ -670,6 +674,7 @@ function registerStudioUi(app, options) {
|
|
|
670
674
|
app.get(`${options.path}/tools`, (c) => redirectWithQuery(c, "/tools"));
|
|
671
675
|
app.get(`${options.path}/mcps`, (c) => redirectWithQuery(c, "/mcps"));
|
|
672
676
|
app.get(`${options.path}/pipelines`, (c) => redirectWithQuery(c, "/pipelines"));
|
|
677
|
+
app.get(`${options.path}/graphs`, (c) => redirectWithQuery(c, "/graphs"));
|
|
673
678
|
app.get(`${options.path}/sandboxes`, (c) => redirectWithQuery(c, "/sandboxes"));
|
|
674
679
|
app.get(
|
|
675
680
|
`${options.path}/sandboxes/:sandboxRef`,
|
|
@@ -694,6 +699,7 @@ function registerStudioUi(app, options) {
|
|
|
694
699
|
app.get("/tools", async (c) => c.html(await renderShell()));
|
|
695
700
|
app.get("/mcps", async (c) => c.html(await renderShell()));
|
|
696
701
|
app.get("/pipelines", shellWhenHtml(renderShell));
|
|
702
|
+
app.get("/graphs", shellWhenHtml(renderShell));
|
|
697
703
|
app.get("/sandboxes", shellWhenHtml(renderShell));
|
|
698
704
|
app.get("/sandboxes/:sandboxRef", shellWhenHtml(renderShell));
|
|
699
705
|
app.get("/memory", async (c) => c.html(await renderShell()));
|
|
@@ -787,8 +793,9 @@ function renderLegacyStudioUiShell(props) {
|
|
|
787
793
|
'<meta charset="utf-8">',
|
|
788
794
|
'<meta name="viewport" content="width=device-width, initial-scale=1">',
|
|
789
795
|
`<title>${title}</title>`,
|
|
790
|
-
'<
|
|
791
|
-
`<link rel="icon" type="image/svg+xml" href="${escapeHtml(props.compatUiPath)}/assets/favicon.svg">`,
|
|
796
|
+
'<meta name="theme-color" content="#09090b">',
|
|
797
|
+
`<link data-anvia-favicon rel="icon" type="image/svg+xml" href="${escapeHtml(props.compatUiPath)}/assets/favicon-dark.svg">`,
|
|
798
|
+
'<script>(()=>{let m="dark";try{const t=localStorage.getItem("anvia-theme");const l=localStorage.getItem("anvia-studio-theme");if(t==="light"||(t!=="dark"&&l==="light"))m="light"}catch{}const r=document.documentElement;r.classList.toggle("dark",m==="dark");r.dataset.theme=m;r.style.colorScheme=m;document.querySelector(\'meta[name="theme-color"]\')?.setAttribute("content",m==="dark"?"#09090b":"#f4f4f5");const f=document.querySelector("link[data-anvia-favicon]");if(f)f.href=f.href.replace("favicon-dark.svg",`favicon-${m}.svg`)})();</script>',
|
|
792
799
|
`<link rel="stylesheet" href="${escapeHtml(props.stylesheet)}">`,
|
|
793
800
|
"</head>",
|
|
794
801
|
"<body>",
|
|
@@ -1005,6 +1012,18 @@ function unsupportedCapability(c, capability) {
|
|
|
1005
1012
|
{ capability }
|
|
1006
1013
|
);
|
|
1007
1014
|
}
|
|
1015
|
+
async function parseJsonBody(c, validate) {
|
|
1016
|
+
let body;
|
|
1017
|
+
try {
|
|
1018
|
+
body = await c.req.json();
|
|
1019
|
+
} catch {
|
|
1020
|
+
return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
|
|
1021
|
+
}
|
|
1022
|
+
if (!isObject(body)) {
|
|
1023
|
+
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
1024
|
+
}
|
|
1025
|
+
return validate(body);
|
|
1026
|
+
}
|
|
1008
1027
|
|
|
1009
1028
|
// src/runtime/models.ts
|
|
1010
1029
|
var STUDIO_MODEL_METADATA_KEY = "studioModel";
|
|
@@ -3089,16 +3108,30 @@ function registerAgentRunRoute(app, props) {
|
|
|
3089
3108
|
app.post("/agents/:agentId/runs", (c) => handleAgentRun(c, props));
|
|
3090
3109
|
}
|
|
3091
3110
|
async function handleAgentRun(c, props) {
|
|
3092
|
-
const
|
|
3093
|
-
if (
|
|
3094
|
-
return
|
|
3111
|
+
const lease = props.runLifecycle.start(c.req.raw.signal);
|
|
3112
|
+
if (lease === void 0) {
|
|
3113
|
+
return errorResponse(c, 503, "service_unavailable", "Anvia Studio is shutting down");
|
|
3095
3114
|
}
|
|
3096
|
-
|
|
3097
|
-
|
|
3115
|
+
try {
|
|
3116
|
+
const prepared = await prepareAgentRun(c, props, lease.abortSignal);
|
|
3117
|
+
if (prepared instanceof Response) {
|
|
3118
|
+
lease.finish();
|
|
3119
|
+
return prepared;
|
|
3120
|
+
}
|
|
3121
|
+
if (prepared.body.stream === true) {
|
|
3122
|
+
return handleStreamingAgentRun(c, prepared, props, lease);
|
|
3123
|
+
}
|
|
3124
|
+
try {
|
|
3125
|
+
return await handleBufferedAgentRun(c, prepared, props);
|
|
3126
|
+
} finally {
|
|
3127
|
+
lease.finish();
|
|
3128
|
+
}
|
|
3129
|
+
} catch (error) {
|
|
3130
|
+
lease.finish();
|
|
3131
|
+
throw error;
|
|
3098
3132
|
}
|
|
3099
|
-
return handleBufferedAgentRun(c, prepared, props);
|
|
3100
3133
|
}
|
|
3101
|
-
async function prepareAgentRun(c, props) {
|
|
3134
|
+
async function prepareAgentRun(c, props, abortSignal) {
|
|
3102
3135
|
const agentId = c.req.param("agentId");
|
|
3103
3136
|
const agent = props.agentMap.get(agentId);
|
|
3104
3137
|
if (agent === void 0) {
|
|
@@ -3132,7 +3165,7 @@ async function prepareAgentRun(c, props) {
|
|
|
3132
3165
|
if (body.stream !== void 0) resumedBody = { ...resumedBody, stream: body.stream };
|
|
3133
3166
|
if (body.metadata !== void 0) resumedBody = { ...resumedBody, metadata: body.metadata };
|
|
3134
3167
|
if (body.trace !== void 0) resumedBody = { ...resumedBody, trace: body.trace };
|
|
3135
|
-
const runOptions = createRunOptions(resumedBody, agentId, source.session,
|
|
3168
|
+
const runOptions = createRunOptions(resumedBody, agentId, source.session, abortSignal);
|
|
3136
3169
|
const execution2 = {
|
|
3137
3170
|
generate: (options) => source.runAgent.generate({
|
|
3138
3171
|
continuation: claimed.continuation,
|
|
@@ -3211,7 +3244,7 @@ async function prepareAgentRun(c, props) {
|
|
|
3211
3244
|
execution,
|
|
3212
3245
|
failureMessages: void 0,
|
|
3213
3246
|
memoryCompactionLogged: false,
|
|
3214
|
-
options: createRunOptions(body, agentId, session,
|
|
3247
|
+
options: createRunOptions(body, agentId, session, abortSignal),
|
|
3215
3248
|
runAgent,
|
|
3216
3249
|
runId,
|
|
3217
3250
|
runStartedAt,
|
|
@@ -3339,7 +3372,7 @@ function createRunOptions(body, agentId, session, abortSignal) {
|
|
|
3339
3372
|
}
|
|
3340
3373
|
return options;
|
|
3341
3374
|
}
|
|
3342
|
-
function handleStreamingAgentRun(c, run, props) {
|
|
3375
|
+
function handleStreamingAgentRun(c, run, props, lease) {
|
|
3343
3376
|
const streamOptions = withInternalAgentRunOptions({ ...run.options }, { runId: run.runId });
|
|
3344
3377
|
const runStream = registerStreamingContinuation(
|
|
3345
3378
|
run.execution.stream(streamOptions),
|
|
@@ -3367,7 +3400,7 @@ function handleStreamingAgentRun(c, run, props) {
|
|
|
3367
3400
|
});
|
|
3368
3401
|
stream = persistedRun.events;
|
|
3369
3402
|
}
|
|
3370
|
-
return streamAgentRunEvents(c, stream, {
|
|
3403
|
+
return streamAgentRunEvents(c, finishRunLease(stream, lease), {
|
|
3371
3404
|
runId: run.runId,
|
|
3372
3405
|
onCancel: async () => {
|
|
3373
3406
|
const persistence = [];
|
|
@@ -3386,6 +3419,13 @@ function handleStreamingAgentRun(c, run, props) {
|
|
|
3386
3419
|
}
|
|
3387
3420
|
});
|
|
3388
3421
|
}
|
|
3422
|
+
async function* finishRunLease(events, lease) {
|
|
3423
|
+
try {
|
|
3424
|
+
yield* events;
|
|
3425
|
+
} finally {
|
|
3426
|
+
lease.finish();
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3389
3429
|
async function handleBufferedAgentRun(c, run, props) {
|
|
3390
3430
|
try {
|
|
3391
3431
|
const runtimeOptions = await startBufferedSessionRun(run);
|
|
@@ -3680,7 +3720,7 @@ function parseTraceStatus(value) {
|
|
|
3680
3720
|
if (status === void 0) {
|
|
3681
3721
|
return void 0;
|
|
3682
3722
|
}
|
|
3683
|
-
return status === "running" || status === "success" || status === "suspended" || status === "error" ? status : false;
|
|
3723
|
+
return status === "running" || status === "success" || status === "suspended" || status === "error" || status === "cancelled" ? status : false;
|
|
3684
3724
|
}
|
|
3685
3725
|
function parseAfter(value) {
|
|
3686
3726
|
if (value === void 0 || value.trim().length === 0) {
|
|
@@ -4193,12 +4233,33 @@ function pipelineConfig(pipeline) {
|
|
|
4193
4233
|
if (pipeline.metadata !== void 0) config.metadata = pipeline.metadata;
|
|
4194
4234
|
return config;
|
|
4195
4235
|
}
|
|
4236
|
+
function graphConfig(registration) {
|
|
4237
|
+
const config = {
|
|
4238
|
+
id: registration.id,
|
|
4239
|
+
nodeTypes: Object.entries(registration.graph.schema.nodes).map(([name, definition]) => ({
|
|
4240
|
+
name,
|
|
4241
|
+
description: definition.description
|
|
4242
|
+
})),
|
|
4243
|
+
relationshipTypes: Object.entries(registration.graph.schema.relationships).map(
|
|
4244
|
+
([name, definition]) => ({
|
|
4245
|
+
name,
|
|
4246
|
+
description: definition.description,
|
|
4247
|
+
from: definition.from,
|
|
4248
|
+
to: definition.to
|
|
4249
|
+
})
|
|
4250
|
+
)
|
|
4251
|
+
};
|
|
4252
|
+
if (registration.name !== void 0) config.name = registration.name;
|
|
4253
|
+
if (registration.description !== void 0) config.description = registration.description;
|
|
4254
|
+
return config;
|
|
4255
|
+
}
|
|
4196
4256
|
function buildConfig(options, agents, pipelines, stores, sandboxCount = 0) {
|
|
4197
4257
|
const models = options.models === void 0 ? void 0 : studioModelsConfig(createStudioModelRegistry(options.models), agents);
|
|
4198
4258
|
const config = {
|
|
4199
4259
|
id: runnerId(options),
|
|
4200
4260
|
agents: agents.map(agentConfig),
|
|
4201
4261
|
pipelines: pipelines.map(pipelineConfig),
|
|
4262
|
+
graphs: options.graphs.map(graphConfig),
|
|
4202
4263
|
evals: options.evals.map(evalConfig),
|
|
4203
4264
|
chat: {
|
|
4204
4265
|
quickPrompts: Object.fromEntries(agents.map((agent) => [agent.id, agent.quickPrompts ?? []]))
|
|
@@ -4230,6 +4291,9 @@ function capabilityConfig(_options, agents, pipelines, stores, sandboxCount = 0)
|
|
|
4230
4291
|
if (pipelines.length > 0) {
|
|
4231
4292
|
capabilities.pipelines = { enabled: true };
|
|
4232
4293
|
}
|
|
4294
|
+
if (_options.graphs.length > 0) {
|
|
4295
|
+
capabilities.graphs = { enabled: true };
|
|
4296
|
+
}
|
|
4233
4297
|
if (_options.evals.length > 0) {
|
|
4234
4298
|
capabilities.evals = { enabled: true };
|
|
4235
4299
|
}
|
|
@@ -4327,6 +4391,110 @@ async function parseEvalRunRequest(c) {
|
|
|
4327
4391
|
return request;
|
|
4328
4392
|
}
|
|
4329
4393
|
|
|
4394
|
+
// src/runtime/graphs.ts
|
|
4395
|
+
import { resolveGraphExploreOptions } from "@anvia/graph/explore";
|
|
4396
|
+
function registerGraphRoutes(app, registrations) {
|
|
4397
|
+
const graphs = graphRegistry(registrations);
|
|
4398
|
+
app.get("/graphs", (c) => c.json({ graphs: [...graphs.values()].map(graphConfig) }));
|
|
4399
|
+
app.post("/graphs/:graphId/explore", async (c) => {
|
|
4400
|
+
const registration = graphs.get(c.req.param("graphId"));
|
|
4401
|
+
if (registration === void 0) {
|
|
4402
|
+
return errorResponse(c, 404, "not_found", "Graph not found");
|
|
4403
|
+
}
|
|
4404
|
+
const body = await parseJsonBody(c, (value) => parseExploreRequest(c, value));
|
|
4405
|
+
if ("error" in body) return body.error;
|
|
4406
|
+
const input = exploreOptionsWithSignal(body, c.req.raw.signal);
|
|
4407
|
+
let options;
|
|
4408
|
+
try {
|
|
4409
|
+
options = resolveGraphExploreOptions(registration.graph.schema, input);
|
|
4410
|
+
} catch (error) {
|
|
4411
|
+
return errorResponse(
|
|
4412
|
+
c,
|
|
4413
|
+
400,
|
|
4414
|
+
"bad_request",
|
|
4415
|
+
error instanceof Error ? error.message : "Invalid graph exploration request"
|
|
4416
|
+
);
|
|
4417
|
+
}
|
|
4418
|
+
return c.json(await registration.graph.explore(options));
|
|
4419
|
+
});
|
|
4420
|
+
}
|
|
4421
|
+
function graphRegistry(registrations) {
|
|
4422
|
+
const graphs = /* @__PURE__ */ new Map();
|
|
4423
|
+
for (const registration of registrations) {
|
|
4424
|
+
if (typeof registration.id !== "string" || registration.id.length === 0) {
|
|
4425
|
+
throw new TypeError("Studio graph id must be a non-empty string.");
|
|
4426
|
+
}
|
|
4427
|
+
if (graphs.has(registration.id)) {
|
|
4428
|
+
throw new TypeError(`Duplicate Studio graph id: ${registration.id}.`);
|
|
4429
|
+
}
|
|
4430
|
+
graphs.set(registration.id, registration);
|
|
4431
|
+
}
|
|
4432
|
+
return graphs;
|
|
4433
|
+
}
|
|
4434
|
+
function parseExploreRequest(c, value) {
|
|
4435
|
+
if (!isObject(value) || value.mode !== "overview" && value.mode !== "expand") {
|
|
4436
|
+
return { error: errorResponse(c, 400, "bad_request", "mode must be overview or expand") };
|
|
4437
|
+
}
|
|
4438
|
+
const common = parseCommonOptions(c, value);
|
|
4439
|
+
if ("error" in common) return common;
|
|
4440
|
+
if (value.mode === "overview") return { ...common, mode: "overview" };
|
|
4441
|
+
const nodeIds = stringList(value.nodeIds);
|
|
4442
|
+
if (nodeIds === void 0) {
|
|
4443
|
+
return { error: errorResponse(c, 400, "bad_request", "nodeIds must be a string array") };
|
|
4444
|
+
}
|
|
4445
|
+
const request = {
|
|
4446
|
+
...common,
|
|
4447
|
+
mode: "expand",
|
|
4448
|
+
nodeIds
|
|
4449
|
+
};
|
|
4450
|
+
if (value.direction === "outgoing" || value.direction === "incoming" || value.direction === "both") {
|
|
4451
|
+
request.direction = value.direction;
|
|
4452
|
+
} else if (value.direction !== void 0) {
|
|
4453
|
+
return {
|
|
4454
|
+
error: errorResponse(c, 400, "bad_request", "direction must be outgoing, incoming, or both")
|
|
4455
|
+
};
|
|
4456
|
+
}
|
|
4457
|
+
if (typeof value.maxDepth === "number") request.maxDepth = value.maxDepth;
|
|
4458
|
+
else if (value.maxDepth !== void 0) {
|
|
4459
|
+
return { error: errorResponse(c, 400, "bad_request", "maxDepth must be a number") };
|
|
4460
|
+
}
|
|
4461
|
+
return request;
|
|
4462
|
+
}
|
|
4463
|
+
function parseCommonOptions(c, value) {
|
|
4464
|
+
const request = {};
|
|
4465
|
+
for (const [key, label] of [
|
|
4466
|
+
["nodeTypes", "nodeTypes"],
|
|
4467
|
+
["relationships", "relationships"]
|
|
4468
|
+
]) {
|
|
4469
|
+
const selected = value[key];
|
|
4470
|
+
if (selected === void 0) continue;
|
|
4471
|
+
const values = stringList(selected);
|
|
4472
|
+
if (values === void 0) {
|
|
4473
|
+
return { error: errorResponse(c, 400, "bad_request", `${label} must be a string array`) };
|
|
4474
|
+
}
|
|
4475
|
+
request[key] = values;
|
|
4476
|
+
}
|
|
4477
|
+
for (const [key, label] of [
|
|
4478
|
+
["maxNodes", "maxNodes"],
|
|
4479
|
+
["maxRelationships", "maxRelationships"]
|
|
4480
|
+
]) {
|
|
4481
|
+
const selected = value[key];
|
|
4482
|
+
if (selected === void 0) continue;
|
|
4483
|
+
if (typeof selected !== "number") {
|
|
4484
|
+
return { error: errorResponse(c, 400, "bad_request", `${label} must be a number`) };
|
|
4485
|
+
}
|
|
4486
|
+
request[key] = selected;
|
|
4487
|
+
}
|
|
4488
|
+
return request;
|
|
4489
|
+
}
|
|
4490
|
+
function exploreOptionsWithSignal(request, abortSignal) {
|
|
4491
|
+
return { ...request, abortSignal };
|
|
4492
|
+
}
|
|
4493
|
+
function stringList(value) {
|
|
4494
|
+
if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) return void 0;
|
|
4495
|
+
return value;
|
|
4496
|
+
}
|
|
4497
|
+
|
|
4330
4498
|
// src/runtime/interactions.ts
|
|
4331
4499
|
import {
|
|
4332
4500
|
assertAgentInteractionResponse
|
|
@@ -4997,7 +5165,7 @@ function registerPipelineRoutes(app, props) {
|
|
|
4997
5165
|
if ("error" in body) {
|
|
4998
5166
|
return body.error;
|
|
4999
5167
|
}
|
|
5000
|
-
return
|
|
5168
|
+
return executeTrackedPipelineRun(c, props, pipeline, body);
|
|
5001
5169
|
});
|
|
5002
5170
|
app.post("/pipelines/:pipelineId/runs/:runId/replay", async (c) => {
|
|
5003
5171
|
const pipeline = props.pipelineMap.get(c.req.param("pipelineId"));
|
|
@@ -5033,10 +5201,22 @@ function registerPipelineRoutes(app, props) {
|
|
|
5033
5201
|
metadata: replayMetadata(sourceRun.metadata, body.metadata, sourceRun.runId)
|
|
5034
5202
|
};
|
|
5035
5203
|
if (body.stream !== void 0) replayRequest.stream = body.stream;
|
|
5036
|
-
return
|
|
5204
|
+
return executeTrackedPipelineRun(c, props, pipeline, replayRequest);
|
|
5037
5205
|
});
|
|
5038
5206
|
}
|
|
5039
|
-
async function
|
|
5207
|
+
async function executeTrackedPipelineRun(c, props, pipeline, body) {
|
|
5208
|
+
const lease = props.runLifecycle.start(c.req.raw.signal);
|
|
5209
|
+
if (lease === void 0) {
|
|
5210
|
+
return errorResponse(c, 503, "service_unavailable", "Anvia Studio is shutting down");
|
|
5211
|
+
}
|
|
5212
|
+
try {
|
|
5213
|
+
return await executePipelineRun(c, props, pipeline, body, lease);
|
|
5214
|
+
} catch (error) {
|
|
5215
|
+
lease.finish();
|
|
5216
|
+
throw error;
|
|
5217
|
+
}
|
|
5218
|
+
}
|
|
5219
|
+
async function executePipelineRun(c, props, pipeline, body, lease) {
|
|
5040
5220
|
const runId = globalThis.crypto.randomUUID();
|
|
5041
5221
|
const startedAt = Date.now();
|
|
5042
5222
|
const startedAtIso = new Date(startedAt).toISOString();
|
|
@@ -5063,12 +5243,13 @@ async function executePipelineRun(c, props, pipeline, body) {
|
|
|
5063
5243
|
runId,
|
|
5064
5244
|
input: body.input,
|
|
5065
5245
|
startedAt,
|
|
5066
|
-
startedAtIso
|
|
5246
|
+
startedAtIso,
|
|
5247
|
+
onFinish: lease.finish
|
|
5067
5248
|
};
|
|
5068
5249
|
if (body.metadata !== void 0) streamOptions.metadata = body.metadata;
|
|
5069
5250
|
if (props.logStore !== void 0) streamOptions.logStore = props.logStore;
|
|
5070
5251
|
if (props.runStore !== void 0) streamOptions.runStore = props.runStore;
|
|
5071
|
-
streamOptions.abortSignal =
|
|
5252
|
+
streamOptions.abortSignal = lease.abortSignal;
|
|
5072
5253
|
return streamPipelineRun(c, streamOptions);
|
|
5073
5254
|
}
|
|
5074
5255
|
try {
|
|
@@ -5077,7 +5258,7 @@ async function executePipelineRun(c, props, pipeline, body) {
|
|
|
5077
5258
|
input: body.input,
|
|
5078
5259
|
runId,
|
|
5079
5260
|
metadata: body.metadata,
|
|
5080
|
-
abortSignal:
|
|
5261
|
+
abortSignal: lease.abortSignal,
|
|
5081
5262
|
observer: {
|
|
5082
5263
|
async onEvent(event) {
|
|
5083
5264
|
await appendPipelineLog(props.logStore, pipelineStageLog(event, pipeline.id));
|
|
@@ -5134,6 +5315,8 @@ async function executePipelineRun(c, props, pipeline, body) {
|
|
|
5134
5315
|
pipelineRunFailedLog(pipeline.id, runId, error, startedAt)
|
|
5135
5316
|
);
|
|
5136
5317
|
return errorResponse(c, 500, "internal_error", "Pipeline run failed", serializeError(error));
|
|
5318
|
+
} finally {
|
|
5319
|
+
lease.finish();
|
|
5137
5320
|
}
|
|
5138
5321
|
}
|
|
5139
5322
|
function pipelineDetail(pipeline) {
|
|
@@ -5232,7 +5415,11 @@ async function* pipelineRunEvents(props) {
|
|
|
5232
5415
|
yield next.value;
|
|
5233
5416
|
}
|
|
5234
5417
|
} finally {
|
|
5235
|
-
|
|
5418
|
+
try {
|
|
5419
|
+
await run;
|
|
5420
|
+
} finally {
|
|
5421
|
+
props.onFinish();
|
|
5422
|
+
}
|
|
5236
5423
|
}
|
|
5237
5424
|
}
|
|
5238
5425
|
async function savePipelineRun(store, input) {
|
|
@@ -5320,6 +5507,61 @@ function parsePipelineLogAfter(value) {
|
|
|
5320
5507
|
return after;
|
|
5321
5508
|
}
|
|
5322
5509
|
|
|
5510
|
+
// src/runtime/run-lifecycle.ts
|
|
5511
|
+
var StudioRunLifecycle = class {
|
|
5512
|
+
shutdownController = new AbortController();
|
|
5513
|
+
active = /* @__PURE__ */ new Set();
|
|
5514
|
+
drainPromise;
|
|
5515
|
+
resolveDrain;
|
|
5516
|
+
closed = false;
|
|
5517
|
+
start(requestSignal) {
|
|
5518
|
+
if (this.closed) return void 0;
|
|
5519
|
+
const token = /* @__PURE__ */ Symbol("studio-run");
|
|
5520
|
+
this.active.add(token);
|
|
5521
|
+
let finished = false;
|
|
5522
|
+
return {
|
|
5523
|
+
abortSignal: AbortSignal.any([requestSignal, this.shutdownController.signal]),
|
|
5524
|
+
finish: () => {
|
|
5525
|
+
if (finished) return;
|
|
5526
|
+
finished = true;
|
|
5527
|
+
this.active.delete(token);
|
|
5528
|
+
if (this.active.size === 0) {
|
|
5529
|
+
this.resolveDrain?.();
|
|
5530
|
+
this.resolveDrain = void 0;
|
|
5531
|
+
this.drainPromise = void 0;
|
|
5532
|
+
}
|
|
5533
|
+
}
|
|
5534
|
+
};
|
|
5535
|
+
}
|
|
5536
|
+
close() {
|
|
5537
|
+
if (this.closed) return;
|
|
5538
|
+
this.closed = true;
|
|
5539
|
+
this.shutdownController.abort(new Error("Anvia Studio is shutting down."));
|
|
5540
|
+
}
|
|
5541
|
+
async drain(timeoutMs) {
|
|
5542
|
+
this.close();
|
|
5543
|
+
if (this.active.size === 0) return;
|
|
5544
|
+
this.drainPromise ??= new Promise((resolve2) => {
|
|
5545
|
+
this.resolveDrain = resolve2;
|
|
5546
|
+
});
|
|
5547
|
+
await withTimeout(this.drainPromise, timeoutMs);
|
|
5548
|
+
}
|
|
5549
|
+
};
|
|
5550
|
+
async function withTimeout(promise, timeoutMs) {
|
|
5551
|
+
let timer;
|
|
5552
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
5553
|
+
timer = setTimeout(
|
|
5554
|
+
() => reject(new Error(`Anvia Studio shutdown timed out after ${timeoutMs}ms.`)),
|
|
5555
|
+
timeoutMs
|
|
5556
|
+
);
|
|
5557
|
+
});
|
|
5558
|
+
try {
|
|
5559
|
+
await Promise.race([promise, timeout]);
|
|
5560
|
+
} finally {
|
|
5561
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
5562
|
+
}
|
|
5563
|
+
}
|
|
5564
|
+
|
|
5323
5565
|
// src/runtime/sandbox-views.ts
|
|
5324
5566
|
import { upgradeWebSocket } from "@hono/node-server";
|
|
5325
5567
|
import { getConnInfo } from "@hono/node-server/conninfo";
|
|
@@ -6810,7 +7052,8 @@ var Studio = class {
|
|
|
6810
7052
|
studio;
|
|
6811
7053
|
server;
|
|
6812
7054
|
websocketServer;
|
|
6813
|
-
|
|
7055
|
+
signalHandlers;
|
|
7056
|
+
shutdownPromise;
|
|
6814
7057
|
constructor(targets = [], options = {}) {
|
|
6815
7058
|
this.options = studioOptionsFromTargets(targets, options);
|
|
6816
7059
|
this.studio = createStudioApp(this.options);
|
|
@@ -6832,6 +7075,7 @@ var Studio = class {
|
|
|
6832
7075
|
start(serveOptions = {}) {
|
|
6833
7076
|
this.close();
|
|
6834
7077
|
this.studio = createStudioApp(this.options);
|
|
7078
|
+
this.shutdownPromise = void 0;
|
|
6835
7079
|
const port = serveOptions.port ?? Number(process.env.RUNNER_PORT ?? 4021);
|
|
6836
7080
|
const serverOptions = {
|
|
6837
7081
|
fetch: (request, env) => this.studio.app.fetch(request, env),
|
|
@@ -6851,16 +7095,27 @@ var Studio = class {
|
|
|
6851
7095
|
this.logAddress(host, port);
|
|
6852
7096
|
}
|
|
6853
7097
|
if (serveOptions.handleSignals ?? true) {
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
7098
|
+
const shutdownFor = (signal) => {
|
|
7099
|
+
process.exitCode = signal === "SIGINT" ? 130 : 143;
|
|
7100
|
+
void this.shutdown(shutdownOptions(serveOptions.shutdownTimeoutMs)).catch(
|
|
7101
|
+
(error) => {
|
|
7102
|
+
console.error(error);
|
|
7103
|
+
process.exitCode = 1;
|
|
7104
|
+
}
|
|
7105
|
+
);
|
|
7106
|
+
};
|
|
7107
|
+
this.signalHandlers = {
|
|
7108
|
+
sigint: () => shutdownFor("SIGINT"),
|
|
7109
|
+
sigterm: () => shutdownFor("SIGTERM")
|
|
6857
7110
|
};
|
|
6858
|
-
process.once("SIGINT", this.
|
|
7111
|
+
process.once("SIGINT", this.signalHandlers.sigint);
|
|
7112
|
+
process.once("SIGTERM", this.signalHandlers.sigterm);
|
|
6859
7113
|
}
|
|
6860
7114
|
return this;
|
|
6861
7115
|
}
|
|
6862
7116
|
async serve(serveOptions = {}) {
|
|
6863
|
-
const { onShutdown, signal, ...startOptions } = serveOptions;
|
|
7117
|
+
const { onShutdown, shutdownTimeoutMs, signal, ...startOptions } = serveOptions;
|
|
7118
|
+
const failures = [];
|
|
6864
7119
|
try {
|
|
6865
7120
|
this.start({ ...startOptions, log: false, handleSignals: false });
|
|
6866
7121
|
const server = this.server;
|
|
@@ -6875,21 +7130,55 @@ var Studio = class {
|
|
|
6875
7130
|
this.logAddress(startOptions.hostname ?? "localhost", port);
|
|
6876
7131
|
}
|
|
6877
7132
|
await waitForShutdown(signal);
|
|
6878
|
-
}
|
|
6879
|
-
|
|
7133
|
+
} catch (error) {
|
|
7134
|
+
failures.push(error);
|
|
7135
|
+
}
|
|
7136
|
+
try {
|
|
7137
|
+
await this.shutdown(shutdownOptions(shutdownTimeoutMs));
|
|
7138
|
+
} catch (error) {
|
|
7139
|
+
failures.push(error);
|
|
7140
|
+
}
|
|
7141
|
+
try {
|
|
6880
7142
|
await onShutdown?.();
|
|
7143
|
+
} catch (error) {
|
|
7144
|
+
failures.push(error);
|
|
7145
|
+
}
|
|
7146
|
+
if (failures.length === 1) throw failures[0];
|
|
7147
|
+
if (failures.length > 1) {
|
|
7148
|
+
throw new AggregateError(failures, "Failed to run and shut down Anvia Studio.");
|
|
6881
7149
|
}
|
|
6882
7150
|
}
|
|
6883
7151
|
close() {
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
7152
|
+
this.removeSignalHandlers();
|
|
7153
|
+
this.closeNetwork();
|
|
7154
|
+
this.studio.close();
|
|
7155
|
+
}
|
|
7156
|
+
shutdown(options = {}) {
|
|
7157
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
7158
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
7159
|
+
return Promise.reject(
|
|
7160
|
+
new TypeError("Anvia Studio shutdown timeoutMs must be a positive number.")
|
|
7161
|
+
);
|
|
6887
7162
|
}
|
|
7163
|
+
this.shutdownPromise ??= this.shutdownResources(timeoutMs);
|
|
7164
|
+
return this.shutdownPromise;
|
|
7165
|
+
}
|
|
7166
|
+
async shutdownResources(timeoutMs) {
|
|
7167
|
+
this.removeSignalHandlers();
|
|
7168
|
+
this.closeNetwork();
|
|
7169
|
+
await this.studio.shutdown({ timeoutMs });
|
|
7170
|
+
}
|
|
7171
|
+
removeSignalHandlers() {
|
|
7172
|
+
if (this.signalHandlers === void 0) return;
|
|
7173
|
+
process.off("SIGINT", this.signalHandlers.sigint);
|
|
7174
|
+
process.off("SIGTERM", this.signalHandlers.sigterm);
|
|
7175
|
+
this.signalHandlers = void 0;
|
|
7176
|
+
}
|
|
7177
|
+
closeNetwork() {
|
|
6888
7178
|
this.server?.close();
|
|
6889
7179
|
this.server = void 0;
|
|
6890
7180
|
this.websocketServer?.close();
|
|
6891
7181
|
this.websocketServer = void 0;
|
|
6892
|
-
this.studio.close();
|
|
6893
7182
|
}
|
|
6894
7183
|
logAddress(host, port) {
|
|
6895
7184
|
if (isStudioUiEnabled(this.options.ui)) {
|
|
@@ -6900,6 +7189,9 @@ var Studio = class {
|
|
|
6900
7189
|
}
|
|
6901
7190
|
}
|
|
6902
7191
|
};
|
|
7192
|
+
function shutdownOptions(timeoutMs) {
|
|
7193
|
+
return timeoutMs === void 0 ? {} : { timeoutMs };
|
|
7194
|
+
}
|
|
6903
7195
|
function waitForServerListening(server) {
|
|
6904
7196
|
if (server.listening) return Promise.resolve();
|
|
6905
7197
|
return new Promise((resolve2, reject) => {
|
|
@@ -6962,7 +7254,8 @@ function studioOptionsFromTargets(targets, options) {
|
|
|
6962
7254
|
const runtimeOptions = {
|
|
6963
7255
|
agents: inferStudioAgents(agents, options.quickPrompts ?? {}),
|
|
6964
7256
|
pipelines: inferStudioPipelines(pipelines),
|
|
6965
|
-
evals: options.evals ?? []
|
|
7257
|
+
evals: options.evals ?? [],
|
|
7258
|
+
graphs: options.graphs === void 0 ? [] : [...options.graphs]
|
|
6966
7259
|
};
|
|
6967
7260
|
if (options.models !== void 0) runtimeOptions.models = options.models;
|
|
6968
7261
|
if (options.stores !== void 0) runtimeOptions.stores = options.stores;
|
|
@@ -7045,6 +7338,7 @@ function createStudioApp(options) {
|
|
|
7045
7338
|
const pipelineMap = new Map(pipelines.map((pipeline) => [pipeline.id, pipeline]));
|
|
7046
7339
|
const evalMap = new Map(options.evals.map((suite) => [suite.id ?? suite.name, suite]));
|
|
7047
7340
|
const continuationRegistry = createStudioContinuationRegistry();
|
|
7341
|
+
const runLifecycle = new StudioRunLifecycle();
|
|
7048
7342
|
const sandboxRegistry = createStudioSandboxRegistry(agents, options.sandboxes ?? []);
|
|
7049
7343
|
const memorySources = createStudioMemorySourceRegistry(agents, stores.sessions);
|
|
7050
7344
|
const app = new HonoApp();
|
|
@@ -7102,12 +7396,14 @@ function createStudioApp(options) {
|
|
|
7102
7396
|
evals: options.evals,
|
|
7103
7397
|
evalMap
|
|
7104
7398
|
});
|
|
7399
|
+
registerGraphRoutes(app, options.graphs);
|
|
7105
7400
|
const knowledgeOptions = { agents };
|
|
7106
7401
|
if (stores.traces !== void 0) knowledgeOptions.traceStore = stores.traces;
|
|
7107
7402
|
registerKnowledgeRoutes(app, knowledgeOptions);
|
|
7108
7403
|
const pipelineOptions = {
|
|
7109
7404
|
pipelines,
|
|
7110
|
-
pipelineMap
|
|
7405
|
+
pipelineMap,
|
|
7406
|
+
runLifecycle
|
|
7111
7407
|
};
|
|
7112
7408
|
if (stores.pipelineLogs !== void 0) pipelineOptions.logStore = stores.pipelineLogs;
|
|
7113
7409
|
if (stores.pipelineRuns !== void 0) pipelineOptions.runStore = stores.pipelineRuns;
|
|
@@ -7116,7 +7412,8 @@ function createStudioApp(options) {
|
|
|
7116
7412
|
agentMap,
|
|
7117
7413
|
stores,
|
|
7118
7414
|
modelRegistry,
|
|
7119
|
-
continuationRegistry
|
|
7415
|
+
continuationRegistry,
|
|
7416
|
+
runLifecycle
|
|
7120
7417
|
});
|
|
7121
7418
|
if (memorySources.size > 0 || stores.sessions !== void 0) {
|
|
7122
7419
|
registerMemoryRoutes(app, {
|
|
@@ -7139,6 +7436,14 @@ function createStudioApp(options) {
|
|
|
7139
7436
|
app.all(`/${capability}`, (c) => unsupportedCapability(c, capability));
|
|
7140
7437
|
app.all(`/${capability}/*`, (c) => unsupportedCapability(c, capability));
|
|
7141
7438
|
}
|
|
7439
|
+
let closing = false;
|
|
7440
|
+
const beginClose = () => {
|
|
7441
|
+
if (closing) return;
|
|
7442
|
+
closing = true;
|
|
7443
|
+
continuationRegistry.clear();
|
|
7444
|
+
closeSandboxViews();
|
|
7445
|
+
runLifecycle.close();
|
|
7446
|
+
};
|
|
7142
7447
|
const studio = {
|
|
7143
7448
|
app,
|
|
7144
7449
|
fetch(request) {
|
|
@@ -7148,8 +7453,11 @@ function createStudioApp(options) {
|
|
|
7148
7453
|
return buildConfig(options, agents, pipelines, stores, sandboxRegistry.size);
|
|
7149
7454
|
},
|
|
7150
7455
|
close() {
|
|
7151
|
-
|
|
7152
|
-
|
|
7456
|
+
beginClose();
|
|
7457
|
+
},
|
|
7458
|
+
async shutdown(shutdownOptions2 = {}) {
|
|
7459
|
+
beginClose();
|
|
7460
|
+
await runLifecycle.drain(shutdownOptions2.timeoutMs ?? 3e4);
|
|
7153
7461
|
}
|
|
7154
7462
|
};
|
|
7155
7463
|
if (stores.sessions !== void 0) Object.assign(studio, { sessionStore: stores.sessions });
|