@anvia/studio 0.8.1 → 1.0.0-rc.10
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 +69 -19
- package/dist/index.d.ts +179 -116
- package/dist/index.js +1683 -1487
- package/dist/index.js.map +1 -1
- package/dist/ui/assets/ArrowClockwise.es-CSEY3Qr6.js +2 -0
- package/dist/ui/assets/{ArrowClockwise.es-CSN-gjxO.js.map → ArrowClockwise.es-CSEY3Qr6.js.map} +1 -1
- package/dist/ui/assets/CaretDown.es-BHAPbv1R.js +2 -0
- package/dist/ui/assets/CaretDown.es-BHAPbv1R.js.map +1 -0
- package/dist/ui/assets/Check.es-BLChmggz.js +2 -0
- package/dist/ui/assets/Check.es-BLChmggz.js.map +1 -0
- package/dist/ui/assets/Wrench.es-BL6BmNv7.js +4 -0
- package/dist/ui/assets/Wrench.es-BL6BmNv7.js.map +1 -0
- package/dist/ui/assets/agents-page-DQqt45If.js +2 -0
- package/dist/ui/assets/agents-page-DQqt45If.js.map +1 -0
- package/dist/ui/assets/{badge-RJJoRC4P.js → badge-CcajoiAt.js} +1 -1
- package/dist/ui/assets/{badge-RJJoRC4P.js.map → badge-CcajoiAt.js.map} +1 -1
- package/dist/ui/assets/button-07gzSO47.js +2 -0
- package/dist/ui/assets/button-07gzSO47.js.map +1 -0
- package/dist/ui/assets/chunk-QGX73TSQ-D9QAGlAY.js +65 -0
- package/dist/ui/assets/chunk-QGX73TSQ-D9QAGlAY.js.map +1 -0
- package/dist/ui/assets/dialog-CNNQ3hoF.js +2 -0
- package/dist/ui/assets/dialog-CNNQ3hoF.js.map +1 -0
- package/dist/ui/assets/dist-CqMdRzwk.js +2 -0
- package/dist/ui/assets/dist-CqMdRzwk.js.map +1 -0
- package/dist/ui/assets/dist-DWqJwN1i.js +2 -0
- package/dist/ui/assets/dist-DWqJwN1i.js.map +1 -0
- package/dist/ui/assets/es2015-DsZq7PFO.js +42 -0
- package/dist/ui/assets/es2015-DsZq7PFO.js.map +1 -0
- package/dist/ui/assets/icon-CqkMSRbt.js +2 -0
- package/dist/ui/assets/icon-CqkMSRbt.js.map +1 -0
- package/dist/ui/assets/index-BdhE3teo.js +12 -0
- package/dist/ui/assets/index-BdhE3teo.js.map +1 -0
- package/dist/ui/assets/index-CFbK-pX6.css +2 -0
- package/dist/ui/assets/{input-BOUv3rgO.js → input-BiI6gsxA.js} +1 -1
- package/dist/ui/assets/{input-BOUv3rgO.js.map → input-BiI6gsxA.js.map} +1 -1
- package/dist/ui/assets/knowledge-model-S51n2rKh.js +2 -0
- package/dist/ui/assets/knowledge-model-S51n2rKh.js.map +1 -0
- package/dist/ui/assets/knowledge-page-DZeLh92t.js +2 -0
- package/dist/ui/assets/{knowledge-page-Cot_uYcE.js.map → knowledge-page-DZeLh92t.js.map} +1 -1
- package/dist/ui/assets/mcps-page-CDPMO2x9.js +2 -0
- package/dist/ui/assets/{mcps-page-BSO6ork4.js.map → mcps-page-CDPMO2x9.js.map} +1 -1
- package/dist/ui/assets/memory-page-D3UhjpTb.js +4 -0
- package/dist/ui/assets/memory-page-D3UhjpTb.js.map +1 -0
- package/dist/ui/assets/pipelines-page-BP8R6NI7.js +8 -0
- package/dist/ui/assets/pipelines-page-BP8R6NI7.js.map +1 -0
- package/dist/ui/assets/{renderers-B8gvjR2u.js → renderers-DHMEAblV.js} +3 -3
- package/dist/ui/assets/{renderers-B8gvjR2u.js.map → renderers-DHMEAblV.js.map} +1 -1
- package/dist/ui/assets/request-7oUPS8zY.js +4 -0
- package/dist/ui/assets/request-7oUPS8zY.js.map +1 -0
- package/dist/ui/assets/rfb-DiW3PDuT.js +6 -0
- package/dist/ui/assets/rfb-DiW3PDuT.js.map +1 -0
- package/dist/ui/assets/sandboxes-page-C6kokYwc.js +2 -0
- package/dist/ui/assets/sandboxes-page-C6kokYwc.js.map +1 -0
- package/dist/ui/assets/select-BOYfrfck.js +2 -0
- package/dist/ui/assets/select-BOYfrfck.js.map +1 -0
- package/dist/ui/assets/sessions-page-ClXzRM9K.js +2 -0
- package/dist/ui/assets/{sessions-page-CSN2vSKZ.js.map → sessions-page-ClXzRM9K.js.map} +1 -1
- package/dist/ui/assets/status-page-eA8uRLZQ.js +2 -0
- package/dist/ui/assets/{status-page-CgRNt0wi.js.map → status-page-eA8uRLZQ.js.map} +1 -1
- package/dist/ui/assets/studio-CeTsQ4gf.js +2 -0
- package/dist/ui/assets/studio-CeTsQ4gf.js.map +1 -0
- package/dist/ui/assets/textarea-DESKg_ZK.js +2 -0
- package/dist/ui/assets/textarea-DESKg_ZK.js.map +1 -0
- package/dist/ui/assets/tool-runner-D3-SlGqQ.js +2 -0
- package/dist/ui/assets/{tool-runner-BZN-PZJU.js.map → tool-runner-D3-SlGqQ.js.map} +1 -1
- package/dist/ui/assets/tools-page-D3gnQf1_.js +2 -0
- package/dist/ui/assets/{tools-page-DRv7aklU.js.map → tools-page-D3gnQf1_.js.map} +1 -1
- package/dist/ui/assets/trace-browser-D93H7Xxs.js +10 -0
- package/dist/ui/assets/trace-browser-D93H7Xxs.js.map +1 -0
- package/dist/ui/assets/transcript-item-BmjdZLbS.js +3 -0
- package/dist/ui/assets/transcript-item-BmjdZLbS.js.map +1 -0
- package/dist/ui/assets/with-selector-CRZWaZzC.js +2 -0
- package/dist/ui/assets/with-selector-CRZWaZzC.js.map +1 -0
- package/dist/ui/index.html +19 -3
- package/package.json +16 -11
- package/dist/ui/assets/ArrowClockwise.es-CSN-gjxO.js +0 -2
- package/dist/ui/assets/agents-page-CkNSbqAj.js +0 -2
- package/dist/ui/assets/agents-page-CkNSbqAj.js.map +0 -1
- package/dist/ui/assets/chunk-ADH7NNCS-DM6fsnDI.js +0 -2
- package/dist/ui/assets/chunk-ADH7NNCS-DM6fsnDI.js.map +0 -1
- package/dist/ui/assets/index-Bh7RLPBw.js +0 -56
- package/dist/ui/assets/index-Bh7RLPBw.js.map +0 -1
- package/dist/ui/assets/index-D-CbFx6c.css +0 -1
- package/dist/ui/assets/knowledge-page-Cot_uYcE.js +0 -2
- package/dist/ui/assets/mcps-page-BSO6ork4.js +0 -2
- package/dist/ui/assets/memory-page-CG84G--r.js +0 -4
- package/dist/ui/assets/memory-page-CG84G--r.js.map +0 -1
- package/dist/ui/assets/pipelines-page-Hbf5ffUH.js +0 -8
- package/dist/ui/assets/pipelines-page-Hbf5ffUH.js.map +0 -1
- package/dist/ui/assets/sandboxes-page-D910dyFO.js +0 -2
- package/dist/ui/assets/sandboxes-page-D910dyFO.js.map +0 -1
- package/dist/ui/assets/sessions-page-CSN2vSKZ.js +0 -2
- package/dist/ui/assets/status-page-CgRNt0wi.js +0 -2
- package/dist/ui/assets/tool-runner-BZN-PZJU.js +0 -2
- package/dist/ui/assets/tools-page-DRv7aklU.js +0 -2
- package/dist/ui/assets/trace-browser-B07coNNE.js +0 -10
- package/dist/ui/assets/trace-browser-B07coNNE.js.map +0 -1
- package/dist/ui/assets/transcript-item-ZNkQEaCw.js +0 -3
- package/dist/ui/assets/transcript-item-ZNkQEaCw.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// src/runtime/studio.ts
|
|
2
|
-
import { Agent as
|
|
2
|
+
import { Agent, getAgentToolState as getAgentToolState3 } from "@anvia/core/internal/agent";
|
|
3
3
|
import { Pipeline } from "@anvia/core/pipeline";
|
|
4
4
|
import { serve } from "@hono/node-server";
|
|
5
5
|
import { Hono as HonoApp } from "hono";
|
|
6
|
+
import { WebSocketServer } from "ws";
|
|
6
7
|
|
|
7
8
|
// src/runtime/json.ts
|
|
8
9
|
function toJsonValue(value) {
|
|
@@ -159,6 +160,20 @@ var StudioRunTraceObserver = class {
|
|
|
159
160
|
this.observations.push(parentObservation);
|
|
160
161
|
this.observations.push(...childTrace.observations(parentObservation.id));
|
|
161
162
|
},
|
|
163
|
+
suspend: (suspendArgs) => {
|
|
164
|
+
this.observations.push(
|
|
165
|
+
traceObservation({
|
|
166
|
+
kind: "tool",
|
|
167
|
+
name: args.toolName,
|
|
168
|
+
status: "suspended",
|
|
169
|
+
turn: args.turn,
|
|
170
|
+
startedAt,
|
|
171
|
+
input: parseOrString(args.args),
|
|
172
|
+
output: toJsonValue({ interaction: suspendArgs.interaction }),
|
|
173
|
+
metadata: toolMetadata(args, false)
|
|
174
|
+
})
|
|
175
|
+
);
|
|
176
|
+
},
|
|
162
177
|
error: (errorArgs) => {
|
|
163
178
|
const parentObservation = traceObservation({
|
|
164
179
|
kind: "tool",
|
|
@@ -176,9 +191,23 @@ var StudioRunTraceObserver = class {
|
|
|
176
191
|
};
|
|
177
192
|
}
|
|
178
193
|
async end(args) {
|
|
179
|
-
|
|
194
|
+
const result = {
|
|
195
|
+
runId: this.props.args.runId,
|
|
196
|
+
status: args.status,
|
|
197
|
+
text: args.text
|
|
198
|
+
};
|
|
199
|
+
if (args.resumedFrom !== void 0) result.resumedFrom = args.resumedFrom;
|
|
200
|
+
if (args.status === "completed") {
|
|
201
|
+
result.output = toJsonValue(args.output);
|
|
202
|
+
} else if (args.status === "blocked") {
|
|
203
|
+
result.stage = args.stage;
|
|
204
|
+
} else {
|
|
205
|
+
result.interaction = toJsonValue(args.interaction);
|
|
206
|
+
}
|
|
207
|
+
await this.save(args.status === "suspended" ? "suspended" : "success", {
|
|
180
208
|
endedAt: /* @__PURE__ */ new Date(),
|
|
181
|
-
output: args.output,
|
|
209
|
+
output: args.status === "completed" ? traceOutput(args.output) : args.text,
|
|
210
|
+
result,
|
|
182
211
|
usage: args.usage,
|
|
183
212
|
messages: toJsonValue(args.messages)
|
|
184
213
|
});
|
|
@@ -198,11 +227,13 @@ var StudioRunTraceObserver = class {
|
|
|
198
227
|
return;
|
|
199
228
|
}
|
|
200
229
|
const metadata = traceMetadata(this.props.args, result.messages);
|
|
230
|
+
if (result.result !== void 0) metadata.result = result.result;
|
|
201
231
|
const trace = {
|
|
202
232
|
id: this.props.id,
|
|
233
|
+
runId: this.props.args.runId,
|
|
203
234
|
sessionId,
|
|
204
235
|
status,
|
|
205
|
-
trace: this.trace,
|
|
236
|
+
trace: { observer: "studio", ...this.trace },
|
|
206
237
|
startedAt: this.startedAt.toISOString(),
|
|
207
238
|
endedAt: result.endedAt.toISOString(),
|
|
208
239
|
durationMs: durationMs(this.startedAt, result.endedAt),
|
|
@@ -281,15 +312,14 @@ var ChildAgentToolTraceAccumulator = class {
|
|
|
281
312
|
}
|
|
282
313
|
if (child.type === "tool_call" && isRecord(child.toolCall)) {
|
|
283
314
|
const toolCall = child.toolCall;
|
|
284
|
-
const
|
|
285
|
-
const
|
|
286
|
-
const callId = typeof toolCall.callId === "string" ? toolCall.callId : typeof toolCall.id === "string" ? toolCall.id : void 0;
|
|
315
|
+
const toolName = typeof toolCall.toolName === "string" ? toolCall.toolName : "tool";
|
|
316
|
+
const callId = typeof toolCall.toolCallId === "string" ? toolCall.toolCallId : typeof toolCall.callId === "string" ? toolCall.callId : void 0;
|
|
287
317
|
const start = {
|
|
288
318
|
startedAt: /* @__PURE__ */ new Date(),
|
|
289
319
|
agentId,
|
|
290
320
|
childTurn,
|
|
291
321
|
toolName,
|
|
292
|
-
input: toJsonValue(
|
|
322
|
+
input: toJsonValue("input" in toolCall ? toolCall.input : {}),
|
|
293
323
|
completed: false
|
|
294
324
|
};
|
|
295
325
|
if (agentName !== void 0) start.agentName = agentName;
|
|
@@ -427,6 +457,7 @@ function traceObservation(props) {
|
|
|
427
457
|
}
|
|
428
458
|
function traceMetadata(args, messages) {
|
|
429
459
|
return compactJsonObject({
|
|
460
|
+
runId: args.runId,
|
|
430
461
|
agentName: args.agentName,
|
|
431
462
|
agentDescription: args.agentDescription,
|
|
432
463
|
maxTurns: args.maxTurns,
|
|
@@ -441,14 +472,12 @@ function generationMetadata(args, endArgs) {
|
|
|
441
472
|
const request = args.request;
|
|
442
473
|
const response = endArgs?.response;
|
|
443
474
|
const rawResponse = isRecord(response?.rawResponse) ? response.rawResponse : void 0;
|
|
444
|
-
const
|
|
475
|
+
const modelId = args.modelInfo?.modelId ?? stringValue(rawResponse?.model) ?? "unknown";
|
|
445
476
|
const providerResponse = providerResponseSummary(rawResponse);
|
|
446
477
|
const usage = response?.usage;
|
|
447
478
|
return compactJsonObject({
|
|
448
479
|
provider: args.modelInfo?.provider,
|
|
449
|
-
|
|
450
|
-
requestedModel: request.model,
|
|
451
|
-
defaultModel: args.modelInfo?.defaultModel,
|
|
480
|
+
modelId,
|
|
452
481
|
messageId: response?.messageId,
|
|
453
482
|
usage,
|
|
454
483
|
toolCount: request.tools.length,
|
|
@@ -458,15 +487,13 @@ function generationMetadata(args, endArgs) {
|
|
|
458
487
|
temperature: request.temperature,
|
|
459
488
|
maxTokens: request.maxTokens,
|
|
460
489
|
toolChoice: request.toolChoice,
|
|
461
|
-
|
|
490
|
+
providerOptionKeys: isRecord(request.providerOptions) ? Object.keys(request.providerOptions).sort() : void 0,
|
|
462
491
|
hasOutputSchema: request.outputSchema !== void 0,
|
|
463
492
|
firstDeltaMs: endArgs?.firstDeltaMs,
|
|
464
493
|
providerResponse,
|
|
465
494
|
modelInfo: compactJsonObject({
|
|
466
495
|
provider: args.modelInfo?.provider,
|
|
467
|
-
|
|
468
|
-
requestedModel: request.model,
|
|
469
|
-
defaultModel: args.modelInfo?.defaultModel,
|
|
496
|
+
modelId,
|
|
470
497
|
capabilities: args.modelInfo?.capabilities
|
|
471
498
|
}),
|
|
472
499
|
modelCall: compactJsonObject({
|
|
@@ -492,7 +519,6 @@ function generationMetadata(args, endArgs) {
|
|
|
492
519
|
}
|
|
493
520
|
function completionRequestSummary(request) {
|
|
494
521
|
return compactJsonObject({
|
|
495
|
-
model: request.model,
|
|
496
522
|
instructions: request.instructions === void 0 ? void 0 : { present: true },
|
|
497
523
|
messageCount: request.chatHistory.length,
|
|
498
524
|
documentCount: request.documents.length,
|
|
@@ -502,7 +528,7 @@ function completionRequestSummary(request) {
|
|
|
502
528
|
temperature: request.temperature,
|
|
503
529
|
maxTokens: request.maxTokens,
|
|
504
530
|
toolChoice: request.toolChoice,
|
|
505
|
-
|
|
531
|
+
providerOptionKeys: isRecord(request.providerOptions) ? Object.keys(request.providerOptions).sort() : void 0,
|
|
506
532
|
hasOutputSchema: request.outputSchema !== void 0
|
|
507
533
|
});
|
|
508
534
|
}
|
|
@@ -539,7 +565,6 @@ function toolMetadata(args, skipped, result) {
|
|
|
539
565
|
argumentBytes: byteLength(args.args),
|
|
540
566
|
resultBytes: result === void 0 ? void 0 : byteLength(result),
|
|
541
567
|
hasCallSignature: args.toolCall.signature !== void 0,
|
|
542
|
-
hasAdditionalParams: args.toolCall.additionalParams !== void 0,
|
|
543
568
|
toolDescription: args.toolDefinition?.description,
|
|
544
569
|
parameterKeys: Object.keys(properties).sort(),
|
|
545
570
|
requiredParameterKeys: required,
|
|
@@ -557,8 +582,7 @@ function toolMetadata(args, skipped, result) {
|
|
|
557
582
|
mcpServerName: args.toolMetadata?.mcpServerName,
|
|
558
583
|
argumentBytes: byteLength(args.args),
|
|
559
584
|
resultBytes: result === void 0 ? void 0 : byteLength(result),
|
|
560
|
-
hasCallSignature: args.toolCall.signature !== void 0
|
|
561
|
-
hasAdditionalParams: args.toolCall.additionalParams !== void 0
|
|
585
|
+
hasCallSignature: args.toolCall.signature !== void 0
|
|
562
586
|
})
|
|
563
587
|
});
|
|
564
588
|
}
|
|
@@ -575,6 +599,16 @@ function parseOrString(value) {
|
|
|
575
599
|
return value;
|
|
576
600
|
}
|
|
577
601
|
}
|
|
602
|
+
function traceOutput(value) {
|
|
603
|
+
if (typeof value === "string") {
|
|
604
|
+
return value;
|
|
605
|
+
}
|
|
606
|
+
try {
|
|
607
|
+
return JSON.stringify(toJsonValue(value));
|
|
608
|
+
} catch {
|
|
609
|
+
return String(value);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
578
612
|
function isRecord(value) {
|
|
579
613
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
580
614
|
}
|
|
@@ -874,70 +908,31 @@ function escapeHtml(value) {
|
|
|
874
908
|
return value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
875
909
|
}
|
|
876
910
|
|
|
911
|
+
// src/runtime/agent-context.ts
|
|
912
|
+
import { isVectorContext } from "@anvia/core/agent";
|
|
913
|
+
function staticContextDocuments(agent) {
|
|
914
|
+
return agent.context.filter((input) => !isVectorContext(input));
|
|
915
|
+
}
|
|
916
|
+
function vectorContexts(agent) {
|
|
917
|
+
return agent.context.filter(isVectorContext);
|
|
918
|
+
}
|
|
919
|
+
|
|
877
920
|
// src/runtime/agent-runs.ts
|
|
878
|
-
import {
|
|
921
|
+
import {
|
|
922
|
+
withInternalAgentRunOptions
|
|
923
|
+
} from "@anvia/core/internal/agent";
|
|
879
924
|
|
|
880
925
|
// src/runtime/agent-utils.ts
|
|
881
926
|
import {
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
927
|
+
createResolvedAgent,
|
|
928
|
+
getResolvedAgentOptions
|
|
929
|
+
} from "@anvia/core/internal/agent";
|
|
885
930
|
function cloneAgent(agent, overrides = {}) {
|
|
886
|
-
return
|
|
887
|
-
|
|
888
|
-
name: agent.name,
|
|
889
|
-
description: agent.description,
|
|
890
|
-
model: agent.model,
|
|
891
|
-
instructions: agent.instructions,
|
|
892
|
-
staticContext: agent.staticContext,
|
|
893
|
-
temperature: agent.temperature,
|
|
894
|
-
maxTokens: agent.maxTokens,
|
|
895
|
-
additionalParams: agent.additionalParams,
|
|
896
|
-
toolSet: agent.toolSet,
|
|
897
|
-
toolChoice: agent.toolChoice,
|
|
898
|
-
defaultMaxTurns: agent.defaultMaxTurns,
|
|
899
|
-
hook: agent.hook,
|
|
900
|
-
outputSchema: agent.outputSchema,
|
|
901
|
-
observers: agent.observers,
|
|
902
|
-
approvals: agent.approvals,
|
|
903
|
-
dynamicContexts: agent.dynamicContexts,
|
|
904
|
-
dynamicTools: agent.dynamicTools,
|
|
905
|
-
middlewares: agent.middlewares,
|
|
906
|
-
memory: agent.memory,
|
|
907
|
-
eventStore: agent.eventStore,
|
|
931
|
+
return createResolvedAgent({
|
|
932
|
+
...getResolvedAgentOptions(agent),
|
|
908
933
|
...overrides
|
|
909
934
|
});
|
|
910
935
|
}
|
|
911
|
-
function composeHooks(first, second) {
|
|
912
|
-
if (first === void 0) {
|
|
913
|
-
return second;
|
|
914
|
-
}
|
|
915
|
-
if (second === void 0) {
|
|
916
|
-
return first;
|
|
917
|
-
}
|
|
918
|
-
return createHook({
|
|
919
|
-
async onCompletionCall(args) {
|
|
920
|
-
const firstAction = await first.onCompletionCall?.(args);
|
|
921
|
-
return firstAction?.type === "terminate" ? firstAction : await second.onCompletionCall?.(args) ?? void 0;
|
|
922
|
-
},
|
|
923
|
-
async onCompletionResponse(args) {
|
|
924
|
-
const firstAction = await first.onCompletionResponse?.(args);
|
|
925
|
-
return firstAction?.type === "terminate" ? firstAction : await second.onCompletionResponse?.(args) ?? void 0;
|
|
926
|
-
},
|
|
927
|
-
async onToolCall(args) {
|
|
928
|
-
const firstAction = await first.onToolCall?.(args);
|
|
929
|
-
if (firstAction?.type === "skip" || firstAction?.type === "terminate" || firstAction?.type === "approval_request") {
|
|
930
|
-
return firstAction;
|
|
931
|
-
}
|
|
932
|
-
const secondAction = await second.onToolCall?.(args);
|
|
933
|
-
return secondAction ?? firstAction ?? void 0;
|
|
934
|
-
},
|
|
935
|
-
async onToolResult(args) {
|
|
936
|
-
const firstAction = await first.onToolResult?.(args);
|
|
937
|
-
return firstAction?.type === "terminate" ? firstAction : await second.onToolResult?.(args) ?? void 0;
|
|
938
|
-
}
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
936
|
|
|
942
937
|
// src/runtime/errors.ts
|
|
943
938
|
function serializeError(error) {
|
|
@@ -952,7 +947,8 @@ function serializeError(error) {
|
|
|
952
947
|
|
|
953
948
|
// src/runtime/type-guards.ts
|
|
954
949
|
import {
|
|
955
|
-
isJsonValue as isCoreJsonValue
|
|
950
|
+
isJsonValue as isCoreJsonValue,
|
|
951
|
+
isMessage
|
|
956
952
|
} from "@anvia/core/completion";
|
|
957
953
|
function isObject(value) {
|
|
958
954
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -963,26 +959,16 @@ function isJsonObject(value) {
|
|
|
963
959
|
function isJsonValue(value) {
|
|
964
960
|
return isCoreJsonValue(value);
|
|
965
961
|
}
|
|
966
|
-
function isMessageInput(value) {
|
|
967
|
-
return typeof value === "string" || isMessage(value);
|
|
968
|
-
}
|
|
969
|
-
function isMessage(value) {
|
|
970
|
-
if (!isObject(value) || typeof value.role !== "string") {
|
|
971
|
-
return false;
|
|
972
|
-
}
|
|
973
|
-
if (value.role === "system") {
|
|
974
|
-
return typeof value.content === "string";
|
|
975
|
-
}
|
|
976
|
-
if (value.role === "user" || value.role === "assistant" || value.role === "tool") {
|
|
977
|
-
return Array.isArray(value.content);
|
|
978
|
-
}
|
|
979
|
-
return false;
|
|
980
|
-
}
|
|
981
962
|
function isAgentTraceOptions(value) {
|
|
982
963
|
if (!isObject(value)) {
|
|
983
964
|
return false;
|
|
984
965
|
}
|
|
985
|
-
|
|
966
|
+
if (!Object.keys(value).every(
|
|
967
|
+
(key) => ["name", "userId", "sessionId", "metadata", "tags", "version", "traceId"].includes(key)
|
|
968
|
+
)) {
|
|
969
|
+
return false;
|
|
970
|
+
}
|
|
971
|
+
return optionalString(value.name) && optionalString(value.userId) && optionalString(value.sessionId) && optionalString(value.version) && optionalString(value.traceId) && optionalStringArray(value.tags) && (value.metadata === void 0 || isJsonObject(value.metadata));
|
|
986
972
|
}
|
|
987
973
|
function isNonNegativeInteger(value) {
|
|
988
974
|
return Number.isInteger(value) && typeof value === "number" && value >= 0;
|
|
@@ -993,15 +979,9 @@ function isPositiveInteger(value) {
|
|
|
993
979
|
function optionalString(value) {
|
|
994
980
|
return value === void 0 || typeof value === "string";
|
|
995
981
|
}
|
|
996
|
-
function optionalBoolean(value) {
|
|
997
|
-
return value === void 0 || typeof value === "boolean";
|
|
998
|
-
}
|
|
999
982
|
function optionalStringArray(value) {
|
|
1000
983
|
return value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
1001
984
|
}
|
|
1002
|
-
function optionalObject(value) {
|
|
1003
|
-
return value === void 0 || isObject(value);
|
|
1004
|
-
}
|
|
1005
985
|
|
|
1006
986
|
// src/runtime/http.ts
|
|
1007
987
|
function errorResponse(c, status, code, message, details) {
|
|
@@ -1051,8 +1031,8 @@ function createStudioModelRegistry(config) {
|
|
|
1051
1031
|
id,
|
|
1052
1032
|
staticModels
|
|
1053
1033
|
};
|
|
1054
|
-
if (provider.
|
|
1055
|
-
runtimeProvider.
|
|
1034
|
+
if (provider.defaultModelId !== void 0) {
|
|
1035
|
+
runtimeProvider.defaultModelId = normalizeModelId(provider.defaultModelId);
|
|
1056
1036
|
}
|
|
1057
1037
|
providers.set(id, runtimeProvider);
|
|
1058
1038
|
}
|
|
@@ -1061,8 +1041,10 @@ function createStudioModelRegistry(config) {
|
|
|
1061
1041
|
agentPolicies: normalizeAgentPolicies(config.agents ?? {}),
|
|
1062
1042
|
modelCache: /* @__PURE__ */ new Map()
|
|
1063
1043
|
};
|
|
1064
|
-
if (config.
|
|
1065
|
-
Object.assign(registry, {
|
|
1044
|
+
if (config.defaultModelRef !== void 0) {
|
|
1045
|
+
Object.assign(registry, {
|
|
1046
|
+
defaultModelRef: normalizeModelRef(config.defaultModelRef)
|
|
1047
|
+
});
|
|
1066
1048
|
}
|
|
1067
1049
|
return registry;
|
|
1068
1050
|
}
|
|
@@ -1079,7 +1061,7 @@ function studioModelsConfig(registry, agents) {
|
|
|
1079
1061
|
models
|
|
1080
1062
|
};
|
|
1081
1063
|
if (provider.name !== void 0) config2.name = provider.name;
|
|
1082
|
-
if (provider.
|
|
1064
|
+
if (provider.defaultModelId !== void 0) config2.defaultModelId = provider.defaultModelId;
|
|
1083
1065
|
if (provider.metadata !== void 0) config2.metadata = provider.metadata;
|
|
1084
1066
|
return config2;
|
|
1085
1067
|
});
|
|
@@ -1091,7 +1073,7 @@ function studioModelsConfig(registry, agents) {
|
|
|
1091
1073
|
providers,
|
|
1092
1074
|
agents: agentsConfig
|
|
1093
1075
|
};
|
|
1094
|
-
if (registry.
|
|
1076
|
+
if (registry.defaultModelRef !== void 0) config.defaultModelRef = registry.defaultModelRef;
|
|
1095
1077
|
return config;
|
|
1096
1078
|
}
|
|
1097
1079
|
function registerModelRoutes(app, props) {
|
|
@@ -1105,8 +1087,8 @@ function registerModelRoutes(app, props) {
|
|
|
1105
1087
|
const response = {
|
|
1106
1088
|
providers
|
|
1107
1089
|
};
|
|
1108
|
-
if (props.registry.
|
|
1109
|
-
response.
|
|
1090
|
+
if (props.registry.defaultModelRef !== void 0) {
|
|
1091
|
+
response.defaultModelRef = props.registry.defaultModelRef;
|
|
1110
1092
|
}
|
|
1111
1093
|
return c.json(response);
|
|
1112
1094
|
});
|
|
@@ -1139,7 +1121,7 @@ function resolveStudioModel(registry, input) {
|
|
|
1139
1121
|
if (registry === void 0) {
|
|
1140
1122
|
return { warnings: [] };
|
|
1141
1123
|
}
|
|
1142
|
-
const selectedRef = normalizeOptionalModelRef(input.request.model) ?? sessionModelRef(input.sessionMetadata) ?? registry.agentPolicies.get(input.agent.id)?.
|
|
1124
|
+
const selectedRef = normalizeOptionalModelRef(input.request.model) ?? sessionModelRef(input.sessionMetadata) ?? registry.agentPolicies.get(input.agent.id)?.defaultModelRef ?? registry.defaultModelRef;
|
|
1143
1125
|
if (selectedRef === void 0) {
|
|
1144
1126
|
return { warnings: [] };
|
|
1145
1127
|
}
|
|
@@ -1151,7 +1133,7 @@ function resolveStudioModel(registry, input) {
|
|
|
1151
1133
|
}
|
|
1152
1134
|
let model = registry.modelCache.get(selectedRef);
|
|
1153
1135
|
if (model === void 0) {
|
|
1154
|
-
model = provider.createCompletionModel(modelId);
|
|
1136
|
+
model = provider.createCompletionModel({ modelId });
|
|
1155
1137
|
registry.modelCache.set(selectedRef, model);
|
|
1156
1138
|
}
|
|
1157
1139
|
const metadata = provider.staticModels.get(modelId);
|
|
@@ -1169,12 +1151,7 @@ function normalizeOptionalModelRef(ref) {
|
|
|
1169
1151
|
return ref === void 0 ? void 0 : normalizeModelRef(ref);
|
|
1170
1152
|
}
|
|
1171
1153
|
function normalizeModelRef(ref) {
|
|
1172
|
-
|
|
1173
|
-
const trimmed = ref.trim();
|
|
1174
|
-
const parsed = parseModelRef(trimmed);
|
|
1175
|
-
return `${parsed.providerId}:${parsed.modelId}`;
|
|
1176
|
-
}
|
|
1177
|
-
return `${normalizeProviderId(ref.provider)}:${normalizeModelId(ref.model)}`;
|
|
1154
|
+
return `${normalizeProviderId(ref.providerId)}:${normalizeModelId(ref.modelId)}`;
|
|
1178
1155
|
}
|
|
1179
1156
|
function parseModelRef(ref) {
|
|
1180
1157
|
const index = ref.indexOf(":");
|
|
@@ -1217,12 +1194,12 @@ async function agentModelsCatalog(registry, agent) {
|
|
|
1217
1194
|
return [];
|
|
1218
1195
|
}
|
|
1219
1196
|
});
|
|
1220
|
-
const
|
|
1197
|
+
const defaultModelRef = policy?.defaultModelRef ?? registry.defaultModelRef;
|
|
1221
1198
|
const summary = {
|
|
1222
1199
|
agentId: agent.id,
|
|
1223
1200
|
models: [...models, ...exactPolicyModels]
|
|
1224
1201
|
};
|
|
1225
|
-
if (
|
|
1202
|
+
if (defaultModelRef !== void 0) summary.defaultModelRef = defaultModelRef;
|
|
1226
1203
|
if (warnings.length > 0) summary.warnings = warnings;
|
|
1227
1204
|
return summary;
|
|
1228
1205
|
}
|
|
@@ -1260,7 +1237,7 @@ async function providerCatalog(provider) {
|
|
|
1260
1237
|
models: [...models.values()].sort((left, right) => left.ref.localeCompare(right.ref))
|
|
1261
1238
|
};
|
|
1262
1239
|
if (provider.name !== void 0) catalog.name = provider.name;
|
|
1263
|
-
if (provider.
|
|
1240
|
+
if (provider.defaultModelId !== void 0) catalog.defaultModelId = provider.defaultModelId;
|
|
1264
1241
|
if (provider.metadata !== void 0) catalog.metadata = provider.metadata;
|
|
1265
1242
|
if (warning !== void 0) catalog.warning = warning;
|
|
1266
1243
|
return catalog;
|
|
@@ -1294,19 +1271,33 @@ function normalizeAgentPolicies(policies) {
|
|
|
1294
1271
|
return new Map(
|
|
1295
1272
|
Object.entries(policies).map(([agentId, policy]) => {
|
|
1296
1273
|
const normalized = {};
|
|
1297
|
-
if (policy.
|
|
1274
|
+
if (policy.defaultModelRef !== void 0) {
|
|
1275
|
+
normalized.defaultModelRef = normalizeModelRef(policy.defaultModelRef);
|
|
1276
|
+
}
|
|
1298
1277
|
if (policy.allowed !== void 0) {
|
|
1299
|
-
normalized.allowed = policy.allowed.map(
|
|
1300
|
-
(
|
|
1301
|
-
|
|
1278
|
+
normalized.allowed = policy.allowed.map((entry) => {
|
|
1279
|
+
if (typeof entry === "string") {
|
|
1280
|
+
return normalizeWildcardModelRef(entry);
|
|
1281
|
+
}
|
|
1282
|
+
return normalizeModelRef(entry);
|
|
1283
|
+
});
|
|
1302
1284
|
}
|
|
1303
1285
|
return [agentId.trim(), normalized];
|
|
1304
1286
|
})
|
|
1305
1287
|
);
|
|
1306
1288
|
}
|
|
1289
|
+
function normalizeWildcardModelRef(ref) {
|
|
1290
|
+
const normalized = ref.trim();
|
|
1291
|
+
if (!normalized.endsWith(":*")) {
|
|
1292
|
+
throw new ModelSelectionError(`Invalid wildcard model reference: ${ref}`);
|
|
1293
|
+
}
|
|
1294
|
+
return `${normalizeProviderId(normalized.slice(0, -2))}:*`;
|
|
1295
|
+
}
|
|
1307
1296
|
function publicPolicy(policy) {
|
|
1308
1297
|
const config = {};
|
|
1309
|
-
if (policy.
|
|
1298
|
+
if (policy.defaultModelRef !== void 0) {
|
|
1299
|
+
config.defaultModelRef = policy.defaultModelRef;
|
|
1300
|
+
}
|
|
1310
1301
|
if (policy.allowed !== void 0) config.allowed = policy.allowed;
|
|
1311
1302
|
return config;
|
|
1312
1303
|
}
|
|
@@ -1337,15 +1328,13 @@ function modelWarnings(ref, model, request) {
|
|
|
1337
1328
|
function requestModalities(request) {
|
|
1338
1329
|
const modalities = /* @__PURE__ */ new Set(["text"]);
|
|
1339
1330
|
for (const message of requestMessages(request)) {
|
|
1340
|
-
if (typeof message === "string") {
|
|
1341
|
-
continue;
|
|
1342
|
-
}
|
|
1343
1331
|
if (message.role === "user" || message.role === "assistant") {
|
|
1332
|
+
if (typeof message.content === "string") continue;
|
|
1344
1333
|
for (const content of message.content) {
|
|
1345
1334
|
if (content.type === "image") {
|
|
1346
1335
|
modalities.add("image");
|
|
1347
1336
|
}
|
|
1348
|
-
if (content.type === "
|
|
1337
|
+
if (content.type === "file") {
|
|
1349
1338
|
modalities.add("document");
|
|
1350
1339
|
}
|
|
1351
1340
|
}
|
|
@@ -1354,7 +1343,7 @@ function requestModalities(request) {
|
|
|
1354
1343
|
return modalities;
|
|
1355
1344
|
}
|
|
1356
1345
|
function requestMessages(request) {
|
|
1357
|
-
return
|
|
1346
|
+
return request.type === "messages" ? request.messages : [];
|
|
1358
1347
|
}
|
|
1359
1348
|
function normalizeProviderId(id) {
|
|
1360
1349
|
const trimmed = id.trim();
|
|
@@ -1372,7 +1361,7 @@ function normalizeModelId(id) {
|
|
|
1372
1361
|
}
|
|
1373
1362
|
|
|
1374
1363
|
// src/runtime/streams.ts
|
|
1375
|
-
import {
|
|
1364
|
+
import { createClientStreamResponse, createEventStreamResponse } from "@anvia/server";
|
|
1376
1365
|
var studioJsonlHeaders = {
|
|
1377
1366
|
"cache-control": "no-cache, no-transform",
|
|
1378
1367
|
connection: "keep-alive",
|
|
@@ -1381,7 +1370,15 @@ var studioJsonlHeaders = {
|
|
|
1381
1370
|
"x-accel-buffering": "no"
|
|
1382
1371
|
};
|
|
1383
1372
|
function streamStudioJsonl(events) {
|
|
1384
|
-
return
|
|
1373
|
+
return createEventStreamResponse({
|
|
1374
|
+
events: withStudioStreamErrors(events),
|
|
1375
|
+
format: "jsonl",
|
|
1376
|
+
headers: studioJsonlHeaders
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
function streamStudioClient(options) {
|
|
1380
|
+
return createClientStreamResponse({
|
|
1381
|
+
events: options.events,
|
|
1385
1382
|
format: "jsonl",
|
|
1386
1383
|
headers: studioJsonlHeaders
|
|
1387
1384
|
});
|
|
@@ -1400,8 +1397,9 @@ function withStudioStreamErrors(events) {
|
|
|
1400
1397
|
const next = await iterator.next();
|
|
1401
1398
|
if (next.done === true) {
|
|
1402
1399
|
done = true;
|
|
1400
|
+
return next;
|
|
1403
1401
|
}
|
|
1404
|
-
return next;
|
|
1402
|
+
return { done: false, value: serializeStreamError(next.value) };
|
|
1405
1403
|
} catch (error) {
|
|
1406
1404
|
done = true;
|
|
1407
1405
|
return {
|
|
@@ -1419,6 +1417,12 @@ function withStudioStreamErrors(events) {
|
|
|
1419
1417
|
}
|
|
1420
1418
|
};
|
|
1421
1419
|
}
|
|
1420
|
+
function serializeStreamError(event) {
|
|
1421
|
+
if (typeof event !== "object" || event === null || !("type" in event) || event.type !== "error" || !("error" in event)) {
|
|
1422
|
+
return event;
|
|
1423
|
+
}
|
|
1424
|
+
return { ...event, error: serializeError(event.error) };
|
|
1425
|
+
}
|
|
1422
1426
|
function studioStreamError(error) {
|
|
1423
1427
|
return {
|
|
1424
1428
|
type: "error",
|
|
@@ -1435,6 +1439,7 @@ function traceSummary(trace) {
|
|
|
1435
1439
|
startedAt: trace.startedAt,
|
|
1436
1440
|
observationCount: trace.observations.length
|
|
1437
1441
|
};
|
|
1442
|
+
if (trace.runId !== void 0) summary.runId = trace.runId;
|
|
1438
1443
|
if (trace.name !== void 0) summary.name = trace.name;
|
|
1439
1444
|
if (trace.endedAt !== void 0) summary.endedAt = trace.endedAt;
|
|
1440
1445
|
if (trace.durationMs !== void 0) summary.durationMs = trace.durationMs;
|
|
@@ -1626,6 +1631,16 @@ function isEventType(value) {
|
|
|
1626
1631
|
return value === "session_log" || value === "pipeline_log" || value === "trace";
|
|
1627
1632
|
}
|
|
1628
1633
|
|
|
1634
|
+
// src/runtime/runs.ts
|
|
1635
|
+
import {
|
|
1636
|
+
customAgentEventsToClientStream
|
|
1637
|
+
} from "@anvia/client";
|
|
1638
|
+
import { parseAgentInteractionResponse } from "@anvia/core/agent/interactions";
|
|
1639
|
+
import {
|
|
1640
|
+
isJsonValue as isJsonValue2,
|
|
1641
|
+
parseMessages
|
|
1642
|
+
} from "@anvia/core/completion";
|
|
1643
|
+
|
|
1629
1644
|
// src/runtime/transcript.ts
|
|
1630
1645
|
function renumberTranscript(entries) {
|
|
1631
1646
|
return entries.map((entry, entryId) => ({ ...entry, entryId }));
|
|
@@ -1639,7 +1654,8 @@ function transcriptFromMessages(messages) {
|
|
|
1639
1654
|
if (message.role === "user") {
|
|
1640
1655
|
const attachments = attachmentsFromMessage(message);
|
|
1641
1656
|
let textEntryAdded = false;
|
|
1642
|
-
|
|
1657
|
+
const contents2 = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
|
|
1658
|
+
for (const content of contents2) {
|
|
1643
1659
|
if (content.type === "text") {
|
|
1644
1660
|
const entry = {
|
|
1645
1661
|
entryId: transcript.length,
|
|
@@ -1653,32 +1669,36 @@ function transcriptFromMessages(messages) {
|
|
|
1653
1669
|
}
|
|
1654
1670
|
}
|
|
1655
1671
|
if (!textEntryAdded && attachments.length > 0) {
|
|
1656
|
-
|
|
1672
|
+
const entry = {
|
|
1657
1673
|
entryId: transcript.length,
|
|
1658
1674
|
kind: "message",
|
|
1659
1675
|
role: "user",
|
|
1660
1676
|
text: "",
|
|
1661
1677
|
attachments
|
|
1662
|
-
}
|
|
1678
|
+
};
|
|
1679
|
+
transcript.push(entry);
|
|
1663
1680
|
}
|
|
1664
1681
|
continue;
|
|
1665
1682
|
}
|
|
1666
1683
|
if (message.role === "tool") {
|
|
1667
1684
|
for (const content of message.content) {
|
|
1668
|
-
|
|
1685
|
+
if (content.type !== "tool-result") {
|
|
1686
|
+
continue;
|
|
1687
|
+
}
|
|
1688
|
+
const entry = {
|
|
1669
1689
|
entryId: transcript.length,
|
|
1670
1690
|
kind: "tool",
|
|
1671
|
-
toolName:
|
|
1672
|
-
callId: content.callId ?? content.
|
|
1673
|
-
result: content.
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
});
|
|
1691
|
+
toolName: content.toolName,
|
|
1692
|
+
callId: content.callId ?? content.toolCallId,
|
|
1693
|
+
result: toolResultText(content.output)
|
|
1694
|
+
};
|
|
1695
|
+
if (content.output.type === "content") entry.structuredResult = content.output.value;
|
|
1696
|
+
transcript.push(entry);
|
|
1678
1697
|
}
|
|
1679
1698
|
continue;
|
|
1680
1699
|
}
|
|
1681
|
-
|
|
1700
|
+
const contents = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
|
|
1701
|
+
for (const content of contents) {
|
|
1682
1702
|
if (content.type === "text") {
|
|
1683
1703
|
appendAssistantTranscriptText(transcript, content.text);
|
|
1684
1704
|
} else if (content.type === "reasoning") {
|
|
@@ -1689,13 +1709,13 @@ function transcriptFromMessages(messages) {
|
|
|
1689
1709
|
};
|
|
1690
1710
|
if (content.id !== void 0) entry.reasoningId = content.id;
|
|
1691
1711
|
transcript.push(entry);
|
|
1692
|
-
} else if (content.type === "
|
|
1712
|
+
} else if (content.type === "tool-call") {
|
|
1693
1713
|
transcript.push({
|
|
1694
1714
|
entryId: transcript.length,
|
|
1695
1715
|
kind: "tool",
|
|
1696
|
-
toolName: content.
|
|
1697
|
-
callId: content.callId ?? content.
|
|
1698
|
-
args: formatJson(content.
|
|
1716
|
+
toolName: content.toolName,
|
|
1717
|
+
callId: content.callId ?? content.toolCallId,
|
|
1718
|
+
args: formatJson(content.input)
|
|
1699
1719
|
});
|
|
1700
1720
|
}
|
|
1701
1721
|
}
|
|
@@ -1706,28 +1726,37 @@ function attachmentsFromMessage(message) {
|
|
|
1706
1726
|
if (message.role !== "user" && message.role !== "assistant") {
|
|
1707
1727
|
return [];
|
|
1708
1728
|
}
|
|
1729
|
+
if (typeof message.content === "string") return [];
|
|
1709
1730
|
return message.content.flatMap((content) => {
|
|
1710
1731
|
if (content.type === "image") {
|
|
1711
1732
|
const attachment = { kind: "image" };
|
|
1712
|
-
if (content.
|
|
1713
|
-
attachment.data = content.
|
|
1714
|
-
attachment.mediaType = content.
|
|
1733
|
+
if (content.image.type === "data") {
|
|
1734
|
+
attachment.data = content.image.data;
|
|
1735
|
+
if (content.mediaType !== void 0) attachment.mediaType = content.mediaType;
|
|
1715
1736
|
} else {
|
|
1716
|
-
attachment.url = content.
|
|
1737
|
+
attachment.url = content.image.url;
|
|
1717
1738
|
}
|
|
1718
1739
|
return [attachment];
|
|
1719
1740
|
}
|
|
1720
|
-
if (content.type === "
|
|
1741
|
+
if (content.type === "file") {
|
|
1721
1742
|
const attachment = { kind: "document" };
|
|
1722
|
-
if (content.
|
|
1723
|
-
|
|
1724
|
-
if (content.
|
|
1725
|
-
if (content.
|
|
1743
|
+
if (content.filename !== void 0) attachment.name = content.filename;
|
|
1744
|
+
attachment.mediaType = content.mediaType;
|
|
1745
|
+
if (content.data.type === "data") attachment.data = content.data.data;
|
|
1746
|
+
if (content.data.type === "url") attachment.url = content.data.url;
|
|
1726
1747
|
return [attachment];
|
|
1727
1748
|
}
|
|
1728
1749
|
return [];
|
|
1729
1750
|
});
|
|
1730
1751
|
}
|
|
1752
|
+
function toolResultText(output) {
|
|
1753
|
+
if (output.type === "text" || output.type === "error-text") return output.value;
|
|
1754
|
+
if (output.type === "json" || output.type === "error-json") return formatJson(output.value);
|
|
1755
|
+
if (output.type === "execution-denied") return output.reason ?? "Execution denied";
|
|
1756
|
+
return output.value.map(
|
|
1757
|
+
(part) => part.type === "text" ? part.text : `[file:${part.mediaType}${part.filename === void 0 ? "" : `:${part.filename}`}]`
|
|
1758
|
+
).join("\n");
|
|
1759
|
+
}
|
|
1731
1760
|
function appendAssistantTranscriptText(transcript, text) {
|
|
1732
1761
|
const last = transcript.at(-1);
|
|
1733
1762
|
if (last?.kind === "message" && last.role === "assistant") {
|
|
@@ -1775,48 +1804,43 @@ var AsyncEventQueue = class {
|
|
|
1775
1804
|
return new Promise((resolve2) => this.resolvers.push(resolve2));
|
|
1776
1805
|
}
|
|
1777
1806
|
};
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
if (runNext !== void 0) {
|
|
1787
|
-
pending.push(runNext.then((value) => ({ source: "run", value })));
|
|
1788
|
-
}
|
|
1789
|
-
if (approvalNext !== void 0) {
|
|
1790
|
-
pending.push(approvalNext.then((value) => ({ source: "approval", value })));
|
|
1791
|
-
}
|
|
1792
|
-
const result = await Promise.race(pending);
|
|
1793
|
-
if (result.source === "run") {
|
|
1794
|
-
if (result.value.done === true) {
|
|
1795
|
-
runDone = true;
|
|
1796
|
-
runNext = void 0;
|
|
1797
|
-
approvalEvents.close();
|
|
1798
|
-
} else {
|
|
1799
|
-
runNext = runIterator.next();
|
|
1800
|
-
yield result.value.value;
|
|
1801
|
-
}
|
|
1802
|
-
continue;
|
|
1803
|
-
}
|
|
1804
|
-
if (result.value.done === true) {
|
|
1805
|
-
approvalNext = void 0;
|
|
1806
|
-
} else {
|
|
1807
|
-
approvalNext = approvalEvents.next();
|
|
1808
|
-
yield result.value.value;
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
} finally {
|
|
1812
|
-
if (!runDone && runIterator.return !== void 0) {
|
|
1813
|
-
await runIterator.return();
|
|
1814
|
-
}
|
|
1815
|
-
approvalEvents.close();
|
|
1816
|
-
}
|
|
1807
|
+
function streamAgentRunEvents(_c, events, options) {
|
|
1808
|
+
return streamStudioClient({
|
|
1809
|
+
events: customAgentEventsToClientStream({
|
|
1810
|
+
events: withAgentRunCancellation(events, options.onCancel),
|
|
1811
|
+
runId: options.runId,
|
|
1812
|
+
mapCustomEvent: studioEventToClientEvent
|
|
1813
|
+
})
|
|
1814
|
+
});
|
|
1817
1815
|
}
|
|
1818
|
-
function
|
|
1819
|
-
|
|
1816
|
+
function studioEventToClientEvent(event, context) {
|
|
1817
|
+
if (event.type === "session_log" && isJsonValue2(event.log)) {
|
|
1818
|
+
return {
|
|
1819
|
+
type: "data",
|
|
1820
|
+
runId: context.runId,
|
|
1821
|
+
name: "studio.session_log",
|
|
1822
|
+
data: event.log,
|
|
1823
|
+
transient: true
|
|
1824
|
+
};
|
|
1825
|
+
}
|
|
1826
|
+
if (event.type === "pipeline_log" && isJsonValue2(event.log)) {
|
|
1827
|
+
return {
|
|
1828
|
+
type: "data",
|
|
1829
|
+
runId: context.runId,
|
|
1830
|
+
name: "studio.pipeline_log",
|
|
1831
|
+
data: event.log,
|
|
1832
|
+
transient: true
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
if (event.type === "pipeline_final" && isJsonValue2(event.output)) {
|
|
1836
|
+
return {
|
|
1837
|
+
type: "data",
|
|
1838
|
+
runId: context.runId,
|
|
1839
|
+
name: "studio.pipeline_final",
|
|
1840
|
+
data: event.output
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
return void 0;
|
|
1820
1844
|
}
|
|
1821
1845
|
function withAgentRunCancellation(events, onCancel) {
|
|
1822
1846
|
const iterator = events[Symbol.asyncIterator]();
|
|
@@ -1926,7 +1950,7 @@ function createPersistedStreamingSessionTranscript(props) {
|
|
|
1926
1950
|
if (event.type === "final" || event.type === "error") {
|
|
1927
1951
|
assignTranscriptRunDuration(transcript, Date.now() - props.startedAt);
|
|
1928
1952
|
}
|
|
1929
|
-
const eventStatus = event.type === "final" ? "success" : event.type === "error" ? "error" : "running";
|
|
1953
|
+
const eventStatus = event.type === "final" ? event.result.status === "suspended" ? "suspended" : "success" : event.type === "error" ? "error" : "running";
|
|
1930
1954
|
const saveInput = {
|
|
1931
1955
|
id: props.session.id,
|
|
1932
1956
|
runId: props.runId,
|
|
@@ -1936,10 +1960,10 @@ function createPersistedStreamingSessionTranscript(props) {
|
|
|
1936
1960
|
};
|
|
1937
1961
|
if (event.type === "error") saveInput.error = serializeError(event.error);
|
|
1938
1962
|
await saveTranscript(saveInput);
|
|
1939
|
-
const generatedMessages = event.type === "final" ? event.messages.slice(1) : [];
|
|
1963
|
+
const generatedMessages = event.type === "final" ? event.result.messages.slice(props.generatedMessagesStartIndex ?? 1) : [];
|
|
1940
1964
|
if (props.persistGeneratedMessages === true && generatedMessages.length > 0) {
|
|
1941
1965
|
await props.store.append({
|
|
1942
|
-
|
|
1966
|
+
scope: { sessionId: props.session.id },
|
|
1943
1967
|
runId: props.runId,
|
|
1944
1968
|
turn: 1,
|
|
1945
1969
|
messages: generatedMessages
|
|
@@ -2041,9 +2065,9 @@ function acceptTranscriptStreamEvent(transcript, event) {
|
|
|
2041
2065
|
transcript.push({
|
|
2042
2066
|
entryId: transcript.length,
|
|
2043
2067
|
kind: "tool",
|
|
2044
|
-
toolName: event.toolCall.
|
|
2045
|
-
callId: event.toolCall.callId ?? event.toolCall.
|
|
2046
|
-
args: formatJson(event.toolCall.
|
|
2068
|
+
toolName: event.toolCall.toolName,
|
|
2069
|
+
callId: event.toolCall.callId ?? event.toolCall.toolCallId,
|
|
2070
|
+
args: formatJson(event.toolCall.input)
|
|
2047
2071
|
});
|
|
2048
2072
|
}
|
|
2049
2073
|
if (event.type === "tool_result") {
|
|
@@ -2084,86 +2108,72 @@ function acceptTranscriptStreamEvent(transcript, event) {
|
|
|
2084
2108
|
}
|
|
2085
2109
|
appendChildAgentTranscriptEvent(matched, event);
|
|
2086
2110
|
}
|
|
2087
|
-
if (event.type === "
|
|
2088
|
-
const
|
|
2089
|
-
transcript,
|
|
2090
|
-
event.approval.toolName,
|
|
2091
|
-
approvalCallId(event.approval)
|
|
2092
|
-
);
|
|
2093
|
-
if (matched !== void 0) {
|
|
2094
|
-
matched.approval = {
|
|
2095
|
-
id: event.approval.id,
|
|
2096
|
-
status: event.approval.status,
|
|
2097
|
-
requestedAt: event.approval.requestedAt
|
|
2098
|
-
};
|
|
2099
|
-
}
|
|
2100
|
-
}
|
|
2101
|
-
if (event.type === "tool_approval_result") {
|
|
2111
|
+
if (event.type === "final" && event.result.status === "suspended") {
|
|
2112
|
+
const interaction = event.result.interaction;
|
|
2102
2113
|
const matched = findTranscriptToolEntry(
|
|
2103
2114
|
transcript,
|
|
2104
|
-
|
|
2105
|
-
|
|
2115
|
+
interaction.toolName,
|
|
2116
|
+
interaction.callId ?? interaction.toolCallId
|
|
2106
2117
|
);
|
|
2107
|
-
if (matched !== void 0) {
|
|
2118
|
+
if (matched !== void 0 && interaction.type === "tool-approval") {
|
|
2108
2119
|
const approval = {
|
|
2109
|
-
id:
|
|
2110
|
-
status:
|
|
2111
|
-
requestedAt:
|
|
2120
|
+
id: interaction.id,
|
|
2121
|
+
status: "pending",
|
|
2122
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2112
2123
|
};
|
|
2113
|
-
if (
|
|
2114
|
-
if (event.approval.reason !== void 0) approval.reason = event.approval.reason;
|
|
2124
|
+
if (interaction.reason !== void 0) approval.reason = interaction.reason;
|
|
2115
2125
|
matched.approval = approval;
|
|
2116
2126
|
}
|
|
2117
|
-
|
|
2118
|
-
if (event.type === "tool_question_request") {
|
|
2119
|
-
const matched = findTranscriptToolEntry(
|
|
2120
|
-
transcript,
|
|
2121
|
-
event.question.toolName,
|
|
2122
|
-
questionCallId(event.question)
|
|
2123
|
-
);
|
|
2124
|
-
if (matched !== void 0) {
|
|
2127
|
+
if (matched !== void 0 && interaction.type === "tool-question") {
|
|
2125
2128
|
matched.question = {
|
|
2126
|
-
id:
|
|
2127
|
-
status:
|
|
2128
|
-
requestedAt:
|
|
2129
|
-
questions:
|
|
2129
|
+
id: interaction.id,
|
|
2130
|
+
status: "pending",
|
|
2131
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2132
|
+
questions: interaction.questions.map((question) => ({
|
|
2133
|
+
id: question.id,
|
|
2134
|
+
question: question.text,
|
|
2135
|
+
choices: [...question.choices ?? []],
|
|
2136
|
+
allowCustom: question.choices === void 0 || question.allowCustom === true
|
|
2137
|
+
}))
|
|
2130
2138
|
};
|
|
2131
2139
|
}
|
|
2132
2140
|
}
|
|
2133
|
-
if (event.type === "
|
|
2141
|
+
if (event.type === "interaction_response") {
|
|
2142
|
+
const response = event.response;
|
|
2134
2143
|
const matched = findTranscriptToolEntry(
|
|
2135
2144
|
transcript,
|
|
2136
|
-
|
|
2137
|
-
|
|
2145
|
+
response.toolName,
|
|
2146
|
+
response.callId ?? response.toolCallId
|
|
2138
2147
|
);
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2148
|
+
const respondedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2149
|
+
if (matched?.approval !== void 0 && response.type === "tool-approval-response") {
|
|
2150
|
+
const approval = {
|
|
2151
|
+
...matched.approval,
|
|
2152
|
+
status: response.approved ? "approved" : "rejected",
|
|
2153
|
+
resolvedAt: respondedAt
|
|
2154
|
+
};
|
|
2155
|
+
if (response.reason !== void 0) approval.reason = response.reason;
|
|
2156
|
+
matched.approval = approval;
|
|
2157
|
+
}
|
|
2158
|
+
if (matched?.question !== void 0 && response.type === "tool-question-response") {
|
|
2159
|
+
matched.question = {
|
|
2160
|
+
...matched.question,
|
|
2161
|
+
status: "answered",
|
|
2162
|
+
answeredAt: respondedAt,
|
|
2163
|
+
answers: response.answers.map((answer) => ({
|
|
2164
|
+
questionId: answer.questionId,
|
|
2165
|
+
answer: answer.value
|
|
2166
|
+
}))
|
|
2145
2167
|
};
|
|
2146
|
-
if (event.question.answeredAt !== void 0) question.answeredAt = event.question.answeredAt;
|
|
2147
|
-
if (event.question.cancelledAt !== void 0) {
|
|
2148
|
-
question.cancelledAt = event.question.cancelledAt;
|
|
2149
|
-
}
|
|
2150
|
-
if (event.question.answers !== void 0) question.answers = event.question.answers;
|
|
2151
|
-
matched.question = question;
|
|
2152
2168
|
}
|
|
2153
2169
|
}
|
|
2154
|
-
if (event.type === "final" && event.trace?.traceId !== void 0) {
|
|
2155
|
-
assignTranscriptTraceId(transcript, event.trace.traceId);
|
|
2170
|
+
if (event.type === "final" && event.result.trace?.traceId !== void 0) {
|
|
2171
|
+
assignTranscriptTraceId(transcript, event.result.trace.traceId);
|
|
2156
2172
|
}
|
|
2157
2173
|
if (event.type === "error") {
|
|
2158
2174
|
appendTranscriptAssistantError(transcript, errorText(event.error));
|
|
2159
2175
|
}
|
|
2160
2176
|
}
|
|
2161
|
-
function approvalCallId(approval) {
|
|
2162
|
-
return approval.callId ?? approval.toolCallId;
|
|
2163
|
-
}
|
|
2164
|
-
function questionCallId(question) {
|
|
2165
|
-
return question.callId ?? question.toolCallId;
|
|
2166
|
-
}
|
|
2167
2177
|
function appendChildAgentTranscriptEvent(entry, event) {
|
|
2168
2178
|
const childEvent = childAgentTranscriptEvent(event);
|
|
2169
2179
|
if (childEvent === void 0) {
|
|
@@ -2224,9 +2234,9 @@ function childAgentTranscriptEvent(event) {
|
|
|
2224
2234
|
const entry = {
|
|
2225
2235
|
kind: "tool",
|
|
2226
2236
|
agentId: event.agentId,
|
|
2227
|
-
toolName: child.toolCall.
|
|
2228
|
-
callId: child.toolCall.callId ?? child.toolCall.
|
|
2229
|
-
args: formatJson(child.toolCall.
|
|
2237
|
+
toolName: child.toolCall.toolName,
|
|
2238
|
+
callId: child.toolCall.callId ?? child.toolCall.toolCallId,
|
|
2239
|
+
args: formatJson(child.toolCall.input)
|
|
2230
2240
|
};
|
|
2231
2241
|
if (event.agentName !== void 0) entry.agentName = event.agentName;
|
|
2232
2242
|
return entry;
|
|
@@ -2363,17 +2373,18 @@ function extractMessageText(message) {
|
|
|
2363
2373
|
if (message.role === "system") {
|
|
2364
2374
|
return message.content;
|
|
2365
2375
|
}
|
|
2376
|
+
if (typeof message.content === "string") {
|
|
2377
|
+
return message.content;
|
|
2378
|
+
}
|
|
2366
2379
|
return message.content.flatMap((item) => {
|
|
2367
2380
|
if (item.type === "text" || item.type === "reasoning") {
|
|
2368
2381
|
return [item.text];
|
|
2369
2382
|
}
|
|
2370
|
-
if (item.type === "
|
|
2371
|
-
return [`${item.
|
|
2383
|
+
if (item.type === "tool-call") {
|
|
2384
|
+
return [`${item.toolName}(${formatJson(item.input)})`];
|
|
2372
2385
|
}
|
|
2373
|
-
if (item.type === "
|
|
2374
|
-
return item.
|
|
2375
|
-
(result) => "text" in result ? result.text : `[image:${result.mediaType ?? "image/png"}]`
|
|
2376
|
-
);
|
|
2386
|
+
if (item.type === "tool-result") {
|
|
2387
|
+
return [toolResultOutputText(item.output)];
|
|
2377
2388
|
}
|
|
2378
2389
|
return [];
|
|
2379
2390
|
}).join("\n");
|
|
@@ -2382,23 +2393,26 @@ function optionalTranscriptAttachments(message) {
|
|
|
2382
2393
|
if (typeof message === "string" || message.role !== "user") {
|
|
2383
2394
|
return {};
|
|
2384
2395
|
}
|
|
2396
|
+
if (typeof message.content === "string") {
|
|
2397
|
+
return {};
|
|
2398
|
+
}
|
|
2385
2399
|
const attachments = message.content.flatMap((content) => {
|
|
2386
2400
|
if (content.type === "image") {
|
|
2387
2401
|
const attachment = { kind: "image" };
|
|
2388
|
-
if (content.
|
|
2389
|
-
attachment.data = content.
|
|
2390
|
-
attachment.mediaType = content.
|
|
2402
|
+
if (content.image.type === "data") {
|
|
2403
|
+
attachment.data = content.image.data;
|
|
2404
|
+
if (content.mediaType !== void 0) attachment.mediaType = content.mediaType;
|
|
2391
2405
|
} else {
|
|
2392
|
-
attachment.url = content.
|
|
2406
|
+
attachment.url = content.image.url;
|
|
2393
2407
|
}
|
|
2394
2408
|
return [attachment];
|
|
2395
2409
|
}
|
|
2396
|
-
if (content.type === "
|
|
2410
|
+
if (content.type === "file") {
|
|
2397
2411
|
const attachment = { kind: "document" };
|
|
2398
|
-
if (content.
|
|
2399
|
-
|
|
2400
|
-
if (content.
|
|
2401
|
-
if (content.
|
|
2412
|
+
if (content.filename !== void 0) attachment.name = content.filename;
|
|
2413
|
+
attachment.mediaType = content.mediaType;
|
|
2414
|
+
if (content.data.type === "data") attachment.data = content.data.data;
|
|
2415
|
+
if (content.data.type === "url") attachment.url = content.data.url;
|
|
2402
2416
|
return [attachment];
|
|
2403
2417
|
}
|
|
2404
2418
|
return [];
|
|
@@ -2415,32 +2429,63 @@ async function parseRunRequest(c) {
|
|
|
2415
2429
|
if (!isObject(body)) {
|
|
2416
2430
|
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
2417
2431
|
}
|
|
2418
|
-
|
|
2432
|
+
if ("message" in body || "history" in body) {
|
|
2433
|
+
return {
|
|
2434
|
+
error: errorResponse(
|
|
2435
|
+
c,
|
|
2436
|
+
400,
|
|
2437
|
+
"bad_request",
|
|
2438
|
+
"Legacy message/history requests are not supported; use messages"
|
|
2439
|
+
)
|
|
2440
|
+
};
|
|
2441
|
+
}
|
|
2442
|
+
const request = parseRunRequestBody(c, body);
|
|
2419
2443
|
if ("error" in request) {
|
|
2420
2444
|
return request;
|
|
2421
2445
|
}
|
|
2422
2446
|
return parseRunRequestOptions(c, body, request);
|
|
2423
2447
|
}
|
|
2424
|
-
function
|
|
2425
|
-
if (
|
|
2448
|
+
function parseRunRequestBody(c, body) {
|
|
2449
|
+
if (body.type === "interaction_response") {
|
|
2450
|
+
if (typeof body.interactionId !== "string" || body.interactionId.trim().length === 0) {
|
|
2451
|
+
return { error: errorResponse(c, 400, "bad_request", "interactionId must be a string") };
|
|
2452
|
+
}
|
|
2453
|
+
if (body.messages !== void 0 || body.sessionId !== void 0 || body.model !== void 0) {
|
|
2454
|
+
return {
|
|
2455
|
+
error: errorResponse(
|
|
2456
|
+
c,
|
|
2457
|
+
400,
|
|
2458
|
+
"bad_request",
|
|
2459
|
+
"Interaction responses cannot include messages, sessionId, or model"
|
|
2460
|
+
)
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
try {
|
|
2464
|
+
return {
|
|
2465
|
+
type: "interaction_response",
|
|
2466
|
+
interactionId: body.interactionId,
|
|
2467
|
+
response: parseAgentInteractionResponse(body.response)
|
|
2468
|
+
};
|
|
2469
|
+
} catch {
|
|
2470
|
+
return {
|
|
2471
|
+
error: errorResponse(c, 400, "bad_request", "response must be an interaction response")
|
|
2472
|
+
};
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
if (body.type !== "messages") {
|
|
2426
2476
|
return {
|
|
2427
|
-
error: errorResponse(
|
|
2477
|
+
error: errorResponse(
|
|
2478
|
+
c,
|
|
2479
|
+
400,
|
|
2480
|
+
"bad_request",
|
|
2481
|
+
'type must be "messages" or "interaction_response"'
|
|
2482
|
+
)
|
|
2428
2483
|
};
|
|
2429
2484
|
}
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
if (!Array.isArray(body.history) || !body.history.every(isMessage)) {
|
|
2435
|
-
return { error: errorResponse(c, 400, "bad_request", "history must be a Message array") };
|
|
2436
|
-
}
|
|
2437
|
-
request.history = body.history;
|
|
2438
|
-
}
|
|
2439
|
-
return request;
|
|
2440
|
-
}
|
|
2441
|
-
function parseUiRunRequestBody(c, body) {
|
|
2442
|
-
const messages = body.messages;
|
|
2443
|
-
if (!Array.isArray(messages) || !messages.every(isMessage)) {
|
|
2485
|
+
let messages;
|
|
2486
|
+
try {
|
|
2487
|
+
messages = parseMessages(body.messages);
|
|
2488
|
+
} catch {
|
|
2444
2489
|
return {
|
|
2445
2490
|
error: errorResponse(c, 400, "bad_request", "messages must be a non-empty Message array")
|
|
2446
2491
|
};
|
|
@@ -2456,19 +2501,21 @@ function parseUiRunRequestBody(c, body) {
|
|
|
2456
2501
|
error: errorResponse(c, 400, "bad_request", "messages must be a non-empty Message array")
|
|
2457
2502
|
};
|
|
2458
2503
|
}
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2504
|
+
if (message.role !== "user") {
|
|
2505
|
+
return {
|
|
2506
|
+
error: errorResponse(c, 400, "bad_request", "The final message must be user-authored")
|
|
2507
|
+
};
|
|
2508
|
+
}
|
|
2509
|
+
return { type: "messages", messages };
|
|
2463
2510
|
}
|
|
2464
2511
|
function parseRunRequestOptions(c, body, request) {
|
|
2465
|
-
if ("sessionId" in body) {
|
|
2512
|
+
if (request.type === "messages" && "sessionId" in body) {
|
|
2466
2513
|
if (typeof body.sessionId !== "string" || body.sessionId.trim().length === 0) {
|
|
2467
2514
|
return { error: errorResponse(c, 400, "bad_request", "sessionId must be a string") };
|
|
2468
2515
|
}
|
|
2469
|
-
if (request.
|
|
2516
|
+
if (request.messages.length !== 1 || request.messages[0]?.role !== "user") {
|
|
2470
2517
|
return {
|
|
2471
|
-
error: errorResponse(c, 400, "bad_request", "sessionId
|
|
2518
|
+
error: errorResponse(c, 400, "bad_request", "sessionId requires exactly one user message")
|
|
2472
2519
|
};
|
|
2473
2520
|
}
|
|
2474
2521
|
request.sessionId = body.sessionId;
|
|
@@ -2479,7 +2526,7 @@ function parseRunRequestOptions(c, body, request) {
|
|
|
2479
2526
|
}
|
|
2480
2527
|
request.stream = body.stream;
|
|
2481
2528
|
}
|
|
2482
|
-
if ("maxTurns" in body) {
|
|
2529
|
+
if (request.type === "messages" && "maxTurns" in body) {
|
|
2483
2530
|
if (!isNonNegativeInteger(body.maxTurns)) {
|
|
2484
2531
|
return {
|
|
2485
2532
|
error: errorResponse(c, 400, "bad_request", "maxTurns must be a non-negative integer")
|
|
@@ -2487,7 +2534,7 @@ function parseRunRequestOptions(c, body, request) {
|
|
|
2487
2534
|
}
|
|
2488
2535
|
request.maxTurns = body.maxTurns;
|
|
2489
2536
|
}
|
|
2490
|
-
if ("toolConcurrency" in body) {
|
|
2537
|
+
if (request.type === "messages" && "toolConcurrency" in body) {
|
|
2491
2538
|
if (!isPositiveInteger(body.toolConcurrency)) {
|
|
2492
2539
|
return {
|
|
2493
2540
|
error: errorResponse(c, 400, "bad_request", "toolConcurrency must be a positive integer")
|
|
@@ -2495,13 +2542,11 @@ function parseRunRequestOptions(c, body, request) {
|
|
|
2495
2542
|
}
|
|
2496
2543
|
request.toolConcurrency = body.toolConcurrency;
|
|
2497
2544
|
}
|
|
2498
|
-
if ("model" in body) {
|
|
2499
|
-
if (typeof body.model === "string") {
|
|
2500
|
-
request.model = body.model;
|
|
2501
|
-
} else if (isObject(body.model) && typeof body.model.provider === "string" && typeof body.model.model === "string") {
|
|
2545
|
+
if (request.type === "messages" && "model" in body) {
|
|
2546
|
+
if (isObject(body.model) && typeof body.model.providerId === "string" && typeof body.model.modelId === "string") {
|
|
2502
2547
|
request.model = {
|
|
2503
|
-
|
|
2504
|
-
|
|
2548
|
+
providerId: body.model.providerId,
|
|
2549
|
+
modelId: body.model.modelId
|
|
2505
2550
|
};
|
|
2506
2551
|
} else {
|
|
2507
2552
|
return {
|
|
@@ -2509,7 +2554,7 @@ function parseRunRequestOptions(c, body, request) {
|
|
|
2509
2554
|
c,
|
|
2510
2555
|
400,
|
|
2511
2556
|
"bad_request",
|
|
2512
|
-
"model must be a
|
|
2557
|
+
"model must be a { providerId, modelId } object"
|
|
2513
2558
|
)
|
|
2514
2559
|
};
|
|
2515
2560
|
}
|
|
@@ -2530,6 +2575,14 @@ function parseRunRequestOptions(c, body, request) {
|
|
|
2530
2575
|
}
|
|
2531
2576
|
return request;
|
|
2532
2577
|
}
|
|
2578
|
+
function toolResultOutputText(output) {
|
|
2579
|
+
if (output.type === "text" || output.type === "error-text") return output.value;
|
|
2580
|
+
if (output.type === "json" || output.type === "error-json") return formatJson(output.value);
|
|
2581
|
+
if (output.type === "execution-denied") return output.reason ?? "Execution denied";
|
|
2582
|
+
return output.value.map(
|
|
2583
|
+
(part) => part.type === "text" ? part.text : `[file:${part.mediaType}${part.filename === void 0 ? "" : `:${part.filename}`}]`
|
|
2584
|
+
).join("\n");
|
|
2585
|
+
}
|
|
2533
2586
|
|
|
2534
2587
|
// src/runtime/session-logs.ts
|
|
2535
2588
|
async function appendSessionLog(store, input) {
|
|
@@ -2664,6 +2717,25 @@ function memorySavedLog(props) {
|
|
|
2664
2717
|
metadata
|
|
2665
2718
|
};
|
|
2666
2719
|
}
|
|
2720
|
+
function memoryCompactedLog(props) {
|
|
2721
|
+
const metadata = {
|
|
2722
|
+
originalMessageCount: props.originalMessageCount,
|
|
2723
|
+
compactedMessageCount: props.compactedMessageCount,
|
|
2724
|
+
retainedMessageCount: props.retainedMessageCount,
|
|
2725
|
+
attempts: props.attempts
|
|
2726
|
+
};
|
|
2727
|
+
const usage = usageSummary(props.usage);
|
|
2728
|
+
if (usage !== void 0) metadata.usage = usage;
|
|
2729
|
+
return {
|
|
2730
|
+
sessionId: props.sessionId,
|
|
2731
|
+
runId: props.runId,
|
|
2732
|
+
level: "info",
|
|
2733
|
+
category: "memory",
|
|
2734
|
+
event: "memory.compacted",
|
|
2735
|
+
message: "Session memory compacted",
|
|
2736
|
+
metadata
|
|
2737
|
+
};
|
|
2738
|
+
}
|
|
2667
2739
|
function runFailedLog(sessionId, runId, error, startedAt) {
|
|
2668
2740
|
return {
|
|
2669
2741
|
sessionId,
|
|
@@ -2680,6 +2752,9 @@ function runFailedLog(sessionId, runId, error, startedAt) {
|
|
|
2680
2752
|
}
|
|
2681
2753
|
function logsFromStreamEvent(props) {
|
|
2682
2754
|
const { event, sessionId, runId } = props;
|
|
2755
|
+
if (event.type === "memory_compaction") {
|
|
2756
|
+
return [memoryCompactedLog({ sessionId, runId, ...event })];
|
|
2757
|
+
}
|
|
2683
2758
|
if (event.type === "turn_start") {
|
|
2684
2759
|
return [
|
|
2685
2760
|
{
|
|
@@ -2705,12 +2780,12 @@ function logsFromStreamEvent(props) {
|
|
|
2705
2780
|
level: "info",
|
|
2706
2781
|
category: "tool",
|
|
2707
2782
|
event: "tool.called",
|
|
2708
|
-
message: `Tool ${event.toolCall.
|
|
2783
|
+
message: `Tool ${event.toolCall.toolName} called`,
|
|
2709
2784
|
metadata: {
|
|
2710
2785
|
turn: event.turn,
|
|
2711
|
-
toolName: event.toolCall.
|
|
2712
|
-
callId: event.toolCall.callId ?? event.toolCall.
|
|
2713
|
-
argumentBytes: byteLength2(formatUnknown(event.toolCall.
|
|
2786
|
+
toolName: event.toolCall.toolName,
|
|
2787
|
+
callId: event.toolCall.callId ?? event.toolCall.toolCallId,
|
|
2788
|
+
argumentBytes: byteLength2(formatUnknown(event.toolCall.input))
|
|
2714
2789
|
}
|
|
2715
2790
|
}
|
|
2716
2791
|
];
|
|
@@ -2759,102 +2834,79 @@ function logsFromStreamEvent(props) {
|
|
|
2759
2834
|
];
|
|
2760
2835
|
}
|
|
2761
2836
|
if (event.type === "final") {
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
durationMs: Date.now() - props.startedAt,
|
|
2767
|
-
usage: event.usage,
|
|
2768
|
-
output: event.output,
|
|
2769
|
-
messageCount: event.messages.length
|
|
2770
|
-
}),
|
|
2771
|
-
memorySavedLog({ sessionId, runId, messageCount: event.messages.length })
|
|
2772
|
-
];
|
|
2773
|
-
}
|
|
2774
|
-
if (event.type === "error") {
|
|
2775
|
-
return [runFailedLog(sessionId, runId, event.error, props.startedAt)];
|
|
2776
|
-
}
|
|
2777
|
-
if (event.type === "tool_approval_request") {
|
|
2778
|
-
const metadata = {
|
|
2779
|
-
approvalId: event.approval.id,
|
|
2780
|
-
toolName: event.approval.toolName,
|
|
2781
|
-
status: event.approval.status,
|
|
2782
|
-
hasReason: event.approval.reason !== void 0,
|
|
2783
|
-
argumentBytes: byteLength2(event.approval.args)
|
|
2784
|
-
};
|
|
2785
|
-
if (event.approval.callId !== void 0) metadata.callId = event.approval.callId;
|
|
2786
|
-
return [
|
|
2787
|
-
{
|
|
2837
|
+
const result = event.result;
|
|
2838
|
+
const logs = [];
|
|
2839
|
+
if (result.status === "suspended") {
|
|
2840
|
+
logs.push({
|
|
2788
2841
|
sessionId,
|
|
2789
2842
|
runId,
|
|
2790
2843
|
level: "info",
|
|
2791
|
-
category: "
|
|
2792
|
-
event: "
|
|
2793
|
-
message: `
|
|
2794
|
-
metadata
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
}
|
|
2816
|
-
];
|
|
2817
|
-
}
|
|
2818
|
-
if (event.type === "tool_question_request") {
|
|
2819
|
-
const metadata = {
|
|
2820
|
-
questionId: event.question.id,
|
|
2821
|
-
toolName: event.question.toolName,
|
|
2822
|
-
status: event.question.status,
|
|
2823
|
-
questionCount: event.question.questions.length,
|
|
2824
|
-
argumentBytes: byteLength2(event.question.args)
|
|
2825
|
-
};
|
|
2826
|
-
if (event.question.callId !== void 0) metadata.callId = event.question.callId;
|
|
2827
|
-
return [
|
|
2828
|
-
{
|
|
2844
|
+
category: "run",
|
|
2845
|
+
event: "run.suspended",
|
|
2846
|
+
message: `Run suspended for ${result.interaction.type}`,
|
|
2847
|
+
metadata: {
|
|
2848
|
+
interactionId: result.interaction.id,
|
|
2849
|
+
interactionType: result.interaction.type,
|
|
2850
|
+
toolName: result.interaction.toolName,
|
|
2851
|
+
sourceRunId: result.continuation.sourceRunId
|
|
2852
|
+
}
|
|
2853
|
+
});
|
|
2854
|
+
} else {
|
|
2855
|
+
logs.push(
|
|
2856
|
+
runCompletedLog({
|
|
2857
|
+
sessionId,
|
|
2858
|
+
runId,
|
|
2859
|
+
durationMs: Date.now() - props.startedAt,
|
|
2860
|
+
usage: result.usage,
|
|
2861
|
+
output: result.text,
|
|
2862
|
+
messageCount: result.messages.length
|
|
2863
|
+
})
|
|
2864
|
+
);
|
|
2865
|
+
}
|
|
2866
|
+
if (result.resumedFrom !== void 0) {
|
|
2867
|
+
logs.push({
|
|
2829
2868
|
sessionId,
|
|
2830
2869
|
runId,
|
|
2831
2870
|
level: "info",
|
|
2832
|
-
category: "
|
|
2833
|
-
event: "
|
|
2834
|
-
message:
|
|
2835
|
-
metadata
|
|
2836
|
-
|
|
2837
|
-
|
|
2871
|
+
category: "run",
|
|
2872
|
+
event: "interaction.resumed",
|
|
2873
|
+
message: "Interaction resumed in a linked run",
|
|
2874
|
+
metadata: {
|
|
2875
|
+
interactionId: result.resumedFrom.interactionId,
|
|
2876
|
+
sourceRunId: result.resumedFrom.runId,
|
|
2877
|
+
resumedRunId: result.runId
|
|
2878
|
+
}
|
|
2879
|
+
});
|
|
2880
|
+
}
|
|
2881
|
+
logs.push(memorySavedLog({ sessionId, runId, messageCount: result.messages.length }));
|
|
2882
|
+
return logs;
|
|
2838
2883
|
}
|
|
2839
|
-
if (event.type === "
|
|
2840
|
-
|
|
2884
|
+
if (event.type === "error") {
|
|
2885
|
+
return [runFailedLog(sessionId, runId, event.error, props.startedAt)];
|
|
2886
|
+
}
|
|
2887
|
+
if (event.type === "interaction_response") {
|
|
2888
|
+
const response = event.response;
|
|
2841
2889
|
const metadata = {
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
argumentBytes: byteLength2(event.question.args),
|
|
2847
|
-
answerCount: event.question.answers?.length ?? 0
|
|
2890
|
+
interactionId: response.interactionId,
|
|
2891
|
+
interactionType: response.type === "tool-approval-response" ? "tool-approval" : "tool-question",
|
|
2892
|
+
toolName: response.toolName,
|
|
2893
|
+
sourceRunId: event.sourceRunId
|
|
2848
2894
|
};
|
|
2849
|
-
if (
|
|
2895
|
+
if (response.callId !== void 0) metadata.callId = response.callId;
|
|
2896
|
+
if (response.type === "tool-approval-response") {
|
|
2897
|
+
metadata.approved = response.approved;
|
|
2898
|
+
metadata.hasReason = response.reason !== void 0;
|
|
2899
|
+
} else {
|
|
2900
|
+
metadata.answerCount = response.answers.length;
|
|
2901
|
+
}
|
|
2850
2902
|
return [
|
|
2851
2903
|
{
|
|
2852
2904
|
sessionId,
|
|
2853
2905
|
runId,
|
|
2854
2906
|
level: "info",
|
|
2855
|
-
category: "
|
|
2856
|
-
event:
|
|
2857
|
-
message:
|
|
2907
|
+
category: "run",
|
|
2908
|
+
event: "interaction.responded",
|
|
2909
|
+
message: `Interaction response received for ${response.toolName}`,
|
|
2858
2910
|
metadata
|
|
2859
2911
|
}
|
|
2860
2912
|
];
|
|
@@ -2880,16 +2932,16 @@ function childAgentLog(event, sessionId, runId) {
|
|
|
2880
2932
|
level: "debug",
|
|
2881
2933
|
category: "tool",
|
|
2882
2934
|
event: "child_tool.called",
|
|
2883
|
-
message: `Child agent ${event.agentName ?? event.agentId} called ${child.toolCall.
|
|
2935
|
+
message: `Child agent ${event.agentName ?? event.agentId} called ${child.toolCall.toolName}`,
|
|
2884
2936
|
metadata: {
|
|
2885
2937
|
parentToolName: event.toolName,
|
|
2886
2938
|
agentId: event.agentId,
|
|
2887
2939
|
hasAgentName: event.agentName !== void 0,
|
|
2888
2940
|
turn: event.turn,
|
|
2889
2941
|
childTurn: child.turn,
|
|
2890
|
-
toolName: child.toolCall.
|
|
2891
|
-
callId: child.toolCall.callId ?? child.toolCall.
|
|
2892
|
-
argumentBytes: byteLength2(formatUnknown(child.toolCall.
|
|
2942
|
+
toolName: child.toolCall.toolName,
|
|
2943
|
+
callId: child.toolCall.callId ?? child.toolCall.toolCallId,
|
|
2944
|
+
argumentBytes: byteLength2(formatUnknown(child.toolCall.input))
|
|
2893
2945
|
}
|
|
2894
2946
|
}
|
|
2895
2947
|
];
|
|
@@ -2940,14 +2992,16 @@ function childAgentLog(event, sessionId, runId) {
|
|
|
2940
2992
|
];
|
|
2941
2993
|
}
|
|
2942
2994
|
if (child.type === "final") {
|
|
2995
|
+
const result = child.result;
|
|
2943
2996
|
const metadata = {
|
|
2944
2997
|
parentToolName: event.toolName,
|
|
2945
2998
|
agentId: event.agentId,
|
|
2946
2999
|
hasAgentName: event.agentName !== void 0,
|
|
2947
|
-
outputBytes: byteLength2(
|
|
2948
|
-
messageCount:
|
|
3000
|
+
outputBytes: byteLength2(result.text),
|
|
3001
|
+
messageCount: result.messages.length,
|
|
3002
|
+
status: result.status
|
|
2949
3003
|
};
|
|
2950
|
-
const usage = usageSummary(
|
|
3004
|
+
const usage = usageSummary(result.usage);
|
|
2951
3005
|
if (usage !== void 0) metadata.usage = usage;
|
|
2952
3006
|
return [
|
|
2953
3007
|
{
|
|
@@ -3047,6 +3101,56 @@ async function prepareAgentRun(c, props) {
|
|
|
3047
3101
|
if ("error" in body) {
|
|
3048
3102
|
return body.error;
|
|
3049
3103
|
}
|
|
3104
|
+
if (body.type === "interaction_response") {
|
|
3105
|
+
const registration = props.continuationRegistry.take(
|
|
3106
|
+
body.interactionId,
|
|
3107
|
+
agentId,
|
|
3108
|
+
body.response
|
|
3109
|
+
);
|
|
3110
|
+
if (registration.status === "missing") {
|
|
3111
|
+
return errorResponse(c, 404, "not_found", "Interaction continuation is unavailable");
|
|
3112
|
+
}
|
|
3113
|
+
if (registration.status === "claimed") {
|
|
3114
|
+
return errorResponse(c, 409, "conflict", "Interaction response was already claimed");
|
|
3115
|
+
}
|
|
3116
|
+
if (registration.status === "invalid") {
|
|
3117
|
+
return errorResponse(c, 400, "bad_request", registration.error.message);
|
|
3118
|
+
}
|
|
3119
|
+
const { registration: claimed } = registration;
|
|
3120
|
+
const source = claimed.context;
|
|
3121
|
+
const runId2 = globalThis.crypto.randomUUID();
|
|
3122
|
+
let resumedBody = {
|
|
3123
|
+
...source.body
|
|
3124
|
+
};
|
|
3125
|
+
if (body.stream !== void 0) resumedBody = { ...resumedBody, stream: body.stream };
|
|
3126
|
+
if (body.metadata !== void 0) resumedBody = { ...resumedBody, metadata: body.metadata };
|
|
3127
|
+
if (body.trace !== void 0) resumedBody = { ...resumedBody, trace: body.trace };
|
|
3128
|
+
const runOptions = createRunOptions(resumedBody, agentId, source.session, c.req.raw.signal);
|
|
3129
|
+
const execution2 = {
|
|
3130
|
+
generate: (options) => source.runAgent.generate({
|
|
3131
|
+
continuation: claimed.continuation,
|
|
3132
|
+
response: body.response,
|
|
3133
|
+
...options
|
|
3134
|
+
}),
|
|
3135
|
+
stream: (options) => source.runAgent.stream({
|
|
3136
|
+
continuation: claimed.continuation,
|
|
3137
|
+
response: body.response,
|
|
3138
|
+
...options
|
|
3139
|
+
})
|
|
3140
|
+
};
|
|
3141
|
+
return {
|
|
3142
|
+
...source,
|
|
3143
|
+
body: resumedBody,
|
|
3144
|
+
execution: execution2,
|
|
3145
|
+
failureMessages: void 0,
|
|
3146
|
+
memoryCompactionLogged: false,
|
|
3147
|
+
options: runOptions,
|
|
3148
|
+
runId: runId2,
|
|
3149
|
+
runStartedAt: Date.now(),
|
|
3150
|
+
generatedMessagesStartIndex: 0,
|
|
3151
|
+
shouldPersistSessionMessages: source.shouldPersistSessionMessages
|
|
3152
|
+
};
|
|
3153
|
+
}
|
|
3050
3154
|
const session = await resolveRunSession(c, body, agentId, props.stores);
|
|
3051
3155
|
if (session instanceof Response) {
|
|
3052
3156
|
return session;
|
|
@@ -3073,18 +3177,18 @@ async function prepareAgentRun(c, props) {
|
|
|
3073
3177
|
store: props.stores.sessions
|
|
3074
3178
|
});
|
|
3075
3179
|
const memoryMetadata = runMemoryMetadata(agentId, body, selectedModel, runId);
|
|
3076
|
-
const promptMessage =
|
|
3180
|
+
const promptMessage = body.messages.at(-1);
|
|
3077
3181
|
const sessionStore = props.stores.sessions;
|
|
3078
3182
|
const shouldPersistSessionMessages = session !== void 0 && sessionStore !== void 0 && !usesStoreAsAgentMemory(runAgent, sessionStore);
|
|
3079
3183
|
if (shouldPersistSessionMessages) {
|
|
3080
3184
|
await sessionStore.append({
|
|
3081
|
-
|
|
3185
|
+
scope: { sessionId: session.id, metadata: memoryMetadata },
|
|
3082
3186
|
runId,
|
|
3083
3187
|
turn: 1,
|
|
3084
3188
|
messages: [promptMessage]
|
|
3085
3189
|
});
|
|
3086
3190
|
}
|
|
3087
|
-
const
|
|
3191
|
+
const execution = createRunExecution({
|
|
3088
3192
|
agentId,
|
|
3089
3193
|
body,
|
|
3090
3194
|
memoryMetadata,
|
|
@@ -3097,10 +3201,14 @@ async function prepareAgentRun(c, props) {
|
|
|
3097
3201
|
agent,
|
|
3098
3202
|
body,
|
|
3099
3203
|
memoryMetadata,
|
|
3100
|
-
|
|
3204
|
+
execution,
|
|
3205
|
+
failureMessages: void 0,
|
|
3206
|
+
memoryCompactionLogged: false,
|
|
3207
|
+
options: createRunOptions(body, agentId, session, c.req.raw.signal),
|
|
3101
3208
|
runAgent,
|
|
3102
3209
|
runId,
|
|
3103
3210
|
runStartedAt,
|
|
3211
|
+
generatedMessagesStartIndex: 1,
|
|
3104
3212
|
selectedModel,
|
|
3105
3213
|
session,
|
|
3106
3214
|
sessionStore,
|
|
@@ -3142,7 +3250,7 @@ async function recordRunReceived(props) {
|
|
|
3142
3250
|
sessionId: props.session.id,
|
|
3143
3251
|
runId: props.runId,
|
|
3144
3252
|
agentId: props.agentId,
|
|
3145
|
-
message: props.body.
|
|
3253
|
+
message: props.body.messages.at(-1),
|
|
3146
3254
|
stream: props.body.stream === true,
|
|
3147
3255
|
hasTrace: props.body.trace !== void 0
|
|
3148
3256
|
};
|
|
@@ -3189,49 +3297,48 @@ function runMemoryMetadata(agentId, body, selectedModel, runId) {
|
|
|
3189
3297
|
metadata.studioRunId = runId;
|
|
3190
3298
|
return metadata;
|
|
3191
3299
|
}
|
|
3192
|
-
function
|
|
3193
|
-
const
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3300
|
+
function createRunExecution(props) {
|
|
3301
|
+
const session = props.session;
|
|
3302
|
+
if (session !== void 0 && props.runAgent.memory !== void 0) {
|
|
3303
|
+
return {
|
|
3304
|
+
generate: (options) => props.runAgent.generate({
|
|
3305
|
+
prompt: props.promptMessage,
|
|
3306
|
+
session: { sessionId: session.id, metadata: props.memoryMetadata },
|
|
3307
|
+
...options
|
|
3308
|
+
}),
|
|
3309
|
+
stream: (options) => props.runAgent.stream({
|
|
3310
|
+
prompt: props.promptMessage,
|
|
3311
|
+
session: { sessionId: session.id, metadata: props.memoryMetadata },
|
|
3312
|
+
...options
|
|
3313
|
+
})
|
|
3314
|
+
};
|
|
3199
3315
|
}
|
|
3200
|
-
|
|
3201
|
-
|
|
3316
|
+
const transcript = session !== void 0 ? [...session.messages, props.promptMessage] : props.body.messages;
|
|
3317
|
+
return {
|
|
3318
|
+
generate: (options) => props.runAgent.generate({ messages: transcript, ...options }),
|
|
3319
|
+
stream: (options) => props.runAgent.stream({ messages: transcript, ...options })
|
|
3320
|
+
};
|
|
3321
|
+
}
|
|
3322
|
+
function createRunOptions(body, agentId, session, abortSignal) {
|
|
3323
|
+
const options = { abortSignal };
|
|
3324
|
+
if (body.type === "messages" && body.maxTurns !== void 0) options.maxTurns = body.maxTurns;
|
|
3325
|
+
if (body.type === "messages" && body.toolConcurrency !== void 0) {
|
|
3326
|
+
options.toolConcurrency = body.toolConcurrency;
|
|
3202
3327
|
}
|
|
3203
|
-
if (
|
|
3204
|
-
|
|
3205
|
-
} else if (
|
|
3206
|
-
|
|
3328
|
+
if (body.trace !== void 0) {
|
|
3329
|
+
options.trace = traceForRun(body.trace, agentId, session);
|
|
3330
|
+
} else if (session !== void 0) {
|
|
3331
|
+
options.trace = traceForRun(void 0, agentId, session);
|
|
3207
3332
|
}
|
|
3208
|
-
return
|
|
3333
|
+
return options;
|
|
3209
3334
|
}
|
|
3210
3335
|
function handleStreamingAgentRun(c, run, props) {
|
|
3211
|
-
const
|
|
3212
|
-
const
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
};
|
|
3217
|
-
if (run.session !== void 0) approvalContext.sessionId = run.session.id;
|
|
3218
|
-
if (run.body.metadata !== void 0) approvalContext.metadata = run.body.metadata;
|
|
3219
|
-
run.request.approvals(props.approvalRuntime.createApprovals(approvalContext));
|
|
3220
|
-
const questionContext = {
|
|
3221
|
-
runId: run.runId,
|
|
3222
|
-
agentId: run.agentId,
|
|
3223
|
-
emit: (event) => runtimeEvents.push(event)
|
|
3224
|
-
};
|
|
3225
|
-
if (run.session !== void 0) questionContext.sessionId = run.session.id;
|
|
3226
|
-
if (run.body.metadata !== void 0) questionContext.metadata = run.body.metadata;
|
|
3227
|
-
const effectiveHook = composeHooks(
|
|
3228
|
-
run.runAgent.hook,
|
|
3229
|
-
props.questionRuntime.createHook(questionContext)
|
|
3336
|
+
const streamOptions = withInternalAgentRunOptions({ ...run.options }, { runId: run.runId });
|
|
3337
|
+
const runStream = registerStreamingContinuation(
|
|
3338
|
+
run.execution.stream(streamOptions),
|
|
3339
|
+
props.continuationRegistry,
|
|
3340
|
+
run
|
|
3230
3341
|
);
|
|
3231
|
-
if (effectiveHook !== void 0) {
|
|
3232
|
-
run.request.withHook(effectiveHook);
|
|
3233
|
-
}
|
|
3234
|
-
const runStream = mergeRunAndApprovalEvents(run.request.stream(), runtimeEvents);
|
|
3235
3342
|
let stream = runStream;
|
|
3236
3343
|
let persistedRun;
|
|
3237
3344
|
if (run.session !== void 0 && run.sessionStore !== void 0) {
|
|
@@ -3245,17 +3352,17 @@ function handleStreamingAgentRun(c, run, props) {
|
|
|
3245
3352
|
}),
|
|
3246
3353
|
store: run.sessionStore,
|
|
3247
3354
|
session: run.session,
|
|
3248
|
-
message: run.body.
|
|
3355
|
+
message: run.body.messages.at(-1),
|
|
3249
3356
|
runId: run.runId,
|
|
3250
3357
|
startedAt: run.runStartedAt,
|
|
3251
|
-
persistGeneratedMessages: run.shouldPersistSessionMessages
|
|
3358
|
+
persistGeneratedMessages: run.shouldPersistSessionMessages,
|
|
3359
|
+
generatedMessagesStartIndex: run.generatedMessagesStartIndex
|
|
3252
3360
|
});
|
|
3253
3361
|
stream = persistedRun.events;
|
|
3254
3362
|
}
|
|
3255
3363
|
return streamAgentRunEvents(c, stream, {
|
|
3364
|
+
runId: run.runId,
|
|
3256
3365
|
onCancel: async () => {
|
|
3257
|
-
props.approvalRuntime.cancelRun(run.runId);
|
|
3258
|
-
props.questionRuntime.cancelRun(run.runId);
|
|
3259
3366
|
const persistence = [];
|
|
3260
3367
|
if (persistedRun !== void 0) {
|
|
3261
3368
|
persistence.push(persistedRun.cancel());
|
|
@@ -3274,39 +3381,57 @@ function handleStreamingAgentRun(c, run, props) {
|
|
|
3274
3381
|
}
|
|
3275
3382
|
async function handleBufferedAgentRun(c, run, props) {
|
|
3276
3383
|
try {
|
|
3277
|
-
await startBufferedSessionRun(run
|
|
3278
|
-
const
|
|
3279
|
-
|
|
3280
|
-
|
|
3384
|
+
const runtimeOptions = await startBufferedSessionRun(run);
|
|
3385
|
+
const result = await run.execution.generate(runtimeOptions);
|
|
3386
|
+
if (result.status === "suspended") {
|
|
3387
|
+
props.continuationRegistry.register({ continuation: result.continuation, context: run });
|
|
3388
|
+
}
|
|
3389
|
+
await completeBufferedSessionRun(run, result);
|
|
3390
|
+
return c.json(agentRunResponse(result));
|
|
3281
3391
|
} catch (error) {
|
|
3282
3392
|
await failBufferedSessionRun(run, error);
|
|
3283
3393
|
return errorResponse(c, 500, "internal_error", "Agent run failed", serializeError(error));
|
|
3284
3394
|
}
|
|
3285
3395
|
}
|
|
3286
|
-
|
|
3396
|
+
function agentRunResponse(result) {
|
|
3397
|
+
if (result.status !== "suspended") return result;
|
|
3398
|
+
const { continuation: _continuation, messages: _messages, ...response } = result;
|
|
3399
|
+
return response;
|
|
3400
|
+
}
|
|
3401
|
+
async function startBufferedSessionRun(run) {
|
|
3287
3402
|
if (run.session !== void 0) {
|
|
3288
3403
|
await appendSessionLog(run.sessionStore, runStartedLog(run.session, run.runId));
|
|
3289
3404
|
await appendSessionLog(run.sessionStore, memoryLoadedLog(run.session, run.runId));
|
|
3290
3405
|
}
|
|
3291
|
-
const
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
if (run.body.metadata !== void 0) questionContext.metadata = run.body.metadata;
|
|
3297
|
-
const effectiveHook = composeHooks(
|
|
3298
|
-
run.runAgent.hook,
|
|
3299
|
-
props.questionRuntime.createHook(questionContext)
|
|
3300
|
-
);
|
|
3301
|
-
const approvalContext = {
|
|
3302
|
-
runId: run.runId,
|
|
3303
|
-
agentId: run.agentId
|
|
3406
|
+
const internalOptions = {
|
|
3407
|
+
onFailure: ({ messages }) => {
|
|
3408
|
+
run.failureMessages = structuredClone(messages);
|
|
3409
|
+
},
|
|
3410
|
+
runId: run.runId
|
|
3304
3411
|
};
|
|
3305
|
-
if (run.session !== void 0
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3412
|
+
if (run.session !== void 0 && run.sessionStore !== void 0) {
|
|
3413
|
+
const sessionId = run.session.id;
|
|
3414
|
+
const sessionStore = run.sessionStore;
|
|
3415
|
+
internalOptions.onMemoryCompaction = async (compaction) => {
|
|
3416
|
+
await appendSessionLog(
|
|
3417
|
+
sessionStore,
|
|
3418
|
+
memoryCompactedLog({
|
|
3419
|
+
sessionId,
|
|
3420
|
+
runId: run.runId,
|
|
3421
|
+
...compaction
|
|
3422
|
+
})
|
|
3423
|
+
);
|
|
3424
|
+
run.memoryCompactionLogged = true;
|
|
3425
|
+
};
|
|
3426
|
+
}
|
|
3427
|
+
return withInternalAgentRunOptions({ ...run.options }, internalOptions);
|
|
3428
|
+
}
|
|
3429
|
+
async function* registerStreamingContinuation(stream, registry, run) {
|
|
3430
|
+
for await (const event of stream) {
|
|
3431
|
+
if (event.type === "final" && event.result.status === "suspended") {
|
|
3432
|
+
registry.register({ continuation: event.result.continuation, context: run });
|
|
3433
|
+
}
|
|
3434
|
+
yield event;
|
|
3310
3435
|
}
|
|
3311
3436
|
}
|
|
3312
3437
|
async function completeBufferedSessionRun(run, response) {
|
|
@@ -3314,10 +3439,10 @@ async function completeBufferedSessionRun(run, response) {
|
|
|
3314
3439
|
return;
|
|
3315
3440
|
}
|
|
3316
3441
|
if (run.shouldPersistSessionMessages) {
|
|
3317
|
-
const generatedMessages = response.messages.slice(
|
|
3442
|
+
const generatedMessages = response.messages.slice(run.generatedMessagesStartIndex);
|
|
3318
3443
|
if (generatedMessages.length > 0) {
|
|
3319
3444
|
await run.sessionStore.append({
|
|
3320
|
-
|
|
3445
|
+
scope: { sessionId: run.session.id, metadata: run.memoryMetadata },
|
|
3321
3446
|
runId: run.runId,
|
|
3322
3447
|
turn: 1,
|
|
3323
3448
|
messages: generatedMessages
|
|
@@ -3330,21 +3455,85 @@ async function completeBufferedSessionRun(run, response) {
|
|
|
3330
3455
|
await run.sessionStore.saveSessionRunTranscript({
|
|
3331
3456
|
id: run.session.id,
|
|
3332
3457
|
runId: run.runId,
|
|
3333
|
-
...optionalTitle(run.body.
|
|
3458
|
+
...optionalTitle(run.body.messages.at(-1)),
|
|
3334
3459
|
transcript,
|
|
3335
|
-
status: "success"
|
|
3460
|
+
status: response.status === "suspended" ? "suspended" : "success"
|
|
3336
3461
|
});
|
|
3462
|
+
if (response.memoryCompaction !== void 0 && !run.memoryCompactionLogged) {
|
|
3463
|
+
await appendSessionLog(
|
|
3464
|
+
run.sessionStore,
|
|
3465
|
+
memoryCompactedLog({
|
|
3466
|
+
sessionId: run.session.id,
|
|
3467
|
+
runId: run.runId,
|
|
3468
|
+
...response.memoryCompaction
|
|
3469
|
+
})
|
|
3470
|
+
);
|
|
3471
|
+
run.memoryCompactionLogged = true;
|
|
3472
|
+
}
|
|
3337
3473
|
await appendSessionLog(
|
|
3338
3474
|
run.sessionStore,
|
|
3339
|
-
|
|
3475
|
+
response.status === "suspended" ? {
|
|
3476
|
+
sessionId: run.session.id,
|
|
3477
|
+
runId: run.runId,
|
|
3478
|
+
level: "info",
|
|
3479
|
+
category: "run",
|
|
3480
|
+
event: "run.suspended",
|
|
3481
|
+
message: `Run suspended for ${response.interaction.type}`,
|
|
3482
|
+
metadata: {
|
|
3483
|
+
interactionId: response.interaction.id,
|
|
3484
|
+
interactionType: response.interaction.type,
|
|
3485
|
+
toolName: response.interaction.toolName,
|
|
3486
|
+
sourceRunId: response.continuation.sourceRunId
|
|
3487
|
+
}
|
|
3488
|
+
} : runCompletedLog({
|
|
3340
3489
|
sessionId: run.session.id,
|
|
3341
3490
|
runId: run.runId,
|
|
3342
3491
|
durationMs: durationMs2,
|
|
3343
3492
|
usage: response.usage,
|
|
3344
|
-
output: response.
|
|
3493
|
+
output: response.text,
|
|
3345
3494
|
messageCount: response.messages.length
|
|
3346
3495
|
})
|
|
3347
3496
|
);
|
|
3497
|
+
if (response.resumedFrom !== void 0) {
|
|
3498
|
+
const responseMessage = response.messages[0];
|
|
3499
|
+
const responsePart = responseMessage?.role === "tool" ? responseMessage.content[0] : void 0;
|
|
3500
|
+
if (responsePart !== void 0 && responsePart.type !== "tool-result") {
|
|
3501
|
+
const metadata = {
|
|
3502
|
+
interactionId: responsePart.interactionId,
|
|
3503
|
+
interactionType: responsePart.type === "tool-approval-response" ? "tool-approval" : "tool-question",
|
|
3504
|
+
toolName: responsePart.toolName,
|
|
3505
|
+
sourceRunId: response.resumedFrom.runId
|
|
3506
|
+
};
|
|
3507
|
+
if (responsePart.type === "tool-approval-response") {
|
|
3508
|
+
metadata.approved = responsePart.approved;
|
|
3509
|
+
metadata.hasReason = responsePart.reason !== void 0;
|
|
3510
|
+
} else {
|
|
3511
|
+
metadata.answerCount = responsePart.answers.length;
|
|
3512
|
+
}
|
|
3513
|
+
await appendSessionLog(run.sessionStore, {
|
|
3514
|
+
sessionId: run.session.id,
|
|
3515
|
+
runId: run.runId,
|
|
3516
|
+
level: "info",
|
|
3517
|
+
category: "run",
|
|
3518
|
+
event: "interaction.responded",
|
|
3519
|
+
message: `Interaction response received for ${responsePart.toolName}`,
|
|
3520
|
+
metadata
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
3523
|
+
await appendSessionLog(run.sessionStore, {
|
|
3524
|
+
sessionId: run.session.id,
|
|
3525
|
+
runId: run.runId,
|
|
3526
|
+
level: "info",
|
|
3527
|
+
category: "run",
|
|
3528
|
+
event: "interaction.resumed",
|
|
3529
|
+
message: "Interaction resumed in a linked run",
|
|
3530
|
+
metadata: {
|
|
3531
|
+
interactionId: response.resumedFrom.interactionId,
|
|
3532
|
+
sourceRunId: response.resumedFrom.runId,
|
|
3533
|
+
resumedRunId: response.runId
|
|
3534
|
+
}
|
|
3535
|
+
});
|
|
3536
|
+
}
|
|
3348
3537
|
await appendSessionLog(
|
|
3349
3538
|
run.sessionStore,
|
|
3350
3539
|
memorySavedLog({
|
|
@@ -3358,17 +3547,14 @@ async function failBufferedSessionRun(run, error) {
|
|
|
3358
3547
|
if (run.session === void 0 || run.sessionStore === void 0) {
|
|
3359
3548
|
return;
|
|
3360
3549
|
}
|
|
3361
|
-
const messages = await run.sessionStore.load({
|
|
3362
|
-
sessionId: run.session.id,
|
|
3363
|
-
metadata: run.memoryMetadata
|
|
3364
|
-
});
|
|
3365
3550
|
const durationMs2 = Date.now() - run.runStartedAt;
|
|
3366
|
-
const
|
|
3551
|
+
const messages = run.failureMessages ?? [run.body.messages.at(-1)];
|
|
3552
|
+
const transcript = transcriptFromMessages([...messages]);
|
|
3367
3553
|
assignTranscriptRunDuration(transcript, durationMs2);
|
|
3368
3554
|
await run.sessionStore.saveSessionRunTranscript({
|
|
3369
3555
|
id: run.session.id,
|
|
3370
3556
|
runId: run.runId,
|
|
3371
|
-
...optionalTitle(run.body.
|
|
3557
|
+
...optionalTitle(run.body.messages.at(-1)),
|
|
3372
3558
|
transcript,
|
|
3373
3559
|
status: "error",
|
|
3374
3560
|
error: serializeError(error)
|
|
@@ -3378,261 +3564,13 @@ async function failBufferedSessionRun(run, error) {
|
|
|
3378
3564
|
runFailedLog(run.session.id, run.runId, error, run.runStartedAt)
|
|
3379
3565
|
);
|
|
3380
3566
|
}
|
|
3381
|
-
function normalizePromptMessage(message) {
|
|
3382
|
-
return typeof message === "string" ? Message.user(message) : message;
|
|
3383
|
-
}
|
|
3384
3567
|
function usesStoreAsAgentMemory(agent, store) {
|
|
3385
3568
|
const memoryStore = agent.memory?.store;
|
|
3386
3569
|
return memoryStore !== void 0 && rawObservedStore(memoryStore) === rawObservedStore(store);
|
|
3387
3570
|
}
|
|
3388
3571
|
|
|
3389
|
-
// src/runtime/
|
|
3390
|
-
|
|
3391
|
-
const trimmed = value?.trim();
|
|
3392
|
-
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
3393
|
-
}
|
|
3394
|
-
function parseLimit(value, defaultMax = 50, max = 100) {
|
|
3395
|
-
if (value === void 0 || value.trim().length === 0) {
|
|
3396
|
-
return defaultMax;
|
|
3397
|
-
}
|
|
3398
|
-
const limit = Number(value);
|
|
3399
|
-
if (!Number.isInteger(limit) || limit <= 0) {
|
|
3400
|
-
return void 0;
|
|
3401
|
-
}
|
|
3402
|
-
return Math.min(limit, max);
|
|
3403
|
-
}
|
|
3404
|
-
function parseTraceStatus(value) {
|
|
3405
|
-
const status = optionalQueryString(value);
|
|
3406
|
-
if (status === void 0) {
|
|
3407
|
-
return void 0;
|
|
3408
|
-
}
|
|
3409
|
-
return status === "running" || status === "success" || status === "error" ? status : false;
|
|
3410
|
-
}
|
|
3411
|
-
function parseAfter(value) {
|
|
3412
|
-
if (value === void 0 || value.trim().length === 0) {
|
|
3413
|
-
return void 0;
|
|
3414
|
-
}
|
|
3415
|
-
const after = Number(value);
|
|
3416
|
-
if (!Number.isInteger(after) || after < 0) {
|
|
3417
|
-
return false;
|
|
3418
|
-
}
|
|
3419
|
-
return after;
|
|
3420
|
-
}
|
|
3421
|
-
|
|
3422
|
-
// src/runtime/approvals.ts
|
|
3423
|
-
function registerApprovalRoutes(app, approvals) {
|
|
3424
|
-
app.get("/approvals", (c) => {
|
|
3425
|
-
const status = parseApprovalStatus(c.req.query("status"));
|
|
3426
|
-
if (status === false) {
|
|
3427
|
-
return errorResponse(c, 400, "bad_request", "status must be pending or resolved");
|
|
3428
|
-
}
|
|
3429
|
-
const options = {};
|
|
3430
|
-
const runId = optionalQueryString(c.req.query("runId"));
|
|
3431
|
-
const agentId = optionalQueryString(c.req.query("agentId"));
|
|
3432
|
-
const sessionId = optionalQueryString(c.req.query("sessionId"));
|
|
3433
|
-
if (status !== void 0) {
|
|
3434
|
-
options.status = status;
|
|
3435
|
-
}
|
|
3436
|
-
if (runId !== void 0) {
|
|
3437
|
-
options.runId = runId;
|
|
3438
|
-
}
|
|
3439
|
-
if (agentId !== void 0) {
|
|
3440
|
-
options.agentId = agentId;
|
|
3441
|
-
}
|
|
3442
|
-
if (sessionId !== void 0) {
|
|
3443
|
-
options.sessionId = sessionId;
|
|
3444
|
-
}
|
|
3445
|
-
return c.json({
|
|
3446
|
-
approvals: approvals.list(options)
|
|
3447
|
-
});
|
|
3448
|
-
});
|
|
3449
|
-
app.post("/approvals/:approvalId/decision", async (c) => {
|
|
3450
|
-
const body = await parseApprovalDecisionRequest(c);
|
|
3451
|
-
if ("error" in body) {
|
|
3452
|
-
return body.error;
|
|
3453
|
-
}
|
|
3454
|
-
const result = approvals.decide(c.req.param("approvalId"), body);
|
|
3455
|
-
if (result === "missing") {
|
|
3456
|
-
return errorResponse(c, 404, "not_found", "Approval not found");
|
|
3457
|
-
}
|
|
3458
|
-
if (result === "resolved") {
|
|
3459
|
-
return errorResponse(c, 409, "conflict", "Approval is already resolved");
|
|
3460
|
-
}
|
|
3461
|
-
return c.json(result);
|
|
3462
|
-
});
|
|
3463
|
-
}
|
|
3464
|
-
function parseApprovalStatus(value) {
|
|
3465
|
-
const status = optionalQueryString(value);
|
|
3466
|
-
if (status === void 0) {
|
|
3467
|
-
return void 0;
|
|
3468
|
-
}
|
|
3469
|
-
return status === "pending" || status === "resolved" ? status : false;
|
|
3470
|
-
}
|
|
3471
|
-
async function parseApprovalDecisionRequest(c) {
|
|
3472
|
-
let body;
|
|
3473
|
-
try {
|
|
3474
|
-
body = await c.req.json();
|
|
3475
|
-
} catch {
|
|
3476
|
-
return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
|
|
3477
|
-
}
|
|
3478
|
-
if (!isObject(body)) {
|
|
3479
|
-
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
3480
|
-
}
|
|
3481
|
-
if (typeof body.approved !== "boolean") {
|
|
3482
|
-
return { error: errorResponse(c, 400, "bad_request", "approved must be a boolean") };
|
|
3483
|
-
}
|
|
3484
|
-
if ("reason" in body && typeof body.reason !== "string") {
|
|
3485
|
-
return { error: errorResponse(c, 400, "bad_request", "reason must be a string") };
|
|
3486
|
-
}
|
|
3487
|
-
const reason = typeof body.reason === "string" && body.reason.trim().length > 0 ? body.reason.trim() : void 0;
|
|
3488
|
-
return approvalDecision(body.approved, reason);
|
|
3489
|
-
}
|
|
3490
|
-
function createApprovalRuntime() {
|
|
3491
|
-
const approvals = /* @__PURE__ */ new Map();
|
|
3492
|
-
return {
|
|
3493
|
-
approvals,
|
|
3494
|
-
createApprovals(context) {
|
|
3495
|
-
return {
|
|
3496
|
-
async handler(request) {
|
|
3497
|
-
const approvalRequest = {
|
|
3498
|
-
toolName: request.toolName,
|
|
3499
|
-
internalCallId: request.internalCallId,
|
|
3500
|
-
args: request.rawArgs
|
|
3501
|
-
};
|
|
3502
|
-
if (request.toolCallId !== void 0) approvalRequest.toolCallId = request.toolCallId;
|
|
3503
|
-
if (request.reason !== void 0) approvalRequest.reason = request.reason;
|
|
3504
|
-
if (request.rejectMessage !== void 0) {
|
|
3505
|
-
approvalRequest.rejectMessage = request.rejectMessage;
|
|
3506
|
-
}
|
|
3507
|
-
const decision = await requestApproval(approvals, context, approvalRequest);
|
|
3508
|
-
return approvalDecision(decision.approved, decision.reason);
|
|
3509
|
-
}
|
|
3510
|
-
};
|
|
3511
|
-
},
|
|
3512
|
-
list(options) {
|
|
3513
|
-
return [...approvals.values()].filter((approval) => {
|
|
3514
|
-
if (options.status === "pending" && approval.status !== "pending") {
|
|
3515
|
-
return false;
|
|
3516
|
-
}
|
|
3517
|
-
if (options.status === "resolved" && approval.status === "pending") {
|
|
3518
|
-
return false;
|
|
3519
|
-
}
|
|
3520
|
-
if (options.runId !== void 0 && approval.runId !== options.runId) {
|
|
3521
|
-
return false;
|
|
3522
|
-
}
|
|
3523
|
-
if (options.agentId !== void 0 && approval.agentId !== options.agentId) {
|
|
3524
|
-
return false;
|
|
3525
|
-
}
|
|
3526
|
-
if (options.sessionId !== void 0 && approval.sessionId !== options.sessionId) {
|
|
3527
|
-
return false;
|
|
3528
|
-
}
|
|
3529
|
-
return true;
|
|
3530
|
-
}).map(publicApproval);
|
|
3531
|
-
},
|
|
3532
|
-
cancelRun(runId) {
|
|
3533
|
-
const cancelled = [];
|
|
3534
|
-
for (const approval of approvals.values()) {
|
|
3535
|
-
if (!isPendingApproval(approval) || approval.runId !== runId) {
|
|
3536
|
-
continue;
|
|
3537
|
-
}
|
|
3538
|
-
const resolved = resolveApproval(approval, "cancelled", {
|
|
3539
|
-
reason: "Run cancelled in Anvia Studio."
|
|
3540
|
-
});
|
|
3541
|
-
approvals.set(approval.id, resolved);
|
|
3542
|
-
approval.emit?.({ type: "tool_approval_result", approval: resolved });
|
|
3543
|
-
approval.resolve(approvalDecision(false, resolved.reason));
|
|
3544
|
-
cancelled.push(resolved);
|
|
3545
|
-
}
|
|
3546
|
-
return cancelled;
|
|
3547
|
-
},
|
|
3548
|
-
decide(id, decision) {
|
|
3549
|
-
const approval = approvals.get(id);
|
|
3550
|
-
if (approval === void 0) {
|
|
3551
|
-
return "missing";
|
|
3552
|
-
}
|
|
3553
|
-
if (!isPendingApproval(approval)) {
|
|
3554
|
-
return "resolved";
|
|
3555
|
-
}
|
|
3556
|
-
const reason = decision.approved ? decision.reason : decision.reason ?? approval.rejectMessage ?? "Rejected in Anvia Studio.";
|
|
3557
|
-
const resolved = resolveApproval(
|
|
3558
|
-
approval,
|
|
3559
|
-
decision.approved ? "approved" : "rejected",
|
|
3560
|
-
reason === void 0 ? {} : { reason }
|
|
3561
|
-
);
|
|
3562
|
-
approvals.set(id, resolved);
|
|
3563
|
-
approval.emit?.({ type: "tool_approval_result", approval: resolved });
|
|
3564
|
-
approval.resolve(approvalDecision(decision.approved, reason));
|
|
3565
|
-
return publicApproval(resolved);
|
|
3566
|
-
}
|
|
3567
|
-
};
|
|
3568
|
-
}
|
|
3569
|
-
async function requestApproval(approvals, context, request) {
|
|
3570
|
-
const id = globalThis.crypto.randomUUID();
|
|
3571
|
-
const approval = {
|
|
3572
|
-
id,
|
|
3573
|
-
runId: context.runId,
|
|
3574
|
-
agentId: context.agentId,
|
|
3575
|
-
toolName: request.toolName,
|
|
3576
|
-
internalCallId: request.internalCallId,
|
|
3577
|
-
args: request.args,
|
|
3578
|
-
status: "pending",
|
|
3579
|
-
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3580
|
-
resolve: () => {
|
|
3581
|
-
}
|
|
3582
|
-
};
|
|
3583
|
-
if (context.sessionId !== void 0) approval.sessionId = context.sessionId;
|
|
3584
|
-
if (request.toolCallId !== void 0) approval.callId = request.toolCallId;
|
|
3585
|
-
if (request.reason !== void 0) approval.reason = request.reason;
|
|
3586
|
-
if (request.rejectMessage !== void 0) approval.rejectMessage = request.rejectMessage;
|
|
3587
|
-
if (context.emit !== void 0) approval.emit = context.emit;
|
|
3588
|
-
const decision = new Promise((resolve2) => {
|
|
3589
|
-
approval.resolve = (decision2) => {
|
|
3590
|
-
const current = approvals.get(id);
|
|
3591
|
-
if (!isPendingApproval(current)) {
|
|
3592
|
-
if (current !== void 0) {
|
|
3593
|
-
resolve2(approvalDecision(current.status === "approved", current.reason));
|
|
3594
|
-
}
|
|
3595
|
-
return;
|
|
3596
|
-
}
|
|
3597
|
-
const reason = decision2.approved ? decision2.reason : decision2.reason ?? request.rejectMessage ?? "Rejected in Anvia Studio.";
|
|
3598
|
-
const resolved = resolveApproval(
|
|
3599
|
-
current,
|
|
3600
|
-
decision2.approved ? "approved" : "rejected",
|
|
3601
|
-
reason === void 0 ? {} : { reason }
|
|
3602
|
-
);
|
|
3603
|
-
approvals.set(id, resolved);
|
|
3604
|
-
context.emit?.({ type: "tool_approval_result", approval: resolved });
|
|
3605
|
-
resolve2(approvalDecision(decision2.approved, reason));
|
|
3606
|
-
};
|
|
3607
|
-
});
|
|
3608
|
-
approvals.set(id, approval);
|
|
3609
|
-
context.emit?.({ type: "tool_approval_request", approval: publicApproval(approval) });
|
|
3610
|
-
return decision;
|
|
3611
|
-
}
|
|
3612
|
-
function isPendingApproval(approval) {
|
|
3613
|
-
return approval !== void 0 && approval.status === "pending" && "resolve" in approval;
|
|
3614
|
-
}
|
|
3615
|
-
function resolveApproval(approval, status, options = {}) {
|
|
3616
|
-
const resolved = {
|
|
3617
|
-
...approval,
|
|
3618
|
-
status,
|
|
3619
|
-
resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3620
|
-
};
|
|
3621
|
-
if (options.reason !== void 0) resolved.reason = options.reason;
|
|
3622
|
-
return publicApproval(resolved);
|
|
3623
|
-
}
|
|
3624
|
-
function approvalDecision(approved, reason) {
|
|
3625
|
-
const decision = { approved };
|
|
3626
|
-
if (reason !== void 0) decision.reason = reason;
|
|
3627
|
-
return decision;
|
|
3628
|
-
}
|
|
3629
|
-
function publicApproval(approval) {
|
|
3630
|
-
const { emit, rejectMessage, resolve: resolve2, ...rest } = approval;
|
|
3631
|
-
void emit;
|
|
3632
|
-
void rejectMessage;
|
|
3633
|
-
void resolve2;
|
|
3634
|
-
return rest;
|
|
3635
|
-
}
|
|
3572
|
+
// src/runtime/config.ts
|
|
3573
|
+
import { isQuestionTool } from "@anvia/core/tool";
|
|
3636
3574
|
|
|
3637
3575
|
// src/runtime/eval-config.ts
|
|
3638
3576
|
var CASE_PREVIEW_LIMIT = 5;
|
|
@@ -3712,239 +3650,40 @@ function isRecord2(value) {
|
|
|
3712
3650
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3713
3651
|
}
|
|
3714
3652
|
|
|
3715
|
-
// src/runtime/
|
|
3716
|
-
import {
|
|
3717
|
-
var MCP_TOOL_METADATA_KEY = /* @__PURE__ */ Symbol.for("anvia.mcp.tool.metadata");
|
|
3718
|
-
function agentToolItems(agent) {
|
|
3719
|
-
return [
|
|
3720
|
-
...agent.agent.toolSet.values().map((tool) => ({ tool, source: "static" })),
|
|
3721
|
-
...agent.agent.dynamicTools.flatMap((registration) => {
|
|
3722
|
-
const maybeToolSet = registration.index.toolSet;
|
|
3723
|
-
if (!(maybeToolSet instanceof ToolSet)) {
|
|
3724
|
-
return [];
|
|
3725
|
-
}
|
|
3726
|
-
return maybeToolSet.values().map((tool) => ({ tool, source: "dynamic" }));
|
|
3727
|
-
})
|
|
3728
|
-
];
|
|
3729
|
-
}
|
|
3730
|
-
function approvalMetadata(tool) {
|
|
3731
|
-
const approval = tool.approval;
|
|
3732
|
-
if (approval === void 0 || typeof approval !== "object" || approval === null) {
|
|
3733
|
-
return { required: false };
|
|
3734
|
-
}
|
|
3735
|
-
const policy = approval;
|
|
3736
|
-
const metadata = { required: true };
|
|
3737
|
-
if (typeof policy.reason === "string") metadata.reason = policy.reason;
|
|
3738
|
-
if (typeof policy.rejectMessage === "string") metadata.rejectMessage = policy.rejectMessage;
|
|
3739
|
-
return metadata;
|
|
3740
|
-
}
|
|
3741
|
-
function mcpServerName(tool) {
|
|
3742
|
-
const metadata = tool[MCP_TOOL_METADATA_KEY];
|
|
3743
|
-
if (typeof metadata !== "object" || metadata === null) {
|
|
3744
|
-
return void 0;
|
|
3745
|
-
}
|
|
3746
|
-
const serverName = metadata.serverName;
|
|
3747
|
-
return typeof serverName === "string" && serverName.length > 0 ? serverName : void 0;
|
|
3748
|
-
}
|
|
3749
|
-
function agentHasMcpTools(agent) {
|
|
3750
|
-
return agentToolItems(agent).some(({ tool }) => mcpServerName(tool) !== void 0);
|
|
3751
|
-
}
|
|
3752
|
-
|
|
3753
|
-
// src/runtime/config.ts
|
|
3754
|
-
function runnerId(options) {
|
|
3755
|
-
return options.id ?? "anvia-studio";
|
|
3756
|
-
}
|
|
3757
|
-
function agentConfig(agent) {
|
|
3758
|
-
const name = agent.name ?? agent.agent.name;
|
|
3759
|
-
const description = agent.description ?? agent.agent.description;
|
|
3760
|
-
const config = {
|
|
3761
|
-
id: agent.id,
|
|
3762
|
-
quickPrompts: agent.quickPrompts ?? []
|
|
3763
|
-
};
|
|
3764
|
-
if (name !== void 0) config.name = name;
|
|
3765
|
-
if (description !== void 0) config.description = description;
|
|
3766
|
-
if (agent.metadata !== void 0) config.metadata = agent.metadata;
|
|
3767
|
-
return config;
|
|
3768
|
-
}
|
|
3769
|
-
function agentRuntimeSummary(agent) {
|
|
3770
|
-
const tools = agentToolItems(agent);
|
|
3771
|
-
const name = agent.name ?? agent.agent.name;
|
|
3772
|
-
const description = agent.description ?? agent.agent.description;
|
|
3773
|
-
const summary = {
|
|
3774
|
-
id: agent.id,
|
|
3775
|
-
model: toJsonValue2(agent.agent.model),
|
|
3776
|
-
toolCount: tools.length,
|
|
3777
|
-
staticToolCount: tools.filter((item) => item.source === "static").length,
|
|
3778
|
-
dynamicToolCount: tools.filter((item) => item.source === "dynamic").length,
|
|
3779
|
-
approvalToolCount: tools.filter((item) => item.tool.approval !== void 0).length,
|
|
3780
|
-
mcpToolCount: tools.filter((item) => mcpServerName(item.tool) !== void 0).length,
|
|
3781
|
-
staticContextCount: agent.agent.staticContext.length,
|
|
3782
|
-
dynamicContextCount: agent.agent.dynamicContexts.length,
|
|
3783
|
-
observerCount: agent.agent.observers.length,
|
|
3784
|
-
hasMemory: agent.agent.memory !== void 0,
|
|
3785
|
-
hasHook: agent.agent.hook !== void 0,
|
|
3786
|
-
hasOutputSchema: agent.agent.outputSchema !== void 0
|
|
3787
|
-
};
|
|
3788
|
-
if (name !== void 0) summary.name = name;
|
|
3789
|
-
if (description !== void 0) summary.description = description;
|
|
3790
|
-
if (agent.agent.defaultMaxTurns !== void 0) {
|
|
3791
|
-
summary.defaultMaxTurns = agent.agent.defaultMaxTurns;
|
|
3792
|
-
}
|
|
3793
|
-
if (agent.metadata !== void 0) summary.metadata = agent.metadata;
|
|
3794
|
-
return summary;
|
|
3795
|
-
}
|
|
3796
|
-
function pipelineConfig(pipeline) {
|
|
3797
|
-
const graph = pipeline.pipeline.graph();
|
|
3798
|
-
const stageNodes = graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output");
|
|
3799
|
-
const config = {
|
|
3800
|
-
id: pipeline.id,
|
|
3801
|
-
stageCount: stageNodes.length,
|
|
3802
|
-
edgeCount: graph.edges.length,
|
|
3803
|
-
hasParallelStages: graph.nodes.some((node) => node.kind === "parallel"),
|
|
3804
|
-
agentCount: graph.nodes.filter((node) => node.kind === "agent").length,
|
|
3805
|
-
extractorCount: graph.nodes.filter((node) => node.kind === "extractor").length
|
|
3806
|
-
};
|
|
3807
|
-
if (pipeline.name !== void 0) config.name = pipeline.name;
|
|
3808
|
-
if (pipeline.description !== void 0) config.description = pipeline.description;
|
|
3809
|
-
if (pipeline.metadata !== void 0) config.metadata = pipeline.metadata;
|
|
3810
|
-
return config;
|
|
3811
|
-
}
|
|
3812
|
-
function buildConfig(options, agents, pipelines, stores, sandboxCount = 0) {
|
|
3813
|
-
const models = options.models === void 0 ? void 0 : studioModelsConfig(createStudioModelRegistry(options.models), agents);
|
|
3814
|
-
const config = {
|
|
3815
|
-
id: runnerId(options),
|
|
3816
|
-
agents: agents.map(agentConfig),
|
|
3817
|
-
pipelines: pipelines.map(pipelineConfig),
|
|
3818
|
-
evals: options.evals.map(evalConfig),
|
|
3819
|
-
chat: {
|
|
3820
|
-
quickPrompts: Object.fromEntries(agents.map((agent) => [agent.id, agent.quickPrompts ?? []]))
|
|
3821
|
-
},
|
|
3822
|
-
capabilities: capabilityConfig(options, agents, pipelines, stores, sandboxCount),
|
|
3823
|
-
unsupportedCapabilities: unsupportedCapabilities(stores)
|
|
3824
|
-
};
|
|
3825
|
-
if (options.name !== void 0) config.name = options.name;
|
|
3826
|
-
if (options.description !== void 0) config.description = options.description;
|
|
3827
|
-
if (options.version !== void 0) config.version = options.version;
|
|
3828
|
-
if (models !== void 0) config.models = models;
|
|
3829
|
-
return config;
|
|
3830
|
-
}
|
|
3831
|
-
function capabilityConfig(_options, agents, pipelines, stores, sandboxCount = 0) {
|
|
3832
|
-
const capabilities = {
|
|
3833
|
-
agents: { enabled: true },
|
|
3834
|
-
observability: { enabled: true },
|
|
3835
|
-
status: { enabled: true }
|
|
3836
|
-
};
|
|
3837
|
-
if (stores.sessions !== void 0) {
|
|
3838
|
-
capabilities.sessions = { enabled: true };
|
|
3839
|
-
}
|
|
3840
|
-
if (stores.sessions !== void 0 || agents.some((agent) => agent.agent.memory !== void 0)) {
|
|
3841
|
-
capabilities.memory = { enabled: true };
|
|
3842
|
-
}
|
|
3843
|
-
if (stores.traces !== void 0) {
|
|
3844
|
-
capabilities.traces = { enabled: true };
|
|
3845
|
-
}
|
|
3846
|
-
if (pipelines.length > 0) {
|
|
3847
|
-
capabilities.pipelines = { enabled: true };
|
|
3848
|
-
}
|
|
3849
|
-
if (_options.evals.length > 0) {
|
|
3850
|
-
capabilities.evals = { enabled: true };
|
|
3851
|
-
}
|
|
3852
|
-
if (agents.some(
|
|
3853
|
-
(agent) => agent.agent.toolSet.values().length > 0 || agent.agent.dynamicTools.length > 0
|
|
3854
|
-
)) {
|
|
3855
|
-
capabilities.tools = { enabled: true };
|
|
3856
|
-
}
|
|
3857
|
-
if (agents.some(agentHasMcpTools)) {
|
|
3858
|
-
capabilities.mcps = { enabled: true };
|
|
3859
|
-
}
|
|
3860
|
-
if (sandboxCount > 0) {
|
|
3861
|
-
capabilities.sandboxes = { enabled: true };
|
|
3862
|
-
}
|
|
3863
|
-
if (agents.some(
|
|
3864
|
-
(agent) => agent.agent.hook !== void 0 || agent.agent.toolSet.values().some((tool) => tool.approval)
|
|
3865
|
-
)) {
|
|
3866
|
-
capabilities.approvals = { enabled: true };
|
|
3867
|
-
}
|
|
3868
|
-
if (agents.some(
|
|
3869
|
-
(agent) => agent.agent.staticContext.length > 0 || agent.agent.dynamicContexts.length > 0 || agent.agent.dynamicTools.length > 0
|
|
3870
|
-
)) {
|
|
3871
|
-
capabilities.knowledge = { enabled: true };
|
|
3872
|
-
}
|
|
3873
|
-
return capabilities;
|
|
3874
|
-
}
|
|
3875
|
-
function unsupportedCapabilities(stores) {
|
|
3876
|
-
const capabilities = [];
|
|
3877
|
-
if (stores.sessions === void 0) capabilities.push("sessions");
|
|
3878
|
-
if (stores.traces === void 0) capabilities.push("traces");
|
|
3879
|
-
return capabilities;
|
|
3880
|
-
}
|
|
3881
|
-
function toJsonValue2(value) {
|
|
3882
|
-
return serializeUnknown(value);
|
|
3883
|
-
}
|
|
3653
|
+
// src/runtime/knowledge.ts
|
|
3654
|
+
import { getAgentToolState } from "@anvia/core/internal/agent";
|
|
3884
3655
|
|
|
3885
|
-
// src/runtime/
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
"/evals",
|
|
3890
|
-
(c) => c.json({
|
|
3891
|
-
evals: props.evals.map(evalConfig)
|
|
3892
|
-
})
|
|
3893
|
-
);
|
|
3894
|
-
app.get("/evals/:evalId", (c) => {
|
|
3895
|
-
const suite = props.evalMap.get(c.req.param("evalId"));
|
|
3896
|
-
if (suite === void 0) {
|
|
3897
|
-
return errorResponse(c, 404, "not_found", "Eval suite not found");
|
|
3898
|
-
}
|
|
3899
|
-
return c.json(evalConfig(suite));
|
|
3900
|
-
});
|
|
3901
|
-
app.post("/evals/:evalId/runs", async (c) => {
|
|
3902
|
-
const suite = props.evalMap.get(c.req.param("evalId"));
|
|
3903
|
-
if (suite === void 0) {
|
|
3904
|
-
return errorResponse(c, 404, "not_found", "Eval suite not found");
|
|
3905
|
-
}
|
|
3906
|
-
const body = await parseEvalRunRequest(c);
|
|
3907
|
-
if ("error" in body) {
|
|
3908
|
-
return body.error;
|
|
3909
|
-
}
|
|
3910
|
-
const runId = globalThis.crypto.randomUUID();
|
|
3911
|
-
const startedAt = Date.now();
|
|
3912
|
-
const runOptions = { ...suite };
|
|
3913
|
-
if (body.concurrency !== void 0) runOptions.concurrency = body.concurrency;
|
|
3914
|
-
const result = await runEvalSuite(runOptions);
|
|
3915
|
-
const endedAt = Date.now();
|
|
3916
|
-
const jsonResult = toJsonValue(result);
|
|
3917
|
-
const response = {
|
|
3918
|
-
runId,
|
|
3919
|
-
suiteId: suite.id ?? suite.name,
|
|
3920
|
-
startedAt: new Date(startedAt).toISOString(),
|
|
3921
|
-
endedAt: new Date(endedAt).toISOString(),
|
|
3922
|
-
durationMs: endedAt - startedAt,
|
|
3923
|
-
result: isJsonObject(jsonResult) ? jsonResult : { value: jsonResult }
|
|
3924
|
-
};
|
|
3925
|
-
return c.json(response);
|
|
3926
|
-
});
|
|
3656
|
+
// src/runtime/query.ts
|
|
3657
|
+
function optionalQueryString(value) {
|
|
3658
|
+
const trimmed = value?.trim();
|
|
3659
|
+
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
3927
3660
|
}
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
body = await c.req.json();
|
|
3932
|
-
} catch {
|
|
3933
|
-
body = {};
|
|
3661
|
+
function parseLimit(value, defaultMax = 50, max = 100) {
|
|
3662
|
+
if (value === void 0 || value.trim().length === 0) {
|
|
3663
|
+
return defaultMax;
|
|
3934
3664
|
}
|
|
3935
|
-
|
|
3936
|
-
|
|
3665
|
+
const limit = Number(value);
|
|
3666
|
+
if (!Number.isInteger(limit) || limit <= 0) {
|
|
3667
|
+
return void 0;
|
|
3937
3668
|
}
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
}
|
|
3945
|
-
request.concurrency = body.concurrency;
|
|
3669
|
+
return Math.min(limit, max);
|
|
3670
|
+
}
|
|
3671
|
+
function parseTraceStatus(value) {
|
|
3672
|
+
const status = optionalQueryString(value);
|
|
3673
|
+
if (status === void 0) {
|
|
3674
|
+
return void 0;
|
|
3946
3675
|
}
|
|
3947
|
-
return
|
|
3676
|
+
return status === "running" || status === "success" || status === "suspended" || status === "error" ? status : false;
|
|
3677
|
+
}
|
|
3678
|
+
function parseAfter(value) {
|
|
3679
|
+
if (value === void 0 || value.trim().length === 0) {
|
|
3680
|
+
return void 0;
|
|
3681
|
+
}
|
|
3682
|
+
const after = Number(value);
|
|
3683
|
+
if (!Number.isInteger(after) || after < 0) {
|
|
3684
|
+
return false;
|
|
3685
|
+
}
|
|
3686
|
+
return after;
|
|
3948
3687
|
}
|
|
3949
3688
|
|
|
3950
3689
|
// src/runtime/knowledge.ts
|
|
@@ -3984,12 +3723,17 @@ function registerKnowledgeRoutes(app, props) {
|
|
|
3984
3723
|
return c.json(page);
|
|
3985
3724
|
});
|
|
3986
3725
|
}
|
|
3726
|
+
function agentHasKnowledge(agent) {
|
|
3727
|
+
const toolIndexes = getAgentToolState(agent.agent).toolIndexes;
|
|
3728
|
+
return agent.agent.context.length > 0 || toolIndexes.length > 0;
|
|
3729
|
+
}
|
|
3987
3730
|
async function agentKnowledgeConfig(agent) {
|
|
3988
3731
|
const agentName = agent.name ?? agent.agent.name;
|
|
3732
|
+
const staticContext = staticContextDocuments(agent.agent);
|
|
3989
3733
|
const config = {
|
|
3990
3734
|
agentId: agent.id,
|
|
3991
3735
|
sources: await knowledgeSources(agent),
|
|
3992
|
-
staticContext:
|
|
3736
|
+
staticContext: staticContext.map((document) => {
|
|
3993
3737
|
const item = { id: document.id, text: document.text };
|
|
3994
3738
|
if (document.additionalProps !== void 0) {
|
|
3995
3739
|
item.additionalProps = jsonObjectFromRecord(document.additionalProps);
|
|
@@ -4001,51 +3745,54 @@ async function agentKnowledgeConfig(agent) {
|
|
|
4001
3745
|
return config;
|
|
4002
3746
|
}
|
|
4003
3747
|
async function knowledgeSources(agent) {
|
|
3748
|
+
const toolIndexes = getAgentToolState(agent.agent).toolIndexes;
|
|
3749
|
+
const staticContext = staticContextDocuments(agent.agent);
|
|
3750
|
+
const indexedContext = vectorContexts(agent.agent);
|
|
4004
3751
|
const sources = [
|
|
4005
3752
|
{
|
|
4006
3753
|
sourceId: staticSourceId(),
|
|
4007
3754
|
kind: "static_context",
|
|
4008
3755
|
label: "Static context",
|
|
4009
|
-
count:
|
|
3756
|
+
count: staticContext.length,
|
|
4010
3757
|
inspectable: true,
|
|
4011
|
-
itemCount:
|
|
3758
|
+
itemCount: staticContext.length
|
|
4012
3759
|
}
|
|
4013
3760
|
];
|
|
4014
3761
|
const dynamicContextSources = await Promise.all(
|
|
4015
|
-
|
|
4016
|
-
const inspect = inspectFn(
|
|
4017
|
-
const count = await inspectableCount(inspect,
|
|
3762
|
+
indexedContext.map(async (vectorContext, index) => {
|
|
3763
|
+
const inspect = inspectFn(vectorContext.store);
|
|
3764
|
+
const count = await inspectableCount(inspect, vectorContext.filter);
|
|
4018
3765
|
const source = {
|
|
4019
3766
|
sourceId: dynamicContextSourceId(index),
|
|
4020
3767
|
kind: "dynamic_context",
|
|
4021
3768
|
label: `Dynamic context ${index + 1}`,
|
|
4022
3769
|
count: 1,
|
|
4023
3770
|
registrationIndex: index,
|
|
4024
|
-
topK:
|
|
3771
|
+
topK: vectorContext.topK,
|
|
4025
3772
|
inspectable: inspect !== void 0
|
|
4026
3773
|
};
|
|
4027
|
-
if (
|
|
4028
|
-
source.
|
|
3774
|
+
if (vectorContext.minScore !== void 0) {
|
|
3775
|
+
source.minScore = vectorContext.minScore;
|
|
4029
3776
|
}
|
|
4030
3777
|
if (count !== void 0) source.itemCount = count;
|
|
4031
3778
|
return source;
|
|
4032
3779
|
})
|
|
4033
3780
|
);
|
|
4034
3781
|
const dynamicToolSources = await Promise.all(
|
|
4035
|
-
|
|
4036
|
-
const inspect = inspectFn(
|
|
4037
|
-
const count = await inspectableCount(inspect,
|
|
3782
|
+
toolIndexes.map(async (toolIndex, index) => {
|
|
3783
|
+
const inspect = inspectFn(toolIndex);
|
|
3784
|
+
const count = await inspectableCount(inspect, toolIndex.filter);
|
|
4038
3785
|
const source = {
|
|
4039
3786
|
sourceId: dynamicToolsSourceId(index),
|
|
4040
3787
|
kind: "dynamic_tools",
|
|
4041
3788
|
label: `Dynamic tools ${index + 1}`,
|
|
4042
3789
|
count: 1,
|
|
4043
3790
|
registrationIndex: index,
|
|
4044
|
-
topK:
|
|
3791
|
+
topK: toolIndex.topK,
|
|
4045
3792
|
inspectable: inspect !== void 0
|
|
4046
3793
|
};
|
|
4047
|
-
if (
|
|
4048
|
-
source.
|
|
3794
|
+
if (toolIndex.minScore !== void 0) {
|
|
3795
|
+
source.minScore = toolIndex.minScore;
|
|
4049
3796
|
}
|
|
4050
3797
|
if (count !== void 0) source.itemCount = count;
|
|
4051
3798
|
return source;
|
|
@@ -4064,20 +3811,20 @@ async function knowledgeItemsPage(agent, sourceId, request) {
|
|
|
4064
3811
|
if (sourceId === staticSourceId()) {
|
|
4065
3812
|
return staticKnowledgeItemsPage(agent, request);
|
|
4066
3813
|
}
|
|
4067
|
-
const
|
|
4068
|
-
if (
|
|
4069
|
-
const
|
|
4070
|
-
if (
|
|
3814
|
+
const vectorContextIndex = dynamicSourceIndex(sourceId, "dynamic_context");
|
|
3815
|
+
if (vectorContextIndex !== void 0) {
|
|
3816
|
+
const vectorContext = vectorContexts(agent.agent)[vectorContextIndex];
|
|
3817
|
+
if (vectorContext === void 0) {
|
|
4071
3818
|
return void 0;
|
|
4072
3819
|
}
|
|
4073
|
-
const inspect = inspectFn(
|
|
3820
|
+
const inspect = inspectFn(vectorContext.store);
|
|
4074
3821
|
if (inspect === void 0) {
|
|
4075
3822
|
return nonInspectablePage(agent.id, sourceId, "dynamic_context");
|
|
4076
3823
|
}
|
|
4077
3824
|
const page = await inspect({
|
|
4078
3825
|
limit: request.limit,
|
|
4079
3826
|
cursor: request.cursor,
|
|
4080
|
-
filter:
|
|
3827
|
+
filter: vectorContext.filter
|
|
4081
3828
|
});
|
|
4082
3829
|
const result = {
|
|
4083
3830
|
agentId: agent.id,
|
|
@@ -4092,18 +3839,18 @@ async function knowledgeItemsPage(agent, sourceId, request) {
|
|
|
4092
3839
|
}
|
|
4093
3840
|
const dynamicToolsIndex = dynamicSourceIndex(sourceId, "dynamic_tools");
|
|
4094
3841
|
if (dynamicToolsIndex !== void 0) {
|
|
4095
|
-
const
|
|
4096
|
-
if (
|
|
3842
|
+
const toolIndex = getAgentToolState(agent.agent).toolIndexes[dynamicToolsIndex];
|
|
3843
|
+
if (toolIndex === void 0) {
|
|
4097
3844
|
return void 0;
|
|
4098
3845
|
}
|
|
4099
|
-
const inspect = inspectFn(
|
|
3846
|
+
const inspect = inspectFn(toolIndex);
|
|
4100
3847
|
if (inspect === void 0) {
|
|
4101
3848
|
return nonInspectablePage(agent.id, sourceId, "dynamic_tools");
|
|
4102
3849
|
}
|
|
4103
3850
|
const page = await inspect({
|
|
4104
3851
|
limit: request.limit,
|
|
4105
3852
|
cursor: request.cursor,
|
|
4106
|
-
filter:
|
|
3853
|
+
filter: toolIndex.filter
|
|
4107
3854
|
});
|
|
4108
3855
|
const result = {
|
|
4109
3856
|
agentId: agent.id,
|
|
@@ -4118,16 +3865,17 @@ async function knowledgeItemsPage(agent, sourceId, request) {
|
|
|
4118
3865
|
}
|
|
4119
3866
|
return void 0;
|
|
4120
3867
|
}
|
|
4121
|
-
function inspectFn(
|
|
4122
|
-
if (!isRecord3(
|
|
3868
|
+
function inspectFn(store) {
|
|
3869
|
+
if (!isRecord3(store) || typeof store.inspect !== "function") {
|
|
4123
3870
|
return void 0;
|
|
4124
3871
|
}
|
|
4125
|
-
const inspect =
|
|
4126
|
-
return (request) => inspect.call(
|
|
3872
|
+
const inspect = store.inspect;
|
|
3873
|
+
return (request) => inspect.call(store, request);
|
|
4127
3874
|
}
|
|
4128
3875
|
function staticKnowledgeItemsPage(agent, request) {
|
|
3876
|
+
const staticContext = staticContextDocuments(agent.agent);
|
|
4129
3877
|
const start = Math.max(0, Math.trunc(Number(request.cursor ?? "0")));
|
|
4130
|
-
const page =
|
|
3878
|
+
const page = staticContext.slice(start, start + request.limit);
|
|
4131
3879
|
const nextOffset = start + page.length;
|
|
4132
3880
|
const result = {
|
|
4133
3881
|
agentId: agent.id,
|
|
@@ -4145,9 +3893,9 @@ function staticKnowledgeItemsPage(agent, request) {
|
|
|
4145
3893
|
}
|
|
4146
3894
|
return item;
|
|
4147
3895
|
}),
|
|
4148
|
-
totalCount:
|
|
3896
|
+
totalCount: staticContext.length
|
|
4149
3897
|
};
|
|
4150
|
-
if (nextOffset <
|
|
3898
|
+
if (nextOffset < staticContext.length) result.nextCursor = String(nextOffset);
|
|
4151
3899
|
return result;
|
|
4152
3900
|
}
|
|
4153
3901
|
function nonInspectablePage(agentId, sourceId, kind) {
|
|
@@ -4336,6 +4084,283 @@ function isRecord3(value) {
|
|
|
4336
4084
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4337
4085
|
}
|
|
4338
4086
|
|
|
4087
|
+
// src/runtime/tool-metadata.ts
|
|
4088
|
+
import { getAgentToolState as getAgentToolState2 } from "@anvia/core/internal/agent";
|
|
4089
|
+
import { isMcpTool } from "@anvia/core/mcp";
|
|
4090
|
+
function agentToolItems(agent) {
|
|
4091
|
+
const state = getAgentToolState2(agent.agent);
|
|
4092
|
+
const items = state.staticTools.map((tool) => ({ tool, source: "static" }));
|
|
4093
|
+
const names = new Set(items.map(({ tool }) => tool.name));
|
|
4094
|
+
for (const index of state.toolIndexes) {
|
|
4095
|
+
for (const tool of index.tools) {
|
|
4096
|
+
if (!names.has(tool.name)) {
|
|
4097
|
+
names.add(tool.name);
|
|
4098
|
+
items.push({ tool, source: "dynamic" });
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
4102
|
+
return items;
|
|
4103
|
+
}
|
|
4104
|
+
function approvalMetadata(tool) {
|
|
4105
|
+
const approval = tool.requiresApproval;
|
|
4106
|
+
if (approval === void 0 || approval === false) {
|
|
4107
|
+
return { required: false };
|
|
4108
|
+
}
|
|
4109
|
+
if (typeof approval !== "object" || approval === null) {
|
|
4110
|
+
return { required: true };
|
|
4111
|
+
}
|
|
4112
|
+
const policy = approval;
|
|
4113
|
+
const metadata = { required: true };
|
|
4114
|
+
if (typeof policy.reason === "string") metadata.reason = policy.reason;
|
|
4115
|
+
return metadata;
|
|
4116
|
+
}
|
|
4117
|
+
function toolRequiresApproval(tool) {
|
|
4118
|
+
const approval = tool.requiresApproval;
|
|
4119
|
+
return approval !== void 0 && approval !== false;
|
|
4120
|
+
}
|
|
4121
|
+
function mcpServerName(tool) {
|
|
4122
|
+
return isMcpTool(tool) ? tool.mcp.serverName : void 0;
|
|
4123
|
+
}
|
|
4124
|
+
function agentHasMcpServers(agent) {
|
|
4125
|
+
return agent.agent.mcpServers.length > 0;
|
|
4126
|
+
}
|
|
4127
|
+
|
|
4128
|
+
// src/runtime/config.ts
|
|
4129
|
+
function runnerId(options) {
|
|
4130
|
+
return options.id ?? "anvia-studio";
|
|
4131
|
+
}
|
|
4132
|
+
function agentConfig(agent) {
|
|
4133
|
+
const name = agent.name ?? agent.agent.name;
|
|
4134
|
+
const description = agent.description ?? agent.agent.description;
|
|
4135
|
+
const config = {
|
|
4136
|
+
id: agent.id,
|
|
4137
|
+
quickPrompts: agent.quickPrompts ?? []
|
|
4138
|
+
};
|
|
4139
|
+
if (name !== void 0) config.name = name;
|
|
4140
|
+
if (description !== void 0) config.description = description;
|
|
4141
|
+
if (agent.metadata !== void 0) config.metadata = agent.metadata;
|
|
4142
|
+
return config;
|
|
4143
|
+
}
|
|
4144
|
+
function agentRuntimeSummary(agent) {
|
|
4145
|
+
const tools = agentToolItems(agent);
|
|
4146
|
+
const staticContext = staticContextDocuments(agent.agent);
|
|
4147
|
+
const indexedContext = vectorContexts(agent.agent);
|
|
4148
|
+
const name = agent.name ?? agent.agent.name;
|
|
4149
|
+
const description = agent.description ?? agent.agent.description;
|
|
4150
|
+
const summary = {
|
|
4151
|
+
id: agent.id,
|
|
4152
|
+
model: toJsonValue2(agent.agent.model),
|
|
4153
|
+
toolCount: tools.length,
|
|
4154
|
+
staticToolCount: tools.filter((item) => item.source === "static").length,
|
|
4155
|
+
dynamicToolCount: tools.filter((item) => item.source === "dynamic").length,
|
|
4156
|
+
approvalToolCount: tools.filter((item) => toolRequiresApproval(item.tool)).length,
|
|
4157
|
+
mcpToolCount: tools.filter((item) => mcpServerName(item.tool) !== void 0).length,
|
|
4158
|
+
staticContextCount: staticContext.length,
|
|
4159
|
+
dynamicContextCount: indexedContext.length,
|
|
4160
|
+
observerCount: Object.keys(agent.agent.observability?.observers ?? {}).length,
|
|
4161
|
+
hasMemory: agent.agent.memory !== void 0,
|
|
4162
|
+
hasLifecycle: agent.agent.lifecycle !== void 0,
|
|
4163
|
+
hasOutputSchema: agent.agent.outputSchema !== void 0
|
|
4164
|
+
};
|
|
4165
|
+
if (name !== void 0) summary.name = name;
|
|
4166
|
+
if (description !== void 0) summary.description = description;
|
|
4167
|
+
if (agent.agent.defaultMaxTurns !== void 0) {
|
|
4168
|
+
summary.defaultMaxTurns = agent.agent.defaultMaxTurns;
|
|
4169
|
+
}
|
|
4170
|
+
if (agent.metadata !== void 0) summary.metadata = agent.metadata;
|
|
4171
|
+
return summary;
|
|
4172
|
+
}
|
|
4173
|
+
function pipelineConfig(pipeline) {
|
|
4174
|
+
const graph = pipeline.pipeline.graph();
|
|
4175
|
+
const stageNodes = graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output");
|
|
4176
|
+
const config = {
|
|
4177
|
+
id: pipeline.id,
|
|
4178
|
+
stageCount: stageNodes.length,
|
|
4179
|
+
edgeCount: graph.edges.length,
|
|
4180
|
+
hasParallelStages: graph.nodes.some((node) => node.kind === "parallel"),
|
|
4181
|
+
agentCount: graph.nodes.filter((node) => node.kind === "agent").length,
|
|
4182
|
+
extractorCount: graph.nodes.filter((node) => node.kind === "extractor").length
|
|
4183
|
+
};
|
|
4184
|
+
if (pipeline.name !== void 0) config.name = pipeline.name;
|
|
4185
|
+
if (pipeline.description !== void 0) config.description = pipeline.description;
|
|
4186
|
+
if (pipeline.metadata !== void 0) config.metadata = pipeline.metadata;
|
|
4187
|
+
return config;
|
|
4188
|
+
}
|
|
4189
|
+
function buildConfig(options, agents, pipelines, stores, sandboxCount = 0) {
|
|
4190
|
+
const models = options.models === void 0 ? void 0 : studioModelsConfig(createStudioModelRegistry(options.models), agents);
|
|
4191
|
+
const config = {
|
|
4192
|
+
id: runnerId(options),
|
|
4193
|
+
agents: agents.map(agentConfig),
|
|
4194
|
+
pipelines: pipelines.map(pipelineConfig),
|
|
4195
|
+
evals: options.evals.map(evalConfig),
|
|
4196
|
+
chat: {
|
|
4197
|
+
quickPrompts: Object.fromEntries(agents.map((agent) => [agent.id, agent.quickPrompts ?? []]))
|
|
4198
|
+
},
|
|
4199
|
+
capabilities: capabilityConfig(options, agents, pipelines, stores, sandboxCount),
|
|
4200
|
+
unsupportedCapabilities: unsupportedCapabilities(stores)
|
|
4201
|
+
};
|
|
4202
|
+
if (options.name !== void 0) config.name = options.name;
|
|
4203
|
+
if (options.description !== void 0) config.description = options.description;
|
|
4204
|
+
if (options.version !== void 0) config.version = options.version;
|
|
4205
|
+
if (models !== void 0) config.models = models;
|
|
4206
|
+
return config;
|
|
4207
|
+
}
|
|
4208
|
+
function capabilityConfig(_options, agents, pipelines, stores, sandboxCount = 0) {
|
|
4209
|
+
const capabilities = {
|
|
4210
|
+
agents: { enabled: true },
|
|
4211
|
+
observability: { enabled: true },
|
|
4212
|
+
status: { enabled: true }
|
|
4213
|
+
};
|
|
4214
|
+
if (stores.sessions !== void 0) {
|
|
4215
|
+
capabilities.sessions = { enabled: true };
|
|
4216
|
+
}
|
|
4217
|
+
if (stores.sessions !== void 0 || agents.some((agent) => agent.agent.memory !== void 0)) {
|
|
4218
|
+
capabilities.memory = { enabled: true };
|
|
4219
|
+
}
|
|
4220
|
+
if (stores.traces !== void 0) {
|
|
4221
|
+
capabilities.traces = { enabled: true };
|
|
4222
|
+
}
|
|
4223
|
+
if (pipelines.length > 0) {
|
|
4224
|
+
capabilities.pipelines = { enabled: true };
|
|
4225
|
+
}
|
|
4226
|
+
if (_options.evals.length > 0) {
|
|
4227
|
+
capabilities.evals = { enabled: true };
|
|
4228
|
+
}
|
|
4229
|
+
if (agents.some((agent) => agent.agent.tools.length > 0)) {
|
|
4230
|
+
capabilities.tools = { enabled: true };
|
|
4231
|
+
}
|
|
4232
|
+
if (agents.some(agentHasMcpServers)) {
|
|
4233
|
+
capabilities.mcps = { enabled: true };
|
|
4234
|
+
}
|
|
4235
|
+
if (sandboxCount > 0) {
|
|
4236
|
+
capabilities.sandboxes = { enabled: true };
|
|
4237
|
+
}
|
|
4238
|
+
if (agents.some(
|
|
4239
|
+
(agent) => agent.agent.tools.some((tool) => toolRequiresApproval(tool) || isQuestionTool(tool))
|
|
4240
|
+
)) {
|
|
4241
|
+
capabilities.interactions = { enabled: true };
|
|
4242
|
+
}
|
|
4243
|
+
if (agents.some(agentHasKnowledge)) {
|
|
4244
|
+
capabilities.knowledge = { enabled: true };
|
|
4245
|
+
}
|
|
4246
|
+
return capabilities;
|
|
4247
|
+
}
|
|
4248
|
+
function unsupportedCapabilities(stores) {
|
|
4249
|
+
const capabilities = [];
|
|
4250
|
+
if (stores.sessions === void 0) capabilities.push("sessions");
|
|
4251
|
+
if (stores.traces === void 0) capabilities.push("traces");
|
|
4252
|
+
return capabilities;
|
|
4253
|
+
}
|
|
4254
|
+
function toJsonValue2(value) {
|
|
4255
|
+
return serializeUnknown(value);
|
|
4256
|
+
}
|
|
4257
|
+
|
|
4258
|
+
// src/runtime/evals.ts
|
|
4259
|
+
import { runEvalSuite } from "@anvia/core/evals";
|
|
4260
|
+
function registerEvalRoutes(app, props) {
|
|
4261
|
+
app.get(
|
|
4262
|
+
"/evals",
|
|
4263
|
+
(c) => c.json({
|
|
4264
|
+
evals: props.evals.map(evalConfig)
|
|
4265
|
+
})
|
|
4266
|
+
);
|
|
4267
|
+
app.get("/evals/:evalId", (c) => {
|
|
4268
|
+
const suite = props.evalMap.get(c.req.param("evalId"));
|
|
4269
|
+
if (suite === void 0) {
|
|
4270
|
+
return errorResponse(c, 404, "not_found", "Eval suite not found");
|
|
4271
|
+
}
|
|
4272
|
+
return c.json(evalConfig(suite));
|
|
4273
|
+
});
|
|
4274
|
+
app.post("/evals/:evalId/runs", async (c) => {
|
|
4275
|
+
const suite = props.evalMap.get(c.req.param("evalId"));
|
|
4276
|
+
if (suite === void 0) {
|
|
4277
|
+
return errorResponse(c, 404, "not_found", "Eval suite not found");
|
|
4278
|
+
}
|
|
4279
|
+
const body = await parseEvalRunRequest(c);
|
|
4280
|
+
if ("error" in body) {
|
|
4281
|
+
return body.error;
|
|
4282
|
+
}
|
|
4283
|
+
const runId = globalThis.crypto.randomUUID();
|
|
4284
|
+
const startedAt = Date.now();
|
|
4285
|
+
const runOptions = { ...suite };
|
|
4286
|
+
if (body.concurrency !== void 0) runOptions.concurrency = body.concurrency;
|
|
4287
|
+
const result = await runEvalSuite(runOptions);
|
|
4288
|
+
const endedAt = Date.now();
|
|
4289
|
+
const jsonResult = toJsonValue(result);
|
|
4290
|
+
const response = {
|
|
4291
|
+
runId,
|
|
4292
|
+
suiteId: suite.id ?? suite.name,
|
|
4293
|
+
startedAt: new Date(startedAt).toISOString(),
|
|
4294
|
+
endedAt: new Date(endedAt).toISOString(),
|
|
4295
|
+
durationMs: endedAt - startedAt,
|
|
4296
|
+
result: isJsonObject(jsonResult) ? jsonResult : { value: jsonResult }
|
|
4297
|
+
};
|
|
4298
|
+
return c.json(response);
|
|
4299
|
+
});
|
|
4300
|
+
}
|
|
4301
|
+
async function parseEvalRunRequest(c) {
|
|
4302
|
+
let body = {};
|
|
4303
|
+
try {
|
|
4304
|
+
body = await c.req.json();
|
|
4305
|
+
} catch {
|
|
4306
|
+
body = {};
|
|
4307
|
+
}
|
|
4308
|
+
if (!isObject(body)) {
|
|
4309
|
+
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
4310
|
+
}
|
|
4311
|
+
const request = {};
|
|
4312
|
+
if ("concurrency" in body) {
|
|
4313
|
+
if (!isPositiveInteger(body.concurrency)) {
|
|
4314
|
+
return {
|
|
4315
|
+
error: errorResponse(c, 400, "bad_request", "concurrency must be a positive integer")
|
|
4316
|
+
};
|
|
4317
|
+
}
|
|
4318
|
+
request.concurrency = body.concurrency;
|
|
4319
|
+
}
|
|
4320
|
+
return request;
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4323
|
+
// src/runtime/interactions.ts
|
|
4324
|
+
import {
|
|
4325
|
+
assertAgentInteractionResponse
|
|
4326
|
+
} from "@anvia/core/agent/interactions";
|
|
4327
|
+
function createStudioContinuationRegistry() {
|
|
4328
|
+
const pending = /* @__PURE__ */ new Map();
|
|
4329
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
4330
|
+
return {
|
|
4331
|
+
register(registration) {
|
|
4332
|
+
const id = registration.continuation.interaction.id;
|
|
4333
|
+
if (pending.has(id) || claimed.has(id)) {
|
|
4334
|
+
throw new TypeError(`Duplicate Studio interaction ID "${id}".`);
|
|
4335
|
+
}
|
|
4336
|
+
pending.set(id, registration);
|
|
4337
|
+
},
|
|
4338
|
+
take(interactionId, agentId, response) {
|
|
4339
|
+
if (claimed.has(interactionId)) return { status: "claimed" };
|
|
4340
|
+
const registration = pending.get(interactionId);
|
|
4341
|
+
if (registration === void 0 || registration.continuation.agentId !== agentId) {
|
|
4342
|
+
return { status: "missing" };
|
|
4343
|
+
}
|
|
4344
|
+
const request = registration.continuation.interaction;
|
|
4345
|
+
try {
|
|
4346
|
+
assertAgentInteractionResponse(request, response);
|
|
4347
|
+
} catch (error) {
|
|
4348
|
+
return {
|
|
4349
|
+
status: "invalid",
|
|
4350
|
+
error: error instanceof TypeError ? error : new TypeError(String(error))
|
|
4351
|
+
};
|
|
4352
|
+
}
|
|
4353
|
+
pending.delete(interactionId);
|
|
4354
|
+
claimed.add(interactionId);
|
|
4355
|
+
return { status: "ready", registration };
|
|
4356
|
+
},
|
|
4357
|
+
clear() {
|
|
4358
|
+
pending.clear();
|
|
4359
|
+
claimed.clear();
|
|
4360
|
+
}
|
|
4361
|
+
};
|
|
4362
|
+
}
|
|
4363
|
+
|
|
4339
4364
|
// src/runtime/mcps.ts
|
|
4340
4365
|
function registerMcpRoutes(app, props) {
|
|
4341
4366
|
app.get("/agents/:agentId/mcps", async (c) => {
|
|
@@ -4351,43 +4376,29 @@ function registerMcpRoutes(app, props) {
|
|
|
4351
4376
|
});
|
|
4352
4377
|
}
|
|
4353
4378
|
async function agentMcpMetadata(agent) {
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
return [...servers.entries()].map(([name, tools]) => {
|
|
4378
|
-
const sortedTools = tools.sort((left, right) => {
|
|
4379
|
-
if (left.source !== right.source) {
|
|
4380
|
-
return left.source === "static" ? -1 : 1;
|
|
4381
|
-
}
|
|
4382
|
-
return left.name.localeCompare(right.name);
|
|
4383
|
-
});
|
|
4384
|
-
return {
|
|
4385
|
-
agentId: agent.id,
|
|
4386
|
-
name,
|
|
4387
|
-
toolCount: sortedTools.length,
|
|
4388
|
-
tools: sortedTools
|
|
4389
|
-
};
|
|
4390
|
-
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
4379
|
+
return Promise.all(
|
|
4380
|
+
agent.agent.mcpServers.map(async (server) => {
|
|
4381
|
+
const tools = await Promise.all(
|
|
4382
|
+
server.tools.map(async (tool) => {
|
|
4383
|
+
const definition = await tool.definition("");
|
|
4384
|
+
return {
|
|
4385
|
+
name: definition.name,
|
|
4386
|
+
description: definition.description,
|
|
4387
|
+
parameters: definition.parameters,
|
|
4388
|
+
source: "static",
|
|
4389
|
+
approval: approvalMetadata(tool)
|
|
4390
|
+
};
|
|
4391
|
+
})
|
|
4392
|
+
);
|
|
4393
|
+
const sortedTools = tools.sort((left, right) => left.name.localeCompare(right.name));
|
|
4394
|
+
return {
|
|
4395
|
+
agentId: agent.id,
|
|
4396
|
+
name: server.name,
|
|
4397
|
+
toolCount: sortedTools.length,
|
|
4398
|
+
tools: sortedTools
|
|
4399
|
+
};
|
|
4400
|
+
})
|
|
4401
|
+
).then((servers) => servers.sort((left, right) => left.name.localeCompare(right.name)));
|
|
4391
4402
|
}
|
|
4392
4403
|
|
|
4393
4404
|
// src/runtime/memory.ts
|
|
@@ -4609,7 +4620,7 @@ function agentMemorySource(ref, label, agentId, storeKindValue, inspector) {
|
|
|
4609
4620
|
).slice(0, options.limit);
|
|
4610
4621
|
},
|
|
4611
4622
|
async getConversation(conversationRef) {
|
|
4612
|
-
const conversation = await inspector.getConversation(conversationRef);
|
|
4623
|
+
const conversation = await inspector.getConversation({ ref: conversationRef });
|
|
4613
4624
|
return conversation === void 0 ? void 0 : inspectorConversationDetail(conversation, summary.agentIds);
|
|
4614
4625
|
}
|
|
4615
4626
|
};
|
|
@@ -4832,12 +4843,12 @@ function pipelineRunFailedLog(pipelineId, runId, error, startedAt) {
|
|
|
4832
4843
|
}
|
|
4833
4844
|
};
|
|
4834
4845
|
}
|
|
4835
|
-
function pipelineStageLog(
|
|
4846
|
+
function pipelineStageLog(event, studioPipelineId = event.pipelineId) {
|
|
4836
4847
|
const category = stageCategory(event.node);
|
|
4837
4848
|
if (event.type === "stage_started") {
|
|
4838
4849
|
return {
|
|
4839
|
-
pipelineId,
|
|
4840
|
-
runId,
|
|
4850
|
+
pipelineId: studioPipelineId,
|
|
4851
|
+
runId: event.runId,
|
|
4841
4852
|
level: "debug",
|
|
4842
4853
|
category,
|
|
4843
4854
|
event: `${event.node.kind}.started`,
|
|
@@ -4847,8 +4858,8 @@ function pipelineStageLog(pipelineId, runId, event) {
|
|
|
4847
4858
|
}
|
|
4848
4859
|
if (event.type === "stage_completed") {
|
|
4849
4860
|
return {
|
|
4850
|
-
pipelineId,
|
|
4851
|
-
runId,
|
|
4861
|
+
pipelineId: studioPipelineId,
|
|
4862
|
+
runId: event.runId,
|
|
4852
4863
|
level: "debug",
|
|
4853
4864
|
category,
|
|
4854
4865
|
event: `${event.node.kind}.completed`,
|
|
@@ -4860,8 +4871,8 @@ function pipelineStageLog(pipelineId, runId, event) {
|
|
|
4860
4871
|
};
|
|
4861
4872
|
}
|
|
4862
4873
|
return {
|
|
4863
|
-
pipelineId,
|
|
4864
|
-
runId,
|
|
4874
|
+
pipelineId: studioPipelineId,
|
|
4875
|
+
runId: event.runId,
|
|
4865
4876
|
level: "error",
|
|
4866
4877
|
category,
|
|
4867
4878
|
event: `${event.node.kind}.failed`,
|
|
@@ -4888,6 +4899,7 @@ function stageCategory(node) {
|
|
|
4888
4899
|
function nodeMetadata(node) {
|
|
4889
4900
|
const metadata = {
|
|
4890
4901
|
nodeId: node.id,
|
|
4902
|
+
nodePath: [...node.path],
|
|
4891
4903
|
kind: node.kind,
|
|
4892
4904
|
label: node.label
|
|
4893
4905
|
};
|
|
@@ -5049,17 +5061,24 @@ async function executePipelineRun(c, props, pipeline, body) {
|
|
|
5049
5061
|
if (body.metadata !== void 0) streamOptions.metadata = body.metadata;
|
|
5050
5062
|
if (props.logStore !== void 0) streamOptions.logStore = props.logStore;
|
|
5051
5063
|
if (props.runStore !== void 0) streamOptions.runStore = props.runStore;
|
|
5064
|
+
streamOptions.abortSignal = c.req.raw.signal;
|
|
5052
5065
|
return streamPipelineRun(c, streamOptions);
|
|
5053
5066
|
}
|
|
5054
5067
|
try {
|
|
5055
5068
|
await appendPipelineLog(props.logStore, pipelineRunStartedLog(pipeline, runId));
|
|
5056
|
-
const
|
|
5069
|
+
const result = await pipeline.pipeline.run({
|
|
5070
|
+
input: body.input,
|
|
5071
|
+
runId,
|
|
5072
|
+
metadata: body.metadata,
|
|
5073
|
+
abortSignal: c.req.raw.signal,
|
|
5057
5074
|
observer: {
|
|
5058
5075
|
async onEvent(event) {
|
|
5059
|
-
await appendPipelineLog(props.logStore, pipelineStageLog(pipeline.id
|
|
5076
|
+
await appendPipelineLog(props.logStore, pipelineStageLog(event, pipeline.id));
|
|
5060
5077
|
}
|
|
5061
|
-
}
|
|
5078
|
+
},
|
|
5079
|
+
failOnObserverError: true
|
|
5062
5080
|
});
|
|
5081
|
+
const output = result.output;
|
|
5063
5082
|
const jsonOutput = toJsonValue(output);
|
|
5064
5083
|
const endedAt = Date.now();
|
|
5065
5084
|
const successRecord = {
|
|
@@ -5124,19 +5143,24 @@ function streamPipelineRun(_c, props) {
|
|
|
5124
5143
|
async function* pipelineRunEvents(props) {
|
|
5125
5144
|
yield* emitPipelineLog(props.logStore, pipelineRunStartedLog(props.pipeline, props.runId));
|
|
5126
5145
|
const events = new AsyncEventQueue();
|
|
5127
|
-
const run = props.pipeline.pipeline.run(
|
|
5146
|
+
const run = props.pipeline.pipeline.run({
|
|
5147
|
+
input: props.input,
|
|
5148
|
+
runId: props.runId,
|
|
5149
|
+
metadata: props.metadata,
|
|
5150
|
+
abortSignal: props.abortSignal,
|
|
5128
5151
|
observer: {
|
|
5129
5152
|
async onEvent(event) {
|
|
5130
5153
|
const log = await appendPipelineLog(
|
|
5131
5154
|
props.logStore,
|
|
5132
|
-
pipelineStageLog(props.pipeline.id
|
|
5155
|
+
pipelineStageLog(event, props.pipeline.id)
|
|
5133
5156
|
);
|
|
5134
5157
|
if (log !== void 0) {
|
|
5135
5158
|
events.push({ type: "pipeline_log", log });
|
|
5136
5159
|
}
|
|
5137
5160
|
}
|
|
5138
|
-
}
|
|
5139
|
-
|
|
5161
|
+
},
|
|
5162
|
+
failOnObserverError: true
|
|
5163
|
+
}).then(async ({ output }) => {
|
|
5140
5164
|
const jsonOutput = toJsonValue(output);
|
|
5141
5165
|
const endedAt = Date.now();
|
|
5142
5166
|
const successRecord = {
|
|
@@ -5289,272 +5313,284 @@ function parsePipelineLogAfter(value) {
|
|
|
5289
5313
|
return after;
|
|
5290
5314
|
}
|
|
5291
5315
|
|
|
5292
|
-
// src/runtime/
|
|
5293
|
-
import {
|
|
5294
|
-
import {
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
const
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
}
|
|
5308
|
-
if (runId !== void 0) {
|
|
5309
|
-
options.runId = runId;
|
|
5310
|
-
}
|
|
5311
|
-
if (agentId !== void 0) {
|
|
5312
|
-
options.agentId = agentId;
|
|
5313
|
-
}
|
|
5314
|
-
if (sessionId !== void 0) {
|
|
5315
|
-
options.sessionId = sessionId;
|
|
5316
|
-
}
|
|
5317
|
-
return c.json({ questions: questions.list(options) });
|
|
5316
|
+
// src/runtime/sandbox-views.ts
|
|
5317
|
+
import { upgradeWebSocket } from "@hono/node-server";
|
|
5318
|
+
import { getConnInfo } from "@hono/node-server/conninfo";
|
|
5319
|
+
import { WebSocket } from "ws";
|
|
5320
|
+
var minLeaseTimeoutMs = 5e3;
|
|
5321
|
+
var maxLeaseTimeoutMs = 12e4;
|
|
5322
|
+
var maxPendingWebSocketBytes = 1024 * 1024;
|
|
5323
|
+
function registerSandboxViewRoutes(app, registry) {
|
|
5324
|
+
const leases = /* @__PURE__ */ new Map();
|
|
5325
|
+
const upstreamSockets = /* @__PURE__ */ new Set();
|
|
5326
|
+
app.get("/sandboxes/:sandboxRef/views/:viewId/control", async (c) => {
|
|
5327
|
+
const resolved = await authorizedView(c, registry);
|
|
5328
|
+
if (resolved instanceof Response) return resolved;
|
|
5329
|
+
pruneExpiredLease(leases, viewKey(resolved));
|
|
5330
|
+
return c.json(resolved.view.source.control.snapshot());
|
|
5318
5331
|
});
|
|
5319
|
-
app.
|
|
5320
|
-
const
|
|
5321
|
-
if (
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
return c.json(result);
|
|
5332
|
+
app.get("/sandboxes/:sandboxRef/views/:viewId/connection", async (c) => {
|
|
5333
|
+
const resolved = await authorizedView(c, registry);
|
|
5334
|
+
if (resolved instanceof Response) return resolved;
|
|
5335
|
+
const response = {
|
|
5336
|
+
sandboxRef: resolved.entry.summary.ref,
|
|
5337
|
+
viewId: resolved.view.id,
|
|
5338
|
+
protocol: "novnc",
|
|
5339
|
+
websocketPath: `/sandboxes/${encodeURIComponent(resolved.entry.summary.ref)}/views/${encodeURIComponent(resolved.view.id)}/ws`,
|
|
5340
|
+
authentication: resolved.view.authentication.type === "password" ? { type: "password", password: resolved.view.authentication.password } : { type: "none" }
|
|
5341
|
+
};
|
|
5342
|
+
c.header("cache-control", "no-store");
|
|
5343
|
+
return c.json(response);
|
|
5332
5344
|
});
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
return
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
let body;
|
|
5343
|
-
try {
|
|
5344
|
-
body = await c.req.json();
|
|
5345
|
-
} catch {
|
|
5346
|
-
return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
|
|
5347
|
-
}
|
|
5348
|
-
if (!isObject(body)) {
|
|
5349
|
-
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
5350
|
-
}
|
|
5351
|
-
if (!Array.isArray(body.answers)) {
|
|
5352
|
-
return { error: errorResponse(c, 400, "bad_request", "answers must be an array") };
|
|
5353
|
-
}
|
|
5354
|
-
const answers = [];
|
|
5355
|
-
for (const answer of body.answers) {
|
|
5356
|
-
if (!isObject(answer)) {
|
|
5357
|
-
return { error: errorResponse(c, 400, "bad_request", "answers must contain objects") };
|
|
5345
|
+
app.post("/sandboxes/:sandboxRef/views/:viewId/control/acquire", async (c) => {
|
|
5346
|
+
const resolved = await authorizedView(c, registry);
|
|
5347
|
+
if (resolved instanceof Response) return resolved;
|
|
5348
|
+
const body = await readControlBody(c);
|
|
5349
|
+
if (body instanceof Response) return body;
|
|
5350
|
+
const key = viewKey(resolved);
|
|
5351
|
+
pruneExpiredLease(leases, key);
|
|
5352
|
+
if (leases.has(key)) {
|
|
5353
|
+
return errorResponse(c, 409, "conflict", "Browser view is already controlled");
|
|
5358
5354
|
}
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5355
|
+
try {
|
|
5356
|
+
const lease = await resolved.view.source.control.acquireHumanControl({
|
|
5357
|
+
ownerId: body.ownerId,
|
|
5358
|
+
leaseTimeoutMs: body.leaseTimeoutMs,
|
|
5359
|
+
abortSignal: c.req.raw.signal
|
|
5360
|
+
});
|
|
5361
|
+
leases.set(key, lease);
|
|
5362
|
+
return c.json(leaseResponse(lease), 201);
|
|
5363
|
+
} catch (error) {
|
|
5364
|
+
return controlErrorResponse(c, error);
|
|
5364
5365
|
}
|
|
5365
|
-
|
|
5366
|
-
|
|
5366
|
+
});
|
|
5367
|
+
app.post("/sandboxes/:sandboxRef/views/:viewId/control/renew", async (c) => {
|
|
5368
|
+
const resolved = await authorizedView(c, registry);
|
|
5369
|
+
if (resolved instanceof Response) return resolved;
|
|
5370
|
+
const body = await readLeaseBody(c);
|
|
5371
|
+
if (body instanceof Response) return body;
|
|
5372
|
+
const key = viewKey(resolved);
|
|
5373
|
+
pruneExpiredLease(leases, key);
|
|
5374
|
+
const lease = leases.get(key);
|
|
5375
|
+
if (lease === void 0 || lease.id !== body.leaseId) {
|
|
5376
|
+
return errorResponse(c, 409, "conflict", "Browser control lease is not active");
|
|
5367
5377
|
}
|
|
5368
|
-
|
|
5369
|
-
|
|
5378
|
+
try {
|
|
5379
|
+
lease.renew({ leaseTimeoutMs: body.leaseTimeoutMs });
|
|
5380
|
+
return c.json(leaseResponse(lease));
|
|
5381
|
+
} catch (error) {
|
|
5382
|
+
leases.delete(key);
|
|
5383
|
+
return controlErrorResponse(c, error);
|
|
5370
5384
|
}
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
if (
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5385
|
+
});
|
|
5386
|
+
app.post("/sandboxes/:sandboxRef/views/:viewId/control/release", async (c) => {
|
|
5387
|
+
const resolved = await authorizedView(c, registry);
|
|
5388
|
+
if (resolved instanceof Response) return resolved;
|
|
5389
|
+
const body = await readReleaseBody(c);
|
|
5390
|
+
if (body instanceof Response) return body;
|
|
5391
|
+
const key = viewKey(resolved);
|
|
5392
|
+
const lease = leases.get(key);
|
|
5393
|
+
if (lease === void 0 || lease.id !== body.leaseId) {
|
|
5394
|
+
return errorResponse(c, 409, "conflict", "Browser control lease is not active");
|
|
5395
|
+
}
|
|
5396
|
+
lease.release();
|
|
5397
|
+
leases.delete(key);
|
|
5398
|
+
return c.json({ released: true });
|
|
5399
|
+
});
|
|
5400
|
+
app.get("/sandboxes/:sandboxRef/views/:viewId/ws", async (c) => {
|
|
5401
|
+
const resolved = await authorizedView(c, registry);
|
|
5402
|
+
if (resolved instanceof Response) return resolved;
|
|
5403
|
+
const upstreamUrl = `ws://${hostForUrl(resolved.host)}:${resolved.port}/websockify`;
|
|
5404
|
+
return upgradeWebSocket(c, createProxyEvents(upstreamUrl, upstreamSockets), {
|
|
5405
|
+
onError: () => void 0
|
|
5406
|
+
});
|
|
5407
|
+
});
|
|
5408
|
+
return () => {
|
|
5409
|
+
for (const lease of leases.values()) lease.release();
|
|
5410
|
+
leases.clear();
|
|
5411
|
+
for (const socket of upstreamSockets) socket.close(1001, "Studio closed");
|
|
5412
|
+
upstreamSockets.clear();
|
|
5413
|
+
};
|
|
5380
5414
|
}
|
|
5381
|
-
function
|
|
5382
|
-
|
|
5415
|
+
function createProxyEvents(upstreamUrl, sockets) {
|
|
5416
|
+
let upstream;
|
|
5417
|
+
let pendingBytes = 0;
|
|
5418
|
+
const pending = [];
|
|
5383
5419
|
return {
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
questions: prompts.questions
|
|
5400
|
-
};
|
|
5401
|
-
if (toolCallId !== void 0) request.toolCallId = toolCallId;
|
|
5402
|
-
const answers = await requestQuestion(questions, context, request);
|
|
5403
|
-
return control.skip(JSON.stringify({ answers }));
|
|
5404
|
-
}
|
|
5420
|
+
onOpen(_event, downstream) {
|
|
5421
|
+
const protocols = downstream.protocol === null || downstream.protocol.length === 0 ? void 0 : [downstream.protocol];
|
|
5422
|
+
upstream = new WebSocket(upstreamUrl, protocols, {
|
|
5423
|
+
headers: { origin: "http://127.0.0.1" }
|
|
5424
|
+
});
|
|
5425
|
+
sockets.add(upstream);
|
|
5426
|
+
upstream.binaryType = "arraybuffer";
|
|
5427
|
+
upstream.once("open", () => {
|
|
5428
|
+
for (const message of pending) upstream?.send(message);
|
|
5429
|
+
pending.length = 0;
|
|
5430
|
+
pendingBytes = 0;
|
|
5431
|
+
});
|
|
5432
|
+
upstream.on("message", (data, isBinary) => {
|
|
5433
|
+
const value = isBinary ? Uint8Array.from(Buffer.from(data)) : data.toString();
|
|
5434
|
+
downstream.send(value);
|
|
5405
5435
|
});
|
|
5436
|
+
upstream.once("close", (code, reason) => {
|
|
5437
|
+
sockets.delete(upstream);
|
|
5438
|
+
downstream.close(normalizeCloseCode(code), reason.toString("utf8").slice(0, 123));
|
|
5439
|
+
});
|
|
5440
|
+
upstream.once("error", () => downstream.close(1011, "noVNC upstream failed"));
|
|
5406
5441
|
},
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
if (
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
if (options.status === "resolved" && question.status === "pending") {
|
|
5413
|
-
return false;
|
|
5414
|
-
}
|
|
5415
|
-
if (options.runId !== void 0 && question.runId !== options.runId) {
|
|
5416
|
-
return false;
|
|
5417
|
-
}
|
|
5418
|
-
if (options.agentId !== void 0 && question.agentId !== options.agentId) {
|
|
5419
|
-
return false;
|
|
5442
|
+
onMessage(event, downstream) {
|
|
5443
|
+
void normalizeWebSocketMessage(event.data).then((message) => {
|
|
5444
|
+
if (upstream?.readyState === WebSocket.OPEN) {
|
|
5445
|
+
upstream.send(message);
|
|
5446
|
+
return;
|
|
5420
5447
|
}
|
|
5421
|
-
|
|
5422
|
-
|
|
5448
|
+
pendingBytes += typeof message === "string" ? Buffer.byteLength(message) : message.byteLength;
|
|
5449
|
+
if (pendingBytes > maxPendingWebSocketBytes) {
|
|
5450
|
+
downstream.close(1009, "Pending noVNC messages exceeded the limit");
|
|
5451
|
+
return;
|
|
5423
5452
|
}
|
|
5424
|
-
|
|
5425
|
-
}).
|
|
5453
|
+
pending.push(message);
|
|
5454
|
+
}).catch(() => downstream.close(1003, "Unsupported noVNC message"));
|
|
5426
5455
|
},
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
if (!isPendingQuestion(question) || question.runId !== runId) {
|
|
5431
|
-
continue;
|
|
5432
|
-
}
|
|
5433
|
-
const resolved = cancelQuestion(question);
|
|
5434
|
-
questions.set(question.id, resolved);
|
|
5435
|
-
question.emit?.({ type: "tool_question_result", question: resolved });
|
|
5436
|
-
question.resolve([]);
|
|
5437
|
-
cancelled.push(resolved);
|
|
5438
|
-
}
|
|
5439
|
-
return cancelled;
|
|
5456
|
+
onClose() {
|
|
5457
|
+
upstream?.close(1e3, "Viewer disconnected");
|
|
5458
|
+
if (upstream !== void 0) sockets.delete(upstream);
|
|
5440
5459
|
},
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
if (question === void 0) {
|
|
5444
|
-
return "missing";
|
|
5445
|
-
}
|
|
5446
|
-
if (!isPendingQuestion(question)) {
|
|
5447
|
-
return "resolved";
|
|
5448
|
-
}
|
|
5449
|
-
const resolved = resolveQuestion(question, answers);
|
|
5450
|
-
questions.set(id, resolved);
|
|
5451
|
-
question.emit?.({ type: "tool_question_result", question: resolved });
|
|
5452
|
-
question.resolve(answers);
|
|
5453
|
-
return publicQuestion(resolved);
|
|
5460
|
+
onError() {
|
|
5461
|
+
upstream?.close(1011, "Viewer connection failed");
|
|
5454
5462
|
}
|
|
5455
5463
|
};
|
|
5456
5464
|
}
|
|
5457
|
-
async function
|
|
5458
|
-
const
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
};
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
if (
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
}
|
|
5484
|
-
function normalizeQuestionPrompts(args) {
|
|
5485
|
-
if (!isObject(args)) {
|
|
5486
|
-
return { error: "ask_question requires a JSON object with questions." };
|
|
5487
|
-
}
|
|
5488
|
-
const rawQuestions = Array.isArray(args.questions) ? args.questions : [args];
|
|
5489
|
-
if (rawQuestions.length === 0) {
|
|
5490
|
-
return { error: "ask_question requires at least one question." };
|
|
5491
|
-
}
|
|
5492
|
-
const questions = [];
|
|
5493
|
-
for (const [index, question] of rawQuestions.entries()) {
|
|
5494
|
-
const normalized = normalizeQuestionPrompt(question, index);
|
|
5495
|
-
if (normalized === void 0) {
|
|
5496
|
-
return {
|
|
5497
|
-
error: "ask_question requires every question to include text and at least one choice."
|
|
5498
|
-
};
|
|
5465
|
+
async function authorizedView(c, registry) {
|
|
5466
|
+
const entry = registry.get(c.req.param("sandboxRef") ?? "");
|
|
5467
|
+
if (entry === void 0) return errorResponse(c, 404, "not_found", "Sandbox not found");
|
|
5468
|
+
const view = entry.views.get(c.req.param("viewId") ?? "");
|
|
5469
|
+
if (view === void 0) return errorResponse(c, 404, "not_found", "Sandbox view not found");
|
|
5470
|
+
if (!await authorize(c, entry, view)) {
|
|
5471
|
+
return errorResponse(c, 403, "forbidden", "Sandbox view access denied");
|
|
5472
|
+
}
|
|
5473
|
+
const published = entry.inspector.publishedPorts?.find(
|
|
5474
|
+
(port) => port.containerPort === view.source.containerPort && port.protocol === "tcp" && isLoopbackAddress(port.host)
|
|
5475
|
+
);
|
|
5476
|
+
if (published === void 0) {
|
|
5477
|
+
return errorResponse(c, 503, "internal_error", "Sandbox view port is unavailable");
|
|
5478
|
+
}
|
|
5479
|
+
return { entry, view, host: published.host, port: published.hostPort };
|
|
5480
|
+
}
|
|
5481
|
+
async function authorize(c, entry, view) {
|
|
5482
|
+
if (view.access.mode === "authorize") {
|
|
5483
|
+
try {
|
|
5484
|
+
return await view.access.authorize({
|
|
5485
|
+
request: c.req.raw,
|
|
5486
|
+
sandboxRef: entry.summary.ref,
|
|
5487
|
+
viewId: view.id
|
|
5488
|
+
}) === true;
|
|
5489
|
+
} catch {
|
|
5490
|
+
return false;
|
|
5499
5491
|
}
|
|
5500
|
-
questions.push(normalized);
|
|
5501
5492
|
}
|
|
5502
|
-
|
|
5493
|
+
let remoteAddress;
|
|
5494
|
+
try {
|
|
5495
|
+
const address = getConnInfo(c).remote.address;
|
|
5496
|
+
if (address === void 0) return false;
|
|
5497
|
+
remoteAddress = address;
|
|
5498
|
+
} catch {
|
|
5499
|
+
return false;
|
|
5500
|
+
}
|
|
5501
|
+
if (!isLoopbackAddress(remoteAddress)) return false;
|
|
5502
|
+
const expectedOrigin = new URL(c.req.url).origin;
|
|
5503
|
+
const origin = c.req.header("origin");
|
|
5504
|
+
return origin === expectedOrigin || origin === void 0 && c.req.header("sec-fetch-site") === "same-origin";
|
|
5503
5505
|
}
|
|
5504
|
-
function
|
|
5505
|
-
|
|
5506
|
-
|
|
5506
|
+
async function readControlBody(c) {
|
|
5507
|
+
const body = await readJsonObject(c);
|
|
5508
|
+
if (body instanceof Response) return body;
|
|
5509
|
+
if (typeof body.ownerId !== "string" || body.ownerId.length === 0 || body.ownerId.length > 200) {
|
|
5510
|
+
return errorResponse(c, 400, "bad_request", "ownerId must be a non-empty string");
|
|
5507
5511
|
}
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
return void 0;
|
|
5512
|
+
if (!isLeaseTimeout(body.leaseTimeoutMs)) {
|
|
5513
|
+
return errorResponse(c, 400, "bad_request", "leaseTimeoutMs is outside the allowed range");
|
|
5511
5514
|
}
|
|
5512
|
-
return {
|
|
5513
|
-
id: typeof value.id === "string" && value.id.trim().length > 0 ? value.id.trim() : `question_${index + 1}`,
|
|
5514
|
-
question: value.question.trim(),
|
|
5515
|
-
choices
|
|
5516
|
-
};
|
|
5515
|
+
return { ownerId: body.ownerId, leaseTimeoutMs: body.leaseTimeoutMs };
|
|
5517
5516
|
}
|
|
5518
|
-
function
|
|
5519
|
-
|
|
5520
|
-
|
|
5517
|
+
async function readLeaseBody(c) {
|
|
5518
|
+
const body = await readJsonObject(c);
|
|
5519
|
+
if (body instanceof Response) return body;
|
|
5520
|
+
if (typeof body.leaseId !== "string" || body.leaseId.length === 0) {
|
|
5521
|
+
return errorResponse(c, 400, "bad_request", "leaseId must be a non-empty string");
|
|
5521
5522
|
}
|
|
5522
|
-
if (!
|
|
5523
|
-
return
|
|
5523
|
+
if (!isLeaseTimeout(body.leaseTimeoutMs)) {
|
|
5524
|
+
return errorResponse(c, 400, "bad_request", "leaseTimeoutMs is outside the allowed range");
|
|
5524
5525
|
}
|
|
5525
|
-
return {
|
|
5526
|
-
label: value.label.trim(),
|
|
5527
|
-
value: typeof value.value === "string" && value.value.trim().length > 0 ? value.value.trim() : value.label.trim()
|
|
5528
|
-
};
|
|
5526
|
+
return { leaseId: body.leaseId, leaseTimeoutMs: body.leaseTimeoutMs };
|
|
5529
5527
|
}
|
|
5530
|
-
function
|
|
5531
|
-
|
|
5528
|
+
async function readReleaseBody(c) {
|
|
5529
|
+
const body = await readJsonObject(c);
|
|
5530
|
+
if (body instanceof Response) return body;
|
|
5531
|
+
if (typeof body.leaseId !== "string" || body.leaseId.length === 0) {
|
|
5532
|
+
return errorResponse(c, 400, "bad_request", "leaseId must be a non-empty string");
|
|
5533
|
+
}
|
|
5534
|
+
return { leaseId: body.leaseId };
|
|
5532
5535
|
}
|
|
5533
|
-
function
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
}
|
|
5536
|
+
async function readJsonObject(c) {
|
|
5537
|
+
let body;
|
|
5538
|
+
try {
|
|
5539
|
+
body = await c.req.json();
|
|
5540
|
+
} catch {
|
|
5541
|
+
return errorResponse(c, 400, "bad_request", "Request body must be valid JSON");
|
|
5542
|
+
}
|
|
5543
|
+
return isRecord4(body) ? body : errorResponse(c, 400, "bad_request", "Request body must be an object");
|
|
5540
5544
|
}
|
|
5541
|
-
function
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5545
|
+
function controlErrorResponse(c, error) {
|
|
5546
|
+
if (isRecord4(error) && error.code === "human_controlled") {
|
|
5547
|
+
return errorResponse(c, 409, "conflict", "Browser view is already controlled");
|
|
5548
|
+
}
|
|
5549
|
+
if (isRecord4(error) && error.code === "invalid_state") {
|
|
5550
|
+
return errorResponse(c, 409, "conflict", "Browser control lease is no longer active");
|
|
5551
|
+
}
|
|
5552
|
+
return errorResponse(c, 500, "internal_error", "Browser control operation failed");
|
|
5553
|
+
}
|
|
5554
|
+
function leaseResponse(lease) {
|
|
5555
|
+
return { id: lease.id, ownerId: lease.ownerId, expiresAt: lease.expiresAt };
|
|
5556
|
+
}
|
|
5557
|
+
function pruneExpiredLease(leases, key) {
|
|
5558
|
+
const lease = leases.get(key);
|
|
5559
|
+
if (lease !== void 0 && Date.parse(lease.expiresAt) <= Date.now()) {
|
|
5560
|
+
lease.release();
|
|
5561
|
+
leases.delete(key);
|
|
5562
|
+
}
|
|
5563
|
+
}
|
|
5564
|
+
function viewKey(resolved) {
|
|
5565
|
+
return `${resolved.entry.summary.ref}\0${resolved.view.id}`;
|
|
5566
|
+
}
|
|
5567
|
+
function isLeaseTimeout(value) {
|
|
5568
|
+
return Number.isSafeInteger(value) && Number(value) >= minLeaseTimeoutMs && Number(value) <= maxLeaseTimeoutMs;
|
|
5569
|
+
}
|
|
5570
|
+
function isLoopbackAddress(value) {
|
|
5571
|
+
return value === "localhost" || value === "127.0.0.1" || value === "::1" || value.startsWith("127.") || value.startsWith("::ffff:127.");
|
|
5572
|
+
}
|
|
5573
|
+
function hostForUrl(host) {
|
|
5574
|
+
return host.includes(":") ? `[${host}]` : host;
|
|
5575
|
+
}
|
|
5576
|
+
async function normalizeWebSocketMessage(value) {
|
|
5577
|
+
if (typeof value === "string") return value;
|
|
5578
|
+
if (value instanceof ArrayBuffer) return Uint8Array.from(new Uint8Array(value));
|
|
5579
|
+
if (ArrayBuffer.isView(value)) {
|
|
5580
|
+
return Uint8Array.from(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));
|
|
5581
|
+
}
|
|
5582
|
+
if (value instanceof Blob) return Uint8Array.from(new Uint8Array(await value.arrayBuffer()));
|
|
5583
|
+
throw new TypeError("Unsupported noVNC WebSocket message type.");
|
|
5584
|
+
}
|
|
5585
|
+
function normalizeCloseCode(code) {
|
|
5586
|
+
return code >= 1e3 && code <= 4999 && code !== 1004 && code !== 1005 && code !== 1006 ? code : 1001;
|
|
5547
5587
|
}
|
|
5548
|
-
function
|
|
5549
|
-
|
|
5550
|
-
void emit;
|
|
5551
|
-
void resolve2;
|
|
5552
|
-
return rest;
|
|
5588
|
+
function isRecord4(value) {
|
|
5589
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5553
5590
|
}
|
|
5554
5591
|
|
|
5555
5592
|
// src/runtime/sandboxes.ts
|
|
5556
5593
|
import path from "path";
|
|
5557
|
-
var sandboxToolMetadataKey = /* @__PURE__ */ Symbol.for("anvia.sandbox.tool.metadata");
|
|
5558
5594
|
var maxFileResponseBytes = 10 * 1024 * 1024;
|
|
5559
5595
|
var defaultProcessLogBytes = 64 * 1024;
|
|
5560
5596
|
var maxProcessLogBytes = 1024 * 1024;
|
|
@@ -5573,51 +5609,41 @@ var StudioSandboxRegistry = class {
|
|
|
5573
5609
|
return this.entries.get(ref);
|
|
5574
5610
|
}
|
|
5575
5611
|
};
|
|
5576
|
-
function createStudioSandboxRegistry(agents) {
|
|
5577
|
-
const
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
draft.toolNames.add(tool.name);
|
|
5591
|
-
drafts.set(session, draft);
|
|
5592
|
-
}
|
|
5593
|
-
}
|
|
5594
|
-
const refCounts = /* @__PURE__ */ new Map();
|
|
5595
|
-
const entries = [...drafts.values()].sort(
|
|
5596
|
-
(left, right) => `${left.session.provider}\0${left.session.id}`.localeCompare(
|
|
5597
|
-
`${right.session.provider}\0${right.session.id}`
|
|
5598
|
-
)
|
|
5599
|
-
).map((draft) => {
|
|
5600
|
-
const baseRef = sandboxRef(draft.session.provider, draft.session.id);
|
|
5601
|
-
const occurrence = (refCounts.get(baseRef) ?? 0) + 1;
|
|
5602
|
-
refCounts.set(baseRef, occurrence);
|
|
5603
|
-
const ref = occurrence === 1 ? baseRef : `${baseRef}.${occurrence}`;
|
|
5612
|
+
function createStudioSandboxRegistry(agents, registrations) {
|
|
5613
|
+
const agentIds = new Set(agents.map((agent) => agent.id));
|
|
5614
|
+
const refs = /* @__PURE__ */ new Set();
|
|
5615
|
+
const entries = registrations.map((registration, index) => {
|
|
5616
|
+
validateRegistration(registration, index, agentIds);
|
|
5617
|
+
const inspector = registration.inspector;
|
|
5618
|
+
const ref = sandboxRef(inspector.provider, inspector.id);
|
|
5619
|
+
if (refs.has(ref)) {
|
|
5620
|
+
throw new TypeError(
|
|
5621
|
+
`sandboxes contains a duplicate provider/id registration: ${inspector.provider}/${inspector.id}`
|
|
5622
|
+
);
|
|
5623
|
+
}
|
|
5624
|
+
refs.add(ref);
|
|
5625
|
+
const views = new Map((registration.views ?? []).map((view) => [view.id, view]));
|
|
5604
5626
|
return {
|
|
5605
|
-
|
|
5627
|
+
inspector,
|
|
5628
|
+
views,
|
|
5606
5629
|
summary: {
|
|
5607
5630
|
ref,
|
|
5608
|
-
id:
|
|
5609
|
-
provider:
|
|
5610
|
-
workdir:
|
|
5611
|
-
agentIds:
|
|
5612
|
-
toolNames:
|
|
5631
|
+
id: inspector.id,
|
|
5632
|
+
provider: inspector.provider,
|
|
5633
|
+
workdir: inspector.workdir,
|
|
5634
|
+
agentIds: sortedUnique(registration.agentIds ?? []),
|
|
5635
|
+
toolNames: sortedUnique(registration.toolNames ?? []),
|
|
5636
|
+
views: [...views.values()].map((view) => ({ id: view.id, label: view.label, protocol: view.source.protocol })).sort((left, right) => left.id.localeCompare(right.id)),
|
|
5613
5637
|
capabilities: {
|
|
5614
|
-
files:
|
|
5615
|
-
ports: supportsPorts(
|
|
5616
|
-
processes: supportsProcesses(
|
|
5638
|
+
files: supportsFiles(inspector),
|
|
5639
|
+
ports: supportsPorts(inspector),
|
|
5640
|
+
processes: supportsProcesses(inspector),
|
|
5641
|
+
views: views.size > 0
|
|
5617
5642
|
}
|
|
5618
5643
|
}
|
|
5619
5644
|
};
|
|
5620
5645
|
});
|
|
5646
|
+
entries.sort((left, right) => left.summary.ref.localeCompare(right.summary.ref));
|
|
5621
5647
|
return new StudioSandboxRegistry(entries);
|
|
5622
5648
|
}
|
|
5623
5649
|
function registerSandboxRoutes(app, registry) {
|
|
@@ -5626,24 +5652,19 @@ function registerSandboxRoutes(app, registry) {
|
|
|
5626
5652
|
app.get("/sandboxes", (c) => c.json({ sandboxes: registry.list() }));
|
|
5627
5653
|
app.get("/sandboxes/:sandboxRef", (c) => {
|
|
5628
5654
|
const entry = registry.get(c.req.param("sandboxRef"));
|
|
5629
|
-
|
|
5630
|
-
return errorResponse(c, 404, "not_found", "Sandbox not found");
|
|
5631
|
-
}
|
|
5632
|
-
return c.json(copySummary(entry.summary));
|
|
5655
|
+
return entry === void 0 ? errorResponse(c, 404, "not_found", "Sandbox not found") : c.json(copySummary(entry.summary));
|
|
5633
5656
|
});
|
|
5634
5657
|
app.get("/sandboxes/:sandboxRef/files", async (c) => {
|
|
5635
5658
|
const entry = registry.get(c.req.param("sandboxRef"));
|
|
5636
|
-
if (entry === void 0)
|
|
5637
|
-
|
|
5638
|
-
}
|
|
5659
|
+
if (entry === void 0) return errorResponse(c, 404, "not_found", "Sandbox not found");
|
|
5660
|
+
if (!supportsFiles(entry.inspector)) return unsupportedSandboxOperation(c, "files");
|
|
5639
5661
|
try {
|
|
5640
5662
|
const requestedPath = c.req.query("path") ?? ".";
|
|
5641
5663
|
const normalizedPath = normalizeSandboxPath(requestedPath, true);
|
|
5642
|
-
const entries = await listSandboxFiles(entry.session, normalizedPath);
|
|
5643
5664
|
return c.json({
|
|
5644
5665
|
sandboxRef: entry.summary.ref,
|
|
5645
5666
|
path: normalizedPath,
|
|
5646
|
-
entries
|
|
5667
|
+
entries: await listSandboxFiles(entry.inspector, normalizedPath, c.req.raw.signal)
|
|
5647
5668
|
});
|
|
5648
5669
|
} catch (error) {
|
|
5649
5670
|
return sandboxErrorResponse(c, error);
|
|
@@ -5651,9 +5672,8 @@ function registerSandboxRoutes(app, registry) {
|
|
|
5651
5672
|
});
|
|
5652
5673
|
app.get("/sandboxes/:sandboxRef/files/content", async (c) => {
|
|
5653
5674
|
const entry = registry.get(c.req.param("sandboxRef"));
|
|
5654
|
-
if (entry === void 0)
|
|
5655
|
-
|
|
5656
|
-
}
|
|
5675
|
+
if (entry === void 0) return errorResponse(c, 404, "not_found", "Sandbox not found");
|
|
5676
|
+
if (!supportsFiles(entry.inspector)) return unsupportedSandboxOperation(c, "files.content");
|
|
5657
5677
|
try {
|
|
5658
5678
|
const requestedPath = c.req.query("path");
|
|
5659
5679
|
if (requestedPath === void 0) {
|
|
@@ -5664,8 +5684,11 @@ function registerSandboxRoutes(app, registry) {
|
|
|
5664
5684
|
throw new SandboxRouteError(400, "bad_request", "download must be 1 when provided");
|
|
5665
5685
|
}
|
|
5666
5686
|
const normalizedPath = normalizeSandboxPath(requestedPath, false);
|
|
5667
|
-
const
|
|
5668
|
-
|
|
5687
|
+
const siblings = await listSandboxFiles(
|
|
5688
|
+
entry.inspector,
|
|
5689
|
+
path.posix.dirname(normalizedPath),
|
|
5690
|
+
c.req.raw.signal
|
|
5691
|
+
);
|
|
5669
5692
|
const file = siblings.find((candidate) => candidate.path === normalizedPath);
|
|
5670
5693
|
if (file === void 0) {
|
|
5671
5694
|
throw new SandboxRouteError(404, "not_found", "Sandbox file not found");
|
|
@@ -5677,25 +5700,24 @@ function registerSandboxRoutes(app, registry) {
|
|
|
5677
5700
|
"Sandbox content path must refer to a regular file"
|
|
5678
5701
|
);
|
|
5679
5702
|
}
|
|
5680
|
-
if (file.size !== void 0 && file.size > maxFileResponseBytes)
|
|
5703
|
+
if (file.size !== void 0 && file.size > maxFileResponseBytes)
|
|
5681
5704
|
throw fileTooLarge(file.size);
|
|
5682
|
-
|
|
5683
|
-
|
|
5705
|
+
const rawBytes = await entry.inspector.readFile({
|
|
5706
|
+
path: normalizedPath,
|
|
5707
|
+
abortSignal: c.req.raw.signal
|
|
5708
|
+
});
|
|
5684
5709
|
if (!(rawBytes instanceof Uint8Array)) {
|
|
5685
5710
|
throw new TypeError("Sandbox readFile returned an invalid byte payload");
|
|
5686
5711
|
}
|
|
5687
|
-
if (rawBytes.byteLength > maxFileResponseBytes)
|
|
5688
|
-
|
|
5689
|
-
}
|
|
5690
|
-
const bytes = new Uint8Array(rawBytes.byteLength);
|
|
5691
|
-
bytes.set(rawBytes);
|
|
5712
|
+
if (rawBytes.byteLength > maxFileResponseBytes) throw fileTooLarge(rawBytes.byteLength);
|
|
5713
|
+
const bytes = rawBytes.slice();
|
|
5692
5714
|
const disposition = download === "1" ? "attachment" : "inline";
|
|
5693
5715
|
const filename = encodeURIComponent(path.posix.basename(normalizedPath));
|
|
5694
5716
|
return new Response(bytes, {
|
|
5695
5717
|
headers: {
|
|
5696
5718
|
"cache-control": "no-store",
|
|
5697
5719
|
"content-disposition": `${disposition}; filename*=UTF-8''${filename}`,
|
|
5698
|
-
"content-length":
|
|
5720
|
+
"content-length": `${bytes.byteLength}`,
|
|
5699
5721
|
"content-type": "application/octet-stream",
|
|
5700
5722
|
"x-content-type-options": "nosniff"
|
|
5701
5723
|
}
|
|
@@ -5706,16 +5728,12 @@ function registerSandboxRoutes(app, registry) {
|
|
|
5706
5728
|
});
|
|
5707
5729
|
app.get("/sandboxes/:sandboxRef/ports", (c) => {
|
|
5708
5730
|
const entry = registry.get(c.req.param("sandboxRef"));
|
|
5709
|
-
if (entry === void 0)
|
|
5710
|
-
|
|
5711
|
-
}
|
|
5712
|
-
if (!supportsPorts(entry.session)) {
|
|
5713
|
-
return unsupportedSandboxOperation(c, "ports");
|
|
5714
|
-
}
|
|
5731
|
+
if (entry === void 0) return errorResponse(c, 404, "not_found", "Sandbox not found");
|
|
5732
|
+
if (!supportsPorts(entry.inspector)) return unsupportedSandboxOperation(c, "ports");
|
|
5715
5733
|
try {
|
|
5716
5734
|
return c.json({
|
|
5717
5735
|
sandboxRef: entry.summary.ref,
|
|
5718
|
-
ports: normalizePorts(entry.
|
|
5736
|
+
ports: normalizePorts(entry.inspector.publishedPorts)
|
|
5719
5737
|
});
|
|
5720
5738
|
} catch (error) {
|
|
5721
5739
|
return sandboxErrorResponse(c, error);
|
|
@@ -5723,16 +5741,16 @@ function registerSandboxRoutes(app, registry) {
|
|
|
5723
5741
|
});
|
|
5724
5742
|
app.get("/sandboxes/:sandboxRef/processes", async (c) => {
|
|
5725
5743
|
const entry = registry.get(c.req.param("sandboxRef"));
|
|
5726
|
-
if (entry === void 0)
|
|
5727
|
-
|
|
5728
|
-
}
|
|
5729
|
-
if (!supportsProcesses(entry.session)) {
|
|
5744
|
+
if (entry === void 0) return errorResponse(c, 404, "not_found", "Sandbox not found");
|
|
5745
|
+
if (!supportsProcesses(entry.inspector)) {
|
|
5730
5746
|
return unsupportedSandboxOperation(c, "processes");
|
|
5731
5747
|
}
|
|
5732
5748
|
try {
|
|
5733
5749
|
return c.json({
|
|
5734
5750
|
sandboxRef: entry.summary.ref,
|
|
5735
|
-
processes: normalizeProcesses(
|
|
5751
|
+
processes: normalizeProcesses(
|
|
5752
|
+
await entry.inspector.listProcesses({ abortSignal: c.req.raw.signal })
|
|
5753
|
+
)
|
|
5736
5754
|
});
|
|
5737
5755
|
} catch (error) {
|
|
5738
5756
|
return sandboxErrorResponse(c, error);
|
|
@@ -5740,21 +5758,25 @@ function registerSandboxRoutes(app, registry) {
|
|
|
5740
5758
|
});
|
|
5741
5759
|
app.get("/sandboxes/:sandboxRef/processes/:processId/logs", async (c) => {
|
|
5742
5760
|
const entry = registry.get(c.req.param("sandboxRef"));
|
|
5743
|
-
if (entry === void 0)
|
|
5744
|
-
|
|
5745
|
-
}
|
|
5746
|
-
if (!supportsProcesses(entry.session)) {
|
|
5761
|
+
if (entry === void 0) return errorResponse(c, 404, "not_found", "Sandbox not found");
|
|
5762
|
+
if (!supportsProcesses(entry.inspector)) {
|
|
5747
5763
|
return unsupportedSandboxOperation(c, "processes.logs");
|
|
5748
5764
|
}
|
|
5749
5765
|
try {
|
|
5750
5766
|
const tailBytes = parseTailBytes(c.req.query("tailBytes"));
|
|
5751
5767
|
const processId = c.req.param("processId");
|
|
5752
|
-
const processes = normalizeProcesses(
|
|
5768
|
+
const processes = normalizeProcesses(
|
|
5769
|
+
await entry.inspector.listProcesses({ abortSignal: c.req.raw.signal })
|
|
5770
|
+
);
|
|
5753
5771
|
if (!processes.some((process2) => process2.id === processId)) {
|
|
5754
5772
|
throw new SandboxRouteError(404, "not_found", "Sandbox process not found");
|
|
5755
5773
|
}
|
|
5756
5774
|
const logs = normalizeProcessLogs(
|
|
5757
|
-
await entry.
|
|
5775
|
+
await entry.inspector.readProcessLogs({
|
|
5776
|
+
processId,
|
|
5777
|
+
tailBytes,
|
|
5778
|
+
abortSignal: c.req.raw.signal
|
|
5779
|
+
}),
|
|
5758
5780
|
tailBytes
|
|
5759
5781
|
);
|
|
5760
5782
|
return c.json({
|
|
@@ -5771,21 +5793,86 @@ async function sandboxNoStore(c, next) {
|
|
|
5771
5793
|
c.header("cache-control", "no-store");
|
|
5772
5794
|
await next();
|
|
5773
5795
|
}
|
|
5774
|
-
function
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5796
|
+
function validateRegistration(registration, index, knownAgentIds) {
|
|
5797
|
+
if (!isRecord5(registration) || !isInspector(registration.inspector)) {
|
|
5798
|
+
throw new TypeError(`sandboxes[${index}] must contain a valid inspector.`);
|
|
5799
|
+
}
|
|
5800
|
+
const inspector = registration.inspector;
|
|
5801
|
+
const files = supportsFiles(inspector);
|
|
5802
|
+
if (inspector.listFiles === void 0 !== (inspector.readFile === void 0)) {
|
|
5803
|
+
throw new TypeError(`sandboxes[${index}] must register both file inspector methods.`);
|
|
5804
|
+
}
|
|
5805
|
+
const processes = supportsProcesses(inspector);
|
|
5806
|
+
if (inspector.listProcesses === void 0 !== (inspector.readProcessLogs === void 0)) {
|
|
5807
|
+
throw new TypeError(`sandboxes[${index}] must register both process inspector methods.`);
|
|
5808
|
+
}
|
|
5809
|
+
if (!files && !supportsPorts(inspector) && !processes) {
|
|
5810
|
+
throw new TypeError(`sandboxes[${index}] inspector exposes no capabilities.`);
|
|
5811
|
+
}
|
|
5812
|
+
for (const agentId of sortedUnique(registration.agentIds ?? [])) {
|
|
5813
|
+
if (!knownAgentIds.has(agentId)) {
|
|
5814
|
+
throw new TypeError(`sandboxes[${index}] references an unknown agent: ${agentId}`);
|
|
5815
|
+
}
|
|
5816
|
+
}
|
|
5817
|
+
sortedUnique(registration.toolNames ?? []);
|
|
5818
|
+
validateViews(registration.views, inspector, index);
|
|
5819
|
+
}
|
|
5820
|
+
function validateViews(views, inspector, registrationIndex) {
|
|
5821
|
+
if (views === void 0) return;
|
|
5822
|
+
if (!Array.isArray(views))
|
|
5823
|
+
throw new TypeError(`sandboxes[${registrationIndex}].views must be an array.`);
|
|
5824
|
+
if (!supportsPorts(inspector)) {
|
|
5825
|
+
throw new TypeError(`sandboxes[${registrationIndex}] views require published port inspection.`);
|
|
5826
|
+
}
|
|
5827
|
+
const ids = /* @__PURE__ */ new Set();
|
|
5828
|
+
for (const [viewIndex, view] of views.entries()) {
|
|
5829
|
+
const prefix = `sandboxes[${registrationIndex}].views[${viewIndex}]`;
|
|
5830
|
+
const candidate = view;
|
|
5831
|
+
if (!isRecord5(candidate) || typeof candidate.id !== "string" || !/^[a-z0-9](?:[a-z0-9_-]{0,62})$/.test(candidate.id)) {
|
|
5832
|
+
throw new TypeError(`${prefix}.id must be a stable lowercase identifier.`);
|
|
5833
|
+
}
|
|
5834
|
+
if (ids.has(candidate.id)) throw new TypeError(`${prefix}.id is duplicated: ${candidate.id}`);
|
|
5835
|
+
ids.add(candidate.id);
|
|
5836
|
+
if (typeof candidate.label !== "string" || candidate.label.length === 0) {
|
|
5837
|
+
throw new TypeError(`${prefix}.label must be a non-empty string.`);
|
|
5838
|
+
}
|
|
5839
|
+
const source = candidate.source;
|
|
5840
|
+
if (!isRecord5(source) || source.protocol !== "novnc" || !isPort(source.containerPort) || !isRecord5(source.control) || typeof source.control.snapshot !== "function" || typeof source.control.acquireHumanControl !== "function") {
|
|
5841
|
+
throw new TypeError(`${prefix}.source must be a valid noVNC view source.`);
|
|
5842
|
+
}
|
|
5843
|
+
const port = inspector.publishedPorts?.find(
|
|
5844
|
+
(candidate2) => candidate2.containerPort === source.containerPort && candidate2.protocol === "tcp"
|
|
5845
|
+
);
|
|
5846
|
+
if (port === void 0 || !isLoopbackHost(port.host)) {
|
|
5847
|
+
throw new TypeError(`${prefix}.source must resolve to a loopback-published TCP port.`);
|
|
5848
|
+
}
|
|
5849
|
+
const access = candidate.access;
|
|
5850
|
+
if (!isRecord5(access) || access.mode !== "local" && access.mode !== "authorize") {
|
|
5851
|
+
throw new TypeError(`${prefix}.access must explicitly select local or authorize mode.`);
|
|
5852
|
+
}
|
|
5853
|
+
if (access.mode === "authorize" && typeof access.authorize !== "function") {
|
|
5854
|
+
throw new TypeError(`${prefix}.access.authorize must be a function.`);
|
|
5855
|
+
}
|
|
5856
|
+
const authentication = candidate.authentication;
|
|
5857
|
+
if (!isRecord5(authentication) || authentication.type !== "none" && authentication.type !== "password") {
|
|
5858
|
+
throw new TypeError(`${prefix}.authentication must explicitly select none or password.`);
|
|
5859
|
+
}
|
|
5860
|
+
if (authentication.type === "password" && (typeof authentication.password !== "string" || authentication.password.length === 0)) {
|
|
5861
|
+
throw new TypeError(`${prefix}.authentication.password must be a non-empty string.`);
|
|
5862
|
+
}
|
|
5778
5863
|
}
|
|
5779
|
-
return isSandboxSession(metadata.session) ? metadata.session : void 0;
|
|
5780
5864
|
}
|
|
5781
|
-
function
|
|
5782
|
-
return
|
|
5865
|
+
function isInspector(value) {
|
|
5866
|
+
return isRecord5(value) && typeof value.id === "string" && value.id.length > 0 && typeof value.provider === "string" && value.provider.length > 0 && typeof value.workdir === "string" && value.workdir.length > 0;
|
|
5783
5867
|
}
|
|
5784
|
-
function
|
|
5785
|
-
return
|
|
5868
|
+
function supportsFiles(inspector) {
|
|
5869
|
+
return typeof inspector.listFiles === "function" && typeof inspector.readFile === "function";
|
|
5786
5870
|
}
|
|
5787
|
-
function
|
|
5788
|
-
return
|
|
5871
|
+
function supportsPorts(inspector) {
|
|
5872
|
+
return Array.isArray(inspector.publishedPorts);
|
|
5873
|
+
}
|
|
5874
|
+
function supportsProcesses(inspector) {
|
|
5875
|
+
return typeof inspector.listProcesses === "function" && typeof inspector.readProcessLogs === "function";
|
|
5789
5876
|
}
|
|
5790
5877
|
function sandboxRef(provider, id) {
|
|
5791
5878
|
return Buffer.from(JSON.stringify([provider, id]), "utf8").toString("base64url");
|
|
@@ -5795,22 +5882,26 @@ function copySummary(summary) {
|
|
|
5795
5882
|
...summary,
|
|
5796
5883
|
agentIds: [...summary.agentIds],
|
|
5797
5884
|
toolNames: [...summary.toolNames],
|
|
5885
|
+
views: summary.views.map((view) => ({ ...view })),
|
|
5798
5886
|
capabilities: { ...summary.capabilities }
|
|
5799
5887
|
};
|
|
5800
5888
|
}
|
|
5801
|
-
|
|
5802
|
-
return
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5889
|
+
function isLoopbackHost(host) {
|
|
5890
|
+
return host === "127.0.0.1" || host === "::1" || host === "localhost";
|
|
5891
|
+
}
|
|
5892
|
+
async function listSandboxFiles(inspector, filePath, abortSignal) {
|
|
5893
|
+
return normalizeFileEntries(await inspector.listFiles({ path: filePath, abortSignal })).sort(
|
|
5894
|
+
(left, right) => {
|
|
5895
|
+
if (left.type === "directory" && right.type !== "directory") return -1;
|
|
5896
|
+
if (left.type !== "directory" && right.type === "directory") return 1;
|
|
5897
|
+
return left.path.localeCompare(right.path);
|
|
5898
|
+
}
|
|
5899
|
+
);
|
|
5807
5900
|
}
|
|
5808
5901
|
function normalizeFileEntries(value) {
|
|
5809
|
-
if (!Array.isArray(value))
|
|
5810
|
-
throw new TypeError("Sandbox listFiles returned an invalid payload");
|
|
5811
|
-
}
|
|
5902
|
+
if (!Array.isArray(value)) throw new TypeError("Sandbox listFiles returned an invalid payload");
|
|
5812
5903
|
return value.map((item) => {
|
|
5813
|
-
if (!
|
|
5904
|
+
if (!isRecord5(item) || typeof item.path !== "string" || !isFileType(item.type)) {
|
|
5814
5905
|
throw new TypeError("Sandbox listFiles returned an invalid entry");
|
|
5815
5906
|
}
|
|
5816
5907
|
let entryPath;
|
|
@@ -5821,7 +5912,7 @@ function normalizeFileEntries(value) {
|
|
|
5821
5912
|
}
|
|
5822
5913
|
const entry = { path: entryPath, type: item.type };
|
|
5823
5914
|
if (item.size !== void 0) {
|
|
5824
|
-
if (
|
|
5915
|
+
if (!Number.isSafeInteger(item.size) || Number(item.size) < 0) {
|
|
5825
5916
|
throw new TypeError("Sandbox listFiles returned an invalid file size");
|
|
5826
5917
|
}
|
|
5827
5918
|
entry.size = item.size;
|
|
@@ -5830,11 +5921,10 @@ function normalizeFileEntries(value) {
|
|
|
5830
5921
|
});
|
|
5831
5922
|
}
|
|
5832
5923
|
function normalizePorts(value) {
|
|
5833
|
-
if (!Array.isArray(value))
|
|
5924
|
+
if (!Array.isArray(value))
|
|
5834
5925
|
throw new TypeError("Sandbox publishedPorts returned an invalid payload");
|
|
5835
|
-
}
|
|
5836
5926
|
return value.map((item) => {
|
|
5837
|
-
if (!
|
|
5927
|
+
if (!isRecord5(item) || !isPort(item.containerPort) || typeof item.host !== "string" || !isPort(item.hostPort) || typeof item.protocol !== "string") {
|
|
5838
5928
|
throw new TypeError("Sandbox publishedPorts returned an invalid entry");
|
|
5839
5929
|
}
|
|
5840
5930
|
return {
|
|
@@ -5846,17 +5936,16 @@ function normalizePorts(value) {
|
|
|
5846
5936
|
});
|
|
5847
5937
|
}
|
|
5848
5938
|
function normalizeProcesses(value) {
|
|
5849
|
-
if (!Array.isArray(value))
|
|
5939
|
+
if (!Array.isArray(value))
|
|
5850
5940
|
throw new TypeError("Sandbox listProcesses returned an invalid payload");
|
|
5851
|
-
}
|
|
5852
5941
|
return value.map((item) => {
|
|
5853
|
-
if (!
|
|
5942
|
+
if (!isRecord5(item) || typeof item.id !== "string" || typeof item.command !== "string" || !Array.isArray(item.args) || !item.args.every((arg) => typeof arg === "string") || !isProcessStatus(item.status) || typeof item.startedAt !== "string") {
|
|
5854
5943
|
throw new TypeError("Sandbox listProcesses returned an invalid entry");
|
|
5855
5944
|
}
|
|
5856
5945
|
const process2 = {
|
|
5857
5946
|
id: item.id,
|
|
5858
5947
|
command: item.command,
|
|
5859
|
-
args: item.args,
|
|
5948
|
+
args: [...item.args],
|
|
5860
5949
|
status: item.status,
|
|
5861
5950
|
startedAt: item.startedAt
|
|
5862
5951
|
};
|
|
@@ -5867,11 +5956,11 @@ function normalizeProcesses(value) {
|
|
|
5867
5956
|
});
|
|
5868
5957
|
}
|
|
5869
5958
|
function normalizeProcessLogs(value, maxBytes) {
|
|
5870
|
-
if (!
|
|
5959
|
+
if (!isRecord5(value) || !(value.stdout instanceof Uint8Array) || !(value.stderr instanceof Uint8Array) || typeof value.stdoutTruncated !== "boolean" || typeof value.stderrTruncated !== "boolean") {
|
|
5871
5960
|
throw new TypeError("Sandbox readProcessLogs returned an invalid payload");
|
|
5872
5961
|
}
|
|
5873
|
-
const stdout =
|
|
5874
|
-
const stderr =
|
|
5962
|
+
const stdout = boundedLogBytes(value.stdout, maxBytes);
|
|
5963
|
+
const stderr = boundedLogBytes(value.stderr, maxBytes);
|
|
5875
5964
|
return {
|
|
5876
5965
|
stdout: stdout.text,
|
|
5877
5966
|
stderr: stderr.text,
|
|
@@ -5879,21 +5968,13 @@ function normalizeProcessLogs(value, maxBytes) {
|
|
|
5879
5968
|
stderrTruncated: value.stderrTruncated || stderr.truncated
|
|
5880
5969
|
};
|
|
5881
5970
|
}
|
|
5882
|
-
function
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
}
|
|
5887
|
-
if (maxBytes === 0) {
|
|
5888
|
-
return { text: "", truncated: true };
|
|
5889
|
-
}
|
|
5890
|
-
let start = bytes.byteLength - maxBytes;
|
|
5891
|
-
while (start < bytes.byteLength && (bytes[start] ?? 0) >> 6 === 2) {
|
|
5892
|
-
start += 1;
|
|
5893
|
-
}
|
|
5971
|
+
function boundedLogBytes(value, maxBytes) {
|
|
5972
|
+
if (maxBytes === 0) return { text: "", truncated: value.byteLength > 0 };
|
|
5973
|
+
let start = Math.max(0, value.byteLength - maxBytes);
|
|
5974
|
+
while (start < value.byteLength && ((value[start] ?? 0) & 192) === 128) start += 1;
|
|
5894
5975
|
return {
|
|
5895
|
-
text: new TextDecoder().decode(
|
|
5896
|
-
truncated:
|
|
5976
|
+
text: new TextDecoder("utf-8", { fatal: true }).decode(value.subarray(start)),
|
|
5977
|
+
truncated: start > 0
|
|
5897
5978
|
};
|
|
5898
5979
|
}
|
|
5899
5980
|
function normalizeSandboxPath(input, allowRoot) {
|
|
@@ -5916,9 +5997,7 @@ function normalizeSandboxPath(input, allowRoot) {
|
|
|
5916
5997
|
return normalized;
|
|
5917
5998
|
}
|
|
5918
5999
|
function parseTailBytes(value) {
|
|
5919
|
-
if (value === void 0)
|
|
5920
|
-
return defaultProcessLogBytes;
|
|
5921
|
-
}
|
|
6000
|
+
if (value === void 0) return defaultProcessLogBytes;
|
|
5922
6001
|
const parsed = Number(value);
|
|
5923
6002
|
if (!Number.isInteger(parsed) || parsed < 0 || parsed > maxProcessLogBytes) {
|
|
5924
6003
|
throw new SandboxRouteError(
|
|
@@ -5939,15 +6018,13 @@ function sandboxErrorResponse(c, error) {
|
|
|
5939
6018
|
if (error instanceof SandboxRouteError) {
|
|
5940
6019
|
return errorResponse(c, error.status, error.code, error.message);
|
|
5941
6020
|
}
|
|
5942
|
-
const
|
|
5943
|
-
if (
|
|
5944
|
-
|
|
5945
|
-
}
|
|
5946
|
-
if (name === "SandboxFileSizeError") {
|
|
6021
|
+
const code = errorCode(error);
|
|
6022
|
+
if (code === "invalid_path") return errorResponse(c, 400, "bad_request", errorMessage(error));
|
|
6023
|
+
if (code === "file_too_large") {
|
|
5947
6024
|
return errorResponse(c, 413, "payload_too_large", errorMessage(error));
|
|
5948
6025
|
}
|
|
5949
|
-
if (
|
|
5950
|
-
return errorResponse(c, 409, "conflict", "Sandbox
|
|
6026
|
+
if (code === "invalid_state" || code === "sandbox_not_found") {
|
|
6027
|
+
return errorResponse(c, 409, "conflict", "Sandbox is no longer available");
|
|
5951
6028
|
}
|
|
5952
6029
|
return errorResponse(
|
|
5953
6030
|
c,
|
|
@@ -5973,6 +6050,18 @@ var SandboxRouteError = class extends Error {
|
|
|
5973
6050
|
status;
|
|
5974
6051
|
code;
|
|
5975
6052
|
};
|
|
6053
|
+
function sortedUnique(values) {
|
|
6054
|
+
if (!Array.isArray(values)) throw new TypeError("Sandbox associations must be arrays.");
|
|
6055
|
+
const result = /* @__PURE__ */ new Set();
|
|
6056
|
+
for (const value of values) {
|
|
6057
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
6058
|
+
throw new TypeError("Sandbox associations must contain non-empty strings.");
|
|
6059
|
+
}
|
|
6060
|
+
if (result.has(value)) throw new TypeError(`Sandbox association is duplicated: ${value}`);
|
|
6061
|
+
result.add(value);
|
|
6062
|
+
}
|
|
6063
|
+
return [...result].sort();
|
|
6064
|
+
}
|
|
5976
6065
|
function isFileType(value) {
|
|
5977
6066
|
return value === "file" || value === "directory" || value === "symlink" || value === "other";
|
|
5978
6067
|
}
|
|
@@ -5982,14 +6071,14 @@ function isProcessStatus(value) {
|
|
|
5982
6071
|
function isPort(value) {
|
|
5983
6072
|
return Number.isInteger(value) && Number(value) >= 1 && Number(value) <= 65535;
|
|
5984
6073
|
}
|
|
5985
|
-
function
|
|
5986
|
-
return typeof value === "object" && value !== null;
|
|
6074
|
+
function isRecord5(value) {
|
|
6075
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5987
6076
|
}
|
|
5988
|
-
function
|
|
5989
|
-
return
|
|
6077
|
+
function errorCode(error) {
|
|
6078
|
+
return isRecord5(error) && typeof error.code === "string" ? error.code : void 0;
|
|
5990
6079
|
}
|
|
5991
6080
|
function errorMessage(error) {
|
|
5992
|
-
return
|
|
6081
|
+
return isRecord5(error) && typeof error.message === "string" ? error.message : "Sandbox failed";
|
|
5993
6082
|
}
|
|
5994
6083
|
|
|
5995
6084
|
// src/runtime/sessions.ts
|
|
@@ -6140,6 +6229,16 @@ function createInMemoryStudioStore() {
|
|
|
6140
6229
|
}
|
|
6141
6230
|
var InMemoryStudioStore = class {
|
|
6142
6231
|
kind = "memory";
|
|
6232
|
+
compaction = {
|
|
6233
|
+
snapshot: ({ scope }) => {
|
|
6234
|
+
const messages = this.sessions.get(scope.sessionId)?.messages ?? [];
|
|
6235
|
+
return Promise.resolve({
|
|
6236
|
+
revision: memoryRevision(messages),
|
|
6237
|
+
messages: cloneMessages(messages)
|
|
6238
|
+
});
|
|
6239
|
+
},
|
|
6240
|
+
replacePrefix: (options) => this.replaceCompactionPrefix(options)
|
|
6241
|
+
};
|
|
6143
6242
|
sessions = /* @__PURE__ */ new Map();
|
|
6144
6243
|
traces = /* @__PURE__ */ new Map();
|
|
6145
6244
|
pipelineLogs = /* @__PURE__ */ new Map();
|
|
@@ -6181,20 +6280,20 @@ var InMemoryStudioStore = class {
|
|
|
6181
6280
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6182
6281
|
return materializeSession(session);
|
|
6183
6282
|
}
|
|
6184
|
-
load(
|
|
6185
|
-
return Promise.resolve(this.sessions.get(
|
|
6283
|
+
load({ scope }) {
|
|
6284
|
+
return Promise.resolve(cloneMessages(this.sessions.get(scope.sessionId)?.messages ?? []));
|
|
6186
6285
|
}
|
|
6187
6286
|
append(input) {
|
|
6188
|
-
const session = this.sessions.get(input.
|
|
6287
|
+
const session = this.sessions.get(input.scope.sessionId);
|
|
6189
6288
|
if (session !== void 0) {
|
|
6190
|
-
session.messages.push(...input.messages);
|
|
6289
|
+
session.messages.push(...cloneMessages(input.messages));
|
|
6191
6290
|
session.messageCount = session.messages.length;
|
|
6192
6291
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6193
6292
|
}
|
|
6194
6293
|
return Promise.resolve();
|
|
6195
6294
|
}
|
|
6196
|
-
clear(
|
|
6197
|
-
const session = this.sessions.get(
|
|
6295
|
+
clear({ scope }) {
|
|
6296
|
+
const session = this.sessions.get(scope.sessionId);
|
|
6198
6297
|
if (session !== void 0) {
|
|
6199
6298
|
session.messages = [];
|
|
6200
6299
|
session.runs = [];
|
|
@@ -6205,13 +6304,26 @@ var InMemoryStudioStore = class {
|
|
|
6205
6304
|
}
|
|
6206
6305
|
async recordError(input) {
|
|
6207
6306
|
await this.saveSessionRunTranscript({
|
|
6208
|
-
id: input.
|
|
6209
|
-
runId: studioRunId(input.
|
|
6307
|
+
id: input.scope.sessionId,
|
|
6308
|
+
runId: studioRunId(input.scope) ?? input.runId,
|
|
6210
6309
|
transcript: transcriptFromMessages(input.messages),
|
|
6211
6310
|
status: "error",
|
|
6212
6311
|
error: serializeJsonError(input.error)
|
|
6213
6312
|
});
|
|
6214
6313
|
}
|
|
6314
|
+
replaceCompactionPrefix(input) {
|
|
6315
|
+
if (!Number.isSafeInteger(input.messageCount) || input.messageCount < 1) {
|
|
6316
|
+
throw new RangeError("messageCount must be a positive integer.");
|
|
6317
|
+
}
|
|
6318
|
+
const session = this.sessions.get(input.scope.sessionId);
|
|
6319
|
+
if (session === void 0 || memoryRevision(session.messages) !== input.revision || input.messageCount > session.messages.length) {
|
|
6320
|
+
return Promise.resolve({ status: "conflict" });
|
|
6321
|
+
}
|
|
6322
|
+
session.messages.splice(0, input.messageCount, structuredClone(input.replacement));
|
|
6323
|
+
session.messageCount = session.messages.length;
|
|
6324
|
+
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6325
|
+
return Promise.resolve({ status: "committed" });
|
|
6326
|
+
}
|
|
6215
6327
|
saveSessionRunTranscript(input) {
|
|
6216
6328
|
const session = this.sessions.get(input.id);
|
|
6217
6329
|
if (session === void 0) {
|
|
@@ -6337,18 +6449,24 @@ function sessionSummary(session) {
|
|
|
6337
6449
|
function materializeSession(session) {
|
|
6338
6450
|
return {
|
|
6339
6451
|
...sessionSummary(session),
|
|
6340
|
-
messages:
|
|
6452
|
+
messages: cloneMessages(session.messages),
|
|
6341
6453
|
transcript: renumberTranscript(session.runs.flatMap((run) => run.transcript))
|
|
6342
6454
|
};
|
|
6343
6455
|
}
|
|
6456
|
+
function cloneMessages(messages) {
|
|
6457
|
+
return structuredClone([...messages]);
|
|
6458
|
+
}
|
|
6344
6459
|
function traceAgentId(trace) {
|
|
6345
6460
|
const nestedMetadata = trace.metadata?.metadata;
|
|
6346
6461
|
return isJsonObject(nestedMetadata) && typeof nestedMetadata.agentId === "string" ? nestedMetadata.agentId : void 0;
|
|
6347
6462
|
}
|
|
6348
|
-
function studioRunId(
|
|
6349
|
-
const value =
|
|
6463
|
+
function studioRunId(scope) {
|
|
6464
|
+
const value = scope.metadata?.studioRunId;
|
|
6350
6465
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
6351
6466
|
}
|
|
6467
|
+
function memoryRevision(messages) {
|
|
6468
|
+
return JSON.stringify(messages);
|
|
6469
|
+
}
|
|
6352
6470
|
function serializeJsonError(error) {
|
|
6353
6471
|
if (error instanceof Error) {
|
|
6354
6472
|
return {
|
|
@@ -6684,6 +6802,7 @@ var Studio = class {
|
|
|
6684
6802
|
options;
|
|
6685
6803
|
studio;
|
|
6686
6804
|
server;
|
|
6805
|
+
websocketServer;
|
|
6687
6806
|
sigintHandler;
|
|
6688
6807
|
constructor(targets = [], options = {}) {
|
|
6689
6808
|
this.options = studioOptionsFromTargets(targets, options);
|
|
@@ -6708,9 +6827,15 @@ var Studio = class {
|
|
|
6708
6827
|
this.studio = createStudioApp(this.options);
|
|
6709
6828
|
const port = serveOptions.port ?? Number(process.env.RUNNER_PORT ?? 4021);
|
|
6710
6829
|
const serverOptions = {
|
|
6711
|
-
fetch: (request) => this.fetch(request),
|
|
6830
|
+
fetch: (request, env) => this.studio.app.fetch(request, env),
|
|
6712
6831
|
port
|
|
6713
6832
|
};
|
|
6833
|
+
this.websocketServer = new WebSocketServer({ noServer: true });
|
|
6834
|
+
serverOptions.websocket = {
|
|
6835
|
+
// @types/ws overloads are stricter than Hono's structural adapter, while Hono officially
|
|
6836
|
+
// supports ws.WebSocketServer. Keep the interop assertion at this single ownership boundary.
|
|
6837
|
+
server: this.websocketServer
|
|
6838
|
+
};
|
|
6714
6839
|
if (serveOptions.hostname !== void 0) serverOptions.hostname = serveOptions.hostname;
|
|
6715
6840
|
this.server = serve(serverOptions);
|
|
6716
6841
|
const log = serveOptions.log ?? true;
|
|
@@ -6755,6 +6880,8 @@ var Studio = class {
|
|
|
6755
6880
|
}
|
|
6756
6881
|
this.server?.close();
|
|
6757
6882
|
this.server = void 0;
|
|
6883
|
+
this.websocketServer?.close();
|
|
6884
|
+
this.websocketServer = void 0;
|
|
6758
6885
|
this.studio.close();
|
|
6759
6886
|
}
|
|
6760
6887
|
logAddress(host, port) {
|
|
@@ -6820,7 +6947,7 @@ function waitForShutdown(signal) {
|
|
|
6820
6947
|
});
|
|
6821
6948
|
}
|
|
6822
6949
|
function studioOptionsFromTargets(targets, options) {
|
|
6823
|
-
const agents = targets.filter((target) => target instanceof
|
|
6950
|
+
const agents = targets.filter((target) => target instanceof Agent);
|
|
6824
6951
|
const pipelines = targets.filter(
|
|
6825
6952
|
// biome-ignore lint/suspicious/noExplicitAny: Studio accepts heterogeneous user pipelines.
|
|
6826
6953
|
(target) => target instanceof Pipeline
|
|
@@ -6833,6 +6960,21 @@ function studioOptionsFromTargets(targets, options) {
|
|
|
6833
6960
|
if (options.models !== void 0) runtimeOptions.models = options.models;
|
|
6834
6961
|
if (options.stores !== void 0) runtimeOptions.stores = options.stores;
|
|
6835
6962
|
if (options.ui !== void 0) runtimeOptions.ui = options.ui;
|
|
6963
|
+
if (options.sandboxes !== void 0) {
|
|
6964
|
+
runtimeOptions.sandboxes = options.sandboxes.map((registration) => {
|
|
6965
|
+
let snapshot = { inspector: registration.inspector };
|
|
6966
|
+
if (registration.agentIds !== void 0) {
|
|
6967
|
+
snapshot = { ...snapshot, agentIds: [...registration.agentIds] };
|
|
6968
|
+
}
|
|
6969
|
+
if (registration.toolNames !== void 0) {
|
|
6970
|
+
snapshot = { ...snapshot, toolNames: [...registration.toolNames] };
|
|
6971
|
+
}
|
|
6972
|
+
if (registration.views !== void 0) {
|
|
6973
|
+
snapshot = { ...snapshot, views: [...registration.views] };
|
|
6974
|
+
}
|
|
6975
|
+
return snapshot;
|
|
6976
|
+
});
|
|
6977
|
+
}
|
|
6836
6978
|
return runtimeOptions;
|
|
6837
6979
|
}
|
|
6838
6980
|
function inferStudioAgents(agents, quickPrompts) {
|
|
@@ -6873,13 +7015,13 @@ function uniqueAgentId(baseId, ids) {
|
|
|
6873
7015
|
}
|
|
6874
7016
|
function agentMetadata(agent) {
|
|
6875
7017
|
const metadata = {
|
|
6876
|
-
staticContextCount: agent.
|
|
6877
|
-
dynamicContextCount: agent.
|
|
6878
|
-
dynamicToolCount: agent.
|
|
7018
|
+
staticContextCount: staticContextDocuments(agent).length,
|
|
7019
|
+
dynamicContextCount: vectorContexts(agent).length,
|
|
7020
|
+
dynamicToolCount: getAgentToolState3(agent).toolIndexes.length,
|
|
7021
|
+
hasLifecycle: agent.lifecycle !== void 0,
|
|
6879
7022
|
hasOutputSchema: agent.outputSchema !== void 0,
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
approvalToolCount: agent.toolSet.values().filter((tool) => tool.approval !== void 0).length
|
|
7023
|
+
observerCount: Object.keys(agent.observability?.observers ?? {}).length,
|
|
7024
|
+
approvalToolCount: agent.tools.filter(toolRequiresApproval).length
|
|
6883
7025
|
};
|
|
6884
7026
|
if (agent.defaultMaxTurns !== void 0) metadata.defaultMaxTurns = agent.defaultMaxTurns;
|
|
6885
7027
|
return metadata;
|
|
@@ -6895,9 +7037,8 @@ function createStudioApp(options) {
|
|
|
6895
7037
|
const agentMap = new Map(agents.map((agent) => [agent.id, agent]));
|
|
6896
7038
|
const pipelineMap = new Map(pipelines.map((pipeline) => [pipeline.id, pipeline]));
|
|
6897
7039
|
const evalMap = new Map(options.evals.map((suite) => [suite.id ?? suite.name, suite]));
|
|
6898
|
-
const
|
|
6899
|
-
const
|
|
6900
|
-
const sandboxRegistry = createStudioSandboxRegistry(agents);
|
|
7040
|
+
const continuationRegistry = createStudioContinuationRegistry();
|
|
7041
|
+
const sandboxRegistry = createStudioSandboxRegistry(agents, options.sandboxes ?? []);
|
|
6901
7042
|
const memorySources = createStudioMemorySourceRegistry(agents, stores.sessions);
|
|
6902
7043
|
const app = new HonoApp();
|
|
6903
7044
|
const uiOptions = isStudioUiEnabled(options.ui) ? resolveStudioUiOptions(options.ui) : void 0;
|
|
@@ -6948,8 +7089,7 @@ function createStudioApp(options) {
|
|
|
6948
7089
|
registerMcpRoutes(app, { agentMap });
|
|
6949
7090
|
registerToolRoutes(app, { agentMap });
|
|
6950
7091
|
registerSandboxRoutes(app, sandboxRegistry);
|
|
6951
|
-
|
|
6952
|
-
registerQuestionRoutes(app, questionRuntime);
|
|
7092
|
+
const closeSandboxViews = registerSandboxViewRoutes(app, sandboxRegistry);
|
|
6953
7093
|
registerObservabilityRoutes(app, observabilityHub);
|
|
6954
7094
|
registerEvalRoutes(app, {
|
|
6955
7095
|
evals: options.evals,
|
|
@@ -6969,8 +7109,7 @@ function createStudioApp(options) {
|
|
|
6969
7109
|
agentMap,
|
|
6970
7110
|
stores,
|
|
6971
7111
|
modelRegistry,
|
|
6972
|
-
|
|
6973
|
-
questionRuntime
|
|
7112
|
+
continuationRegistry
|
|
6974
7113
|
});
|
|
6975
7114
|
if (memorySources.size > 0 || stores.sessions !== void 0) {
|
|
6976
7115
|
registerMemoryRoutes(app, {
|
|
@@ -7002,6 +7141,8 @@ function createStudioApp(options) {
|
|
|
7002
7141
|
return buildConfig(options, agents, pipelines, stores, sandboxRegistry.size);
|
|
7003
7142
|
},
|
|
7004
7143
|
close() {
|
|
7144
|
+
continuationRegistry.clear();
|
|
7145
|
+
closeSandboxViews();
|
|
7005
7146
|
}
|
|
7006
7147
|
};
|
|
7007
7148
|
if (stores.sessions !== void 0) Object.assign(studio, { sessionStore: stores.sessions });
|
|
@@ -7009,30 +7150,37 @@ function createStudioApp(options) {
|
|
|
7009
7150
|
return studio;
|
|
7010
7151
|
}
|
|
7011
7152
|
function withStudioTraceObserver(studioAgent, traceStore) {
|
|
7012
|
-
if (traceStore === void 0
|
|
7013
|
-
|
|
7153
|
+
if (traceStore === void 0) return studioAgent;
|
|
7154
|
+
const existing = studioAgent.agent.observability;
|
|
7155
|
+
const studioObserver = existing?.observers.studio;
|
|
7156
|
+
if (studioObserver !== void 0 && !(studioObserver instanceof StudioTraceObserver)) {
|
|
7157
|
+
throw new TypeError('Studio reserves the observer name "studio" for local trace persistence.');
|
|
7158
|
+
}
|
|
7159
|
+
for (const [name, observer] of Object.entries(existing?.observers ?? {})) {
|
|
7160
|
+
if (observer instanceof StudioTraceObserver && name !== "studio") {
|
|
7161
|
+
throw new TypeError('StudioTraceObserver must be registered with the name "studio".');
|
|
7162
|
+
}
|
|
7014
7163
|
}
|
|
7015
7164
|
return {
|
|
7016
7165
|
...studioAgent,
|
|
7017
7166
|
agent: cloneAgent(studioAgent.agent, {
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7167
|
+
observability: {
|
|
7168
|
+
observers: {
|
|
7169
|
+
...existing?.observers ?? {},
|
|
7170
|
+
studio: studioObserver ?? new StudioTraceObserver({ store: traceStore })
|
|
7171
|
+
},
|
|
7172
|
+
primaryTrace: "studio",
|
|
7173
|
+
errorPolicy: existing?.errorPolicy ?? "ignore"
|
|
7174
|
+
}
|
|
7022
7175
|
})
|
|
7023
7176
|
};
|
|
7024
7177
|
}
|
|
7025
|
-
function hasStudioTraceObserver(agent) {
|
|
7026
|
-
return agent.observers.some(
|
|
7027
|
-
(registration) => registration.observer instanceof StudioTraceObserver
|
|
7028
|
-
);
|
|
7029
|
-
}
|
|
7030
7178
|
|
|
7031
7179
|
// src/storage/sqlite-store.ts
|
|
7032
7180
|
import { mkdirSync } from "fs";
|
|
7033
7181
|
import { createRequire } from "module";
|
|
7034
7182
|
import { dirname, resolve } from "path";
|
|
7035
|
-
import { isJsonValue as
|
|
7183
|
+
import { isJsonValue as isJsonValue3 } from "@anvia/core/completion";
|
|
7036
7184
|
var DatabaseSync;
|
|
7037
7185
|
function createSqliteSessionStore(options = {}) {
|
|
7038
7186
|
return new SqliteSessionStore(options.path ?? ":memory:");
|
|
@@ -7043,6 +7191,13 @@ var SqliteSessionStore = class {
|
|
|
7043
7191
|
}
|
|
7044
7192
|
path;
|
|
7045
7193
|
kind = "sqlite";
|
|
7194
|
+
compaction = {
|
|
7195
|
+
snapshot: ({ scope }) => {
|
|
7196
|
+
const messages = this.listSessionMessages(scope.sessionId);
|
|
7197
|
+
return Promise.resolve({ revision: memoryRevision2(messages), messages });
|
|
7198
|
+
},
|
|
7199
|
+
replacePrefix: (options) => this.replaceCompactionPrefix(options)
|
|
7200
|
+
};
|
|
7046
7201
|
db;
|
|
7047
7202
|
listSessions(options) {
|
|
7048
7203
|
const db = this.database();
|
|
@@ -7114,8 +7269,8 @@ var SqliteSessionStore = class {
|
|
|
7114
7269
|
}
|
|
7115
7270
|
return this.getSession(id);
|
|
7116
7271
|
}
|
|
7117
|
-
load(
|
|
7118
|
-
const session = this.getSession(
|
|
7272
|
+
load({ scope }) {
|
|
7273
|
+
const session = this.getSession(scope.sessionId);
|
|
7119
7274
|
return Promise.resolve(session?.messages ?? []);
|
|
7120
7275
|
}
|
|
7121
7276
|
append(input) {
|
|
@@ -7126,20 +7281,20 @@ var SqliteSessionStore = class {
|
|
|
7126
7281
|
`SELECT id, agent_id, title, metadata_json, created_at, updated_at
|
|
7127
7282
|
FROM anvia_studio_sessions
|
|
7128
7283
|
WHERE id = $id`
|
|
7129
|
-
).get({ $id: input.
|
|
7284
|
+
).get({ $id: input.scope.sessionId });
|
|
7130
7285
|
if (row === void 0) {
|
|
7131
7286
|
db.exec("ROLLBACK");
|
|
7132
7287
|
return Promise.resolve();
|
|
7133
7288
|
}
|
|
7134
7289
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7135
|
-
const nextIndex = this.nextMessageIndex(input.
|
|
7136
|
-
this.insertMessages(input.
|
|
7290
|
+
const nextIndex = this.nextMessageIndex(input.scope.sessionId);
|
|
7291
|
+
this.insertMessages(input.scope.sessionId, input.messages, nextIndex, updatedAt);
|
|
7137
7292
|
db.prepare(
|
|
7138
7293
|
`UPDATE anvia_studio_sessions
|
|
7139
7294
|
SET updated_at = $updatedAt
|
|
7140
7295
|
WHERE id = $id`
|
|
7141
7296
|
).run({
|
|
7142
|
-
$id: input.
|
|
7297
|
+
$id: input.scope.sessionId,
|
|
7143
7298
|
$updatedAt: updatedAt
|
|
7144
7299
|
});
|
|
7145
7300
|
db.exec("COMMIT");
|
|
@@ -7151,7 +7306,7 @@ var SqliteSessionStore = class {
|
|
|
7151
7306
|
throw error;
|
|
7152
7307
|
}
|
|
7153
7308
|
}
|
|
7154
|
-
clear(
|
|
7309
|
+
clear({ scope }) {
|
|
7155
7310
|
const db = this.database();
|
|
7156
7311
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7157
7312
|
try {
|
|
@@ -7161,14 +7316,14 @@ var SqliteSessionStore = class {
|
|
|
7161
7316
|
SET updated_at = $updatedAt
|
|
7162
7317
|
WHERE id = $id`
|
|
7163
7318
|
).run({
|
|
7164
|
-
$id:
|
|
7319
|
+
$id: scope.sessionId,
|
|
7165
7320
|
$updatedAt: updatedAt
|
|
7166
7321
|
});
|
|
7167
7322
|
db.prepare("DELETE FROM anvia_studio_session_messages WHERE session_id = $id").run({
|
|
7168
|
-
$id:
|
|
7323
|
+
$id: scope.sessionId
|
|
7169
7324
|
});
|
|
7170
7325
|
db.prepare("DELETE FROM anvia_studio_session_runs WHERE session_id = $id").run({
|
|
7171
|
-
$id:
|
|
7326
|
+
$id: scope.sessionId
|
|
7172
7327
|
});
|
|
7173
7328
|
db.exec("COMMIT");
|
|
7174
7329
|
return Promise.resolve();
|
|
@@ -7180,17 +7335,51 @@ var SqliteSessionStore = class {
|
|
|
7180
7335
|
}
|
|
7181
7336
|
}
|
|
7182
7337
|
async recordError(input) {
|
|
7183
|
-
const runId = studioRunId2(input.
|
|
7184
|
-
const existing = this.getSessionRun(input.
|
|
7338
|
+
const runId = studioRunId2(input.scope) ?? input.runId;
|
|
7339
|
+
const existing = this.getSessionRun(input.scope.sessionId, runId);
|
|
7185
7340
|
const transcript = existing === void 0 || parseJsonArray(existing.transcript_json).length === 0 ? transcriptFromMessages(input.messages) : parseJsonArray(existing.transcript_json);
|
|
7186
7341
|
await this.saveSessionRunTranscript({
|
|
7187
|
-
id: input.
|
|
7342
|
+
id: input.scope.sessionId,
|
|
7188
7343
|
runId,
|
|
7189
7344
|
transcript,
|
|
7190
7345
|
status: "error",
|
|
7191
7346
|
error: serializeJsonError2(input.error)
|
|
7192
7347
|
});
|
|
7193
7348
|
}
|
|
7349
|
+
replaceCompactionPrefix(input) {
|
|
7350
|
+
if (!Number.isSafeInteger(input.messageCount) || input.messageCount < 1) {
|
|
7351
|
+
throw new RangeError("messageCount must be a positive integer.");
|
|
7352
|
+
}
|
|
7353
|
+
const db = this.database();
|
|
7354
|
+
try {
|
|
7355
|
+
db.exec("BEGIN IMMEDIATE");
|
|
7356
|
+
const messages = this.listSessionMessages(input.scope.sessionId);
|
|
7357
|
+
if (memoryRevision2(messages) !== input.revision || input.messageCount > messages.length || this.getSessionRow(input.scope.sessionId) === void 0) {
|
|
7358
|
+
db.exec("ROLLBACK");
|
|
7359
|
+
return Promise.resolve({ status: "conflict" });
|
|
7360
|
+
}
|
|
7361
|
+
db.prepare("DELETE FROM anvia_studio_session_messages WHERE session_id = $id").run({
|
|
7362
|
+
$id: input.scope.sessionId
|
|
7363
|
+
});
|
|
7364
|
+
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7365
|
+
this.insertMessages(
|
|
7366
|
+
input.scope.sessionId,
|
|
7367
|
+
[input.replacement, ...messages.slice(input.messageCount)],
|
|
7368
|
+
0,
|
|
7369
|
+
updatedAt
|
|
7370
|
+
);
|
|
7371
|
+
db.prepare(
|
|
7372
|
+
`UPDATE anvia_studio_sessions
|
|
7373
|
+
SET updated_at = $updatedAt
|
|
7374
|
+
WHERE id = $id`
|
|
7375
|
+
).run({ $id: input.scope.sessionId, $updatedAt: updatedAt });
|
|
7376
|
+
db.exec("COMMIT");
|
|
7377
|
+
return Promise.resolve({ status: "committed" });
|
|
7378
|
+
} catch (error) {
|
|
7379
|
+
if (db.isTransaction) db.exec("ROLLBACK");
|
|
7380
|
+
throw error;
|
|
7381
|
+
}
|
|
7382
|
+
}
|
|
7194
7383
|
saveSessionRunTranscript(input) {
|
|
7195
7384
|
const db = this.database();
|
|
7196
7385
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -7886,7 +8075,7 @@ var SqliteSessionStore = class {
|
|
|
7886
8075
|
);
|
|
7887
8076
|
messages.forEach((message, messageOffset) => {
|
|
7888
8077
|
const messageIndex = startIndex + messageOffset;
|
|
7889
|
-
if (message.metadata !== void 0 && !
|
|
8078
|
+
if (message.metadata !== void 0 && !isJsonValue3(message.metadata)) {
|
|
7890
8079
|
throw new TypeError("Studio message metadata must be a strict JSON value.");
|
|
7891
8080
|
}
|
|
7892
8081
|
insertMessage.run({
|
|
@@ -7987,6 +8176,9 @@ function messageParts(message) {
|
|
|
7987
8176
|
if (message.role === "system") {
|
|
7988
8177
|
return [{ type: "text", value: { type: "text", text: message.content } }];
|
|
7989
8178
|
}
|
|
8179
|
+
if (typeof message.content === "string") {
|
|
8180
|
+
return [{ type: "text", value: { type: "text", text: message.content } }];
|
|
8181
|
+
}
|
|
7990
8182
|
return message.content.map((content) => ({
|
|
7991
8183
|
type: content.type,
|
|
7992
8184
|
value: content
|
|
@@ -7995,40 +8187,40 @@ function messageParts(message) {
|
|
|
7995
8187
|
function messageFromRows(row, partRows) {
|
|
7996
8188
|
const parts = partRows.map((partRow) => JSON.parse(partRow.part_json));
|
|
7997
8189
|
const metadata = parseJsonValue(row.metadata_json);
|
|
7998
|
-
if (metadata !== void 0 && !
|
|
7999
|
-
throw new TypeError("Stored Studio message metadata is not a strict JSON
|
|
8190
|
+
if (metadata !== void 0 && (!isJsonValue3(metadata) || typeof metadata !== "object" || metadata === null || Array.isArray(metadata))) {
|
|
8191
|
+
throw new TypeError("Stored Studio message metadata is not a strict JSON object.");
|
|
8000
8192
|
}
|
|
8001
8193
|
if (row.role === "system") {
|
|
8002
|
-
|
|
8194
|
+
let message = {
|
|
8003
8195
|
role: "system",
|
|
8004
8196
|
content: systemContentFromParts(parts)
|
|
8005
8197
|
};
|
|
8006
|
-
if (metadata !== void 0) message
|
|
8198
|
+
if (metadata !== void 0) message = { ...message, metadata };
|
|
8007
8199
|
return message;
|
|
8008
8200
|
}
|
|
8009
8201
|
if (row.role === "user") {
|
|
8010
|
-
|
|
8202
|
+
let message = {
|
|
8011
8203
|
role: "user",
|
|
8012
8204
|
content: parts
|
|
8013
8205
|
};
|
|
8014
|
-
if (metadata !== void 0) message
|
|
8206
|
+
if (metadata !== void 0) message = { ...message, metadata };
|
|
8015
8207
|
return message;
|
|
8016
8208
|
}
|
|
8017
8209
|
if (row.role === "assistant") {
|
|
8018
|
-
|
|
8210
|
+
let message = {
|
|
8019
8211
|
role: "assistant",
|
|
8020
8212
|
content: parts
|
|
8021
8213
|
};
|
|
8022
|
-
if (row.message_id !== null) message
|
|
8023
|
-
if (metadata !== void 0) message
|
|
8214
|
+
if (row.message_id !== null) message = { ...message, id: row.message_id };
|
|
8215
|
+
if (metadata !== void 0) message = { ...message, metadata };
|
|
8024
8216
|
return message;
|
|
8025
8217
|
}
|
|
8026
8218
|
if (row.role === "tool") {
|
|
8027
|
-
|
|
8219
|
+
let message = {
|
|
8028
8220
|
role: "tool",
|
|
8029
8221
|
content: parts
|
|
8030
8222
|
};
|
|
8031
|
-
if (metadata !== void 0) message
|
|
8223
|
+
if (metadata !== void 0) message = { ...message, metadata };
|
|
8032
8224
|
return message;
|
|
8033
8225
|
}
|
|
8034
8226
|
throw new Error(`Unsupported stored message role: ${row.role}`);
|
|
@@ -8100,6 +8292,7 @@ function toTraceSummary(row) {
|
|
|
8100
8292
|
if (error !== void 0) summary.error = error;
|
|
8101
8293
|
if (usage !== void 0) summary.usage = usage;
|
|
8102
8294
|
if (metadata !== void 0) summary.metadata = metadata;
|
|
8295
|
+
if (typeof metadata?.runId === "string") summary.runId = metadata.runId;
|
|
8103
8296
|
return summary;
|
|
8104
8297
|
}
|
|
8105
8298
|
function parseJsonArray(value) {
|
|
@@ -8112,10 +8305,13 @@ function parseJsonValue(value) {
|
|
|
8112
8305
|
}
|
|
8113
8306
|
return JSON.parse(value);
|
|
8114
8307
|
}
|
|
8115
|
-
function studioRunId2(
|
|
8116
|
-
const value =
|
|
8308
|
+
function studioRunId2(scope) {
|
|
8309
|
+
const value = scope.metadata?.studioRunId;
|
|
8117
8310
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
8118
8311
|
}
|
|
8312
|
+
function memoryRevision2(messages) {
|
|
8313
|
+
return JSON.stringify(messages);
|
|
8314
|
+
}
|
|
8119
8315
|
function serializeJsonError2(error) {
|
|
8120
8316
|
if (error instanceof Error) {
|
|
8121
8317
|
return {
|