@anvia/studio 0.5.14 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -0
- package/dist/index.d.ts +79 -2
- package/dist/index.js +1626 -1147
- package/dist/index.js.map +1 -1
- package/dist/ui/assets/{ArrowClockwise.es-cF7OPZy5.js → ArrowClockwise.es-BA79KX3F.js} +2 -2
- package/dist/ui/assets/{ArrowClockwise.es-cF7OPZy5.js.map → ArrowClockwise.es-BA79KX3F.js.map} +1 -1
- package/dist/ui/assets/{Path.es-D-NB-Xon.js → Path.es-DTZ3zsLn.js} +2 -2
- package/dist/ui/assets/{Path.es-D-NB-Xon.js.map → Path.es-DTZ3zsLn.js.map} +1 -1
- package/dist/ui/assets/{Play.es-BoMnJL28.js → Play.es-CJTRfv9R.js} +2 -2
- package/dist/ui/assets/{Play.es-BoMnJL28.js.map → Play.es-CJTRfv9R.js.map} +1 -1
- package/dist/ui/assets/{evals-page-Cx4Ycr-Y.js → evals-page-rS-P7eLF.js} +2 -2
- package/dist/ui/assets/{evals-page-Cx4Ycr-Y.js.map → evals-page-rS-P7eLF.js.map} +1 -1
- package/dist/ui/assets/index-B1s3oC-V.css +1 -0
- package/dist/ui/assets/index-ChlKOnbD.js +54 -0
- package/dist/ui/assets/index-ChlKOnbD.js.map +1 -0
- package/dist/ui/assets/{knowledge-page-DASnGzYP.js → knowledge-page-CR0JUneq.js} +2 -2
- package/dist/ui/assets/{knowledge-page-DASnGzYP.js.map → knowledge-page-CR0JUneq.js.map} +1 -1
- package/dist/ui/assets/{mcps-page-B7VAqsoU.js → mcps-page-D3P0UAWf.js} +2 -2
- package/dist/ui/assets/{mcps-page-B7VAqsoU.js.map → mcps-page-D3P0UAWf.js.map} +1 -1
- package/dist/ui/assets/{memory-page-BCv19Tw_.js → memory-page-kVDqOAOd.js} +2 -2
- package/dist/ui/assets/{memory-page-BCv19Tw_.js.map → memory-page-kVDqOAOd.js.map} +1 -1
- package/dist/ui/assets/{pipelines-page-Byb_JYxi.js → pipelines-page-lMfsVNRy.js} +2 -2
- package/dist/ui/assets/{pipelines-page-Byb_JYxi.js.map → pipelines-page-lMfsVNRy.js.map} +1 -1
- package/dist/ui/assets/{renderers-C8RHOlPz.js → renderers-Bc89UGTN.js} +2 -2
- package/dist/ui/assets/{renderers-C8RHOlPz.js.map → renderers-Bc89UGTN.js.map} +1 -1
- package/dist/ui/assets/{sessions-page-CV8GZKjN.js → sessions-page-CVlkRPfT.js} +2 -2
- package/dist/ui/assets/{sessions-page-CV8GZKjN.js.map → sessions-page-CVlkRPfT.js.map} +1 -1
- package/dist/ui/assets/{status-page-a6SMAcLu.js → status-page-XKvTGruQ.js} +2 -2
- package/dist/ui/assets/{status-page-a6SMAcLu.js.map → status-page-XKvTGruQ.js.map} +1 -1
- package/dist/ui/assets/{tools-page-Dpj7hI8q.js → tools-page-DJt_QdDe.js} +2 -2
- package/dist/ui/assets/{tools-page-Dpj7hI8q.js.map → tools-page-DJt_QdDe.js.map} +1 -1
- package/dist/ui/assets/{trace-browser-dvGDi7ji.js → trace-browser-BBITQELO.js} +2 -2
- package/dist/ui/assets/{trace-browser-dvGDi7ji.js.map → trace-browser-BBITQELO.js.map} +1 -1
- package/dist/ui/assets/{transcript-item-GmOQdc53.js → transcript-item-BvaA1PBu.js} +3 -3
- package/dist/ui/assets/transcript-item-BvaA1PBu.js.map +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +4 -4
- package/dist/ui/assets/index-BBfu6qlV.css +0 -1
- package/dist/ui/assets/index-rc2RWnWD.js +0 -54
- package/dist/ui/assets/index-rc2RWnWD.js.map +0 -1
- package/dist/ui/assets/transcript-item-GmOQdc53.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createHook as createHook3
|
|
4
4
|
} from "@anvia/core/agent";
|
|
5
|
+
|
|
6
|
+
// src/runtime/compact.ts
|
|
7
|
+
function compact(obj) {
|
|
8
|
+
const result = {};
|
|
9
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
10
|
+
if (value !== void 0) {
|
|
11
|
+
result[key] = value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/runtime/studio.ts
|
|
5
18
|
import { Message } from "@anvia/core/completion";
|
|
6
19
|
import { Agent } from "@anvia/core/internal/agent";
|
|
7
20
|
import { Pipeline } from "@anvia/core/pipeline";
|
|
@@ -65,6 +78,20 @@ function serializeUnknown(error) {
|
|
|
65
78
|
}
|
|
66
79
|
return toJsonValue(error);
|
|
67
80
|
}
|
|
81
|
+
function formatJson(value) {
|
|
82
|
+
try {
|
|
83
|
+
return JSON.stringify(value, null, 2);
|
|
84
|
+
} catch {
|
|
85
|
+
return String(value);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function formatUnknown(value) {
|
|
89
|
+
try {
|
|
90
|
+
return JSON.stringify(value);
|
|
91
|
+
} catch {
|
|
92
|
+
return void 0;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
68
95
|
|
|
69
96
|
// src/traces/trace-observer.ts
|
|
70
97
|
var StudioTraceObserver = class {
|
|
@@ -191,7 +218,7 @@ var StudioRunTraceObserver = class {
|
|
|
191
218
|
const trace = {
|
|
192
219
|
id: this.props.id,
|
|
193
220
|
sessionId,
|
|
194
|
-
...
|
|
221
|
+
...compact({ name: this.props.args.trace?.name }),
|
|
195
222
|
status,
|
|
196
223
|
trace: this.trace,
|
|
197
224
|
startedAt: this.startedAt.toISOString(),
|
|
@@ -202,9 +229,9 @@ var StudioRunTraceObserver = class {
|
|
|
202
229
|
prompt: this.props.args.prompt,
|
|
203
230
|
history: this.props.args.history
|
|
204
231
|
}),
|
|
205
|
-
...
|
|
206
|
-
...
|
|
207
|
-
...
|
|
232
|
+
...compact({ output: result.output }),
|
|
233
|
+
...compact({ error: result.error }),
|
|
234
|
+
...compact({ usage: result.usage }),
|
|
208
235
|
metadata,
|
|
209
236
|
observations: this.observations,
|
|
210
237
|
observationCount: this.observations.length
|
|
@@ -234,7 +261,7 @@ var ChildAgentToolTraceAccumulator = class {
|
|
|
234
261
|
this.agentStarts.set(agentId, {
|
|
235
262
|
startedAt: /* @__PURE__ */ new Date(),
|
|
236
263
|
agentId,
|
|
237
|
-
...
|
|
264
|
+
...compact({ agentName })
|
|
238
265
|
});
|
|
239
266
|
}
|
|
240
267
|
if (child.type === "turn_start") {
|
|
@@ -245,7 +272,7 @@ var ChildAgentToolTraceAccumulator = class {
|
|
|
245
272
|
history: child.history
|
|
246
273
|
}),
|
|
247
274
|
agentId,
|
|
248
|
-
...
|
|
275
|
+
...compact({ agentName }),
|
|
249
276
|
childTurn
|
|
250
277
|
});
|
|
251
278
|
return;
|
|
@@ -261,7 +288,7 @@ var ChildAgentToolTraceAccumulator = class {
|
|
|
261
288
|
status: "success",
|
|
262
289
|
turn: this.parent.turn,
|
|
263
290
|
startedAt: start?.startedAt ?? /* @__PURE__ */ new Date(),
|
|
264
|
-
...
|
|
291
|
+
...compact({ input: start?.input }),
|
|
265
292
|
output: toJsonValue(child.response),
|
|
266
293
|
metadata: this.childMetadata(agentId, agentName, childTurn)
|
|
267
294
|
})
|
|
@@ -276,10 +303,10 @@ var ChildAgentToolTraceAccumulator = class {
|
|
|
276
303
|
this.toolStarts.push({
|
|
277
304
|
startedAt: /* @__PURE__ */ new Date(),
|
|
278
305
|
agentId,
|
|
279
|
-
...
|
|
306
|
+
...compact({ agentName }),
|
|
280
307
|
childTurn,
|
|
281
308
|
toolName,
|
|
282
|
-
...
|
|
309
|
+
...compact({ toolCallId: callId }),
|
|
283
310
|
input: toJsonValue(toolCallFunction?.arguments ?? {}),
|
|
284
311
|
completed: false
|
|
285
312
|
});
|
|
@@ -301,12 +328,12 @@ var ChildAgentToolTraceAccumulator = class {
|
|
|
301
328
|
status: "success",
|
|
302
329
|
turn: this.parent.turn,
|
|
303
330
|
startedAt: start?.startedAt ?? /* @__PURE__ */ new Date(),
|
|
304
|
-
...
|
|
331
|
+
...compact({ input }),
|
|
305
332
|
...typeof child.result === "string" ? { output: parseOrString(child.result) } : {},
|
|
306
333
|
metadata: {
|
|
307
334
|
...this.childMetadata(agentId, agentName, childTurn),
|
|
308
|
-
...
|
|
309
|
-
...
|
|
335
|
+
...compact({ toolCallId }),
|
|
336
|
+
...compact({ internalCallId })
|
|
310
337
|
}
|
|
311
338
|
})
|
|
312
339
|
);
|
|
@@ -404,10 +431,10 @@ function traceObservation(props) {
|
|
|
404
431
|
startedAt: props.startedAt.toISOString(),
|
|
405
432
|
endedAt: endedAt.toISOString(),
|
|
406
433
|
durationMs: durationMs(props.startedAt, endedAt),
|
|
407
|
-
...
|
|
408
|
-
...
|
|
409
|
-
...
|
|
410
|
-
...
|
|
434
|
+
...compact({ input: props.input }),
|
|
435
|
+
...compact({ output: props.output }),
|
|
436
|
+
...compact({ error: props.error }),
|
|
437
|
+
...compact({ metadata: props.metadata })
|
|
411
438
|
};
|
|
412
439
|
}
|
|
413
440
|
function traceMetadata(args, messages) {
|
|
@@ -824,709 +851,134 @@ import {
|
|
|
824
851
|
parseToolArgs
|
|
825
852
|
} from "@anvia/core/tool";
|
|
826
853
|
|
|
827
|
-
// src/runtime/
|
|
828
|
-
function
|
|
829
|
-
return
|
|
854
|
+
// src/runtime/type-guards.ts
|
|
855
|
+
function isObject(value) {
|
|
856
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
830
857
|
}
|
|
831
|
-
function
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
if (message.role === "user") {
|
|
838
|
-
for (const content of message.content) {
|
|
839
|
-
if (content.type === "text") {
|
|
840
|
-
transcript.push({
|
|
841
|
-
entryId: transcript.length,
|
|
842
|
-
kind: "message",
|
|
843
|
-
role: "user",
|
|
844
|
-
text: content.text
|
|
845
|
-
});
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
continue;
|
|
849
|
-
}
|
|
850
|
-
if (message.role === "tool") {
|
|
851
|
-
for (const content of message.content) {
|
|
852
|
-
transcript.push({
|
|
853
|
-
entryId: transcript.length,
|
|
854
|
-
kind: "tool",
|
|
855
|
-
toolName: "tool_result",
|
|
856
|
-
callId: content.callId ?? content.id,
|
|
857
|
-
result: content.content.map(
|
|
858
|
-
(item) => "text" in item ? item.text : `[image:${item.mediaType ?? "image/png"}]`
|
|
859
|
-
).join("\n"),
|
|
860
|
-
structuredResult: content.content
|
|
861
|
-
});
|
|
862
|
-
}
|
|
863
|
-
continue;
|
|
864
|
-
}
|
|
865
|
-
for (const content of message.content) {
|
|
866
|
-
if (content.type === "text") {
|
|
867
|
-
appendAssistantTranscriptText(transcript, content.text);
|
|
868
|
-
} else if (content.type === "reasoning") {
|
|
869
|
-
transcript.push({
|
|
870
|
-
entryId: transcript.length,
|
|
871
|
-
kind: "reasoning",
|
|
872
|
-
...content.id === void 0 ? {} : { reasoningId: content.id },
|
|
873
|
-
text: content.text
|
|
874
|
-
});
|
|
875
|
-
} else if (content.type === "tool_call") {
|
|
876
|
-
transcript.push({
|
|
877
|
-
entryId: transcript.length,
|
|
878
|
-
kind: "tool",
|
|
879
|
-
toolName: content.function.name,
|
|
880
|
-
callId: content.callId ?? content.id,
|
|
881
|
-
args: formatJson(content.function.arguments)
|
|
882
|
-
});
|
|
883
|
-
}
|
|
884
|
-
}
|
|
858
|
+
function isJsonObject(value) {
|
|
859
|
+
return isObject(value) && Object.values(value).every(isJsonValue);
|
|
860
|
+
}
|
|
861
|
+
function isJsonValue(value) {
|
|
862
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
863
|
+
return true;
|
|
885
864
|
}
|
|
886
|
-
|
|
865
|
+
if (Array.isArray(value)) {
|
|
866
|
+
return value.every(isJsonValue);
|
|
867
|
+
}
|
|
868
|
+
return isJsonObject(value);
|
|
887
869
|
}
|
|
888
|
-
function
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
870
|
+
function isMessageInput(value) {
|
|
871
|
+
return typeof value === "string" || isMessage(value);
|
|
872
|
+
}
|
|
873
|
+
function isMessage(value) {
|
|
874
|
+
if (!isObject(value) || typeof value.role !== "string") {
|
|
875
|
+
return false;
|
|
893
876
|
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
}
|
|
877
|
+
if (value.role === "system") {
|
|
878
|
+
return typeof value.content === "string";
|
|
879
|
+
}
|
|
880
|
+
if (value.role === "user" || value.role === "assistant" || value.role === "tool") {
|
|
881
|
+
return Array.isArray(value.content);
|
|
882
|
+
}
|
|
883
|
+
return false;
|
|
900
884
|
}
|
|
901
|
-
function
|
|
902
|
-
|
|
903
|
-
return
|
|
904
|
-
}
|
|
905
|
-
|
|
885
|
+
function isAgentTraceOptions(value) {
|
|
886
|
+
if (!isObject(value)) {
|
|
887
|
+
return false;
|
|
888
|
+
}
|
|
889
|
+
return optionalString(value.name) && optionalString(value.userId) && optionalString(value.sessionId) && optionalString(value.version) && optionalString(value.traceId) && optionalBoolean(value.failOnObserverError) && optionalStringArray(value.tags) && optionalObject(value.metadata);
|
|
890
|
+
}
|
|
891
|
+
function isNonNegativeInteger(value) {
|
|
892
|
+
return Number.isInteger(value) && typeof value === "number" && value >= 0;
|
|
893
|
+
}
|
|
894
|
+
function isPositiveInteger(value) {
|
|
895
|
+
return Number.isInteger(value) && typeof value === "number" && value > 0;
|
|
896
|
+
}
|
|
897
|
+
function optionalString(value) {
|
|
898
|
+
return value === void 0 || typeof value === "string";
|
|
899
|
+
}
|
|
900
|
+
function optionalBoolean(value) {
|
|
901
|
+
return value === void 0 || typeof value === "boolean";
|
|
902
|
+
}
|
|
903
|
+
function optionalStringArray(value) {
|
|
904
|
+
return value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
905
|
+
}
|
|
906
|
+
function optionalObject(value) {
|
|
907
|
+
return value === void 0 || isObject(value);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// src/runtime/http.ts
|
|
911
|
+
function errorResponse(c, status, code, message, details) {
|
|
912
|
+
const body = {
|
|
913
|
+
error: {
|
|
914
|
+
code,
|
|
915
|
+
message
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
if (details !== void 0) {
|
|
919
|
+
body.error.details = details;
|
|
906
920
|
}
|
|
921
|
+
return c.json(body, status);
|
|
922
|
+
}
|
|
923
|
+
function unsupportedCapability(c, capability) {
|
|
924
|
+
return errorResponse(
|
|
925
|
+
c,
|
|
926
|
+
501,
|
|
927
|
+
"unsupported_capability",
|
|
928
|
+
`Capability "${capability}" is not implemented by this runner`,
|
|
929
|
+
{ capability }
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
function serializeError(error) {
|
|
933
|
+
return serializeUnknown(error);
|
|
907
934
|
}
|
|
908
935
|
|
|
909
|
-
// src/
|
|
910
|
-
function
|
|
911
|
-
|
|
936
|
+
// src/runtime/query.ts
|
|
937
|
+
function optionalQueryString(value) {
|
|
938
|
+
const trimmed = value?.trim();
|
|
939
|
+
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
912
940
|
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
traces = /* @__PURE__ */ new Map();
|
|
917
|
-
pipelineLogs = /* @__PURE__ */ new Map();
|
|
918
|
-
pipelineRuns = /* @__PURE__ */ new Map();
|
|
919
|
-
listSessions(options) {
|
|
920
|
-
return [...this.sessions.values()].filter((session) => options.agentId === void 0 || session.agentId === options.agentId).sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt)).slice(0, options.limit).map(sessionSummary);
|
|
941
|
+
function parseLimit(value, defaultMax = 50, max = 100) {
|
|
942
|
+
if (value === void 0 || value.trim().length === 0) {
|
|
943
|
+
return defaultMax;
|
|
921
944
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
id: input.id,
|
|
926
|
-
agentId: input.agentId,
|
|
927
|
-
...input.title === void 0 ? {} : { title: input.title },
|
|
928
|
-
createdAt: now,
|
|
929
|
-
updatedAt: now,
|
|
930
|
-
messageCount: 0,
|
|
931
|
-
...input.metadata === void 0 ? {} : { metadata: input.metadata },
|
|
932
|
-
messages: [],
|
|
933
|
-
runs: [],
|
|
934
|
-
logs: []
|
|
935
|
-
};
|
|
936
|
-
this.sessions.set(input.id, session);
|
|
937
|
-
return sessionSummary(session);
|
|
945
|
+
const limit = Number(value);
|
|
946
|
+
if (!Number.isInteger(limit) || limit <= 0) {
|
|
947
|
+
return void 0;
|
|
938
948
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
949
|
+
return Math.min(limit, max);
|
|
950
|
+
}
|
|
951
|
+
function parseTraceStatus(value) {
|
|
952
|
+
const status = optionalQueryString(value);
|
|
953
|
+
if (status === void 0) {
|
|
954
|
+
return void 0;
|
|
942
955
|
}
|
|
943
|
-
|
|
944
|
-
|
|
956
|
+
return status === "running" || status === "success" || status === "error" ? status : false;
|
|
957
|
+
}
|
|
958
|
+
function parseAfter(value) {
|
|
959
|
+
if (value === void 0 || value.trim().length === 0) {
|
|
960
|
+
return void 0;
|
|
945
961
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
session.messages.push(...input.messages);
|
|
950
|
-
session.messageCount = session.messages.length;
|
|
951
|
-
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
952
|
-
}
|
|
953
|
-
return Promise.resolve();
|
|
962
|
+
const after = Number(value);
|
|
963
|
+
if (!Number.isInteger(after) || after < 0) {
|
|
964
|
+
return false;
|
|
954
965
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
966
|
+
return after;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// src/runtime/approvals.ts
|
|
970
|
+
function registerApprovalRoutes(app, approvals) {
|
|
971
|
+
app.get("/approvals", (c) => {
|
|
972
|
+
const status = parseApprovalStatus(c.req.query("status"));
|
|
973
|
+
if (status === false) {
|
|
974
|
+
return errorResponse(c, 400, "bad_request", "status must be pending or resolved");
|
|
962
975
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
transcript: transcriptFromMessages(input.messages),
|
|
970
|
-
status: "error",
|
|
971
|
-
error: serializeJsonError(input.error)
|
|
972
|
-
});
|
|
973
|
-
}
|
|
974
|
-
saveSessionRunTranscript(input) {
|
|
975
|
-
const session = this.sessions.get(input.id);
|
|
976
|
-
if (session === void 0) {
|
|
977
|
-
return void 0;
|
|
978
|
-
}
|
|
979
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
980
|
-
const existingIndex = session.runs.findIndex((run2) => run2.runId === input.runId);
|
|
981
|
-
const run = {
|
|
982
|
-
...input,
|
|
983
|
-
transcript: renumberTranscript(input.transcript),
|
|
984
|
-
createdAt: existingIndex === -1 ? now : session.runs[existingIndex]?.createdAt ?? now,
|
|
985
|
-
updatedAt: now
|
|
986
|
-
};
|
|
987
|
-
if (existingIndex === -1) {
|
|
988
|
-
session.runs.push(run);
|
|
989
|
-
} else {
|
|
990
|
-
session.runs[existingIndex] = run;
|
|
991
|
-
}
|
|
992
|
-
session.updatedAt = now;
|
|
993
|
-
return materializeSession(session);
|
|
994
|
-
}
|
|
995
|
-
appendSessionLog(input) {
|
|
996
|
-
const session = this.sessions.get(input.sessionId);
|
|
997
|
-
const logs = session?.logs ?? [];
|
|
998
|
-
const entry = {
|
|
999
|
-
id: globalThis.crypto.randomUUID(),
|
|
1000
|
-
sessionId: input.sessionId,
|
|
1001
|
-
...input.runId === void 0 ? {} : { runId: input.runId },
|
|
1002
|
-
sequence: logs.length,
|
|
1003
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1004
|
-
level: input.level,
|
|
1005
|
-
category: input.category,
|
|
1006
|
-
event: input.event,
|
|
1007
|
-
message: input.message,
|
|
1008
|
-
...input.metadata === void 0 ? {} : { metadata: input.metadata }
|
|
1009
|
-
};
|
|
1010
|
-
if (session !== void 0) {
|
|
1011
|
-
session.logs.push(entry);
|
|
1012
|
-
session.updatedAt = entry.timestamp;
|
|
1013
|
-
}
|
|
1014
|
-
return entry;
|
|
1015
|
-
}
|
|
1016
|
-
listSessionLogs(options) {
|
|
1017
|
-
return (this.sessions.get(options.sessionId)?.logs ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
|
|
1018
|
-
}
|
|
1019
|
-
deleteSession(id) {
|
|
1020
|
-
for (const trace of this.traces.values()) {
|
|
1021
|
-
if (trace.sessionId === id) {
|
|
1022
|
-
this.traces.delete(trace.id);
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
return this.sessions.delete(id);
|
|
1026
|
-
}
|
|
1027
|
-
listTraces(options) {
|
|
1028
|
-
return [...this.traces.values()].filter((trace) => options.sessionId === void 0 || trace.sessionId === options.sessionId).filter((trace) => options.status === void 0 || trace.status === options.status).filter((trace) => options.agentId === void 0 || traceAgentId(trace) === options.agentId).sort((left, right) => Date.parse(right.startedAt) - Date.parse(left.startedAt)).slice(0, options.limit).map(traceSummary);
|
|
1029
|
-
}
|
|
1030
|
-
listSessionTraces(options) {
|
|
1031
|
-
return this.listTraces({ sessionId: options.sessionId, limit: options.limit });
|
|
1032
|
-
}
|
|
1033
|
-
getTrace(id) {
|
|
1034
|
-
return this.traces.get(id);
|
|
1035
|
-
}
|
|
1036
|
-
saveTrace(trace) {
|
|
1037
|
-
this.traces.set(trace.id, trace);
|
|
1038
|
-
return trace;
|
|
1039
|
-
}
|
|
1040
|
-
appendPipelineLog(input) {
|
|
1041
|
-
const logs = this.pipelineLogs.get(input.pipelineId) ?? [];
|
|
1042
|
-
const entry = {
|
|
1043
|
-
id: globalThis.crypto.randomUUID(),
|
|
1044
|
-
pipelineId: input.pipelineId,
|
|
1045
|
-
...input.runId === void 0 ? {} : { runId: input.runId },
|
|
1046
|
-
sequence: logs.length,
|
|
1047
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1048
|
-
level: input.level,
|
|
1049
|
-
category: input.category,
|
|
1050
|
-
event: input.event,
|
|
1051
|
-
message: input.message,
|
|
1052
|
-
...input.metadata === void 0 ? {} : { metadata: input.metadata }
|
|
1053
|
-
};
|
|
1054
|
-
this.pipelineLogs.set(input.pipelineId, [...logs, entry]);
|
|
1055
|
-
return entry;
|
|
1056
|
-
}
|
|
1057
|
-
listPipelineLogs(options) {
|
|
1058
|
-
return (this.pipelineLogs.get(options.pipelineId) ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
|
|
1059
|
-
}
|
|
1060
|
-
savePipelineRun(input) {
|
|
1061
|
-
const record = {
|
|
1062
|
-
runId: input.runId,
|
|
1063
|
-
pipelineId: input.pipelineId,
|
|
1064
|
-
status: input.status,
|
|
1065
|
-
input: input.input,
|
|
1066
|
-
...input.output === void 0 ? {} : { output: input.output },
|
|
1067
|
-
...input.error === void 0 ? {} : { error: input.error },
|
|
1068
|
-
...input.metadata === void 0 ? {} : { metadata: input.metadata },
|
|
1069
|
-
startedAt: input.startedAt,
|
|
1070
|
-
...input.endedAt === void 0 ? {} : { endedAt: input.endedAt },
|
|
1071
|
-
...input.durationMs === void 0 ? {} : { durationMs: input.durationMs }
|
|
1072
|
-
};
|
|
1073
|
-
this.pipelineRuns.set(input.runId, record);
|
|
1074
|
-
return record;
|
|
1075
|
-
}
|
|
1076
|
-
getPipelineRun(options) {
|
|
1077
|
-
const run = this.pipelineRuns.get(options.runId);
|
|
1078
|
-
return run?.pipelineId === options.pipelineId ? run : void 0;
|
|
1079
|
-
}
|
|
1080
|
-
listPipelineRuns(options) {
|
|
1081
|
-
return [...this.pipelineRuns.values()].filter((run) => run.pipelineId === options.pipelineId).sort((left, right) => Date.parse(right.startedAt) - Date.parse(left.startedAt)).slice(0, options.limit);
|
|
1082
|
-
}
|
|
1083
|
-
};
|
|
1084
|
-
function sessionSummary(session) {
|
|
1085
|
-
return {
|
|
1086
|
-
id: session.id,
|
|
1087
|
-
agentId: session.agentId,
|
|
1088
|
-
...session.title === void 0 ? {} : { title: session.title },
|
|
1089
|
-
createdAt: session.createdAt,
|
|
1090
|
-
updatedAt: session.updatedAt,
|
|
1091
|
-
messageCount: session.messages.length,
|
|
1092
|
-
...session.metadata === void 0 ? {} : { metadata: session.metadata }
|
|
1093
|
-
};
|
|
1094
|
-
}
|
|
1095
|
-
function materializeSession(session) {
|
|
1096
|
-
return {
|
|
1097
|
-
...sessionSummary(session),
|
|
1098
|
-
messages: [...session.messages],
|
|
1099
|
-
transcript: renumberTranscript(session.runs.flatMap((run) => run.transcript))
|
|
1100
|
-
};
|
|
1101
|
-
}
|
|
1102
|
-
function traceSummary(trace) {
|
|
1103
|
-
return {
|
|
1104
|
-
id: trace.id,
|
|
1105
|
-
sessionId: trace.sessionId,
|
|
1106
|
-
...trace.name === void 0 ? {} : { name: trace.name },
|
|
1107
|
-
status: trace.status,
|
|
1108
|
-
startedAt: trace.startedAt,
|
|
1109
|
-
...trace.endedAt === void 0 ? {} : { endedAt: trace.endedAt },
|
|
1110
|
-
...trace.durationMs === void 0 ? {} : { durationMs: trace.durationMs },
|
|
1111
|
-
...trace.output === void 0 ? {} : { output: trace.output },
|
|
1112
|
-
...trace.error === void 0 ? {} : { error: trace.error },
|
|
1113
|
-
...trace.usage === void 0 ? {} : { usage: trace.usage },
|
|
1114
|
-
...trace.metadata === void 0 ? {} : { metadata: trace.metadata },
|
|
1115
|
-
observationCount: trace.observations.length
|
|
1116
|
-
};
|
|
1117
|
-
}
|
|
1118
|
-
function traceAgentId(trace) {
|
|
1119
|
-
const nestedMetadata = trace.metadata?.metadata;
|
|
1120
|
-
return isJsonObject(nestedMetadata) && typeof nestedMetadata.agentId === "string" ? nestedMetadata.agentId : void 0;
|
|
1121
|
-
}
|
|
1122
|
-
function studioRunId(context) {
|
|
1123
|
-
const value = context.metadata?.studioRunId;
|
|
1124
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1125
|
-
}
|
|
1126
|
-
function serializeJsonError(error) {
|
|
1127
|
-
if (error instanceof Error) {
|
|
1128
|
-
return {
|
|
1129
|
-
name: error.name,
|
|
1130
|
-
message: error.message
|
|
1131
|
-
};
|
|
1132
|
-
}
|
|
1133
|
-
return isJsonValue(error) ? error : String(error);
|
|
1134
|
-
}
|
|
1135
|
-
function isJsonObject(value) {
|
|
1136
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1137
|
-
}
|
|
1138
|
-
function isJsonValue(value) {
|
|
1139
|
-
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1140
|
-
return true;
|
|
1141
|
-
}
|
|
1142
|
-
if (Array.isArray(value)) {
|
|
1143
|
-
return value.every(isJsonValue);
|
|
1144
|
-
}
|
|
1145
|
-
return isJsonObject(value) && Object.values(value).every(isJsonValue);
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
// src/runtime/tool-metadata.ts
|
|
1149
|
-
import { ToolSet } from "@anvia/core/tool";
|
|
1150
|
-
var MCP_TOOL_METADATA_KEY = /* @__PURE__ */ Symbol.for("anvia.mcp.tool.metadata");
|
|
1151
|
-
function agentToolItems(agent) {
|
|
1152
|
-
return [
|
|
1153
|
-
...agent.agent.toolSet.values().map((tool) => ({ tool, source: "static" })),
|
|
1154
|
-
...agent.agent.dynamicTools.flatMap((registration) => {
|
|
1155
|
-
const maybeToolSet = registration.index.toolSet;
|
|
1156
|
-
if (!(maybeToolSet instanceof ToolSet)) {
|
|
1157
|
-
return [];
|
|
1158
|
-
}
|
|
1159
|
-
return maybeToolSet.values().map((tool) => ({ tool, source: "dynamic" }));
|
|
1160
|
-
})
|
|
1161
|
-
];
|
|
1162
|
-
}
|
|
1163
|
-
function approvalMetadata(tool) {
|
|
1164
|
-
const approval = tool.approval;
|
|
1165
|
-
if (approval === void 0 || typeof approval !== "object" || approval === null) {
|
|
1166
|
-
return { required: false };
|
|
1167
|
-
}
|
|
1168
|
-
const policy = approval;
|
|
1169
|
-
return {
|
|
1170
|
-
required: true,
|
|
1171
|
-
...typeof policy.reason === "string" ? { reason: policy.reason } : {},
|
|
1172
|
-
...typeof policy.rejectMessage === "string" ? { rejectMessage: policy.rejectMessage } : {}
|
|
1173
|
-
};
|
|
1174
|
-
}
|
|
1175
|
-
function mcpServerName(tool) {
|
|
1176
|
-
const metadata = tool[MCP_TOOL_METADATA_KEY];
|
|
1177
|
-
if (typeof metadata !== "object" || metadata === null) {
|
|
1178
|
-
return void 0;
|
|
1179
|
-
}
|
|
1180
|
-
const serverName = metadata.serverName;
|
|
1181
|
-
return typeof serverName === "string" && serverName.length > 0 ? serverName : void 0;
|
|
1182
|
-
}
|
|
1183
|
-
function agentHasMcpTools(agent) {
|
|
1184
|
-
return agentToolItems(agent).some(({ tool }) => mcpServerName(tool) !== void 0);
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
// src/runtime/shared.ts
|
|
1188
|
-
function resolveStores(options) {
|
|
1189
|
-
const defaultStore = defaultStudioStore();
|
|
1190
|
-
const sessions = resolveSessionStore(options, defaultStore);
|
|
1191
|
-
const traces = resolveTraceStore(options, sessions, defaultStore);
|
|
1192
|
-
const pipelineLogs = resolvePipelineLogStore(options, sessions, defaultStore);
|
|
1193
|
-
const pipelineRuns = resolvePipelineRunStore(options, sessions, pipelineLogs, defaultStore);
|
|
1194
|
-
return {
|
|
1195
|
-
...sessions === void 0 ? {} : { sessions },
|
|
1196
|
-
...traces === void 0 ? {} : { traces },
|
|
1197
|
-
...pipelineLogs === void 0 ? {} : { pipelineLogs },
|
|
1198
|
-
...pipelineRuns === void 0 ? {} : { pipelineRuns }
|
|
1199
|
-
};
|
|
1200
|
-
}
|
|
1201
|
-
function defaultStudioStore() {
|
|
1202
|
-
return createInMemoryStudioStore();
|
|
1203
|
-
}
|
|
1204
|
-
function resolveSessionStore(options, defaultStore) {
|
|
1205
|
-
if (options.stores?.sessions === false) {
|
|
1206
|
-
return void 0;
|
|
1207
|
-
}
|
|
1208
|
-
if (options.stores?.sessions !== void 0) {
|
|
1209
|
-
return options.stores.sessions;
|
|
1210
|
-
}
|
|
1211
|
-
return defaultStore;
|
|
1212
|
-
}
|
|
1213
|
-
function resolveTraceStore(options, sessionStore, defaultStore) {
|
|
1214
|
-
if (options.stores?.traces !== void 0) {
|
|
1215
|
-
return options.stores.traces;
|
|
1216
|
-
}
|
|
1217
|
-
if (sessionStore === void 0) {
|
|
1218
|
-
return void 0;
|
|
1219
|
-
}
|
|
1220
|
-
if (isTraceStore(sessionStore)) {
|
|
1221
|
-
return sessionStore;
|
|
1222
|
-
}
|
|
1223
|
-
return defaultStore;
|
|
1224
|
-
}
|
|
1225
|
-
function resolvePipelineLogStore(options, sessionStore, defaultStore) {
|
|
1226
|
-
if (options.stores?.pipelineLogs === false) {
|
|
1227
|
-
return void 0;
|
|
1228
|
-
}
|
|
1229
|
-
if (options.stores?.pipelineLogs !== void 0) {
|
|
1230
|
-
return options.stores.pipelineLogs;
|
|
1231
|
-
}
|
|
1232
|
-
if (sessionStore !== void 0 && isPipelineLogStore(sessionStore)) {
|
|
1233
|
-
return sessionStore;
|
|
1234
|
-
}
|
|
1235
|
-
return defaultStore;
|
|
1236
|
-
}
|
|
1237
|
-
function resolvePipelineRunStore(options, sessionStore, pipelineLogStore, defaultStore) {
|
|
1238
|
-
if (options.stores?.pipelineRuns === false) {
|
|
1239
|
-
return void 0;
|
|
1240
|
-
}
|
|
1241
|
-
if (options.stores?.pipelineRuns !== void 0) {
|
|
1242
|
-
return options.stores.pipelineRuns;
|
|
1243
|
-
}
|
|
1244
|
-
if (sessionStore !== void 0 && isPipelineRunStore(sessionStore)) {
|
|
1245
|
-
return sessionStore;
|
|
1246
|
-
}
|
|
1247
|
-
if (pipelineLogStore !== void 0 && isPipelineRunStore(pipelineLogStore)) {
|
|
1248
|
-
return pipelineLogStore;
|
|
1249
|
-
}
|
|
1250
|
-
return defaultStore;
|
|
1251
|
-
}
|
|
1252
|
-
function isTraceStore(store) {
|
|
1253
|
-
const candidate = store;
|
|
1254
|
-
return typeof candidate.listSessionTraces === "function" && typeof candidate.getTrace === "function" && typeof candidate.saveTrace === "function";
|
|
1255
|
-
}
|
|
1256
|
-
function isPipelineLogStore(store) {
|
|
1257
|
-
const candidate = store;
|
|
1258
|
-
return typeof candidate.appendPipelineLog === "function" && typeof candidate.listPipelineLogs === "function";
|
|
1259
|
-
}
|
|
1260
|
-
function isPipelineRunStore(store) {
|
|
1261
|
-
const candidate = store;
|
|
1262
|
-
return typeof candidate.savePipelineRun === "function" && typeof candidate.getPipelineRun === "function" && typeof candidate.listPipelineRuns === "function";
|
|
1263
|
-
}
|
|
1264
|
-
function unsupportedCapabilities(stores) {
|
|
1265
|
-
return [
|
|
1266
|
-
...stores.sessions === void 0 ? ["sessions"] : [],
|
|
1267
|
-
...stores.traces === void 0 ? ["traces"] : []
|
|
1268
|
-
];
|
|
1269
|
-
}
|
|
1270
|
-
function normalizeAgents(agents) {
|
|
1271
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1272
|
-
return agents.map((agent) => {
|
|
1273
|
-
const id = agent.id.trim();
|
|
1274
|
-
if (id.length === 0) {
|
|
1275
|
-
throw new Error("Studio agent id cannot be empty");
|
|
1276
|
-
}
|
|
1277
|
-
if (ids.has(id)) {
|
|
1278
|
-
throw new Error(`Duplicate runner agent id: ${id}`);
|
|
1279
|
-
}
|
|
1280
|
-
ids.add(id);
|
|
1281
|
-
return { ...agent, id };
|
|
1282
|
-
});
|
|
1283
|
-
}
|
|
1284
|
-
function normalizePipelines(pipelines) {
|
|
1285
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1286
|
-
return pipelines.map((pipeline) => {
|
|
1287
|
-
const id = pipeline.id.trim();
|
|
1288
|
-
if (id.length === 0) {
|
|
1289
|
-
throw new Error("Studio pipeline id cannot be empty");
|
|
1290
|
-
}
|
|
1291
|
-
if (ids.has(id)) {
|
|
1292
|
-
throw new Error(`Duplicate Studio pipeline id: ${id}`);
|
|
1293
|
-
}
|
|
1294
|
-
ids.add(id);
|
|
1295
|
-
return { ...pipeline, id };
|
|
1296
|
-
});
|
|
1297
|
-
}
|
|
1298
|
-
function buildConfig(options, agents, pipelines, stores) {
|
|
1299
|
-
return {
|
|
1300
|
-
id: runnerId(options),
|
|
1301
|
-
...options.name === void 0 ? {} : { name: options.name },
|
|
1302
|
-
...options.description === void 0 ? {} : { description: options.description },
|
|
1303
|
-
...options.version === void 0 ? {} : { version: options.version },
|
|
1304
|
-
agents: agents.map(agentConfig),
|
|
1305
|
-
pipelines: pipelines.map(pipelineConfig),
|
|
1306
|
-
evals: options.evals.map(evalConfig),
|
|
1307
|
-
chat: {
|
|
1308
|
-
quickPrompts: Object.fromEntries(agents.map((agent) => [agent.id, agent.quickPrompts ?? []]))
|
|
1309
|
-
},
|
|
1310
|
-
capabilities: capabilityConfig(options, agents, pipelines, stores),
|
|
1311
|
-
unsupportedCapabilities: unsupportedCapabilities(stores)
|
|
1312
|
-
};
|
|
1313
|
-
}
|
|
1314
|
-
function runnerId(options) {
|
|
1315
|
-
return options.id ?? "anvia-studio";
|
|
1316
|
-
}
|
|
1317
|
-
function agentConfig(agent) {
|
|
1318
|
-
const name = agent.name ?? agent.agent.name;
|
|
1319
|
-
const description = agent.description ?? agent.agent.description;
|
|
1320
|
-
return {
|
|
1321
|
-
id: agent.id,
|
|
1322
|
-
...name === void 0 ? {} : { name },
|
|
1323
|
-
...description === void 0 ? {} : { description },
|
|
1324
|
-
quickPrompts: agent.quickPrompts ?? [],
|
|
1325
|
-
...agent.metadata === void 0 ? {} : { metadata: agent.metadata }
|
|
1326
|
-
};
|
|
1327
|
-
}
|
|
1328
|
-
function agentRuntimeSummary(agent) {
|
|
1329
|
-
const tools = agentToolItems(agent);
|
|
1330
|
-
const name = agent.name ?? agent.agent.name;
|
|
1331
|
-
const description = agent.description ?? agent.agent.description;
|
|
1332
|
-
return {
|
|
1333
|
-
id: agent.id,
|
|
1334
|
-
...name === void 0 ? {} : { name },
|
|
1335
|
-
...description === void 0 ? {} : { description },
|
|
1336
|
-
model: toJsonValue(agent.agent.model),
|
|
1337
|
-
toolCount: tools.length,
|
|
1338
|
-
staticToolCount: tools.filter((item) => item.source === "static").length,
|
|
1339
|
-
dynamicToolCount: tools.filter((item) => item.source === "dynamic").length,
|
|
1340
|
-
approvalToolCount: tools.filter((item) => item.tool.approval !== void 0).length,
|
|
1341
|
-
mcpToolCount: tools.filter((item) => mcpServerName(item.tool) !== void 0).length,
|
|
1342
|
-
staticContextCount: agent.agent.staticContext.length,
|
|
1343
|
-
dynamicContextCount: agent.agent.dynamicContexts.length,
|
|
1344
|
-
observerCount: agent.agent.observers.length,
|
|
1345
|
-
hasMemory: agent.agent.memory !== void 0,
|
|
1346
|
-
hasHook: agent.agent.hook !== void 0,
|
|
1347
|
-
hasOutputSchema: agent.agent.outputSchema !== void 0,
|
|
1348
|
-
...agent.agent.defaultMaxTurns === void 0 ? {} : { defaultMaxTurns: agent.agent.defaultMaxTurns },
|
|
1349
|
-
...agent.metadata === void 0 ? {} : { metadata: agent.metadata }
|
|
1350
|
-
};
|
|
1351
|
-
}
|
|
1352
|
-
function pipelineConfig(pipeline) {
|
|
1353
|
-
const graph = pipeline.pipeline.graph();
|
|
1354
|
-
const stageNodes = graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output");
|
|
1355
|
-
return {
|
|
1356
|
-
id: pipeline.id,
|
|
1357
|
-
...pipeline.name === void 0 ? {} : { name: pipeline.name },
|
|
1358
|
-
...pipeline.description === void 0 ? {} : { description: pipeline.description },
|
|
1359
|
-
...pipeline.metadata === void 0 ? {} : { metadata: pipeline.metadata },
|
|
1360
|
-
stageCount: stageNodes.length,
|
|
1361
|
-
edgeCount: graph.edges.length,
|
|
1362
|
-
hasParallelStages: graph.nodes.some((node) => node.kind === "parallel"),
|
|
1363
|
-
agentCount: graph.nodes.filter((node) => node.kind === "agent").length,
|
|
1364
|
-
extractorCount: graph.nodes.filter((node) => node.kind === "extractor").length
|
|
1365
|
-
};
|
|
1366
|
-
}
|
|
1367
|
-
function capabilityConfig(_options, agents, pipelines, stores) {
|
|
1368
|
-
const capabilities = {
|
|
1369
|
-
agents: { enabled: true },
|
|
1370
|
-
observability: { enabled: true },
|
|
1371
|
-
status: { enabled: true }
|
|
1372
|
-
};
|
|
1373
|
-
if (stores.sessions !== void 0) {
|
|
1374
|
-
capabilities.sessions = { enabled: true };
|
|
1375
|
-
capabilities.memory = { enabled: true };
|
|
1376
|
-
}
|
|
1377
|
-
if (stores.traces !== void 0) {
|
|
1378
|
-
capabilities.traces = { enabled: true };
|
|
1379
|
-
}
|
|
1380
|
-
if (pipelines.length > 0) {
|
|
1381
|
-
capabilities.pipelines = { enabled: true };
|
|
1382
|
-
}
|
|
1383
|
-
if (_options.evals.length > 0) {
|
|
1384
|
-
capabilities.evals = { enabled: true };
|
|
1385
|
-
}
|
|
1386
|
-
if (agents.some(
|
|
1387
|
-
(agent) => agent.agent.toolSet.values().length > 0 || agent.agent.dynamicTools.length > 0
|
|
1388
|
-
)) {
|
|
1389
|
-
capabilities.tools = { enabled: true };
|
|
1390
|
-
}
|
|
1391
|
-
if (agents.some(agentHasMcpTools)) {
|
|
1392
|
-
capabilities.mcps = { enabled: true };
|
|
1393
|
-
}
|
|
1394
|
-
if (agents.some(
|
|
1395
|
-
(agent) => agent.agent.hook !== void 0 || agent.agent.toolSet.values().some((tool) => tool.approval)
|
|
1396
|
-
)) {
|
|
1397
|
-
capabilities.approvals = { enabled: true };
|
|
1398
|
-
}
|
|
1399
|
-
if (agents.some(
|
|
1400
|
-
(agent) => agent.agent.staticContext.length > 0 || agent.agent.dynamicContexts.length > 0 || agent.agent.dynamicTools.length > 0
|
|
1401
|
-
)) {
|
|
1402
|
-
capabilities.knowledge = { enabled: true };
|
|
1403
|
-
}
|
|
1404
|
-
return capabilities;
|
|
1405
|
-
}
|
|
1406
|
-
function evalConfig(suite) {
|
|
1407
|
-
return {
|
|
1408
|
-
id: suite.id ?? suite.name,
|
|
1409
|
-
name: suite.name,
|
|
1410
|
-
...suite.description === void 0 ? {} : { description: suite.description },
|
|
1411
|
-
caseCount: suite.cases.length,
|
|
1412
|
-
metricNames: suite.metrics.map((metric) => metric.name),
|
|
1413
|
-
...suite.concurrency === void 0 ? {} : { concurrency: suite.concurrency },
|
|
1414
|
-
...suite.metadata === void 0 ? {} : { metadata: suite.metadata }
|
|
1415
|
-
};
|
|
1416
|
-
}
|
|
1417
|
-
function optionalQueryString(value) {
|
|
1418
|
-
const trimmed = value?.trim();
|
|
1419
|
-
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
1420
|
-
}
|
|
1421
|
-
function parseLimit(value) {
|
|
1422
|
-
if (value === void 0 || value.trim().length === 0) {
|
|
1423
|
-
return 50;
|
|
1424
|
-
}
|
|
1425
|
-
const limit = Number(value);
|
|
1426
|
-
if (!Number.isInteger(limit) || limit <= 0) {
|
|
1427
|
-
return void 0;
|
|
1428
|
-
}
|
|
1429
|
-
return Math.min(limit, 100);
|
|
1430
|
-
}
|
|
1431
|
-
function parseTraceStatus(value) {
|
|
1432
|
-
const status = optionalQueryString(value);
|
|
1433
|
-
if (status === void 0) {
|
|
1434
|
-
return void 0;
|
|
1435
|
-
}
|
|
1436
|
-
return status === "running" || status === "success" || status === "error" ? status : false;
|
|
1437
|
-
}
|
|
1438
|
-
function isMessageInput(value) {
|
|
1439
|
-
return typeof value === "string" || isMessage(value);
|
|
1440
|
-
}
|
|
1441
|
-
function isMessage(value) {
|
|
1442
|
-
if (!isObject(value) || typeof value.role !== "string") {
|
|
1443
|
-
return false;
|
|
1444
|
-
}
|
|
1445
|
-
if (value.role === "system") {
|
|
1446
|
-
return typeof value.content === "string";
|
|
1447
|
-
}
|
|
1448
|
-
if (value.role === "user" || value.role === "assistant" || value.role === "tool") {
|
|
1449
|
-
return Array.isArray(value.content);
|
|
1450
|
-
}
|
|
1451
|
-
return false;
|
|
1452
|
-
}
|
|
1453
|
-
function isObject(value) {
|
|
1454
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1455
|
-
}
|
|
1456
|
-
function isJsonObject2(value) {
|
|
1457
|
-
return isObject(value) && Object.values(value).every(isJsonValue2);
|
|
1458
|
-
}
|
|
1459
|
-
function isJsonValue2(value) {
|
|
1460
|
-
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1461
|
-
return true;
|
|
1462
|
-
}
|
|
1463
|
-
if (Array.isArray(value)) {
|
|
1464
|
-
return value.every(isJsonValue2);
|
|
1465
|
-
}
|
|
1466
|
-
return isJsonObject2(value);
|
|
1467
|
-
}
|
|
1468
|
-
function isAgentTraceOptions(value) {
|
|
1469
|
-
if (!isObject(value)) {
|
|
1470
|
-
return false;
|
|
1471
|
-
}
|
|
1472
|
-
return optionalString(value.name) && optionalString(value.userId) && optionalString(value.sessionId) && optionalString(value.version) && optionalString(value.traceId) && optionalBoolean(value.failOnObserverError) && optionalStringArray(value.tags) && optionalObject(value.metadata);
|
|
1473
|
-
}
|
|
1474
|
-
function optionalString(value) {
|
|
1475
|
-
return value === void 0 || typeof value === "string";
|
|
1476
|
-
}
|
|
1477
|
-
function optionalBoolean(value) {
|
|
1478
|
-
return value === void 0 || typeof value === "boolean";
|
|
1479
|
-
}
|
|
1480
|
-
function optionalStringArray(value) {
|
|
1481
|
-
return value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
1482
|
-
}
|
|
1483
|
-
function optionalObject(value) {
|
|
1484
|
-
return value === void 0 || isObject(value);
|
|
1485
|
-
}
|
|
1486
|
-
function isNonNegativeInteger(value) {
|
|
1487
|
-
return Number.isInteger(value) && typeof value === "number" && value >= 0;
|
|
1488
|
-
}
|
|
1489
|
-
function isPositiveInteger(value) {
|
|
1490
|
-
return Number.isInteger(value) && typeof value === "number" && value > 0;
|
|
1491
|
-
}
|
|
1492
|
-
function unsupportedCapability(c, capability) {
|
|
1493
|
-
return errorResponse(
|
|
1494
|
-
c,
|
|
1495
|
-
501,
|
|
1496
|
-
"unsupported_capability",
|
|
1497
|
-
`Capability "${capability}" is not implemented by this runner`,
|
|
1498
|
-
{ capability }
|
|
1499
|
-
);
|
|
1500
|
-
}
|
|
1501
|
-
function errorResponse(c, status, code, message, details) {
|
|
1502
|
-
const body = {
|
|
1503
|
-
error: {
|
|
1504
|
-
code,
|
|
1505
|
-
message
|
|
1506
|
-
}
|
|
1507
|
-
};
|
|
1508
|
-
if (details !== void 0) {
|
|
1509
|
-
body.error.details = details;
|
|
1510
|
-
}
|
|
1511
|
-
return c.json(body, status);
|
|
1512
|
-
}
|
|
1513
|
-
function serializeError(error) {
|
|
1514
|
-
return serializeUnknown(error);
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
|
-
// src/runtime/approvals.ts
|
|
1518
|
-
function registerApprovalRoutes(app, approvals) {
|
|
1519
|
-
app.get("/approvals", (c) => {
|
|
1520
|
-
const status = parseApprovalStatus(c.req.query("status"));
|
|
1521
|
-
if (status === false) {
|
|
1522
|
-
return errorResponse(c, 400, "bad_request", "status must be pending or resolved");
|
|
1523
|
-
}
|
|
1524
|
-
const options = {};
|
|
1525
|
-
const runId = optionalQueryString(c.req.query("runId"));
|
|
1526
|
-
const agentId = optionalQueryString(c.req.query("agentId"));
|
|
1527
|
-
const sessionId = optionalQueryString(c.req.query("sessionId"));
|
|
1528
|
-
if (status !== void 0) {
|
|
1529
|
-
options.status = status;
|
|
976
|
+
const options = {};
|
|
977
|
+
const runId = optionalQueryString(c.req.query("runId"));
|
|
978
|
+
const agentId = optionalQueryString(c.req.query("agentId"));
|
|
979
|
+
const sessionId = optionalQueryString(c.req.query("sessionId"));
|
|
980
|
+
if (status !== void 0) {
|
|
981
|
+
options.status = status;
|
|
1530
982
|
}
|
|
1531
983
|
if (runId !== void 0) {
|
|
1532
984
|
options.runId = runId;
|
|
@@ -1579,10 +1031,10 @@ async function parseApprovalDecisionRequest(c) {
|
|
|
1579
1031
|
if ("reason" in body && typeof body.reason !== "string") {
|
|
1580
1032
|
return { error: errorResponse(c, 400, "bad_request", "reason must be a string") };
|
|
1581
1033
|
}
|
|
1582
|
-
return {
|
|
1034
|
+
return compact({
|
|
1583
1035
|
approved: body.approved,
|
|
1584
|
-
|
|
1585
|
-
};
|
|
1036
|
+
reason: typeof body.reason === "string" && body.reason.trim().length > 0 ? body.reason.trim() : void 0
|
|
1037
|
+
});
|
|
1586
1038
|
}
|
|
1587
1039
|
function createApprovalRuntime() {
|
|
1588
1040
|
const approvals = /* @__PURE__ */ new Map();
|
|
@@ -1590,14 +1042,14 @@ function createApprovalRuntime() {
|
|
|
1590
1042
|
approvals,
|
|
1591
1043
|
createHook(context) {
|
|
1592
1044
|
const handleApprovalRequest = async ({ toolName, toolCallId, internalCallId, args, tool: control }, request) => {
|
|
1593
|
-
const decision = await requestApproval(approvals, context, {
|
|
1045
|
+
const decision = await requestApproval(approvals, context, compact({
|
|
1594
1046
|
toolName,
|
|
1595
|
-
|
|
1047
|
+
toolCallId,
|
|
1596
1048
|
internalCallId,
|
|
1597
1049
|
args,
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
});
|
|
1050
|
+
reason: request.reason,
|
|
1051
|
+
rejectMessage: request.rejectMessage
|
|
1052
|
+
}));
|
|
1601
1053
|
return decision.approved ? control.run() : control.skip(decision.reason ?? request.rejectMessage ?? "Rejected in Anvia Studio.");
|
|
1602
1054
|
};
|
|
1603
1055
|
return {
|
|
@@ -1610,19 +1062,19 @@ function createApprovalRuntime() {
|
|
|
1610
1062
|
const approval = registeredTool.approval;
|
|
1611
1063
|
const rawParsedArgs = parseToolArgs(args);
|
|
1612
1064
|
const parsedArgs = registeredTool.parseApprovalArgs?.(rawParsedArgs) ?? rawParsedArgs;
|
|
1613
|
-
const approvalContext = {
|
|
1065
|
+
const approvalContext = compact({
|
|
1614
1066
|
toolName,
|
|
1615
1067
|
args: parsedArgs,
|
|
1616
1068
|
rawArgs: args,
|
|
1617
|
-
|
|
1069
|
+
toolCallId,
|
|
1618
1070
|
internalCallId,
|
|
1619
|
-
run: {
|
|
1071
|
+
run: compact({
|
|
1620
1072
|
agentId: context.agentId,
|
|
1621
1073
|
runId: context.runId,
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
}
|
|
1625
|
-
};
|
|
1074
|
+
sessionId: context.sessionId,
|
|
1075
|
+
metadata: context.metadata
|
|
1076
|
+
})
|
|
1077
|
+
});
|
|
1626
1078
|
const required = await approval.when(approvalContext);
|
|
1627
1079
|
if (!required) {
|
|
1628
1080
|
return control.run();
|
|
@@ -1632,14 +1084,14 @@ function createApprovalRuntime() {
|
|
|
1632
1084
|
approval.rejectMessage,
|
|
1633
1085
|
approvalContext
|
|
1634
1086
|
);
|
|
1635
|
-
const decision = await requestApproval(approvals, context, {
|
|
1087
|
+
const decision = await requestApproval(approvals, context, compact({
|
|
1636
1088
|
toolName,
|
|
1637
|
-
|
|
1089
|
+
toolCallId,
|
|
1638
1090
|
internalCallId,
|
|
1639
1091
|
args,
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
});
|
|
1092
|
+
reason,
|
|
1093
|
+
rejectMessage
|
|
1094
|
+
}));
|
|
1643
1095
|
return decision.approved ? control.run() : control.skip(decision.reason ?? rejectMessage ?? "Rejected in Anvia Studio.");
|
|
1644
1096
|
}
|
|
1645
1097
|
}),
|
|
@@ -1675,90 +1127,592 @@ function createApprovalRuntime() {
|
|
|
1675
1127
|
return "resolved";
|
|
1676
1128
|
}
|
|
1677
1129
|
const reason = decision.approved ? decision.reason : decision.reason ?? approval.rejectMessage ?? "Rejected in Anvia Studio.";
|
|
1678
|
-
const resolved = resolveApproval(approval, decision.approved ? "approved" : "rejected", {
|
|
1679
|
-
...reason === void 0 ? {} : { reason }
|
|
1680
|
-
});
|
|
1130
|
+
const resolved = resolveApproval(approval, decision.approved ? "approved" : "rejected", compact({ reason }));
|
|
1681
1131
|
approvals.set(id, resolved);
|
|
1682
1132
|
approval.emit?.({ type: "tool_approval_result", approval: resolved });
|
|
1683
|
-
approval.resolve({
|
|
1133
|
+
approval.resolve(compact({
|
|
1684
1134
|
approved: decision.approved,
|
|
1685
|
-
|
|
1686
|
-
});
|
|
1135
|
+
reason
|
|
1136
|
+
}));
|
|
1687
1137
|
return publicApproval(resolved);
|
|
1688
1138
|
}
|
|
1689
1139
|
};
|
|
1690
1140
|
}
|
|
1691
|
-
async function requestApproval(approvals, context, request) {
|
|
1692
|
-
const id = globalThis.crypto.randomUUID();
|
|
1693
|
-
const approval = {
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
});
|
|
1726
|
-
approvals.set(id, resolved);
|
|
1727
|
-
context.emit?.({ type: "tool_approval_result", approval: resolved });
|
|
1728
|
-
resolve2({
|
|
1729
|
-
approved: decision2.approved,
|
|
1730
|
-
|
|
1731
|
-
});
|
|
1732
|
-
};
|
|
1141
|
+
async function requestApproval(approvals, context, request) {
|
|
1142
|
+
const id = globalThis.crypto.randomUUID();
|
|
1143
|
+
const approval = {
|
|
1144
|
+
...compact({
|
|
1145
|
+
id,
|
|
1146
|
+
runId: context.runId,
|
|
1147
|
+
agentId: context.agentId,
|
|
1148
|
+
sessionId: context.sessionId,
|
|
1149
|
+
toolName: request.toolName,
|
|
1150
|
+
callId: request.toolCallId,
|
|
1151
|
+
internalCallId: request.internalCallId,
|
|
1152
|
+
args: request.args,
|
|
1153
|
+
status: "pending",
|
|
1154
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1155
|
+
reason: request.reason,
|
|
1156
|
+
rejectMessage: request.rejectMessage,
|
|
1157
|
+
emit: context.emit
|
|
1158
|
+
}),
|
|
1159
|
+
resolve: () => {
|
|
1160
|
+
}
|
|
1161
|
+
};
|
|
1162
|
+
const decision = new Promise((resolve2) => {
|
|
1163
|
+
approval.resolve = (decision2) => {
|
|
1164
|
+
const current = approvals.get(id);
|
|
1165
|
+
if (!isPendingApproval(current)) {
|
|
1166
|
+
if (current !== void 0) {
|
|
1167
|
+
resolve2(compact({
|
|
1168
|
+
approved: current.status === "approved",
|
|
1169
|
+
reason: current.reason
|
|
1170
|
+
}));
|
|
1171
|
+
}
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
const reason = decision2.approved ? decision2.reason : decision2.reason ?? request.rejectMessage ?? "Rejected in Anvia Studio.";
|
|
1175
|
+
const resolved = resolveApproval(current, decision2.approved ? "approved" : "rejected", compact({ reason }));
|
|
1176
|
+
approvals.set(id, resolved);
|
|
1177
|
+
context.emit?.({ type: "tool_approval_result", approval: resolved });
|
|
1178
|
+
resolve2(compact({
|
|
1179
|
+
approved: decision2.approved,
|
|
1180
|
+
reason
|
|
1181
|
+
}));
|
|
1182
|
+
};
|
|
1183
|
+
});
|
|
1184
|
+
approvals.set(id, approval);
|
|
1185
|
+
context.emit?.({ type: "tool_approval_request", approval: publicApproval(approval) });
|
|
1186
|
+
return decision;
|
|
1187
|
+
}
|
|
1188
|
+
async function resolveApprovalText(value, context) {
|
|
1189
|
+
return typeof value === "function" ? value(context) : value;
|
|
1190
|
+
}
|
|
1191
|
+
function isPendingApproval(approval) {
|
|
1192
|
+
return approval !== void 0 && approval.status === "pending" && "resolve" in approval;
|
|
1193
|
+
}
|
|
1194
|
+
function resolveApproval(approval, status, options = {}) {
|
|
1195
|
+
return publicApproval({
|
|
1196
|
+
...approval,
|
|
1197
|
+
...compact({
|
|
1198
|
+
status,
|
|
1199
|
+
resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1200
|
+
reason: options.reason
|
|
1201
|
+
})
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
function publicApproval(approval) {
|
|
1205
|
+
const { emit, rejectMessage, resolve: resolve2, ...rest } = approval;
|
|
1206
|
+
void emit;
|
|
1207
|
+
void rejectMessage;
|
|
1208
|
+
void resolve2;
|
|
1209
|
+
return rest;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// src/runtime/evals.ts
|
|
1213
|
+
import { runEvalSuite } from "@anvia/core/evals";
|
|
1214
|
+
|
|
1215
|
+
// src/runtime/models.ts
|
|
1216
|
+
var STUDIO_MODEL_METADATA_KEY = "studioModel";
|
|
1217
|
+
function createStudioModelRegistry(config) {
|
|
1218
|
+
if (config === void 0) {
|
|
1219
|
+
return void 0;
|
|
1220
|
+
}
|
|
1221
|
+
const providers = /* @__PURE__ */ new Map();
|
|
1222
|
+
for (const provider of config.providers) {
|
|
1223
|
+
const id = normalizeProviderId(provider.id);
|
|
1224
|
+
if (providers.has(id)) {
|
|
1225
|
+
throw new Error(`Duplicate Studio model provider id: ${id}`);
|
|
1226
|
+
}
|
|
1227
|
+
const staticModels = /* @__PURE__ */ new Map();
|
|
1228
|
+
for (const model of provider.models ?? []) {
|
|
1229
|
+
const modelId = normalizeModelId(model.id);
|
|
1230
|
+
if (staticModels.has(modelId)) {
|
|
1231
|
+
throw new Error(`Duplicate Studio model id for provider ${id}: ${modelId}`);
|
|
1232
|
+
}
|
|
1233
|
+
staticModels.set(modelId, { ...model, id: modelId });
|
|
1234
|
+
}
|
|
1235
|
+
providers.set(id, {
|
|
1236
|
+
...provider,
|
|
1237
|
+
id,
|
|
1238
|
+
...compact({ defaultModel: provider.defaultModel !== void 0 ? normalizeModelId(provider.defaultModel) : void 0 }),
|
|
1239
|
+
staticModels
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
return {
|
|
1243
|
+
...compact({ defaultModel: config.default !== void 0 ? normalizeModelRef(config.default) : void 0 }),
|
|
1244
|
+
providers,
|
|
1245
|
+
agentPolicies: normalizeAgentPolicies(config.agents ?? {}),
|
|
1246
|
+
modelCache: /* @__PURE__ */ new Map()
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
function studioModelsConfig(registry, agents) {
|
|
1250
|
+
if (registry === void 0) {
|
|
1251
|
+
return void 0;
|
|
1252
|
+
}
|
|
1253
|
+
const providers = [...registry.providers.values()].map((provider) => {
|
|
1254
|
+
const models = [...provider.staticModels.values()].map(
|
|
1255
|
+
(model) => modelSummary(provider, model.id, model)
|
|
1256
|
+
);
|
|
1257
|
+
return {
|
|
1258
|
+
id: provider.id,
|
|
1259
|
+
...compact({ name: provider.name, defaultModel: provider.defaultModel, metadata: provider.metadata }),
|
|
1260
|
+
models
|
|
1261
|
+
};
|
|
1262
|
+
});
|
|
1263
|
+
const agentIds = new Set(agents.map((agent) => agent.id));
|
|
1264
|
+
const agentsConfig = Object.fromEntries(
|
|
1265
|
+
[...registry.agentPolicies.entries()].filter(([agentId]) => agentIds.has(agentId)).map(([agentId, policy]) => [agentId, publicPolicy(policy)])
|
|
1266
|
+
);
|
|
1267
|
+
return {
|
|
1268
|
+
providers,
|
|
1269
|
+
...compact({ default: registry.defaultModel }),
|
|
1270
|
+
agents: agentsConfig
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
function registerModelRoutes(app, props) {
|
|
1274
|
+
app.get("/models", async (c) => {
|
|
1275
|
+
if (props.registry === void 0) {
|
|
1276
|
+
return errorResponse(c, 404, "not_found", "Model registry not configured");
|
|
1277
|
+
}
|
|
1278
|
+
const providers = await Promise.all(
|
|
1279
|
+
[...props.registry.providers.values()].map((provider) => providerCatalog(provider))
|
|
1280
|
+
);
|
|
1281
|
+
return c.json({
|
|
1282
|
+
providers,
|
|
1283
|
+
...compact({ defaultModel: props.registry.defaultModel })
|
|
1284
|
+
});
|
|
1285
|
+
});
|
|
1286
|
+
app.get("/models/:providerId", async (c) => {
|
|
1287
|
+
if (props.registry === void 0) {
|
|
1288
|
+
return errorResponse(c, 404, "not_found", "Model registry not configured");
|
|
1289
|
+
}
|
|
1290
|
+
const provider = props.registry.providers.get(c.req.param("providerId"));
|
|
1291
|
+
if (provider === void 0) {
|
|
1292
|
+
return errorResponse(c, 404, "not_found", "Model provider not found");
|
|
1293
|
+
}
|
|
1294
|
+
return c.json(await providerCatalog(provider));
|
|
1295
|
+
});
|
|
1296
|
+
app.get("/agents/:agentId/models", async (c) => {
|
|
1297
|
+
const agentId = c.req.param("agentId");
|
|
1298
|
+
const agent = props.agentMap.get(agentId);
|
|
1299
|
+
if (agent === void 0) {
|
|
1300
|
+
return errorResponse(c, 404, "not_found", "Agent not found");
|
|
1301
|
+
}
|
|
1302
|
+
if (props.registry === void 0) {
|
|
1303
|
+
return c.json({
|
|
1304
|
+
agentId,
|
|
1305
|
+
models: []
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
return c.json(await agentModelsCatalog(props.registry, agent));
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
function resolveStudioModel(registry, input) {
|
|
1312
|
+
if (registry === void 0) {
|
|
1313
|
+
return { warnings: [] };
|
|
1314
|
+
}
|
|
1315
|
+
const selectedRef = normalizeOptionalModelRef(input.request.model) ?? sessionModelRef(input.sessionMetadata) ?? registry.agentPolicies.get(input.agent.id)?.default ?? registry.defaultModel;
|
|
1316
|
+
if (selectedRef === void 0) {
|
|
1317
|
+
return { warnings: [] };
|
|
1318
|
+
}
|
|
1319
|
+
ensureModelAllowed(registry, input.agent.id, selectedRef);
|
|
1320
|
+
const { providerId, modelId } = parseModelRef(selectedRef);
|
|
1321
|
+
const provider = registry.providers.get(providerId);
|
|
1322
|
+
if (provider === void 0) {
|
|
1323
|
+
throw new ModelSelectionError(`Unknown model provider: ${providerId}`);
|
|
1324
|
+
}
|
|
1325
|
+
let model = registry.modelCache.get(selectedRef);
|
|
1326
|
+
if (model === void 0) {
|
|
1327
|
+
model = provider.createCompletionModel(modelId);
|
|
1328
|
+
registry.modelCache.set(selectedRef, model);
|
|
1329
|
+
}
|
|
1330
|
+
const metadata = provider.staticModels.get(modelId);
|
|
1331
|
+
return {
|
|
1332
|
+
ref: selectedRef,
|
|
1333
|
+
model,
|
|
1334
|
+
warnings: modelWarnings(selectedRef, metadata, input.request)
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
function sessionModelRef(metadata) {
|
|
1338
|
+
const value = metadata?.[STUDIO_MODEL_METADATA_KEY];
|
|
1339
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
1340
|
+
}
|
|
1341
|
+
function normalizeOptionalModelRef(ref) {
|
|
1342
|
+
return ref === void 0 ? void 0 : normalizeModelRef(ref);
|
|
1343
|
+
}
|
|
1344
|
+
function normalizeModelRef(ref) {
|
|
1345
|
+
if (typeof ref === "string") {
|
|
1346
|
+
const trimmed = ref.trim();
|
|
1347
|
+
const parsed = parseModelRef(trimmed);
|
|
1348
|
+
return `${parsed.providerId}:${parsed.modelId}`;
|
|
1349
|
+
}
|
|
1350
|
+
return `${normalizeProviderId(ref.provider)}:${normalizeModelId(ref.model)}`;
|
|
1351
|
+
}
|
|
1352
|
+
function parseModelRef(ref) {
|
|
1353
|
+
const index = ref.indexOf(":");
|
|
1354
|
+
if (index <= 0 || index === ref.length - 1) {
|
|
1355
|
+
throw new ModelSelectionError(`Model ref must use provider:model format: ${ref}`);
|
|
1356
|
+
}
|
|
1357
|
+
return {
|
|
1358
|
+
providerId: normalizeProviderId(ref.slice(0, index)),
|
|
1359
|
+
modelId: normalizeModelId(ref.slice(index + 1))
|
|
1360
|
+
};
|
|
1361
|
+
}
|
|
1362
|
+
var ModelSelectionError = class extends Error {
|
|
1363
|
+
constructor(message) {
|
|
1364
|
+
super(message);
|
|
1365
|
+
this.name = "ModelSelectionError";
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
1368
|
+
async function agentModelsCatalog(registry, agent) {
|
|
1369
|
+
const policy = registry.agentPolicies.get(agent.id);
|
|
1370
|
+
const catalogs = await Promise.all([...registry.providers.values()].map(providerCatalog));
|
|
1371
|
+
const warnings = catalogs.flatMap(
|
|
1372
|
+
(catalog) => catalog.warning === void 0 ? [] : [{ providerId: catalog.id, warning: catalog.warning }]
|
|
1373
|
+
);
|
|
1374
|
+
const models = catalogs.flatMap((catalog) => catalog.models).filter((model) => {
|
|
1375
|
+
if (policy?.allowed === void 0) {
|
|
1376
|
+
return true;
|
|
1377
|
+
}
|
|
1378
|
+
return allowedByPolicy(policy.allowed, model.ref);
|
|
1379
|
+
});
|
|
1380
|
+
const exactPolicyModels = (policy?.allowed ?? []).filter((allowed) => !allowed.endsWith(":*")).filter((allowed) => models.every((model) => model.ref !== allowed)).flatMap((ref) => {
|
|
1381
|
+
try {
|
|
1382
|
+
const { providerId, modelId } = parseModelRef(ref);
|
|
1383
|
+
const provider = registry.providers.get(providerId);
|
|
1384
|
+
return provider === void 0 ? [] : [
|
|
1385
|
+
modelSummary(provider, modelId, {
|
|
1386
|
+
id: modelId
|
|
1387
|
+
})
|
|
1388
|
+
];
|
|
1389
|
+
} catch {
|
|
1390
|
+
return [];
|
|
1391
|
+
}
|
|
1392
|
+
});
|
|
1393
|
+
const defaultModel = policy?.default ?? registry.defaultModel;
|
|
1394
|
+
return {
|
|
1395
|
+
agentId: agent.id,
|
|
1396
|
+
...compact({ defaultModel }),
|
|
1397
|
+
models: [...models, ...exactPolicyModels],
|
|
1398
|
+
...compact({ warnings: warnings.length === 0 ? void 0 : warnings })
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
async function providerCatalog(provider) {
|
|
1402
|
+
const models = /* @__PURE__ */ new Map();
|
|
1403
|
+
for (const model of provider.staticModels.values()) {
|
|
1404
|
+
models.set(model.id, modelSummary(provider, model.id, model));
|
|
1405
|
+
}
|
|
1406
|
+
let warning;
|
|
1407
|
+
if (provider.listModels !== void 0) {
|
|
1408
|
+
try {
|
|
1409
|
+
const listed = await provider.listModels();
|
|
1410
|
+
for (const model of listed.data) {
|
|
1411
|
+
const staticModel = provider.staticModels.get(model.id);
|
|
1412
|
+
models.set(
|
|
1413
|
+
model.id,
|
|
1414
|
+
modelSummary(provider, model.id, {
|
|
1415
|
+
id: model.id,
|
|
1416
|
+
...compact({ name: model.name, description: model.description }),
|
|
1417
|
+
...staticModel ?? {},
|
|
1418
|
+
metadata: {
|
|
1419
|
+
...compact({
|
|
1420
|
+
type: model.type,
|
|
1421
|
+
createdAt: model.createdAt,
|
|
1422
|
+
ownedBy: model.ownedBy,
|
|
1423
|
+
contextLength: model.contextLength
|
|
1424
|
+
}),
|
|
1425
|
+
...staticModel?.metadata ?? {}
|
|
1426
|
+
}
|
|
1427
|
+
})
|
|
1428
|
+
);
|
|
1429
|
+
}
|
|
1430
|
+
} catch (error) {
|
|
1431
|
+
const serialized = serializeError(error);
|
|
1432
|
+
warning = typeof serialized === "object" && serialized !== null && "message" in serialized ? String(serialized.message) : String(error);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
return {
|
|
1436
|
+
id: provider.id,
|
|
1437
|
+
...compact({ name: provider.name, defaultModel: provider.defaultModel, metadata: provider.metadata, warning }),
|
|
1438
|
+
models: [...models.values()].sort((left, right) => left.ref.localeCompare(right.ref))
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
function modelSummary(provider, modelId, model) {
|
|
1442
|
+
return {
|
|
1443
|
+
...model,
|
|
1444
|
+
id: modelId,
|
|
1445
|
+
ref: `${provider.id}:${modelId}`,
|
|
1446
|
+
providerId: provider.id,
|
|
1447
|
+
...compact({ providerName: provider.name })
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
function ensureModelAllowed(registry, agentId, ref) {
|
|
1451
|
+
const { providerId } = parseModelRef(ref);
|
|
1452
|
+
if (!registry.providers.has(providerId)) {
|
|
1453
|
+
throw new ModelSelectionError(`Unknown model provider: ${providerId}`);
|
|
1454
|
+
}
|
|
1455
|
+
const policy = registry.agentPolicies.get(agentId);
|
|
1456
|
+
if (policy?.allowed !== void 0 && !allowedByPolicy(policy.allowed, ref)) {
|
|
1457
|
+
throw new ModelSelectionError(`Model ${ref} is not allowed for agent ${agentId}`);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
function allowedByPolicy(allowed, ref) {
|
|
1461
|
+
return allowed.some(
|
|
1462
|
+
(entry) => entry.endsWith(":*") ? ref.startsWith(entry.slice(0, -1)) : entry === ref
|
|
1463
|
+
);
|
|
1464
|
+
}
|
|
1465
|
+
function normalizeAgentPolicies(policies) {
|
|
1466
|
+
return new Map(
|
|
1467
|
+
Object.entries(policies).map(([agentId, policy]) => [
|
|
1468
|
+
agentId.trim(),
|
|
1469
|
+
{
|
|
1470
|
+
...compact({
|
|
1471
|
+
default: policy.default !== void 0 ? normalizeModelRef(policy.default) : void 0,
|
|
1472
|
+
allowed: policy.allowed?.map(
|
|
1473
|
+
(entry) => typeof entry === "string" && entry.trim().endsWith(":*") ? `${normalizeProviderId(entry.trim().slice(0, -2))}:*` : normalizeModelRef(entry)
|
|
1474
|
+
)
|
|
1475
|
+
})
|
|
1476
|
+
}
|
|
1477
|
+
])
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
function publicPolicy(policy) {
|
|
1481
|
+
return compact({ default: policy.default, allowed: policy.allowed });
|
|
1482
|
+
}
|
|
1483
|
+
function modelWarnings(ref, model, request) {
|
|
1484
|
+
const warnings = [];
|
|
1485
|
+
const modalities = requestModalities(request);
|
|
1486
|
+
const missingModalities = [...modalities].filter(
|
|
1487
|
+
(modality) => !model?.modalities?.input.includes(modality)
|
|
1488
|
+
);
|
|
1489
|
+
if (model?.modalities !== void 0 && missingModalities.length > 0) {
|
|
1490
|
+
warnings.push({
|
|
1491
|
+
model: ref,
|
|
1492
|
+
kind: "modality",
|
|
1493
|
+
message: `Model ${ref} does not declare input support for ${missingModalities.join(", ")}`,
|
|
1494
|
+
missing: missingModalities
|
|
1495
|
+
});
|
|
1496
|
+
}
|
|
1497
|
+
if (request.stream === true && model?.capabilities?.streaming === false) {
|
|
1498
|
+
warnings.push({
|
|
1499
|
+
model: ref,
|
|
1500
|
+
kind: "capability",
|
|
1501
|
+
message: `Model ${ref} is configured as non-streaming but the run requested streaming`,
|
|
1502
|
+
capability: "streaming"
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
return warnings;
|
|
1506
|
+
}
|
|
1507
|
+
function requestModalities(request) {
|
|
1508
|
+
const modalities = /* @__PURE__ */ new Set(["text"]);
|
|
1509
|
+
for (const message of requestMessages(request)) {
|
|
1510
|
+
if (typeof message === "string") {
|
|
1511
|
+
continue;
|
|
1512
|
+
}
|
|
1513
|
+
if (message.role === "user" || message.role === "assistant") {
|
|
1514
|
+
for (const content of message.content) {
|
|
1515
|
+
if (content.type === "image") {
|
|
1516
|
+
modalities.add("image");
|
|
1517
|
+
}
|
|
1518
|
+
if (content.type === "document") {
|
|
1519
|
+
modalities.add("document");
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
return modalities;
|
|
1525
|
+
}
|
|
1526
|
+
function requestMessages(request) {
|
|
1527
|
+
return [...request.history ?? [], request.message];
|
|
1528
|
+
}
|
|
1529
|
+
function normalizeProviderId(id) {
|
|
1530
|
+
const trimmed = id.trim();
|
|
1531
|
+
if (trimmed.length === 0 || trimmed.includes(":")) {
|
|
1532
|
+
throw new ModelSelectionError("Model provider id must be non-empty and cannot contain ':'");
|
|
1533
|
+
}
|
|
1534
|
+
return trimmed;
|
|
1535
|
+
}
|
|
1536
|
+
function normalizeModelId(id) {
|
|
1537
|
+
const trimmed = id.trim();
|
|
1538
|
+
if (trimmed.length === 0) {
|
|
1539
|
+
throw new ModelSelectionError("Model id cannot be empty");
|
|
1540
|
+
}
|
|
1541
|
+
return trimmed;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
// src/runtime/tool-metadata.ts
|
|
1545
|
+
import { ToolSet } from "@anvia/core/tool";
|
|
1546
|
+
var MCP_TOOL_METADATA_KEY = /* @__PURE__ */ Symbol.for("anvia.mcp.tool.metadata");
|
|
1547
|
+
function agentToolItems(agent) {
|
|
1548
|
+
return [
|
|
1549
|
+
...agent.agent.toolSet.values().map((tool) => ({ tool, source: "static" })),
|
|
1550
|
+
...agent.agent.dynamicTools.flatMap((registration) => {
|
|
1551
|
+
const maybeToolSet = registration.index.toolSet;
|
|
1552
|
+
if (!(maybeToolSet instanceof ToolSet)) {
|
|
1553
|
+
return [];
|
|
1554
|
+
}
|
|
1555
|
+
return maybeToolSet.values().map((tool) => ({ tool, source: "dynamic" }));
|
|
1556
|
+
})
|
|
1557
|
+
];
|
|
1558
|
+
}
|
|
1559
|
+
function approvalMetadata(tool) {
|
|
1560
|
+
const approval = tool.approval;
|
|
1561
|
+
if (approval === void 0 || typeof approval !== "object" || approval === null) {
|
|
1562
|
+
return { required: false };
|
|
1563
|
+
}
|
|
1564
|
+
const policy = approval;
|
|
1565
|
+
return {
|
|
1566
|
+
required: true,
|
|
1567
|
+
...typeof policy.reason === "string" ? { reason: policy.reason } : {},
|
|
1568
|
+
...typeof policy.rejectMessage === "string" ? { rejectMessage: policy.rejectMessage } : {}
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
function mcpServerName(tool) {
|
|
1572
|
+
const metadata = tool[MCP_TOOL_METADATA_KEY];
|
|
1573
|
+
if (typeof metadata !== "object" || metadata === null) {
|
|
1574
|
+
return void 0;
|
|
1575
|
+
}
|
|
1576
|
+
const serverName = metadata.serverName;
|
|
1577
|
+
return typeof serverName === "string" && serverName.length > 0 ? serverName : void 0;
|
|
1578
|
+
}
|
|
1579
|
+
function agentHasMcpTools(agent) {
|
|
1580
|
+
return agentToolItems(agent).some(({ tool }) => mcpServerName(tool) !== void 0);
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
// src/runtime/config.ts
|
|
1584
|
+
function runnerId(options) {
|
|
1585
|
+
return options.id ?? "anvia-studio";
|
|
1586
|
+
}
|
|
1587
|
+
function agentConfig(agent) {
|
|
1588
|
+
const name = agent.name ?? agent.agent.name;
|
|
1589
|
+
const description = agent.description ?? agent.agent.description;
|
|
1590
|
+
return compact({
|
|
1591
|
+
id: agent.id,
|
|
1592
|
+
name,
|
|
1593
|
+
description,
|
|
1594
|
+
quickPrompts: agent.quickPrompts ?? [],
|
|
1595
|
+
metadata: agent.metadata
|
|
1733
1596
|
});
|
|
1734
|
-
approvals.set(id, approval);
|
|
1735
|
-
context.emit?.({ type: "tool_approval_request", approval: publicApproval(approval) });
|
|
1736
|
-
return decision;
|
|
1737
1597
|
}
|
|
1738
|
-
|
|
1739
|
-
|
|
1598
|
+
function agentRuntimeSummary(agent) {
|
|
1599
|
+
const tools = agentToolItems(agent);
|
|
1600
|
+
const name = agent.name ?? agent.agent.name;
|
|
1601
|
+
const description = agent.description ?? agent.agent.description;
|
|
1602
|
+
return compact({
|
|
1603
|
+
id: agent.id,
|
|
1604
|
+
name,
|
|
1605
|
+
description,
|
|
1606
|
+
model: toJsonValue2(agent.agent.model),
|
|
1607
|
+
toolCount: tools.length,
|
|
1608
|
+
staticToolCount: tools.filter((item) => item.source === "static").length,
|
|
1609
|
+
dynamicToolCount: tools.filter((item) => item.source === "dynamic").length,
|
|
1610
|
+
approvalToolCount: tools.filter((item) => item.tool.approval !== void 0).length,
|
|
1611
|
+
mcpToolCount: tools.filter((item) => mcpServerName(item.tool) !== void 0).length,
|
|
1612
|
+
staticContextCount: agent.agent.staticContext.length,
|
|
1613
|
+
dynamicContextCount: agent.agent.dynamicContexts.length,
|
|
1614
|
+
observerCount: agent.agent.observers.length,
|
|
1615
|
+
hasMemory: agent.agent.memory !== void 0,
|
|
1616
|
+
hasHook: agent.agent.hook !== void 0,
|
|
1617
|
+
hasOutputSchema: agent.agent.outputSchema !== void 0,
|
|
1618
|
+
defaultMaxTurns: agent.agent.defaultMaxTurns,
|
|
1619
|
+
metadata: agent.metadata
|
|
1620
|
+
});
|
|
1740
1621
|
}
|
|
1741
|
-
function
|
|
1742
|
-
|
|
1622
|
+
function pipelineConfig(pipeline) {
|
|
1623
|
+
const graph = pipeline.pipeline.graph();
|
|
1624
|
+
const stageNodes = graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output");
|
|
1625
|
+
return compact({
|
|
1626
|
+
id: pipeline.id,
|
|
1627
|
+
name: pipeline.name,
|
|
1628
|
+
description: pipeline.description,
|
|
1629
|
+
metadata: pipeline.metadata,
|
|
1630
|
+
stageCount: stageNodes.length,
|
|
1631
|
+
edgeCount: graph.edges.length,
|
|
1632
|
+
hasParallelStages: graph.nodes.some((node) => node.kind === "parallel"),
|
|
1633
|
+
agentCount: graph.nodes.filter((node) => node.kind === "agent").length,
|
|
1634
|
+
extractorCount: graph.nodes.filter((node) => node.kind === "extractor").length
|
|
1635
|
+
});
|
|
1743
1636
|
}
|
|
1744
|
-
function
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1637
|
+
function buildConfig(options, agents, pipelines, stores) {
|
|
1638
|
+
const models = options.models === void 0 ? void 0 : studioModelsConfig(createStudioModelRegistry(options.models), agents);
|
|
1639
|
+
return compact({
|
|
1640
|
+
id: runnerId(options),
|
|
1641
|
+
name: options.name,
|
|
1642
|
+
description: options.description,
|
|
1643
|
+
version: options.version,
|
|
1644
|
+
agents: agents.map(agentConfig),
|
|
1645
|
+
models,
|
|
1646
|
+
pipelines: pipelines.map(pipelineConfig),
|
|
1647
|
+
evals: options.evals.map(evalConfig),
|
|
1648
|
+
chat: {
|
|
1649
|
+
quickPrompts: Object.fromEntries(agents.map((agent) => [agent.id, agent.quickPrompts ?? []]))
|
|
1650
|
+
},
|
|
1651
|
+
capabilities: capabilityConfig(options, agents, pipelines, stores),
|
|
1652
|
+
unsupportedCapabilities: unsupportedCapabilities(stores)
|
|
1750
1653
|
});
|
|
1751
1654
|
}
|
|
1752
|
-
function
|
|
1753
|
-
const
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1655
|
+
function capabilityConfig(_options, agents, pipelines, stores) {
|
|
1656
|
+
const capabilities = {
|
|
1657
|
+
agents: { enabled: true },
|
|
1658
|
+
observability: { enabled: true },
|
|
1659
|
+
status: { enabled: true }
|
|
1660
|
+
};
|
|
1661
|
+
if (stores.sessions !== void 0) {
|
|
1662
|
+
capabilities.sessions = { enabled: true };
|
|
1663
|
+
capabilities.memory = { enabled: true };
|
|
1664
|
+
}
|
|
1665
|
+
if (stores.traces !== void 0) {
|
|
1666
|
+
capabilities.traces = { enabled: true };
|
|
1667
|
+
}
|
|
1668
|
+
if (pipelines.length > 0) {
|
|
1669
|
+
capabilities.pipelines = { enabled: true };
|
|
1670
|
+
}
|
|
1671
|
+
if (_options.evals.length > 0) {
|
|
1672
|
+
capabilities.evals = { enabled: true };
|
|
1673
|
+
}
|
|
1674
|
+
if (agents.some(
|
|
1675
|
+
(agent) => agent.agent.toolSet.values().length > 0 || agent.agent.dynamicTools.length > 0
|
|
1676
|
+
)) {
|
|
1677
|
+
capabilities.tools = { enabled: true };
|
|
1678
|
+
}
|
|
1679
|
+
if (agents.some(agentHasMcpTools)) {
|
|
1680
|
+
capabilities.mcps = { enabled: true };
|
|
1681
|
+
}
|
|
1682
|
+
if (agents.some(
|
|
1683
|
+
(agent) => agent.agent.hook !== void 0 || agent.agent.toolSet.values().some((tool) => tool.approval)
|
|
1684
|
+
)) {
|
|
1685
|
+
capabilities.approvals = { enabled: true };
|
|
1686
|
+
}
|
|
1687
|
+
if (agents.some(
|
|
1688
|
+
(agent) => agent.agent.staticContext.length > 0 || agent.agent.dynamicContexts.length > 0 || agent.agent.dynamicTools.length > 0
|
|
1689
|
+
)) {
|
|
1690
|
+
capabilities.knowledge = { enabled: true };
|
|
1691
|
+
}
|
|
1692
|
+
return capabilities;
|
|
1693
|
+
}
|
|
1694
|
+
function evalConfig(suite) {
|
|
1695
|
+
return compact({
|
|
1696
|
+
id: suite.id ?? suite.name,
|
|
1697
|
+
name: suite.name,
|
|
1698
|
+
description: suite.description,
|
|
1699
|
+
caseCount: suite.cases.length,
|
|
1700
|
+
metricNames: suite.metrics.map((metric) => metric.name),
|
|
1701
|
+
concurrency: suite.concurrency,
|
|
1702
|
+
metadata: suite.metadata
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
function unsupportedCapabilities(stores) {
|
|
1706
|
+
return [
|
|
1707
|
+
...stores.sessions === void 0 ? ["sessions"] : [],
|
|
1708
|
+
...stores.traces === void 0 ? ["traces"] : []
|
|
1709
|
+
];
|
|
1710
|
+
}
|
|
1711
|
+
function toJsonValue2(value) {
|
|
1712
|
+
return serializeUnknown(value);
|
|
1758
1713
|
}
|
|
1759
1714
|
|
|
1760
1715
|
// src/runtime/evals.ts
|
|
1761
|
-
import { runEvalSuite } from "@anvia/core/evals";
|
|
1762
1716
|
function registerEvalRoutes(app, props) {
|
|
1763
1717
|
app.get(
|
|
1764
1718
|
"/evals",
|
|
@@ -1786,7 +1740,7 @@ function registerEvalRoutes(app, props) {
|
|
|
1786
1740
|
const startedAt = Date.now();
|
|
1787
1741
|
const result = await runEvalSuite({
|
|
1788
1742
|
...suite,
|
|
1789
|
-
...
|
|
1743
|
+
...compact({ concurrency: body.concurrency })
|
|
1790
1744
|
});
|
|
1791
1745
|
const endedAt = Date.now();
|
|
1792
1746
|
const jsonResult = toJsonValue(result);
|
|
@@ -1796,7 +1750,7 @@ function registerEvalRoutes(app, props) {
|
|
|
1796
1750
|
startedAt: new Date(startedAt).toISOString(),
|
|
1797
1751
|
endedAt: new Date(endedAt).toISOString(),
|
|
1798
1752
|
durationMs: endedAt - startedAt,
|
|
1799
|
-
result:
|
|
1753
|
+
result: isJsonObject(jsonResult) ? jsonResult : { value: jsonResult }
|
|
1800
1754
|
};
|
|
1801
1755
|
return c.json(response);
|
|
1802
1756
|
});
|
|
@@ -1864,12 +1818,12 @@ async function agentKnowledgeConfig(agent) {
|
|
|
1864
1818
|
const agentName = agent.name ?? agent.agent.name;
|
|
1865
1819
|
return {
|
|
1866
1820
|
agentId: agent.id,
|
|
1867
|
-
...
|
|
1821
|
+
...compact({ agentName }),
|
|
1868
1822
|
sources: await knowledgeSources(agent),
|
|
1869
1823
|
staticContext: agent.agent.staticContext.map((document) => ({
|
|
1870
1824
|
id: document.id,
|
|
1871
1825
|
text: document.text,
|
|
1872
|
-
...document.additionalProps
|
|
1826
|
+
...compact({ additionalProps: document.additionalProps !== void 0 ? jsonObjectFromRecord(document.additionalProps) : void 0 })
|
|
1873
1827
|
}))
|
|
1874
1828
|
};
|
|
1875
1829
|
}
|
|
@@ -1895,9 +1849,9 @@ async function knowledgeSources(agent) {
|
|
|
1895
1849
|
count: 1,
|
|
1896
1850
|
registrationIndex: index,
|
|
1897
1851
|
topK: registration.options.topK,
|
|
1898
|
-
...
|
|
1852
|
+
...compact({ threshold: registration.options.threshold }),
|
|
1899
1853
|
inspectable: inspect !== void 0,
|
|
1900
|
-
...
|
|
1854
|
+
...compact({ itemCount: count })
|
|
1901
1855
|
};
|
|
1902
1856
|
})
|
|
1903
1857
|
);
|
|
@@ -1912,9 +1866,9 @@ async function knowledgeSources(agent) {
|
|
|
1912
1866
|
count: 1,
|
|
1913
1867
|
registrationIndex: index,
|
|
1914
1868
|
topK: registration.options.topK,
|
|
1915
|
-
...
|
|
1869
|
+
...compact({ threshold: registration.options.threshold }),
|
|
1916
1870
|
inspectable: inspect !== void 0,
|
|
1917
|
-
...
|
|
1871
|
+
...compact({ itemCount: count })
|
|
1918
1872
|
};
|
|
1919
1873
|
})
|
|
1920
1874
|
);
|
|
@@ -1952,8 +1906,7 @@ async function knowledgeItemsPage(agent, sourceId, request) {
|
|
|
1952
1906
|
kind: "dynamic_context",
|
|
1953
1907
|
inspectable: true,
|
|
1954
1908
|
items: page.items.map((item) => dynamicContextItem(item)),
|
|
1955
|
-
...
|
|
1956
|
-
...page.totalCount === void 0 ? {} : { totalCount: page.totalCount }
|
|
1909
|
+
...compact({ nextCursor: page.nextCursor, totalCount: page.totalCount })
|
|
1957
1910
|
};
|
|
1958
1911
|
}
|
|
1959
1912
|
const dynamicToolsIndex = dynamicSourceIndex(sourceId, "dynamic_tools");
|
|
@@ -1977,8 +1930,7 @@ async function knowledgeItemsPage(agent, sourceId, request) {
|
|
|
1977
1930
|
kind: "dynamic_tools",
|
|
1978
1931
|
inspectable: true,
|
|
1979
1932
|
items: page.items.map((item) => dynamicToolItem(item)),
|
|
1980
|
-
...
|
|
1981
|
-
...page.totalCount === void 0 ? {} : { totalCount: page.totalCount }
|
|
1933
|
+
...compact({ nextCursor: page.nextCursor, totalCount: page.totalCount })
|
|
1982
1934
|
};
|
|
1983
1935
|
}
|
|
1984
1936
|
return void 0;
|
|
@@ -2003,9 +1955,9 @@ function staticKnowledgeItemsPage(agent, request) {
|
|
|
2003
1955
|
id: document.id,
|
|
2004
1956
|
kind: "static_context",
|
|
2005
1957
|
text: document.text,
|
|
2006
|
-
...document.additionalProps
|
|
1958
|
+
...compact({ metadata: document.additionalProps !== void 0 ? jsonObjectFromRecord(document.additionalProps) : void 0 })
|
|
2007
1959
|
})),
|
|
2008
|
-
...nextOffset < agent.agent.staticContext.length ?
|
|
1960
|
+
...compact({ nextCursor: nextOffset < agent.agent.staticContext.length ? String(nextOffset) : void 0 }),
|
|
2009
1961
|
totalCount: agent.agent.staticContext.length
|
|
2010
1962
|
};
|
|
2011
1963
|
}
|
|
@@ -2025,7 +1977,7 @@ function dynamicContextItem(item) {
|
|
|
2025
1977
|
id: item.id,
|
|
2026
1978
|
kind: "dynamic_context",
|
|
2027
1979
|
...text === void 0 ? { document: toJsonValue(item.document) } : { text },
|
|
2028
|
-
...item.metadata
|
|
1980
|
+
...compact({ metadata: item.metadata !== void 0 ? jsonObjectFromRecord(item.metadata) : void 0 })
|
|
2029
1981
|
};
|
|
2030
1982
|
}
|
|
2031
1983
|
function dynamicToolItem(item) {
|
|
@@ -2040,7 +1992,7 @@ function dynamicToolItem(item) {
|
|
|
2040
1992
|
description,
|
|
2041
1993
|
parameterKeys: parameterKeys(definition.parameters),
|
|
2042
1994
|
document: toJsonValue(item.document),
|
|
2043
|
-
...item.metadata
|
|
1995
|
+
...compact({ metadata: item.metadata !== void 0 ? jsonObjectFromRecord(item.metadata) : void 0 })
|
|
2044
1996
|
};
|
|
2045
1997
|
}
|
|
2046
1998
|
function parameterKeys(parameters) {
|
|
@@ -2102,7 +2054,7 @@ function evidenceFromTrace(trace) {
|
|
|
2102
2054
|
observationName: observation.name,
|
|
2103
2055
|
turn: observation.turn,
|
|
2104
2056
|
startedAt: observation.startedAt,
|
|
2105
|
-
...
|
|
2057
|
+
...compact({ query }),
|
|
2106
2058
|
documentCount: documents.length,
|
|
2107
2059
|
toolCount: tools.length,
|
|
2108
2060
|
documents,
|
|
@@ -2175,11 +2127,7 @@ function evidenceDocument(value) {
|
|
|
2175
2127
|
return [];
|
|
2176
2128
|
}
|
|
2177
2129
|
return [
|
|
2178
|
-
{
|
|
2179
|
-
...id === void 0 ? {} : { id },
|
|
2180
|
-
...text === void 0 ? {} : { text },
|
|
2181
|
-
...additionalProps === void 0 ? {} : { additionalProps }
|
|
2182
|
-
}
|
|
2130
|
+
compact({ id, text, additionalProps })
|
|
2183
2131
|
];
|
|
2184
2132
|
}
|
|
2185
2133
|
function evidenceToolName(value) {
|
|
@@ -2291,7 +2239,7 @@ function registerMemoryRoutes(app, props) {
|
|
|
2291
2239
|
const agentId = optionalQueryString(c.req.query("agentId"));
|
|
2292
2240
|
const userId = optionalQueryString(c.req.query("userId"));
|
|
2293
2241
|
const sessions = await props.sessionStore.listSessions({
|
|
2294
|
-
...
|
|
2242
|
+
...compact({ agentId }),
|
|
2295
2243
|
limit: 100
|
|
2296
2244
|
});
|
|
2297
2245
|
const conversations = sessions.map(memoryConversationSummary).filter((session) => userId === void 0 || session.userId === userId).slice(0, limit);
|
|
@@ -2323,16 +2271,16 @@ function registerMemoryRoutes(app, props) {
|
|
|
2323
2271
|
});
|
|
2324
2272
|
}
|
|
2325
2273
|
function memoryConversationSummary(session) {
|
|
2326
|
-
return {
|
|
2274
|
+
return compact({
|
|
2327
2275
|
id: session.id,
|
|
2328
2276
|
userId: sessionUserId(session),
|
|
2329
2277
|
agentId: session.agentId,
|
|
2330
|
-
|
|
2278
|
+
title: session.title,
|
|
2331
2279
|
createdAt: session.createdAt,
|
|
2332
2280
|
updatedAt: session.updatedAt,
|
|
2333
2281
|
messageCount: session.messageCount,
|
|
2334
|
-
|
|
2335
|
-
};
|
|
2282
|
+
metadata: session.metadata
|
|
2283
|
+
});
|
|
2336
2284
|
}
|
|
2337
2285
|
function sessionUserId(session) {
|
|
2338
2286
|
const userId = session.metadata?.userId;
|
|
@@ -2419,9 +2367,11 @@ var StudioObservabilityHub = class {
|
|
|
2419
2367
|
function observeStores(stores, hub) {
|
|
2420
2368
|
return {
|
|
2421
2369
|
...stores,
|
|
2422
|
-
...
|
|
2423
|
-
|
|
2424
|
-
|
|
2370
|
+
...compact({
|
|
2371
|
+
sessions: stores.sessions !== void 0 ? observeSessionStore(stores.sessions, hub) : void 0,
|
|
2372
|
+
traces: stores.traces !== void 0 ? observeTraceStore(stores.traces, hub) : void 0,
|
|
2373
|
+
pipelineLogs: stores.pipelineLogs !== void 0 ? observePipelineLogStore(stores.pipelineLogs, hub) : void 0
|
|
2374
|
+
})
|
|
2425
2375
|
};
|
|
2426
2376
|
}
|
|
2427
2377
|
function registerObservabilityRoutes(app, hub) {
|
|
@@ -2442,7 +2392,7 @@ function registerObservabilityRoutes(app, hub) {
|
|
|
2442
2392
|
});
|
|
2443
2393
|
}
|
|
2444
2394
|
function observabilityEvents(hub, types) {
|
|
2445
|
-
const subscription = hub.subscribe(
|
|
2395
|
+
const subscription = hub.subscribe(compact({ types }));
|
|
2446
2396
|
return {
|
|
2447
2397
|
[Symbol.asyncIterator]() {
|
|
2448
2398
|
return {
|
|
@@ -2534,7 +2484,7 @@ function observeTraceStore(store, hub) {
|
|
|
2534
2484
|
const saveTrace = target.saveTrace.bind(target);
|
|
2535
2485
|
return async (...args) => {
|
|
2536
2486
|
const trace = await saveTrace(...args);
|
|
2537
|
-
hub.emit({ type: "trace", trace:
|
|
2487
|
+
hub.emit({ type: "trace", trace: traceSummary(trace) });
|
|
2538
2488
|
return trace;
|
|
2539
2489
|
};
|
|
2540
2490
|
}
|
|
@@ -2561,20 +2511,22 @@ function parseEventTypes(value) {
|
|
|
2561
2511
|
function isEventType(value) {
|
|
2562
2512
|
return value === "session_log" || value === "pipeline_log" || value === "trace";
|
|
2563
2513
|
}
|
|
2564
|
-
function
|
|
2514
|
+
function traceSummary(trace) {
|
|
2565
2515
|
return {
|
|
2566
2516
|
id: trace.id,
|
|
2567
2517
|
sessionId: trace.sessionId,
|
|
2568
|
-
...trace.name === void 0 ? {} : { name: trace.name },
|
|
2569
2518
|
status: trace.status,
|
|
2570
2519
|
startedAt: trace.startedAt,
|
|
2571
|
-
|
|
2572
|
-
...
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2520
|
+
observationCount: trace.observations.length,
|
|
2521
|
+
...compact({
|
|
2522
|
+
name: trace.name,
|
|
2523
|
+
endedAt: trace.endedAt,
|
|
2524
|
+
durationMs: trace.durationMs,
|
|
2525
|
+
output: trace.output,
|
|
2526
|
+
error: trace.error,
|
|
2527
|
+
usage: trace.usage,
|
|
2528
|
+
metadata: trace.metadata
|
|
2529
|
+
})
|
|
2578
2530
|
};
|
|
2579
2531
|
}
|
|
2580
2532
|
|
|
@@ -2596,7 +2548,7 @@ function pipelineRunReceivedLog(props) {
|
|
|
2596
2548
|
category: "api",
|
|
2597
2549
|
event: "pipeline.run_received",
|
|
2598
2550
|
message: "Pipeline run request received",
|
|
2599
|
-
metadata:
|
|
2551
|
+
metadata: compact({
|
|
2600
2552
|
stream: props.stream,
|
|
2601
2553
|
inputBytes: byteLength2(formatUnknown(props.input)),
|
|
2602
2554
|
metadataKeys: Object.keys(props.metadata ?? {})
|
|
@@ -2612,7 +2564,7 @@ function pipelineRunStartedLog(pipeline, runId) {
|
|
|
2612
2564
|
category: "run",
|
|
2613
2565
|
event: "pipeline.run_started",
|
|
2614
2566
|
message: "Pipeline run started",
|
|
2615
|
-
metadata:
|
|
2567
|
+
metadata: compact({
|
|
2616
2568
|
stageCount: graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output").length,
|
|
2617
2569
|
edgeCount: graph.edges.length
|
|
2618
2570
|
})
|
|
@@ -2626,7 +2578,7 @@ function pipelineRunCompletedLog(props) {
|
|
|
2626
2578
|
category: "run",
|
|
2627
2579
|
event: "pipeline.run_completed",
|
|
2628
2580
|
message: "Pipeline run completed",
|
|
2629
|
-
metadata:
|
|
2581
|
+
metadata: compact({
|
|
2630
2582
|
durationMs: props.durationMs,
|
|
2631
2583
|
outputBytes: byteLength2(formatUnknown(props.output))
|
|
2632
2584
|
})
|
|
@@ -2640,7 +2592,7 @@ function pipelineRunFailedLog(pipelineId, runId, error, startedAt) {
|
|
|
2640
2592
|
category: "run",
|
|
2641
2593
|
event: "pipeline.run_failed",
|
|
2642
2594
|
message: "Pipeline run failed",
|
|
2643
|
-
metadata:
|
|
2595
|
+
metadata: compact({
|
|
2644
2596
|
durationMs: Date.now() - startedAt,
|
|
2645
2597
|
error: serializeError(error)
|
|
2646
2598
|
})
|
|
@@ -2667,7 +2619,7 @@ function pipelineStageLog(pipelineId, runId, event) {
|
|
|
2667
2619
|
category,
|
|
2668
2620
|
event: `${event.node.kind}.completed`,
|
|
2669
2621
|
message: `${event.node.label} completed`,
|
|
2670
|
-
metadata:
|
|
2622
|
+
metadata: compact({
|
|
2671
2623
|
...nodeMetadata(event.node),
|
|
2672
2624
|
durationMs: event.durationMs
|
|
2673
2625
|
})
|
|
@@ -2680,7 +2632,7 @@ function pipelineStageLog(pipelineId, runId, event) {
|
|
|
2680
2632
|
category,
|
|
2681
2633
|
event: `${event.node.kind}.failed`,
|
|
2682
2634
|
message: `${event.node.label} failed`,
|
|
2683
|
-
metadata:
|
|
2635
|
+
metadata: compact({
|
|
2684
2636
|
...nodeMetadata(event.node),
|
|
2685
2637
|
durationMs: event.durationMs,
|
|
2686
2638
|
error: serializeError(event.error)
|
|
@@ -2700,7 +2652,7 @@ function stageCategory(node) {
|
|
|
2700
2652
|
return "stage";
|
|
2701
2653
|
}
|
|
2702
2654
|
function nodeMetadata(node) {
|
|
2703
|
-
return
|
|
2655
|
+
return compact({
|
|
2704
2656
|
nodeId: node.id,
|
|
2705
2657
|
kind: node.kind,
|
|
2706
2658
|
label: node.label,
|
|
@@ -2709,20 +2661,123 @@ function nodeMetadata(node) {
|
|
|
2709
2661
|
branchKey: node.branchKey
|
|
2710
2662
|
});
|
|
2711
2663
|
}
|
|
2712
|
-
function cleanMetadata(value) {
|
|
2713
|
-
return Object.fromEntries(
|
|
2714
|
-
Object.entries(value).filter(([, item]) => item !== void 0)
|
|
2715
|
-
);
|
|
2716
|
-
}
|
|
2717
2664
|
function byteLength2(value) {
|
|
2718
2665
|
return value === void 0 ? void 0 : new TextEncoder().encode(value).length;
|
|
2719
2666
|
}
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2667
|
+
|
|
2668
|
+
// src/runtime/transcript.ts
|
|
2669
|
+
function renumberTranscript(entries) {
|
|
2670
|
+
return entries.map((entry, entryId) => ({ ...entry, entryId }));
|
|
2671
|
+
}
|
|
2672
|
+
function transcriptFromMessages(messages) {
|
|
2673
|
+
const transcript = [];
|
|
2674
|
+
for (const message of messages) {
|
|
2675
|
+
if (message.role === "system") {
|
|
2676
|
+
continue;
|
|
2677
|
+
}
|
|
2678
|
+
if (message.role === "user") {
|
|
2679
|
+
const attachments = attachmentsFromMessage(message);
|
|
2680
|
+
let textEntryAdded = false;
|
|
2681
|
+
for (const content of message.content) {
|
|
2682
|
+
if (content.type === "text") {
|
|
2683
|
+
transcript.push(compact({
|
|
2684
|
+
entryId: transcript.length,
|
|
2685
|
+
kind: "message",
|
|
2686
|
+
role: "user",
|
|
2687
|
+
text: content.text,
|
|
2688
|
+
attachments: attachments.length === 0 ? void 0 : attachments
|
|
2689
|
+
}));
|
|
2690
|
+
textEntryAdded = true;
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
if (!textEntryAdded && attachments.length > 0) {
|
|
2694
|
+
transcript.push({
|
|
2695
|
+
entryId: transcript.length,
|
|
2696
|
+
kind: "message",
|
|
2697
|
+
role: "user",
|
|
2698
|
+
text: "",
|
|
2699
|
+
attachments
|
|
2700
|
+
});
|
|
2701
|
+
}
|
|
2702
|
+
continue;
|
|
2703
|
+
}
|
|
2704
|
+
if (message.role === "tool") {
|
|
2705
|
+
for (const content of message.content) {
|
|
2706
|
+
transcript.push({
|
|
2707
|
+
entryId: transcript.length,
|
|
2708
|
+
kind: "tool",
|
|
2709
|
+
toolName: "tool_result",
|
|
2710
|
+
callId: content.callId ?? content.id,
|
|
2711
|
+
result: content.content.map(
|
|
2712
|
+
(item) => "text" in item ? item.text : `[image:${item.mediaType ?? "image/png"}]`
|
|
2713
|
+
).join("\n"),
|
|
2714
|
+
structuredResult: content.content
|
|
2715
|
+
});
|
|
2716
|
+
}
|
|
2717
|
+
continue;
|
|
2718
|
+
}
|
|
2719
|
+
for (const content of message.content) {
|
|
2720
|
+
if (content.type === "text") {
|
|
2721
|
+
appendAssistantTranscriptText(transcript, content.text);
|
|
2722
|
+
} else if (content.type === "reasoning") {
|
|
2723
|
+
transcript.push(compact({
|
|
2724
|
+
entryId: transcript.length,
|
|
2725
|
+
kind: "reasoning",
|
|
2726
|
+
reasoningId: content.id,
|
|
2727
|
+
text: content.text
|
|
2728
|
+
}));
|
|
2729
|
+
} else if (content.type === "tool_call") {
|
|
2730
|
+
transcript.push({
|
|
2731
|
+
entryId: transcript.length,
|
|
2732
|
+
kind: "tool",
|
|
2733
|
+
toolName: content.function.name,
|
|
2734
|
+
callId: content.callId ?? content.id,
|
|
2735
|
+
args: formatJson(content.function.arguments)
|
|
2736
|
+
});
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
return transcript;
|
|
2741
|
+
}
|
|
2742
|
+
function attachmentsFromMessage(message) {
|
|
2743
|
+
if (message.role !== "user" && message.role !== "assistant") {
|
|
2744
|
+
return [];
|
|
2745
|
+
}
|
|
2746
|
+
return message.content.flatMap((content) => {
|
|
2747
|
+
if (content.type === "image") {
|
|
2748
|
+
return [
|
|
2749
|
+
{
|
|
2750
|
+
kind: "image",
|
|
2751
|
+
...content.source.type === "base64" ? { data: content.source.data, mediaType: content.source.mediaType } : { url: content.source.url }
|
|
2752
|
+
}
|
|
2753
|
+
];
|
|
2754
|
+
}
|
|
2755
|
+
if (content.type === "document") {
|
|
2756
|
+
return [
|
|
2757
|
+
compact({
|
|
2758
|
+
kind: "document",
|
|
2759
|
+
name: content.source.filename,
|
|
2760
|
+
mediaType: content.source.mediaType,
|
|
2761
|
+
data: content.source.type === "base64" ? content.source.data : void 0,
|
|
2762
|
+
url: content.source.type === "url" ? content.source.url : void 0
|
|
2763
|
+
})
|
|
2764
|
+
];
|
|
2765
|
+
}
|
|
2766
|
+
return [];
|
|
2767
|
+
});
|
|
2768
|
+
}
|
|
2769
|
+
function appendAssistantTranscriptText(transcript, text) {
|
|
2770
|
+
const last = transcript.at(-1);
|
|
2771
|
+
if (last?.kind === "message" && last.role === "assistant") {
|
|
2772
|
+
last.text = `${last.text}${text}`;
|
|
2773
|
+
return;
|
|
2725
2774
|
}
|
|
2775
|
+
transcript.push({
|
|
2776
|
+
entryId: transcript.length,
|
|
2777
|
+
kind: "message",
|
|
2778
|
+
role: "assistant",
|
|
2779
|
+
text
|
|
2780
|
+
});
|
|
2726
2781
|
}
|
|
2727
2782
|
|
|
2728
2783
|
// src/runtime/runs.ts
|
|
@@ -2873,21 +2928,21 @@ function acceptTranscriptStreamEvent(transcript, event) {
|
|
|
2873
2928
|
kind: "tool",
|
|
2874
2929
|
toolName: event.toolCall.function.name,
|
|
2875
2930
|
callId: event.toolCall.callId ?? event.toolCall.id,
|
|
2876
|
-
args:
|
|
2931
|
+
args: formatJson(event.toolCall.function.arguments)
|
|
2877
2932
|
});
|
|
2878
2933
|
}
|
|
2879
2934
|
if (event.type === "tool_result") {
|
|
2880
2935
|
const matched = findTranscriptToolEntry(transcript, event.toolName, event.toolCallId);
|
|
2881
2936
|
if (matched === void 0) {
|
|
2882
|
-
transcript.push({
|
|
2937
|
+
transcript.push(compact({
|
|
2883
2938
|
entryId: transcript.length,
|
|
2884
2939
|
kind: "tool",
|
|
2885
2940
|
toolName: event.toolName,
|
|
2886
|
-
|
|
2941
|
+
callId: event.toolCallId,
|
|
2887
2942
|
args: event.args,
|
|
2888
2943
|
result: event.result,
|
|
2889
|
-
|
|
2890
|
-
});
|
|
2944
|
+
structuredResult: event.structuredResult
|
|
2945
|
+
}));
|
|
2891
2946
|
return;
|
|
2892
2947
|
}
|
|
2893
2948
|
matched.args = matched.args ?? event.args;
|
|
@@ -2899,15 +2954,15 @@ function acceptTranscriptStreamEvent(transcript, event) {
|
|
|
2899
2954
|
if (event.type === "agent_tool_event") {
|
|
2900
2955
|
const matched = findTranscriptToolEntry(transcript, event.toolName, event.toolCallId);
|
|
2901
2956
|
if (matched === void 0) {
|
|
2902
|
-
transcript.push({
|
|
2957
|
+
transcript.push(compact({
|
|
2903
2958
|
entryId: transcript.length,
|
|
2904
2959
|
kind: "tool",
|
|
2905
2960
|
toolName: event.toolName,
|
|
2906
|
-
|
|
2961
|
+
callId: event.toolCallId,
|
|
2907
2962
|
childEvents: [childAgentTranscriptEvent(event)].filter(
|
|
2908
2963
|
(childEvent) => childEvent !== void 0
|
|
2909
2964
|
)
|
|
2910
|
-
});
|
|
2965
|
+
}));
|
|
2911
2966
|
return;
|
|
2912
2967
|
}
|
|
2913
2968
|
appendChildAgentTranscriptEvent(matched, event);
|
|
@@ -2933,13 +2988,13 @@ function acceptTranscriptStreamEvent(transcript, event) {
|
|
|
2933
2988
|
approvalCallId(event.approval)
|
|
2934
2989
|
);
|
|
2935
2990
|
if (matched !== void 0) {
|
|
2936
|
-
matched.approval = {
|
|
2991
|
+
matched.approval = compact({
|
|
2937
2992
|
id: event.approval.id,
|
|
2938
2993
|
status: event.approval.status,
|
|
2939
2994
|
requestedAt: event.approval.requestedAt,
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
};
|
|
2995
|
+
resolvedAt: event.approval.resolvedAt,
|
|
2996
|
+
reason: event.approval.reason
|
|
2997
|
+
});
|
|
2943
2998
|
}
|
|
2944
2999
|
}
|
|
2945
3000
|
if (event.type === "tool_question_request") {
|
|
@@ -2964,14 +3019,14 @@ function acceptTranscriptStreamEvent(transcript, event) {
|
|
|
2964
3019
|
questionCallId(event.question)
|
|
2965
3020
|
);
|
|
2966
3021
|
if (matched !== void 0) {
|
|
2967
|
-
matched.question = {
|
|
3022
|
+
matched.question = compact({
|
|
2968
3023
|
id: event.question.id,
|
|
2969
3024
|
status: event.question.status,
|
|
2970
3025
|
requestedAt: event.question.requestedAt,
|
|
2971
|
-
|
|
3026
|
+
answeredAt: event.question.answeredAt,
|
|
2972
3027
|
questions: event.question.questions,
|
|
2973
|
-
|
|
2974
|
-
};
|
|
3028
|
+
answers: event.question.answers
|
|
3029
|
+
});
|
|
2975
3030
|
}
|
|
2976
3031
|
}
|
|
2977
3032
|
if (event.type === "final" && event.trace?.traceId !== void 0) {
|
|
@@ -3025,51 +3080,51 @@ function appendChildAgentTranscriptEvent(entry, event) {
|
|
|
3025
3080
|
function childAgentTranscriptEvent(event) {
|
|
3026
3081
|
const child = event.event;
|
|
3027
3082
|
if (child.type === "text_delta") {
|
|
3028
|
-
return {
|
|
3083
|
+
return compact({
|
|
3029
3084
|
kind: "message",
|
|
3030
3085
|
agentId: event.agentId,
|
|
3031
|
-
|
|
3086
|
+
agentName: event.agentName,
|
|
3032
3087
|
text: child.delta
|
|
3033
|
-
};
|
|
3088
|
+
});
|
|
3034
3089
|
}
|
|
3035
3090
|
if (child.type === "reasoning_delta") {
|
|
3036
|
-
return {
|
|
3091
|
+
return compact({
|
|
3037
3092
|
kind: "reasoning",
|
|
3038
3093
|
agentId: event.agentId,
|
|
3039
|
-
|
|
3040
|
-
|
|
3094
|
+
agentName: event.agentName,
|
|
3095
|
+
reasoningId: child.id,
|
|
3041
3096
|
text: child.delta
|
|
3042
|
-
};
|
|
3097
|
+
});
|
|
3043
3098
|
}
|
|
3044
3099
|
if (child.type === "tool_call") {
|
|
3045
|
-
return {
|
|
3100
|
+
return compact({
|
|
3046
3101
|
kind: "tool",
|
|
3047
3102
|
agentId: event.agentId,
|
|
3048
|
-
|
|
3103
|
+
agentName: event.agentName,
|
|
3049
3104
|
toolName: child.toolCall.function.name,
|
|
3050
|
-
|
|
3051
|
-
args:
|
|
3052
|
-
};
|
|
3105
|
+
callId: child.toolCall.callId ?? child.toolCall.id,
|
|
3106
|
+
args: formatJson(child.toolCall.function.arguments)
|
|
3107
|
+
});
|
|
3053
3108
|
}
|
|
3054
3109
|
if (child.type === "tool_result") {
|
|
3055
|
-
return {
|
|
3110
|
+
return compact({
|
|
3056
3111
|
kind: "tool",
|
|
3057
3112
|
agentId: event.agentId,
|
|
3058
|
-
|
|
3113
|
+
agentName: event.agentName,
|
|
3059
3114
|
toolName: child.toolName,
|
|
3060
|
-
|
|
3115
|
+
callId: child.toolCallId,
|
|
3061
3116
|
args: child.args,
|
|
3062
3117
|
result: child.result,
|
|
3063
|
-
|
|
3064
|
-
};
|
|
3118
|
+
structuredResult: child.structuredResult
|
|
3119
|
+
});
|
|
3065
3120
|
}
|
|
3066
3121
|
if (child.type === "error") {
|
|
3067
|
-
return {
|
|
3122
|
+
return compact({
|
|
3068
3123
|
kind: "message",
|
|
3069
3124
|
agentId: event.agentId,
|
|
3070
|
-
|
|
3125
|
+
agentName: event.agentName,
|
|
3071
3126
|
text: `Error: ${errorText(child.error)}`
|
|
3072
|
-
};
|
|
3127
|
+
});
|
|
3073
3128
|
}
|
|
3074
3129
|
return void 0;
|
|
3075
3130
|
}
|
|
@@ -3097,7 +3152,8 @@ function messageToTranscriptEntry(message, entryId) {
|
|
|
3097
3152
|
entryId,
|
|
3098
3153
|
kind: "message",
|
|
3099
3154
|
role,
|
|
3100
|
-
text: extractMessageText(message)
|
|
3155
|
+
text: extractMessageText(message),
|
|
3156
|
+
...role === "user" ? optionalTranscriptAttachments(message) : {}
|
|
3101
3157
|
};
|
|
3102
3158
|
}
|
|
3103
3159
|
function appendTranscriptAssistantText(transcript, delta) {
|
|
@@ -3141,12 +3197,12 @@ function appendTranscriptReasoningText(transcript, delta, reasoningId) {
|
|
|
3141
3197
|
last.text = `${last.text}${delta}`;
|
|
3142
3198
|
return;
|
|
3143
3199
|
}
|
|
3144
|
-
transcript.push({
|
|
3200
|
+
transcript.push(compact({
|
|
3145
3201
|
entryId: transcript.length,
|
|
3146
3202
|
kind: "reasoning",
|
|
3147
|
-
|
|
3203
|
+
reasoningId,
|
|
3148
3204
|
text: delta
|
|
3149
|
-
});
|
|
3205
|
+
}));
|
|
3150
3206
|
}
|
|
3151
3207
|
function findTranscriptToolEntry(transcript, toolName, callId) {
|
|
3152
3208
|
for (let index = transcript.length - 1; index >= 0; index -= 1) {
|
|
@@ -3183,7 +3239,7 @@ function extractMessageText(message) {
|
|
|
3183
3239
|
return [item.text];
|
|
3184
3240
|
}
|
|
3185
3241
|
if (item.type === "tool_call") {
|
|
3186
|
-
return [`${item.function.name}(${
|
|
3242
|
+
return [`${item.function.name}(${formatJson(item.function.arguments)})`];
|
|
3187
3243
|
}
|
|
3188
3244
|
if (item.type === "tool_result") {
|
|
3189
3245
|
return item.content.map(
|
|
@@ -3193,12 +3249,33 @@ function extractMessageText(message) {
|
|
|
3193
3249
|
return [];
|
|
3194
3250
|
}).join("\n");
|
|
3195
3251
|
}
|
|
3196
|
-
function
|
|
3197
|
-
|
|
3198
|
-
return
|
|
3199
|
-
} catch {
|
|
3200
|
-
return String(value);
|
|
3252
|
+
function optionalTranscriptAttachments(message) {
|
|
3253
|
+
if (typeof message === "string" || message.role !== "user") {
|
|
3254
|
+
return {};
|
|
3201
3255
|
}
|
|
3256
|
+
const attachments = message.content.flatMap((content) => {
|
|
3257
|
+
if (content.type === "image") {
|
|
3258
|
+
return [
|
|
3259
|
+
{
|
|
3260
|
+
kind: "image",
|
|
3261
|
+
...content.source.type === "base64" ? { data: content.source.data, mediaType: content.source.mediaType } : { url: content.source.url }
|
|
3262
|
+
}
|
|
3263
|
+
];
|
|
3264
|
+
}
|
|
3265
|
+
if (content.type === "document") {
|
|
3266
|
+
return [
|
|
3267
|
+
compact({
|
|
3268
|
+
kind: "document",
|
|
3269
|
+
name: content.source.filename,
|
|
3270
|
+
mediaType: content.source.mediaType,
|
|
3271
|
+
data: content.source.type === "base64" ? content.source.data : void 0,
|
|
3272
|
+
url: content.source.type === "url" ? content.source.url : void 0
|
|
3273
|
+
})
|
|
3274
|
+
];
|
|
3275
|
+
}
|
|
3276
|
+
return [];
|
|
3277
|
+
});
|
|
3278
|
+
return attachments.length === 0 ? {} : { attachments };
|
|
3202
3279
|
}
|
|
3203
3280
|
async function parseRunRequest(c) {
|
|
3204
3281
|
let body;
|
|
@@ -3257,8 +3334,27 @@ async function parseRunRequest(c) {
|
|
|
3257
3334
|
}
|
|
3258
3335
|
request.toolConcurrency = body.toolConcurrency;
|
|
3259
3336
|
}
|
|
3337
|
+
if ("model" in body) {
|
|
3338
|
+
if (typeof body.model === "string") {
|
|
3339
|
+
request.model = body.model;
|
|
3340
|
+
} else if (isObject(body.model) && typeof body.model.provider === "string" && typeof body.model.model === "string") {
|
|
3341
|
+
request.model = {
|
|
3342
|
+
provider: body.model.provider,
|
|
3343
|
+
model: body.model.model
|
|
3344
|
+
};
|
|
3345
|
+
} else {
|
|
3346
|
+
return {
|
|
3347
|
+
error: errorResponse(
|
|
3348
|
+
c,
|
|
3349
|
+
400,
|
|
3350
|
+
"bad_request",
|
|
3351
|
+
"model must be a provider:model string or { provider, model } object"
|
|
3352
|
+
)
|
|
3353
|
+
};
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3260
3356
|
if ("metadata" in body) {
|
|
3261
|
-
if (!
|
|
3357
|
+
if (!isJsonObject(body.metadata)) {
|
|
3262
3358
|
return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
|
|
3263
3359
|
}
|
|
3264
3360
|
request.metadata = body.metadata;
|
|
@@ -3314,7 +3410,7 @@ function registerPipelineRoutes(app, props) {
|
|
|
3314
3410
|
const logs = await props.logStore.listPipelineLogs({
|
|
3315
3411
|
pipelineId,
|
|
3316
3412
|
limit,
|
|
3317
|
-
...
|
|
3413
|
+
...compact({ after })
|
|
3318
3414
|
});
|
|
3319
3415
|
const last = logs.at(-1);
|
|
3320
3416
|
return c.json({
|
|
@@ -3385,7 +3481,7 @@ function registerPipelineRoutes(app, props) {
|
|
|
3385
3481
|
}
|
|
3386
3482
|
return executePipelineRun(c, props, pipeline, {
|
|
3387
3483
|
input: sourceRun.input,
|
|
3388
|
-
...
|
|
3484
|
+
...compact({ stream: body.stream }),
|
|
3389
3485
|
metadata: replayMetadata(sourceRun.metadata, body.metadata, sourceRun.runId)
|
|
3390
3486
|
});
|
|
3391
3487
|
});
|
|
@@ -3401,7 +3497,7 @@ async function executePipelineRun(c, props, pipeline, body) {
|
|
|
3401
3497
|
runId,
|
|
3402
3498
|
stream: body.stream === true,
|
|
3403
3499
|
input: body.input,
|
|
3404
|
-
...
|
|
3500
|
+
...compact({ metadata: body.metadata })
|
|
3405
3501
|
})
|
|
3406
3502
|
);
|
|
3407
3503
|
await savePipelineRun(props.runStore, {
|
|
@@ -3409,7 +3505,7 @@ async function executePipelineRun(c, props, pipeline, body) {
|
|
|
3409
3505
|
pipelineId: pipeline.id,
|
|
3410
3506
|
status: "running",
|
|
3411
3507
|
input: body.input,
|
|
3412
|
-
...
|
|
3508
|
+
...compact({ metadata: body.metadata }),
|
|
3413
3509
|
startedAt: startedAtIso
|
|
3414
3510
|
});
|
|
3415
3511
|
if (body.stream === true) {
|
|
@@ -3419,9 +3515,8 @@ async function executePipelineRun(c, props, pipeline, body) {
|
|
|
3419
3515
|
input: body.input,
|
|
3420
3516
|
startedAt,
|
|
3421
3517
|
startedAtIso,
|
|
3422
|
-
...
|
|
3423
|
-
...
|
|
3424
|
-
...props.runStore === void 0 ? {} : { runStore: props.runStore }
|
|
3518
|
+
...compact({ metadata: body.metadata }),
|
|
3519
|
+
...compact({ logStore: props.logStore, runStore: props.runStore })
|
|
3425
3520
|
});
|
|
3426
3521
|
}
|
|
3427
3522
|
try {
|
|
@@ -3441,7 +3536,7 @@ async function executePipelineRun(c, props, pipeline, body) {
|
|
|
3441
3536
|
status: "success",
|
|
3442
3537
|
input: body.input,
|
|
3443
3538
|
output: jsonOutput,
|
|
3444
|
-
...
|
|
3539
|
+
...compact({ metadata: body.metadata }),
|
|
3445
3540
|
startedAt: startedAtIso,
|
|
3446
3541
|
endedAt: new Date(endedAt).toISOString(),
|
|
3447
3542
|
durationMs: endedAt - startedAt
|
|
@@ -3469,7 +3564,7 @@ async function executePipelineRun(c, props, pipeline, body) {
|
|
|
3469
3564
|
status: "error",
|
|
3470
3565
|
input: body.input,
|
|
3471
3566
|
error: serializeError(error),
|
|
3472
|
-
...
|
|
3567
|
+
...compact({ metadata: body.metadata }),
|
|
3473
3568
|
startedAt: startedAtIso,
|
|
3474
3569
|
endedAt: new Date(endedAt).toISOString(),
|
|
3475
3570
|
durationMs: endedAt - startedAt
|
|
@@ -3516,7 +3611,7 @@ async function* pipelineRunEvents(props) {
|
|
|
3516
3611
|
status: "success",
|
|
3517
3612
|
input: props.input,
|
|
3518
3613
|
output: jsonOutput,
|
|
3519
|
-
...
|
|
3614
|
+
...compact({ metadata: props.metadata }),
|
|
3520
3615
|
startedAt: props.startedAtIso,
|
|
3521
3616
|
endedAt: new Date(endedAt).toISOString(),
|
|
3522
3617
|
durationMs: endedAt - props.startedAt
|
|
@@ -3547,7 +3642,7 @@ async function* pipelineRunEvents(props) {
|
|
|
3547
3642
|
status: "error",
|
|
3548
3643
|
input: props.input,
|
|
3549
3644
|
error: serializeError(error),
|
|
3550
|
-
...
|
|
3645
|
+
...compact({ metadata: props.metadata }),
|
|
3551
3646
|
startedAt: props.startedAtIso,
|
|
3552
3647
|
endedAt: new Date(endedAt).toISOString(),
|
|
3553
3648
|
durationMs: endedAt - props.startedAt
|
|
@@ -3586,7 +3681,7 @@ async function parsePipelineRunRequest(c) {
|
|
|
3586
3681
|
if (!isObject(body)) {
|
|
3587
3682
|
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
3588
3683
|
}
|
|
3589
|
-
if (!("input" in body) || !
|
|
3684
|
+
if (!("input" in body) || !isJsonValue2(body.input)) {
|
|
3590
3685
|
return { error: errorResponse(c, 400, "bad_request", "input must be JSON-compatible") };
|
|
3591
3686
|
}
|
|
3592
3687
|
const request = {
|
|
@@ -3599,7 +3694,7 @@ async function parsePipelineRunRequest(c) {
|
|
|
3599
3694
|
request.stream = body.stream;
|
|
3600
3695
|
}
|
|
3601
3696
|
if ("metadata" in body) {
|
|
3602
|
-
if (!
|
|
3697
|
+
if (!isJsonObject(body.metadata)) {
|
|
3603
3698
|
return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
|
|
3604
3699
|
}
|
|
3605
3700
|
request.metadata = body.metadata;
|
|
@@ -3624,7 +3719,7 @@ async function parsePipelineReplayRequest(c) {
|
|
|
3624
3719
|
request.stream = body.stream;
|
|
3625
3720
|
}
|
|
3626
3721
|
if ("metadata" in body) {
|
|
3627
|
-
if (!
|
|
3722
|
+
if (!isJsonObject(body.metadata)) {
|
|
3628
3723
|
return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
|
|
3629
3724
|
}
|
|
3630
3725
|
request.metadata = body.metadata;
|
|
@@ -3658,15 +3753,15 @@ function parsePipelineLogAfter(value) {
|
|
|
3658
3753
|
}
|
|
3659
3754
|
return after;
|
|
3660
3755
|
}
|
|
3661
|
-
function
|
|
3756
|
+
function isJsonValue2(value) {
|
|
3662
3757
|
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
3663
3758
|
return Number.isFinite(value) || typeof value !== "number";
|
|
3664
3759
|
}
|
|
3665
3760
|
if (Array.isArray(value)) {
|
|
3666
|
-
return value.every(
|
|
3761
|
+
return value.every(isJsonValue2);
|
|
3667
3762
|
}
|
|
3668
3763
|
if (isObject(value)) {
|
|
3669
|
-
return Object.values(value).every((item) => item === void 0 ||
|
|
3764
|
+
return Object.values(value).every((item) => item === void 0 || isJsonValue2(item));
|
|
3670
3765
|
}
|
|
3671
3766
|
return false;
|
|
3672
3767
|
}
|
|
@@ -3750,12 +3845,12 @@ async function parseQuestionAnswerRequest(c) {
|
|
|
3750
3845
|
if ("custom" in answer && typeof answer.custom !== "boolean") {
|
|
3751
3846
|
return { error: errorResponse(c, 400, "bad_request", "custom must be a boolean") };
|
|
3752
3847
|
}
|
|
3753
|
-
answers.push({
|
|
3848
|
+
answers.push(compact({
|
|
3754
3849
|
questionId: answer.questionId.trim(),
|
|
3755
3850
|
answer: answer.answer.trim(),
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
});
|
|
3851
|
+
choice: typeof answer.choice === "string" ? answer.choice : void 0,
|
|
3852
|
+
custom: typeof answer.custom === "boolean" ? answer.custom : void 0
|
|
3853
|
+
}));
|
|
3759
3854
|
}
|
|
3760
3855
|
return { answers };
|
|
3761
3856
|
}
|
|
@@ -3773,13 +3868,13 @@ function createQuestionRuntime() {
|
|
|
3773
3868
|
if ("error" in prompts) {
|
|
3774
3869
|
return control.skip(prompts.error);
|
|
3775
3870
|
}
|
|
3776
|
-
const answers = await requestQuestion(questions, context, {
|
|
3871
|
+
const answers = await requestQuestion(questions, context, compact({
|
|
3777
3872
|
toolName,
|
|
3778
|
-
|
|
3873
|
+
toolCallId,
|
|
3779
3874
|
internalCallId,
|
|
3780
3875
|
args,
|
|
3781
3876
|
questions: prompts.questions
|
|
3782
|
-
});
|
|
3877
|
+
}));
|
|
3783
3878
|
return control.skip(JSON.stringify({ answers }));
|
|
3784
3879
|
}
|
|
3785
3880
|
});
|
|
@@ -3823,18 +3918,20 @@ function createQuestionRuntime() {
|
|
|
3823
3918
|
async function requestQuestion(questions, context, request) {
|
|
3824
3919
|
const id = globalThis.crypto.randomUUID();
|
|
3825
3920
|
const question = {
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3921
|
+
...compact({
|
|
3922
|
+
id,
|
|
3923
|
+
runId: context.runId,
|
|
3924
|
+
agentId: context.agentId,
|
|
3925
|
+
sessionId: context.sessionId,
|
|
3926
|
+
toolName: request.toolName,
|
|
3927
|
+
callId: request.toolCallId,
|
|
3928
|
+
internalCallId: request.internalCallId,
|
|
3929
|
+
args: request.args,
|
|
3930
|
+
questions: request.questions,
|
|
3931
|
+
status: "pending",
|
|
3932
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3933
|
+
emit: context.emit
|
|
3934
|
+
}),
|
|
3838
3935
|
resolve: () => {
|
|
3839
3936
|
}
|
|
3840
3937
|
};
|
|
@@ -3945,7 +4042,7 @@ function sessionCreatedLog(session) {
|
|
|
3945
4042
|
category: "session",
|
|
3946
4043
|
event: "session.created",
|
|
3947
4044
|
message: "Session created",
|
|
3948
|
-
metadata:
|
|
4045
|
+
metadata: compact({
|
|
3949
4046
|
agentId: session.agentId,
|
|
3950
4047
|
hasTitle: session.title !== void 0,
|
|
3951
4048
|
titleLength: session.title?.length ?? 0
|
|
@@ -3960,7 +4057,7 @@ function runReceivedLog(props) {
|
|
|
3960
4057
|
category: "api",
|
|
3961
4058
|
event: "run.received",
|
|
3962
4059
|
message: "Run request received",
|
|
3963
|
-
metadata:
|
|
4060
|
+
metadata: compact({
|
|
3964
4061
|
agentId: props.agentId,
|
|
3965
4062
|
stream: props.stream,
|
|
3966
4063
|
message: messageSummary(props.message),
|
|
@@ -3979,7 +4076,7 @@ function runStartedLog(session, runId) {
|
|
|
3979
4076
|
category: "run",
|
|
3980
4077
|
event: "run.started",
|
|
3981
4078
|
message: "Run started",
|
|
3982
|
-
metadata:
|
|
4079
|
+
metadata: compact({
|
|
3983
4080
|
agentId: session.agentId,
|
|
3984
4081
|
existingMessageCount: session.messageCount
|
|
3985
4082
|
})
|
|
@@ -3993,7 +4090,7 @@ function memoryLoadedLog(session, runId) {
|
|
|
3993
4090
|
category: "memory",
|
|
3994
4091
|
event: "memory.loaded",
|
|
3995
4092
|
message: "Session memory loaded",
|
|
3996
|
-
metadata:
|
|
4093
|
+
metadata: compact({
|
|
3997
4094
|
messageCount: session.messageCount,
|
|
3998
4095
|
transcriptEntries: session.transcript.length
|
|
3999
4096
|
})
|
|
@@ -4007,7 +4104,7 @@ function runCompletedLog(props) {
|
|
|
4007
4104
|
category: "run",
|
|
4008
4105
|
event: "run.completed",
|
|
4009
4106
|
message: "Run completed",
|
|
4010
|
-
metadata:
|
|
4107
|
+
metadata: compact({
|
|
4011
4108
|
durationMs: props.durationMs,
|
|
4012
4109
|
usage: usageSummary(props.usage),
|
|
4013
4110
|
outputBytes: byteLength3(props.output),
|
|
@@ -4023,7 +4120,7 @@ function memorySavedLog(props) {
|
|
|
4023
4120
|
category: "memory",
|
|
4024
4121
|
event: "memory.saved",
|
|
4025
4122
|
message: "Session memory saved",
|
|
4026
|
-
metadata:
|
|
4123
|
+
metadata: compact({
|
|
4027
4124
|
messageCount: props.messageCount
|
|
4028
4125
|
})
|
|
4029
4126
|
};
|
|
@@ -4036,7 +4133,7 @@ function runFailedLog(sessionId, runId, error, startedAt) {
|
|
|
4036
4133
|
category: "run",
|
|
4037
4134
|
event: "run.failed",
|
|
4038
4135
|
message: "Run failed",
|
|
4039
|
-
metadata:
|
|
4136
|
+
metadata: compact({
|
|
4040
4137
|
durationMs: Date.now() - startedAt,
|
|
4041
4138
|
error: serializeError(error)
|
|
4042
4139
|
})
|
|
@@ -4053,7 +4150,7 @@ function logsFromStreamEvent(props) {
|
|
|
4053
4150
|
category: "prompt",
|
|
4054
4151
|
event: "prompt.prepared",
|
|
4055
4152
|
message: `Turn ${event.turn} prompt prepared`,
|
|
4056
|
-
metadata:
|
|
4153
|
+
metadata: compact({
|
|
4057
4154
|
turn: event.turn,
|
|
4058
4155
|
prompt: messageSummary(event.prompt),
|
|
4059
4156
|
historyCount: event.history.length
|
|
@@ -4070,11 +4167,11 @@ function logsFromStreamEvent(props) {
|
|
|
4070
4167
|
category: "tool",
|
|
4071
4168
|
event: "tool.called",
|
|
4072
4169
|
message: `Tool ${event.toolCall.function.name} called`,
|
|
4073
|
-
metadata:
|
|
4170
|
+
metadata: compact({
|
|
4074
4171
|
turn: event.turn,
|
|
4075
4172
|
toolName: event.toolCall.function.name,
|
|
4076
4173
|
callId: event.toolCall.callId ?? event.toolCall.id,
|
|
4077
|
-
argumentBytes: byteLength3(
|
|
4174
|
+
argumentBytes: byteLength3(formatUnknown(event.toolCall.function.arguments))
|
|
4078
4175
|
})
|
|
4079
4176
|
}
|
|
4080
4177
|
];
|
|
@@ -4088,7 +4185,7 @@ function logsFromStreamEvent(props) {
|
|
|
4088
4185
|
category: "tool",
|
|
4089
4186
|
event: "tool.completed",
|
|
4090
4187
|
message: `Tool ${event.toolName} completed`,
|
|
4091
|
-
metadata:
|
|
4188
|
+
metadata: compact({
|
|
4092
4189
|
turn: event.turn,
|
|
4093
4190
|
toolName: event.toolName,
|
|
4094
4191
|
callId: event.toolCallId,
|
|
@@ -4109,7 +4206,7 @@ function logsFromStreamEvent(props) {
|
|
|
4109
4206
|
category: "model",
|
|
4110
4207
|
event: "model.turn.completed",
|
|
4111
4208
|
message: `Model turn ${event.turn} completed`,
|
|
4112
|
-
metadata:
|
|
4209
|
+
metadata: compact({
|
|
4113
4210
|
turn: event.turn,
|
|
4114
4211
|
contentCount: event.response.choice.length,
|
|
4115
4212
|
usage: usageSummary(event.response.usage)
|
|
@@ -4142,7 +4239,7 @@ function logsFromStreamEvent(props) {
|
|
|
4142
4239
|
category: "approval",
|
|
4143
4240
|
event: "approval.requested",
|
|
4144
4241
|
message: `Approval requested for ${event.approval.toolName}`,
|
|
4145
|
-
metadata:
|
|
4242
|
+
metadata: compact({
|
|
4146
4243
|
approvalId: event.approval.id,
|
|
4147
4244
|
toolName: event.approval.toolName,
|
|
4148
4245
|
callId: event.approval.callId,
|
|
@@ -4162,7 +4259,7 @@ function logsFromStreamEvent(props) {
|
|
|
4162
4259
|
category: "approval",
|
|
4163
4260
|
event: "approval.resolved",
|
|
4164
4261
|
message: `Approval ${event.approval.status} for ${event.approval.toolName}`,
|
|
4165
|
-
metadata:
|
|
4262
|
+
metadata: compact({
|
|
4166
4263
|
approvalId: event.approval.id,
|
|
4167
4264
|
toolName: event.approval.toolName,
|
|
4168
4265
|
callId: event.approval.callId,
|
|
@@ -4181,7 +4278,7 @@ function logsFromStreamEvent(props) {
|
|
|
4181
4278
|
category: "question",
|
|
4182
4279
|
event: "question.requested",
|
|
4183
4280
|
message: `Question requested by ${event.question.toolName}`,
|
|
4184
|
-
metadata:
|
|
4281
|
+
metadata: compact({
|
|
4185
4282
|
questionId: event.question.id,
|
|
4186
4283
|
toolName: event.question.toolName,
|
|
4187
4284
|
callId: event.question.callId,
|
|
@@ -4201,7 +4298,7 @@ function logsFromStreamEvent(props) {
|
|
|
4201
4298
|
category: "question",
|
|
4202
4299
|
event: "question.answered",
|
|
4203
4300
|
message: `Question answered for ${event.question.toolName}`,
|
|
4204
|
-
metadata:
|
|
4301
|
+
metadata: compact({
|
|
4205
4302
|
questionId: event.question.id,
|
|
4206
4303
|
toolName: event.question.toolName,
|
|
4207
4304
|
callId: event.question.callId,
|
|
@@ -4233,7 +4330,7 @@ function childAgentLog(event, sessionId, runId) {
|
|
|
4233
4330
|
category: "tool",
|
|
4234
4331
|
event: "child_tool.called",
|
|
4235
4332
|
message: `Child agent ${event.agentName ?? event.agentId} called ${child.toolCall.function.name}`,
|
|
4236
|
-
metadata:
|
|
4333
|
+
metadata: compact({
|
|
4237
4334
|
parentToolName: event.toolName,
|
|
4238
4335
|
agentId: event.agentId,
|
|
4239
4336
|
hasAgentName: event.agentName !== void 0,
|
|
@@ -4241,7 +4338,7 @@ function childAgentLog(event, sessionId, runId) {
|
|
|
4241
4338
|
childTurn: child.turn,
|
|
4242
4339
|
toolName: child.toolCall.function.name,
|
|
4243
4340
|
callId: child.toolCall.callId ?? child.toolCall.id,
|
|
4244
|
-
argumentBytes: byteLength3(
|
|
4341
|
+
argumentBytes: byteLength3(formatUnknown(child.toolCall.function.arguments))
|
|
4245
4342
|
})
|
|
4246
4343
|
}
|
|
4247
4344
|
];
|
|
@@ -4255,7 +4352,7 @@ function childAgentLog(event, sessionId, runId) {
|
|
|
4255
4352
|
category: "tool",
|
|
4256
4353
|
event: "child_tool.completed",
|
|
4257
4354
|
message: `Child agent ${event.agentName ?? event.agentId} completed ${child.toolName}`,
|
|
4258
|
-
metadata:
|
|
4355
|
+
metadata: compact({
|
|
4259
4356
|
parentToolName: event.toolName,
|
|
4260
4357
|
agentId: event.agentId,
|
|
4261
4358
|
hasAgentName: event.agentName !== void 0,
|
|
@@ -4278,7 +4375,7 @@ function childAgentLog(event, sessionId, runId) {
|
|
|
4278
4375
|
category: "run",
|
|
4279
4376
|
event: "child_agent.turn_started",
|
|
4280
4377
|
message: `Child agent ${event.agentName ?? event.agentId} turn ${child.turn} started`,
|
|
4281
|
-
metadata:
|
|
4378
|
+
metadata: compact({
|
|
4282
4379
|
parentToolName: event.toolName,
|
|
4283
4380
|
agentId: event.agentId,
|
|
4284
4381
|
hasAgentName: event.agentName !== void 0,
|
|
@@ -4297,7 +4394,7 @@ function childAgentLog(event, sessionId, runId) {
|
|
|
4297
4394
|
category: "run",
|
|
4298
4395
|
event: "child_agent.completed",
|
|
4299
4396
|
message: `Child agent ${event.agentName ?? event.agentId} completed`,
|
|
4300
|
-
metadata:
|
|
4397
|
+
metadata: compact({
|
|
4301
4398
|
parentToolName: event.toolName,
|
|
4302
4399
|
agentId: event.agentId,
|
|
4303
4400
|
hasAgentName: event.agentName !== void 0,
|
|
@@ -4317,7 +4414,7 @@ function childAgentLog(event, sessionId, runId) {
|
|
|
4317
4414
|
category: "run",
|
|
4318
4415
|
event: "child_agent.failed",
|
|
4319
4416
|
message: `Child agent ${event.agentName ?? event.agentId} failed`,
|
|
4320
|
-
metadata:
|
|
4417
|
+
metadata: compact({
|
|
4321
4418
|
parentToolName: event.toolName,
|
|
4322
4419
|
agentId: event.agentId,
|
|
4323
4420
|
hasAgentName: event.agentName !== void 0,
|
|
@@ -4340,7 +4437,7 @@ function messageSummary(message) {
|
|
|
4340
4437
|
role: message.role,
|
|
4341
4438
|
contentKind: Array.isArray(message.content) ? "parts" : "text",
|
|
4342
4439
|
partCount: Array.isArray(message.content) ? message.content.length : 1,
|
|
4343
|
-
byteLength: byteLength3(
|
|
4440
|
+
byteLength: byteLength3(formatUnknown(message.content))
|
|
4344
4441
|
};
|
|
4345
4442
|
}
|
|
4346
4443
|
function usageSummary(value) {
|
|
@@ -4348,7 +4445,7 @@ function usageSummary(value) {
|
|
|
4348
4445
|
return void 0;
|
|
4349
4446
|
}
|
|
4350
4447
|
const record = value;
|
|
4351
|
-
return
|
|
4448
|
+
return compact({
|
|
4352
4449
|
inputTokens: numericValue(record.inputTokens),
|
|
4353
4450
|
outputTokens: numericValue(record.outputTokens),
|
|
4354
4451
|
totalTokens: numericValue(record.totalTokens),
|
|
@@ -4356,47 +4453,12 @@ function usageSummary(value) {
|
|
|
4356
4453
|
cacheCreationInputTokens: numericValue(record.cacheCreationInputTokens)
|
|
4357
4454
|
});
|
|
4358
4455
|
}
|
|
4359
|
-
function cleanMetadata2(value) {
|
|
4360
|
-
const cleaned = {};
|
|
4361
|
-
for (const [key, item] of Object.entries(value)) {
|
|
4362
|
-
if (item === void 0) {
|
|
4363
|
-
continue;
|
|
4364
|
-
}
|
|
4365
|
-
const jsonValue = cleanJsonValue(item);
|
|
4366
|
-
if (jsonValue !== void 0) {
|
|
4367
|
-
cleaned[key] = jsonValue;
|
|
4368
|
-
}
|
|
4369
|
-
}
|
|
4370
|
-
return cleaned;
|
|
4371
|
-
}
|
|
4372
|
-
function cleanJsonValue(value) {
|
|
4373
|
-
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
4374
|
-
return value;
|
|
4375
|
-
}
|
|
4376
|
-
if (Array.isArray(value)) {
|
|
4377
|
-
return value.map((item) => cleanJsonValue(item)).filter((item) => item !== void 0);
|
|
4378
|
-
}
|
|
4379
|
-
if (typeof value === "object" && value !== null) {
|
|
4380
|
-
return cleanMetadata2(value);
|
|
4381
|
-
}
|
|
4382
|
-
return void 0;
|
|
4383
|
-
}
|
|
4384
4456
|
function numericValue(value) {
|
|
4385
4457
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4386
4458
|
}
|
|
4387
4459
|
function byteLength3(value) {
|
|
4388
4460
|
return value === void 0 ? 0 : new TextEncoder().encode(value).byteLength;
|
|
4389
4461
|
}
|
|
4390
|
-
function formatUnknown2(value) {
|
|
4391
|
-
if (typeof value === "string") {
|
|
4392
|
-
return value;
|
|
4393
|
-
}
|
|
4394
|
-
try {
|
|
4395
|
-
return JSON.stringify(value);
|
|
4396
|
-
} catch {
|
|
4397
|
-
return String(value);
|
|
4398
|
-
}
|
|
4399
|
-
}
|
|
4400
4462
|
|
|
4401
4463
|
// src/runtime/sessions.ts
|
|
4402
4464
|
function registerSessionRoutes(app, props) {
|
|
@@ -4410,7 +4472,7 @@ function registerSessionRoutes(app, props) {
|
|
|
4410
4472
|
return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
|
|
4411
4473
|
}
|
|
4412
4474
|
const sessions = await props.sessionStore.listSessions({
|
|
4413
|
-
...
|
|
4475
|
+
...compact({ agentId }),
|
|
4414
4476
|
limit
|
|
4415
4477
|
});
|
|
4416
4478
|
return c.json({ sessions });
|
|
@@ -4426,8 +4488,7 @@ function registerSessionRoutes(app, props) {
|
|
|
4426
4488
|
const session = await props.sessionStore.createSession({
|
|
4427
4489
|
id: globalThis.crypto.randomUUID(),
|
|
4428
4490
|
agentId: body.agentId,
|
|
4429
|
-
...
|
|
4430
|
-
...body.metadata === void 0 ? {} : { metadata: body.metadata }
|
|
4491
|
+
...compact({ title: body.title, metadata: body.metadata })
|
|
4431
4492
|
});
|
|
4432
4493
|
await appendSessionLog(props.sessionStore, sessionCreatedLog(session));
|
|
4433
4494
|
return c.json(session, 201);
|
|
@@ -4454,18 +4515,18 @@ function registerSessionRoutes(app, props) {
|
|
|
4454
4515
|
{ capability: "sessions", operation: "logs" }
|
|
4455
4516
|
);
|
|
4456
4517
|
}
|
|
4457
|
-
const limit =
|
|
4518
|
+
const limit = parseLimit(c.req.query("limit"), 200, 1e3);
|
|
4458
4519
|
if (limit === void 0) {
|
|
4459
4520
|
return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
|
|
4460
4521
|
}
|
|
4461
|
-
const after =
|
|
4522
|
+
const after = parseAfter(c.req.query("after"));
|
|
4462
4523
|
if (after === false) {
|
|
4463
4524
|
return errorResponse(c, 400, "bad_request", "after must be a non-negative integer");
|
|
4464
4525
|
}
|
|
4465
4526
|
const logs = await props.sessionStore.listSessionLogs({
|
|
4466
4527
|
sessionId,
|
|
4467
4528
|
limit,
|
|
4468
|
-
...
|
|
4529
|
+
...compact({ after })
|
|
4469
4530
|
});
|
|
4470
4531
|
const last = logs.at(-1);
|
|
4471
4532
|
return c.json({
|
|
@@ -4473,91 +4534,431 @@ function registerSessionRoutes(app, props) {
|
|
|
4473
4534
|
...logs.length === limit && last !== void 0 ? { nextCursor: last.sequence } : {}
|
|
4474
4535
|
});
|
|
4475
4536
|
});
|
|
4476
|
-
app.delete("/sessions/:sessionId", async (c) => {
|
|
4477
|
-
if (props.sessionStore.deleteSession === void 0) {
|
|
4478
|
-
return errorResponse(
|
|
4479
|
-
c,
|
|
4480
|
-
501,
|
|
4481
|
-
"unsupported_capability",
|
|
4482
|
-
'Capability "sessions.delete" is not implemented by this runner',
|
|
4483
|
-
{ capability: "sessions", operation: "delete" }
|
|
4484
|
-
);
|
|
4485
|
-
}
|
|
4486
|
-
const deleted = await props.sessionStore.deleteSession(c.req.param("sessionId"));
|
|
4487
|
-
if (!deleted) {
|
|
4488
|
-
return errorResponse(c, 404, "not_found", "Session not found");
|
|
4489
|
-
}
|
|
4490
|
-
return c.body(null, 204);
|
|
4537
|
+
app.delete("/sessions/:sessionId", async (c) => {
|
|
4538
|
+
if (props.sessionStore.deleteSession === void 0) {
|
|
4539
|
+
return errorResponse(
|
|
4540
|
+
c,
|
|
4541
|
+
501,
|
|
4542
|
+
"unsupported_capability",
|
|
4543
|
+
'Capability "sessions.delete" is not implemented by this runner',
|
|
4544
|
+
{ capability: "sessions", operation: "delete" }
|
|
4545
|
+
);
|
|
4546
|
+
}
|
|
4547
|
+
const deleted = await props.sessionStore.deleteSession(c.req.param("sessionId"));
|
|
4548
|
+
if (!deleted) {
|
|
4549
|
+
return errorResponse(c, 404, "not_found", "Session not found");
|
|
4550
|
+
}
|
|
4551
|
+
return c.body(null, 204);
|
|
4552
|
+
});
|
|
4553
|
+
app.get("/sessions/:sessionId/traces", async (c) => {
|
|
4554
|
+
if (props.traceStore === void 0) {
|
|
4555
|
+
return unsupportedCapability(c, "traces");
|
|
4556
|
+
}
|
|
4557
|
+
const sessionId = c.req.param("sessionId");
|
|
4558
|
+
const session = await props.sessionStore.getSession(sessionId);
|
|
4559
|
+
if (session === void 0) {
|
|
4560
|
+
return errorResponse(c, 404, "not_found", "Session not found");
|
|
4561
|
+
}
|
|
4562
|
+
const limit = parseLimit(c.req.query("limit"));
|
|
4563
|
+
if (limit === void 0) {
|
|
4564
|
+
return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
|
|
4565
|
+
}
|
|
4566
|
+
const traces = await props.traceStore.listSessionTraces({ sessionId, limit });
|
|
4567
|
+
return c.json({ traces });
|
|
4568
|
+
});
|
|
4569
|
+
}
|
|
4570
|
+
async function parseCreateSessionRequest(c) {
|
|
4571
|
+
let body;
|
|
4572
|
+
try {
|
|
4573
|
+
body = await c.req.json();
|
|
4574
|
+
} catch {
|
|
4575
|
+
return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
|
|
4576
|
+
}
|
|
4577
|
+
if (!isObject(body)) {
|
|
4578
|
+
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
4579
|
+
}
|
|
4580
|
+
if (typeof body.agentId !== "string" || body.agentId.trim().length === 0) {
|
|
4581
|
+
return { error: errorResponse(c, 400, "bad_request", "agentId must be a string") };
|
|
4582
|
+
}
|
|
4583
|
+
const request = {
|
|
4584
|
+
agentId: body.agentId.trim()
|
|
4585
|
+
};
|
|
4586
|
+
if ("title" in body) {
|
|
4587
|
+
if (typeof body.title !== "string") {
|
|
4588
|
+
return { error: errorResponse(c, 400, "bad_request", "title must be a string") };
|
|
4589
|
+
}
|
|
4590
|
+
const title = body.title.trim();
|
|
4591
|
+
if (title.length > 0) {
|
|
4592
|
+
request.title = title;
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4595
|
+
if ("metadata" in body) {
|
|
4596
|
+
if (!isJsonObject(body.metadata)) {
|
|
4597
|
+
return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
|
|
4598
|
+
}
|
|
4599
|
+
request.metadata = body.metadata;
|
|
4600
|
+
}
|
|
4601
|
+
return request;
|
|
4602
|
+
}
|
|
4603
|
+
|
|
4604
|
+
// src/storage/memory-store.ts
|
|
4605
|
+
function createInMemoryStudioStore() {
|
|
4606
|
+
return new InMemoryStudioStore();
|
|
4607
|
+
}
|
|
4608
|
+
var InMemoryStudioStore = class {
|
|
4609
|
+
kind = "memory";
|
|
4610
|
+
sessions = /* @__PURE__ */ new Map();
|
|
4611
|
+
traces = /* @__PURE__ */ new Map();
|
|
4612
|
+
pipelineLogs = /* @__PURE__ */ new Map();
|
|
4613
|
+
pipelineRuns = /* @__PURE__ */ new Map();
|
|
4614
|
+
listSessions(options) {
|
|
4615
|
+
return [...this.sessions.values()].filter((session) => options.agentId === void 0 || session.agentId === options.agentId).sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt)).slice(0, options.limit).map(sessionSummary);
|
|
4616
|
+
}
|
|
4617
|
+
createSession(input) {
|
|
4618
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4619
|
+
const session = {
|
|
4620
|
+
...compact({
|
|
4621
|
+
id: input.id,
|
|
4622
|
+
agentId: input.agentId,
|
|
4623
|
+
title: input.title,
|
|
4624
|
+
createdAt: now,
|
|
4625
|
+
updatedAt: now,
|
|
4626
|
+
messageCount: 0,
|
|
4627
|
+
metadata: input.metadata
|
|
4628
|
+
}),
|
|
4629
|
+
messages: [],
|
|
4630
|
+
runs: [],
|
|
4631
|
+
logs: []
|
|
4632
|
+
};
|
|
4633
|
+
this.sessions.set(input.id, session);
|
|
4634
|
+
return sessionSummary(session);
|
|
4635
|
+
}
|
|
4636
|
+
getSession(id) {
|
|
4637
|
+
const session = this.sessions.get(id);
|
|
4638
|
+
return session === void 0 ? void 0 : materializeSession(session);
|
|
4639
|
+
}
|
|
4640
|
+
updateSessionMetadata(id, metadata) {
|
|
4641
|
+
const session = this.sessions.get(id);
|
|
4642
|
+
if (session === void 0) {
|
|
4643
|
+
return void 0;
|
|
4644
|
+
}
|
|
4645
|
+
if (metadata === void 0) {
|
|
4646
|
+
delete session.metadata;
|
|
4647
|
+
} else {
|
|
4648
|
+
session.metadata = metadata;
|
|
4649
|
+
}
|
|
4650
|
+
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4651
|
+
return materializeSession(session);
|
|
4652
|
+
}
|
|
4653
|
+
load(context) {
|
|
4654
|
+
return Promise.resolve(this.sessions.get(context.sessionId)?.messages ?? []);
|
|
4655
|
+
}
|
|
4656
|
+
append(input) {
|
|
4657
|
+
const session = this.sessions.get(input.context.sessionId);
|
|
4658
|
+
if (session !== void 0) {
|
|
4659
|
+
session.messages.push(...input.messages);
|
|
4660
|
+
session.messageCount = session.messages.length;
|
|
4661
|
+
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4662
|
+
}
|
|
4663
|
+
return Promise.resolve();
|
|
4664
|
+
}
|
|
4665
|
+
clear(context) {
|
|
4666
|
+
const session = this.sessions.get(context.sessionId);
|
|
4667
|
+
if (session !== void 0) {
|
|
4668
|
+
session.messages = [];
|
|
4669
|
+
session.runs = [];
|
|
4670
|
+
session.messageCount = 0;
|
|
4671
|
+
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4672
|
+
}
|
|
4673
|
+
return Promise.resolve();
|
|
4674
|
+
}
|
|
4675
|
+
async recordError(input) {
|
|
4676
|
+
await this.saveSessionRunTranscript({
|
|
4677
|
+
id: input.context.sessionId,
|
|
4678
|
+
runId: studioRunId(input.context) ?? input.runId,
|
|
4679
|
+
transcript: transcriptFromMessages(input.messages),
|
|
4680
|
+
status: "error",
|
|
4681
|
+
error: serializeJsonError(input.error)
|
|
4682
|
+
});
|
|
4683
|
+
}
|
|
4684
|
+
saveSessionRunTranscript(input) {
|
|
4685
|
+
const session = this.sessions.get(input.id);
|
|
4686
|
+
if (session === void 0) {
|
|
4687
|
+
return void 0;
|
|
4688
|
+
}
|
|
4689
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4690
|
+
const existingIndex = session.runs.findIndex((run2) => run2.runId === input.runId);
|
|
4691
|
+
const run = {
|
|
4692
|
+
...input,
|
|
4693
|
+
transcript: renumberTranscript(input.transcript),
|
|
4694
|
+
createdAt: existingIndex === -1 ? now : session.runs[existingIndex]?.createdAt ?? now,
|
|
4695
|
+
updatedAt: now
|
|
4696
|
+
};
|
|
4697
|
+
if (existingIndex === -1) {
|
|
4698
|
+
session.runs.push(run);
|
|
4699
|
+
} else {
|
|
4700
|
+
session.runs[existingIndex] = run;
|
|
4701
|
+
}
|
|
4702
|
+
session.updatedAt = now;
|
|
4703
|
+
return materializeSession(session);
|
|
4704
|
+
}
|
|
4705
|
+
appendSessionLog(input) {
|
|
4706
|
+
const session = this.sessions.get(input.sessionId);
|
|
4707
|
+
const logs = session?.logs ?? [];
|
|
4708
|
+
const entry = compact({
|
|
4709
|
+
id: globalThis.crypto.randomUUID(),
|
|
4710
|
+
sessionId: input.sessionId,
|
|
4711
|
+
runId: input.runId,
|
|
4712
|
+
sequence: logs.length,
|
|
4713
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4714
|
+
level: input.level,
|
|
4715
|
+
category: input.category,
|
|
4716
|
+
event: input.event,
|
|
4717
|
+
message: input.message,
|
|
4718
|
+
metadata: input.metadata
|
|
4719
|
+
});
|
|
4720
|
+
if (session !== void 0) {
|
|
4721
|
+
session.logs.push(entry);
|
|
4722
|
+
session.updatedAt = entry.timestamp;
|
|
4723
|
+
}
|
|
4724
|
+
return entry;
|
|
4725
|
+
}
|
|
4726
|
+
listSessionLogs(options) {
|
|
4727
|
+
return (this.sessions.get(options.sessionId)?.logs ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
|
|
4728
|
+
}
|
|
4729
|
+
deleteSession(id) {
|
|
4730
|
+
for (const trace of this.traces.values()) {
|
|
4731
|
+
if (trace.sessionId === id) {
|
|
4732
|
+
this.traces.delete(trace.id);
|
|
4733
|
+
}
|
|
4734
|
+
}
|
|
4735
|
+
return this.sessions.delete(id);
|
|
4736
|
+
}
|
|
4737
|
+
listTraces(options) {
|
|
4738
|
+
return [...this.traces.values()].filter((trace) => options.sessionId === void 0 || trace.sessionId === options.sessionId).filter((trace) => options.status === void 0 || trace.status === options.status).filter((trace) => options.agentId === void 0 || traceAgentId(trace) === options.agentId).sort((left, right) => Date.parse(right.startedAt) - Date.parse(left.startedAt)).slice(0, options.limit).map(traceSummary2);
|
|
4739
|
+
}
|
|
4740
|
+
listSessionTraces(options) {
|
|
4741
|
+
return this.listTraces({ sessionId: options.sessionId, limit: options.limit });
|
|
4742
|
+
}
|
|
4743
|
+
getTrace(id) {
|
|
4744
|
+
return this.traces.get(id);
|
|
4745
|
+
}
|
|
4746
|
+
saveTrace(trace) {
|
|
4747
|
+
this.traces.set(trace.id, trace);
|
|
4748
|
+
return trace;
|
|
4749
|
+
}
|
|
4750
|
+
appendPipelineLog(input) {
|
|
4751
|
+
const logs = this.pipelineLogs.get(input.pipelineId) ?? [];
|
|
4752
|
+
const entry = compact({
|
|
4753
|
+
id: globalThis.crypto.randomUUID(),
|
|
4754
|
+
pipelineId: input.pipelineId,
|
|
4755
|
+
runId: input.runId,
|
|
4756
|
+
sequence: logs.length,
|
|
4757
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4758
|
+
level: input.level,
|
|
4759
|
+
category: input.category,
|
|
4760
|
+
event: input.event,
|
|
4761
|
+
message: input.message,
|
|
4762
|
+
metadata: input.metadata
|
|
4763
|
+
});
|
|
4764
|
+
this.pipelineLogs.set(input.pipelineId, [...logs, entry]);
|
|
4765
|
+
return entry;
|
|
4766
|
+
}
|
|
4767
|
+
listPipelineLogs(options) {
|
|
4768
|
+
return (this.pipelineLogs.get(options.pipelineId) ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
|
|
4769
|
+
}
|
|
4770
|
+
savePipelineRun(input) {
|
|
4771
|
+
const record = compact({
|
|
4772
|
+
runId: input.runId,
|
|
4773
|
+
pipelineId: input.pipelineId,
|
|
4774
|
+
status: input.status,
|
|
4775
|
+
input: input.input,
|
|
4776
|
+
output: input.output,
|
|
4777
|
+
error: input.error,
|
|
4778
|
+
metadata: input.metadata,
|
|
4779
|
+
startedAt: input.startedAt,
|
|
4780
|
+
endedAt: input.endedAt,
|
|
4781
|
+
durationMs: input.durationMs
|
|
4782
|
+
});
|
|
4783
|
+
this.pipelineRuns.set(input.runId, record);
|
|
4784
|
+
return record;
|
|
4785
|
+
}
|
|
4786
|
+
getPipelineRun(options) {
|
|
4787
|
+
const run = this.pipelineRuns.get(options.runId);
|
|
4788
|
+
return run?.pipelineId === options.pipelineId ? run : void 0;
|
|
4789
|
+
}
|
|
4790
|
+
listPipelineRuns(options) {
|
|
4791
|
+
return [...this.pipelineRuns.values()].filter((run) => run.pipelineId === options.pipelineId).sort((left, right) => Date.parse(right.startedAt) - Date.parse(left.startedAt)).slice(0, options.limit);
|
|
4792
|
+
}
|
|
4793
|
+
};
|
|
4794
|
+
function sessionSummary(session) {
|
|
4795
|
+
return compact({
|
|
4796
|
+
id: session.id,
|
|
4797
|
+
agentId: session.agentId,
|
|
4798
|
+
title: session.title,
|
|
4799
|
+
createdAt: session.createdAt,
|
|
4800
|
+
updatedAt: session.updatedAt,
|
|
4801
|
+
messageCount: session.messages.length,
|
|
4802
|
+
metadata: session.metadata
|
|
4803
|
+
});
|
|
4804
|
+
}
|
|
4805
|
+
function materializeSession(session) {
|
|
4806
|
+
return {
|
|
4807
|
+
...sessionSummary(session),
|
|
4808
|
+
messages: [...session.messages],
|
|
4809
|
+
transcript: renumberTranscript(session.runs.flatMap((run) => run.transcript))
|
|
4810
|
+
};
|
|
4811
|
+
}
|
|
4812
|
+
function traceSummary2(trace) {
|
|
4813
|
+
return compact({
|
|
4814
|
+
id: trace.id,
|
|
4815
|
+
sessionId: trace.sessionId,
|
|
4816
|
+
name: trace.name,
|
|
4817
|
+
status: trace.status,
|
|
4818
|
+
startedAt: trace.startedAt,
|
|
4819
|
+
endedAt: trace.endedAt,
|
|
4820
|
+
durationMs: trace.durationMs,
|
|
4821
|
+
output: trace.output,
|
|
4822
|
+
error: trace.error,
|
|
4823
|
+
usage: trace.usage,
|
|
4824
|
+
metadata: trace.metadata,
|
|
4825
|
+
observationCount: trace.observations.length
|
|
4491
4826
|
});
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4827
|
+
}
|
|
4828
|
+
function traceAgentId(trace) {
|
|
4829
|
+
const nestedMetadata = trace.metadata?.metadata;
|
|
4830
|
+
return isJsonObject2(nestedMetadata) && typeof nestedMetadata.agentId === "string" ? nestedMetadata.agentId : void 0;
|
|
4831
|
+
}
|
|
4832
|
+
function studioRunId(context) {
|
|
4833
|
+
const value = context.metadata?.studioRunId;
|
|
4834
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
4835
|
+
}
|
|
4836
|
+
function serializeJsonError(error) {
|
|
4837
|
+
if (error instanceof Error) {
|
|
4838
|
+
return {
|
|
4839
|
+
name: error.name,
|
|
4840
|
+
message: error.message
|
|
4841
|
+
};
|
|
4842
|
+
}
|
|
4843
|
+
return isJsonValue3(error) ? error : String(error);
|
|
4844
|
+
}
|
|
4845
|
+
function isJsonObject2(value) {
|
|
4846
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4847
|
+
}
|
|
4848
|
+
function isJsonValue3(value) {
|
|
4849
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
4850
|
+
return true;
|
|
4851
|
+
}
|
|
4852
|
+
if (Array.isArray(value)) {
|
|
4853
|
+
return value.every(isJsonValue3);
|
|
4854
|
+
}
|
|
4855
|
+
return isJsonObject2(value) && Object.values(value).every(isJsonValue3);
|
|
4856
|
+
}
|
|
4857
|
+
|
|
4858
|
+
// src/runtime/shared.ts
|
|
4859
|
+
function resolveStores(options) {
|
|
4860
|
+
const defaultStore = defaultStudioStore();
|
|
4861
|
+
const sessions = resolveSessionStore(options, defaultStore);
|
|
4862
|
+
const traces = resolveTraceStore(options, sessions, defaultStore);
|
|
4863
|
+
const pipelineLogs = resolvePipelineLogStore(options, sessions, defaultStore);
|
|
4864
|
+
const pipelineRuns = resolvePipelineRunStore(options, sessions, pipelineLogs, defaultStore);
|
|
4865
|
+
return compact({
|
|
4866
|
+
sessions,
|
|
4867
|
+
traces,
|
|
4868
|
+
pipelineLogs,
|
|
4869
|
+
pipelineRuns
|
|
4507
4870
|
});
|
|
4508
4871
|
}
|
|
4509
|
-
function
|
|
4510
|
-
|
|
4511
|
-
|
|
4872
|
+
function defaultStudioStore() {
|
|
4873
|
+
return createInMemoryStudioStore();
|
|
4874
|
+
}
|
|
4875
|
+
function resolveSessionStore(options, defaultStore) {
|
|
4876
|
+
if (options.stores?.sessions === false) {
|
|
4877
|
+
return void 0;
|
|
4512
4878
|
}
|
|
4513
|
-
|
|
4514
|
-
|
|
4879
|
+
if (options.stores?.sessions !== void 0) {
|
|
4880
|
+
return options.stores.sessions;
|
|
4881
|
+
}
|
|
4882
|
+
return defaultStore;
|
|
4883
|
+
}
|
|
4884
|
+
function resolveTraceStore(options, sessionStore, defaultStore) {
|
|
4885
|
+
if (options.stores?.traces !== void 0) {
|
|
4886
|
+
return options.stores.traces;
|
|
4887
|
+
}
|
|
4888
|
+
if (sessionStore === void 0) {
|
|
4515
4889
|
return void 0;
|
|
4516
4890
|
}
|
|
4517
|
-
|
|
4891
|
+
if (isTraceStore(sessionStore)) {
|
|
4892
|
+
return sessionStore;
|
|
4893
|
+
}
|
|
4894
|
+
return defaultStore;
|
|
4518
4895
|
}
|
|
4519
|
-
function
|
|
4520
|
-
if (
|
|
4896
|
+
function resolvePipelineLogStore(options, sessionStore, defaultStore) {
|
|
4897
|
+
if (options.stores?.pipelineLogs === false) {
|
|
4521
4898
|
return void 0;
|
|
4522
4899
|
}
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
return false;
|
|
4900
|
+
if (options.stores?.pipelineLogs !== void 0) {
|
|
4901
|
+
return options.stores.pipelineLogs;
|
|
4526
4902
|
}
|
|
4527
|
-
|
|
4903
|
+
if (sessionStore !== void 0 && isPipelineLogStore(sessionStore)) {
|
|
4904
|
+
return sessionStore;
|
|
4905
|
+
}
|
|
4906
|
+
return defaultStore;
|
|
4528
4907
|
}
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
body = await c.req.json();
|
|
4533
|
-
} catch {
|
|
4534
|
-
return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
|
|
4908
|
+
function resolvePipelineRunStore(options, sessionStore, pipelineLogStore, defaultStore) {
|
|
4909
|
+
if (options.stores?.pipelineRuns === false) {
|
|
4910
|
+
return void 0;
|
|
4535
4911
|
}
|
|
4536
|
-
if (
|
|
4537
|
-
return
|
|
4912
|
+
if (options.stores?.pipelineRuns !== void 0) {
|
|
4913
|
+
return options.stores.pipelineRuns;
|
|
4538
4914
|
}
|
|
4539
|
-
if (
|
|
4540
|
-
return
|
|
4915
|
+
if (sessionStore !== void 0 && isPipelineRunStore(sessionStore)) {
|
|
4916
|
+
return sessionStore;
|
|
4541
4917
|
}
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
}
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4918
|
+
if (pipelineLogStore !== void 0 && isPipelineRunStore(pipelineLogStore)) {
|
|
4919
|
+
return pipelineLogStore;
|
|
4920
|
+
}
|
|
4921
|
+
return defaultStore;
|
|
4922
|
+
}
|
|
4923
|
+
function isTraceStore(store) {
|
|
4924
|
+
const candidate = store;
|
|
4925
|
+
return typeof candidate.listSessionTraces === "function" && typeof candidate.getTrace === "function" && typeof candidate.saveTrace === "function";
|
|
4926
|
+
}
|
|
4927
|
+
function isPipelineLogStore(store) {
|
|
4928
|
+
const candidate = store;
|
|
4929
|
+
return typeof candidate.appendPipelineLog === "function" && typeof candidate.listPipelineLogs === "function";
|
|
4930
|
+
}
|
|
4931
|
+
function isPipelineRunStore(store) {
|
|
4932
|
+
const candidate = store;
|
|
4933
|
+
return typeof candidate.savePipelineRun === "function" && typeof candidate.getPipelineRun === "function" && typeof candidate.listPipelineRuns === "function";
|
|
4934
|
+
}
|
|
4935
|
+
function normalizeAgents(agents) {
|
|
4936
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4937
|
+
return agents.map((agent) => {
|
|
4938
|
+
const id = agent.id.trim();
|
|
4939
|
+
if (id.length === 0) {
|
|
4940
|
+
throw new Error("Studio agent id cannot be empty");
|
|
4548
4941
|
}
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
request.title = title;
|
|
4942
|
+
if (ids.has(id)) {
|
|
4943
|
+
throw new Error(`Duplicate runner agent id: ${id}`);
|
|
4552
4944
|
}
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4945
|
+
ids.add(id);
|
|
4946
|
+
return { ...agent, id };
|
|
4947
|
+
});
|
|
4948
|
+
}
|
|
4949
|
+
function normalizePipelines(pipelines) {
|
|
4950
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4951
|
+
return pipelines.map((pipeline) => {
|
|
4952
|
+
const id = pipeline.id.trim();
|
|
4953
|
+
if (id.length === 0) {
|
|
4954
|
+
throw new Error("Studio pipeline id cannot be empty");
|
|
4557
4955
|
}
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4956
|
+
if (ids.has(id)) {
|
|
4957
|
+
throw new Error(`Duplicate Studio pipeline id: ${id}`);
|
|
4958
|
+
}
|
|
4959
|
+
ids.add(id);
|
|
4960
|
+
return { ...pipeline, id };
|
|
4961
|
+
});
|
|
4561
4962
|
}
|
|
4562
4963
|
|
|
4563
4964
|
// src/runtime/status.ts
|
|
@@ -4566,30 +4967,31 @@ function registerStatusRoutes(app, props) {
|
|
|
4566
4967
|
const summary = {
|
|
4567
4968
|
runner: {
|
|
4568
4969
|
id: runnerId(props.options),
|
|
4569
|
-
...props.options.name
|
|
4570
|
-
...props.options.version === void 0 ? {} : { version: props.options.version }
|
|
4970
|
+
...compact({ name: props.options.name, version: props.options.version })
|
|
4571
4971
|
},
|
|
4572
4972
|
storage: {
|
|
4573
|
-
...
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4973
|
+
...compact({
|
|
4974
|
+
sessions: props.stores.sessions?.kind,
|
|
4975
|
+
traces: props.stores.traces?.kind,
|
|
4976
|
+
pipelineLogs: props.stores.pipelineLogs !== void 0 ? "available" : void 0,
|
|
4977
|
+
pipelineRuns: props.stores.pipelineRuns !== void 0 ? "available" : void 0
|
|
4978
|
+
})
|
|
4577
4979
|
},
|
|
4578
4980
|
counts: {
|
|
4579
4981
|
agents: props.agents.length,
|
|
4580
4982
|
pipelines: props.pipelines.length,
|
|
4581
|
-
...
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
pipelineRuns: (await Promise.all(
|
|
4983
|
+
...compact({
|
|
4984
|
+
sessions: props.stores.sessions !== void 0 ? (await props.stores.sessions.listSessions({ limit: 100 })).length : void 0,
|
|
4985
|
+
traces: props.stores.traces?.listTraces !== void 0 ? (await props.stores.traces.listTraces({ limit: 100 })).length : void 0,
|
|
4986
|
+
pipelineRuns: props.stores.pipelineRuns !== void 0 && props.pipelines.length > 0 ? (await Promise.all(
|
|
4585
4987
|
props.pipelines.map(
|
|
4586
4988
|
(pipeline) => props.stores.pipelineRuns?.listPipelineRuns({
|
|
4587
4989
|
pipelineId: pipeline.id,
|
|
4588
4990
|
limit: 100
|
|
4589
4991
|
})
|
|
4590
4992
|
)
|
|
4591
|
-
)).reduce((sum, runs) => sum + (runs?.length ?? 0), 0)
|
|
4592
|
-
}
|
|
4993
|
+
)).reduce((sum, runs) => sum + (runs?.length ?? 0), 0) : void 0
|
|
4994
|
+
})
|
|
4593
4995
|
},
|
|
4594
4996
|
capabilities: capabilityConfig(props.options, props.agents, props.pipelines, props.stores),
|
|
4595
4997
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -4673,16 +5075,16 @@ async function parseToolRunRequest(c) {
|
|
|
4673
5075
|
if (body === void 0 || body === null) {
|
|
4674
5076
|
return { args: {} };
|
|
4675
5077
|
}
|
|
4676
|
-
if (!
|
|
5078
|
+
if (!isJsonObject(body)) {
|
|
4677
5079
|
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
4678
5080
|
}
|
|
4679
5081
|
const args = Object.hasOwn(body, "args") ? body.args : {};
|
|
4680
|
-
if (!
|
|
5082
|
+
if (!isJsonValue(args)) {
|
|
4681
5083
|
return { error: errorResponse(c, 400, "bad_request", "args must be JSON-compatible") };
|
|
4682
5084
|
}
|
|
4683
5085
|
const request = { args };
|
|
4684
5086
|
if (Object.hasOwn(body, "context")) {
|
|
4685
|
-
if (!
|
|
5087
|
+
if (!isJsonObject(body.context)) {
|
|
4686
5088
|
return { error: errorResponse(c, 400, "bad_request", "context must be an object") };
|
|
4687
5089
|
}
|
|
4688
5090
|
request.context = body.context;
|
|
@@ -4740,9 +5142,7 @@ function registerTraceRoutes(app, traceStore) {
|
|
|
4740
5142
|
const sessionId = optionalQueryString(c.req.query("sessionId"));
|
|
4741
5143
|
const traces = await traceStore.listTraces({
|
|
4742
5144
|
limit,
|
|
4743
|
-
...
|
|
4744
|
-
...sessionId === void 0 ? {} : { sessionId },
|
|
4745
|
-
...status === void 0 ? {} : { status }
|
|
5145
|
+
...compact({ agentId, sessionId, status })
|
|
4746
5146
|
});
|
|
4747
5147
|
return c.json({ traces });
|
|
4748
5148
|
});
|
|
@@ -4785,7 +5185,7 @@ var Studio = class {
|
|
|
4785
5185
|
const port = serveOptions.port ?? Number(process.env.RUNNER_PORT ?? 4021);
|
|
4786
5186
|
this.server = serve({
|
|
4787
5187
|
fetch: (request) => this.fetch(request),
|
|
4788
|
-
...
|
|
5188
|
+
...compact({ hostname: serveOptions.hostname }),
|
|
4789
5189
|
port
|
|
4790
5190
|
});
|
|
4791
5191
|
const log = serveOptions.log ?? true;
|
|
@@ -4825,8 +5225,9 @@ function studioOptionsFromTargets(targets, options) {
|
|
|
4825
5225
|
agents: inferStudioAgents(agents, options.quickPrompts ?? {}),
|
|
4826
5226
|
pipelines: inferStudioPipelines(pipelines),
|
|
4827
5227
|
evals: options.evals ?? [],
|
|
4828
|
-
...
|
|
4829
|
-
...
|
|
5228
|
+
...compact({ models: options.models }),
|
|
5229
|
+
...compact({ stores: options.stores }),
|
|
5230
|
+
...compact({ ui: options.ui })
|
|
4830
5231
|
};
|
|
4831
5232
|
}
|
|
4832
5233
|
function inferStudioAgents(agents, quickPrompts) {
|
|
@@ -4848,9 +5249,9 @@ function inferStudioPipelines(pipelines) {
|
|
|
4848
5249
|
return {
|
|
4849
5250
|
id,
|
|
4850
5251
|
pipeline,
|
|
4851
|
-
...
|
|
4852
|
-
...
|
|
4853
|
-
...
|
|
5252
|
+
...compact({ name: pipeline.name }),
|
|
5253
|
+
...compact({ description: pipeline.description }),
|
|
5254
|
+
...compact({ metadata: pipeline.metadata })
|
|
4854
5255
|
};
|
|
4855
5256
|
});
|
|
4856
5257
|
}
|
|
@@ -4866,7 +5267,7 @@ function uniqueAgentId(baseId, ids) {
|
|
|
4866
5267
|
}
|
|
4867
5268
|
function agentMetadata(agent) {
|
|
4868
5269
|
return {
|
|
4869
|
-
...
|
|
5270
|
+
...compact({ defaultMaxTurns: agent.defaultMaxTurns }),
|
|
4870
5271
|
staticContextCount: agent.staticContext.length,
|
|
4871
5272
|
dynamicContextCount: agent.dynamicContexts.length,
|
|
4872
5273
|
dynamicToolCount: agent.dynamicTools.length,
|
|
@@ -4882,6 +5283,7 @@ function createStudioApp(options) {
|
|
|
4882
5283
|
const agents = normalizeAgents(options.agents).map(
|
|
4883
5284
|
(agent) => withStudioTraceObserver(agent, stores.traces)
|
|
4884
5285
|
);
|
|
5286
|
+
const modelRegistry = createStudioModelRegistry(options.models);
|
|
4885
5287
|
const pipelines = normalizePipelines(options.pipelines);
|
|
4886
5288
|
const agentMap = new Map(agents.map((agent) => [agent.id, agent]));
|
|
4887
5289
|
const pipelineMap = new Map(pipelines.map((pipeline) => [pipeline.id, pipeline]));
|
|
@@ -4924,6 +5326,7 @@ function createStudioApp(options) {
|
|
|
4924
5326
|
}
|
|
4925
5327
|
return c.json(agentRuntimeSummary(agent));
|
|
4926
5328
|
});
|
|
5329
|
+
registerModelRoutes(app, { registry: modelRegistry, agentMap });
|
|
4927
5330
|
registerMcpRoutes(app, { agentMap });
|
|
4928
5331
|
registerToolRoutes(app, { agentMap });
|
|
4929
5332
|
registerApprovalRoutes(app, approvalRuntime);
|
|
@@ -4935,13 +5338,13 @@ function createStudioApp(options) {
|
|
|
4935
5338
|
});
|
|
4936
5339
|
registerKnowledgeRoutes(app, {
|
|
4937
5340
|
agents,
|
|
4938
|
-
...
|
|
5341
|
+
...compact({ traceStore: stores.traces })
|
|
4939
5342
|
});
|
|
4940
5343
|
registerPipelineRoutes(app, {
|
|
4941
5344
|
pipelines,
|
|
4942
5345
|
pipelineMap,
|
|
4943
|
-
...
|
|
4944
|
-
...
|
|
5346
|
+
...compact({ logStore: stores.pipelineLogs }),
|
|
5347
|
+
...compact({ runStore: stores.pipelineRuns })
|
|
4945
5348
|
});
|
|
4946
5349
|
app.post("/agents/:agentId/runs", async (c) => {
|
|
4947
5350
|
const agentId = c.req.param("agentId");
|
|
@@ -4963,6 +5366,20 @@ function createStudioApp(options) {
|
|
|
4963
5366
|
if (session !== void 0 && session.agentId !== agentId) {
|
|
4964
5367
|
return errorResponse(c, 400, "bad_request", "Session belongs to another agent");
|
|
4965
5368
|
}
|
|
5369
|
+
let selectedModel;
|
|
5370
|
+
try {
|
|
5371
|
+
selectedModel = resolveStudioModel(modelRegistry, {
|
|
5372
|
+
agent,
|
|
5373
|
+
request: body,
|
|
5374
|
+
sessionMetadata: session?.metadata
|
|
5375
|
+
});
|
|
5376
|
+
} catch (error) {
|
|
5377
|
+
if (error instanceof ModelSelectionError) {
|
|
5378
|
+
return errorResponse(c, 400, "bad_request", error.message);
|
|
5379
|
+
}
|
|
5380
|
+
throw error;
|
|
5381
|
+
}
|
|
5382
|
+
const runAgent = selectedModel.model === void 0 ? agent.agent : cloneAgent(agent.agent, { model: selectedModel.model });
|
|
4966
5383
|
const runId = globalThis.crypto.randomUUID();
|
|
4967
5384
|
const runStartedAt = Date.now();
|
|
4968
5385
|
if (session !== void 0) {
|
|
@@ -4974,21 +5391,46 @@ function createStudioApp(options) {
|
|
|
4974
5391
|
agentId,
|
|
4975
5392
|
message: body.message,
|
|
4976
5393
|
stream: body.stream === true,
|
|
4977
|
-
...
|
|
4978
|
-
...
|
|
5394
|
+
...compact({ maxTurns: body.maxTurns }),
|
|
5395
|
+
...compact({ toolConcurrency: body.toolConcurrency }),
|
|
4979
5396
|
hasTrace: body.trace !== void 0,
|
|
4980
|
-
...body.metadata === void 0 ? {} : {
|
|
5397
|
+
...body.metadata === void 0 && selectedModel.ref === void 0 ? {} : {
|
|
5398
|
+
metadata: {
|
|
5399
|
+
...body.metadata ?? {},
|
|
5400
|
+
...selectedModel.ref === void 0 ? {} : { [STUDIO_MODEL_METADATA_KEY]: selectedModel.ref }
|
|
5401
|
+
}
|
|
5402
|
+
}
|
|
4981
5403
|
})
|
|
4982
5404
|
);
|
|
4983
5405
|
}
|
|
5406
|
+
if (session !== void 0 && selectedModel.ref !== void 0) {
|
|
5407
|
+
for (const warning of selectedModel.warnings) {
|
|
5408
|
+
await appendSessionLog(stores.sessions, {
|
|
5409
|
+
sessionId: session.id,
|
|
5410
|
+
runId,
|
|
5411
|
+
level: "warn",
|
|
5412
|
+
category: "model",
|
|
5413
|
+
event: "model.warning",
|
|
5414
|
+
message: typeof warning.message === "string" ? warning.message : "Model warning",
|
|
5415
|
+
metadata: warning
|
|
5416
|
+
});
|
|
5417
|
+
}
|
|
5418
|
+
if (sessionModelRef(session.metadata) !== selectedModel.ref) {
|
|
5419
|
+
await stores.sessions?.updateSessionMetadata?.(session.id, {
|
|
5420
|
+
...session.metadata ?? {},
|
|
5421
|
+
[STUDIO_MODEL_METADATA_KEY]: selectedModel.ref
|
|
5422
|
+
});
|
|
5423
|
+
}
|
|
5424
|
+
}
|
|
4984
5425
|
const memoryMetadata = {
|
|
4985
5426
|
agentId,
|
|
4986
5427
|
...body.metadata ?? {},
|
|
5428
|
+
...selectedModel.ref === void 0 ? {} : { [STUDIO_MODEL_METADATA_KEY]: selectedModel.ref },
|
|
4987
5429
|
studioRunId: runId
|
|
4988
5430
|
};
|
|
4989
5431
|
const promptMessage = normalizePromptMessage(body.message);
|
|
4990
5432
|
const sessionStore = stores.sessions;
|
|
4991
|
-
const shouldPersistSessionMessages = session !== void 0 && sessionStore !== void 0 && !usesStoreAsAgentMemory(
|
|
5433
|
+
const shouldPersistSessionMessages = session !== void 0 && sessionStore !== void 0 && !usesStoreAsAgentMemory(runAgent, sessionStore);
|
|
4992
5434
|
if (shouldPersistSessionMessages) {
|
|
4993
5435
|
await sessionStore.append({
|
|
4994
5436
|
context: { sessionId: session.id, metadata: memoryMetadata },
|
|
@@ -4997,7 +5439,7 @@ function createStudioApp(options) {
|
|
|
4997
5439
|
messages: [promptMessage]
|
|
4998
5440
|
});
|
|
4999
5441
|
}
|
|
5000
|
-
const request = session !== void 0 ?
|
|
5442
|
+
const request = session !== void 0 ? runAgent.memory === void 0 ? runAgent.prompt([...session.messages, promptMessage]) : runAgent.session(session.id, { metadata: memoryMetadata }).prompt(body.message) : runAgent.prompt(
|
|
5001
5443
|
body.history !== void 0 ? [...body.history, promptMessage] : body.message
|
|
5002
5444
|
);
|
|
5003
5445
|
if (body.maxTurns !== void 0) {
|
|
@@ -5015,21 +5457,21 @@ function createStudioApp(options) {
|
|
|
5015
5457
|
const runtimeEvents = new AsyncEventQueue();
|
|
5016
5458
|
const effectiveHook = composeHooks(
|
|
5017
5459
|
composeHooks(
|
|
5018
|
-
|
|
5460
|
+
runAgent.hook,
|
|
5019
5461
|
approvalRuntime.createHook({
|
|
5020
5462
|
runId,
|
|
5021
5463
|
agentId,
|
|
5022
|
-
...
|
|
5023
|
-
...
|
|
5024
|
-
getTool: (toolName) =>
|
|
5464
|
+
...compact({ sessionId: session?.id }),
|
|
5465
|
+
...compact({ metadata: body.metadata }),
|
|
5466
|
+
getTool: (toolName) => runAgent.getTool(toolName),
|
|
5025
5467
|
emit: (event) => runtimeEvents.push(event)
|
|
5026
5468
|
})
|
|
5027
5469
|
),
|
|
5028
5470
|
questionRuntime.createHook({
|
|
5029
5471
|
runId,
|
|
5030
5472
|
agentId,
|
|
5031
|
-
...
|
|
5032
|
-
...
|
|
5473
|
+
...compact({ sessionId: session?.id }),
|
|
5474
|
+
...compact({ metadata: body.metadata }),
|
|
5033
5475
|
emit: (event) => runtimeEvents.push(event)
|
|
5034
5476
|
})
|
|
5035
5477
|
);
|
|
@@ -5060,20 +5502,20 @@ function createStudioApp(options) {
|
|
|
5060
5502
|
}
|
|
5061
5503
|
const effectiveHook = composeHooks(
|
|
5062
5504
|
composeHooks(
|
|
5063
|
-
|
|
5505
|
+
runAgent.hook,
|
|
5064
5506
|
approvalRuntime.createHook({
|
|
5065
5507
|
runId,
|
|
5066
5508
|
agentId,
|
|
5067
|
-
...
|
|
5068
|
-
...
|
|
5069
|
-
getTool: (toolName) =>
|
|
5509
|
+
...compact({ sessionId: session?.id }),
|
|
5510
|
+
...compact({ metadata: body.metadata }),
|
|
5511
|
+
getTool: (toolName) => runAgent.getTool(toolName)
|
|
5070
5512
|
})
|
|
5071
5513
|
),
|
|
5072
5514
|
questionRuntime.createHook({
|
|
5073
5515
|
runId,
|
|
5074
5516
|
agentId,
|
|
5075
|
-
...
|
|
5076
|
-
...
|
|
5517
|
+
...compact({ sessionId: session?.id }),
|
|
5518
|
+
...compact({ metadata: body.metadata })
|
|
5077
5519
|
})
|
|
5078
5520
|
);
|
|
5079
5521
|
if (effectiveHook !== void 0) {
|
|
@@ -5146,7 +5588,7 @@ function createStudioApp(options) {
|
|
|
5146
5588
|
registerSessionRoutes(app, {
|
|
5147
5589
|
agentMap,
|
|
5148
5590
|
sessionStore: stores.sessions,
|
|
5149
|
-
...
|
|
5591
|
+
...compact({ traceStore: stores.traces })
|
|
5150
5592
|
});
|
|
5151
5593
|
}
|
|
5152
5594
|
if (stores.traces !== void 0) {
|
|
@@ -5166,8 +5608,8 @@ function createStudioApp(options) {
|
|
|
5166
5608
|
},
|
|
5167
5609
|
close() {
|
|
5168
5610
|
},
|
|
5169
|
-
...
|
|
5170
|
-
...
|
|
5611
|
+
...compact({ sessionStore: stores.sessions }),
|
|
5612
|
+
...compact({ traceStore: stores.traces })
|
|
5171
5613
|
};
|
|
5172
5614
|
}
|
|
5173
5615
|
function normalizePromptMessage(message) {
|
|
@@ -5311,17 +5753,35 @@ var SqliteSessionStore = class {
|
|
|
5311
5753
|
return {
|
|
5312
5754
|
id: input.id,
|
|
5313
5755
|
agentId: input.agentId,
|
|
5314
|
-
...
|
|
5756
|
+
...compact({ title: input.title }),
|
|
5315
5757
|
createdAt: now,
|
|
5316
5758
|
updatedAt: now,
|
|
5317
5759
|
messageCount: 0,
|
|
5318
|
-
...
|
|
5760
|
+
...compact({ metadata: input.metadata })
|
|
5319
5761
|
};
|
|
5320
5762
|
}
|
|
5321
5763
|
getSession(id) {
|
|
5322
5764
|
const row = this.getSessionRow(id);
|
|
5323
5765
|
return row === void 0 ? void 0 : toSession(row, this.listSessionMessages(id), this.listSessionRunRows(id));
|
|
5324
5766
|
}
|
|
5767
|
+
updateSessionMetadata(id, metadata) {
|
|
5768
|
+
const db = this.database();
|
|
5769
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5770
|
+
const result = db.prepare(
|
|
5771
|
+
`UPDATE anvia_studio_sessions
|
|
5772
|
+
SET metadata_json = $metadata,
|
|
5773
|
+
updated_at = $now
|
|
5774
|
+
WHERE id = $id`
|
|
5775
|
+
).run({
|
|
5776
|
+
$id: id,
|
|
5777
|
+
$metadata: metadata === void 0 ? null : JSON.stringify(metadata),
|
|
5778
|
+
$now: now
|
|
5779
|
+
});
|
|
5780
|
+
if (result.changes === 0) {
|
|
5781
|
+
return void 0;
|
|
5782
|
+
}
|
|
5783
|
+
return this.getSession(id);
|
|
5784
|
+
}
|
|
5325
5785
|
load(context) {
|
|
5326
5786
|
const session = this.getSession(context.sessionId);
|
|
5327
5787
|
return Promise.resolve(session?.messages ?? []);
|
|
@@ -5483,14 +5943,14 @@ var SqliteSessionStore = class {
|
|
|
5483
5943
|
const entry = {
|
|
5484
5944
|
id: globalThis.crypto.randomUUID(),
|
|
5485
5945
|
sessionId: input.sessionId,
|
|
5486
|
-
...
|
|
5946
|
+
...compact({ runId: input.runId }),
|
|
5487
5947
|
sequence,
|
|
5488
5948
|
timestamp: now,
|
|
5489
5949
|
level: input.level,
|
|
5490
5950
|
category: input.category,
|
|
5491
5951
|
event: input.event,
|
|
5492
5952
|
message: input.message,
|
|
5493
|
-
...
|
|
5953
|
+
...compact({ metadata: input.metadata })
|
|
5494
5954
|
};
|
|
5495
5955
|
db.prepare(
|
|
5496
5956
|
`INSERT INTO anvia_studio_session_logs (
|
|
@@ -5564,14 +6024,14 @@ var SqliteSessionStore = class {
|
|
|
5564
6024
|
const entry = {
|
|
5565
6025
|
id: globalThis.crypto.randomUUID(),
|
|
5566
6026
|
pipelineId: input.pipelineId,
|
|
5567
|
-
...
|
|
6027
|
+
...compact({ runId: input.runId }),
|
|
5568
6028
|
sequence,
|
|
5569
6029
|
timestamp: now,
|
|
5570
6030
|
level: input.level,
|
|
5571
6031
|
category: input.category,
|
|
5572
6032
|
event: input.event,
|
|
5573
6033
|
message: input.message,
|
|
5574
|
-
...
|
|
6034
|
+
...compact({ metadata: input.metadata })
|
|
5575
6035
|
};
|
|
5576
6036
|
db.prepare(
|
|
5577
6037
|
`INSERT INTO anvia_studio_pipeline_logs (
|
|
@@ -5689,12 +6149,12 @@ var SqliteSessionStore = class {
|
|
|
5689
6149
|
pipelineId: input.pipelineId,
|
|
5690
6150
|
status: input.status,
|
|
5691
6151
|
input: input.input,
|
|
5692
|
-
...
|
|
5693
|
-
...
|
|
5694
|
-
...
|
|
6152
|
+
...compact({ output: input.output }),
|
|
6153
|
+
...compact({ error: input.error }),
|
|
6154
|
+
...compact({ metadata: input.metadata }),
|
|
5695
6155
|
startedAt: input.startedAt,
|
|
5696
|
-
...
|
|
5697
|
-
...
|
|
6156
|
+
...compact({ endedAt: input.endedAt }),
|
|
6157
|
+
...compact({ durationMs: input.durationMs })
|
|
5698
6158
|
};
|
|
5699
6159
|
}
|
|
5700
6160
|
getPipelineRun(options) {
|
|
@@ -6125,11 +6585,11 @@ function toSessionSummary(row) {
|
|
|
6125
6585
|
return {
|
|
6126
6586
|
id: row.id,
|
|
6127
6587
|
agentId: row.agent_id,
|
|
6128
|
-
...
|
|
6588
|
+
...compact({ title: row.title ?? void 0 }),
|
|
6129
6589
|
createdAt: row.created_at,
|
|
6130
6590
|
updatedAt: row.updated_at,
|
|
6131
6591
|
messageCount: row.message_count,
|
|
6132
|
-
...
|
|
6592
|
+
...compact({ metadata })
|
|
6133
6593
|
};
|
|
6134
6594
|
}
|
|
6135
6595
|
function toSessionLog(row) {
|
|
@@ -6137,14 +6597,14 @@ function toSessionLog(row) {
|
|
|
6137
6597
|
return {
|
|
6138
6598
|
id: row.id,
|
|
6139
6599
|
sessionId: row.session_id,
|
|
6140
|
-
...
|
|
6600
|
+
...compact({ runId: row.run_id ?? void 0 }),
|
|
6141
6601
|
sequence: row.sequence,
|
|
6142
6602
|
timestamp: row.timestamp,
|
|
6143
6603
|
level: row.level,
|
|
6144
6604
|
category: row.category,
|
|
6145
6605
|
event: row.event,
|
|
6146
6606
|
message: row.message,
|
|
6147
|
-
...
|
|
6607
|
+
...compact({ metadata })
|
|
6148
6608
|
};
|
|
6149
6609
|
}
|
|
6150
6610
|
function toPipelineLog(row) {
|
|
@@ -6152,14 +6612,14 @@ function toPipelineLog(row) {
|
|
|
6152
6612
|
return {
|
|
6153
6613
|
id: row.id,
|
|
6154
6614
|
pipelineId: row.pipeline_id,
|
|
6155
|
-
...
|
|
6615
|
+
...compact({ runId: row.run_id ?? void 0 }),
|
|
6156
6616
|
sequence: row.sequence,
|
|
6157
6617
|
timestamp: row.timestamp,
|
|
6158
6618
|
level: row.level,
|
|
6159
6619
|
category: row.category,
|
|
6160
6620
|
event: row.event,
|
|
6161
6621
|
message: row.message,
|
|
6162
|
-
...
|
|
6622
|
+
...compact({ metadata })
|
|
6163
6623
|
};
|
|
6164
6624
|
}
|
|
6165
6625
|
function toPipelineRun(row) {
|
|
@@ -6171,12 +6631,12 @@ function toPipelineRun(row) {
|
|
|
6171
6631
|
pipelineId: row.pipeline_id,
|
|
6172
6632
|
status: row.status,
|
|
6173
6633
|
input: JSON.parse(row.input_json),
|
|
6174
|
-
...
|
|
6175
|
-
...
|
|
6176
|
-
...
|
|
6634
|
+
...compact({ output }),
|
|
6635
|
+
...compact({ error }),
|
|
6636
|
+
...compact({ metadata }),
|
|
6177
6637
|
startedAt: row.started_at,
|
|
6178
|
-
...
|
|
6179
|
-
...
|
|
6638
|
+
...compact({ endedAt: row.ended_at ?? void 0 }),
|
|
6639
|
+
...compact({ durationMs: row.duration_ms ?? void 0 })
|
|
6180
6640
|
};
|
|
6181
6641
|
}
|
|
6182
6642
|
function messageParts(message) {
|
|
@@ -6202,7 +6662,7 @@ function messageFromRows(row, partRows) {
|
|
|
6202
6662
|
if (row.role === "assistant") {
|
|
6203
6663
|
return {
|
|
6204
6664
|
role: "assistant",
|
|
6205
|
-
...
|
|
6665
|
+
...compact({ id: row.message_id ?? void 0 }),
|
|
6206
6666
|
content: parts
|
|
6207
6667
|
};
|
|
6208
6668
|
}
|
|
@@ -6250,8 +6710,8 @@ function toTrace(row) {
|
|
|
6250
6710
|
const input = parseJsonValue(row.input_json);
|
|
6251
6711
|
return {
|
|
6252
6712
|
...toTraceSummary(row),
|
|
6253
|
-
...
|
|
6254
|
-
...
|
|
6713
|
+
...compact({ trace }),
|
|
6714
|
+
...compact({ input }),
|
|
6255
6715
|
observations: parseJsonArray(row.observations_json)
|
|
6256
6716
|
};
|
|
6257
6717
|
}
|
|
@@ -6263,15 +6723,15 @@ function toTraceSummary(row) {
|
|
|
6263
6723
|
return {
|
|
6264
6724
|
id: row.id,
|
|
6265
6725
|
sessionId: row.session_id,
|
|
6266
|
-
...
|
|
6726
|
+
...compact({ name: row.name ?? void 0 }),
|
|
6267
6727
|
status: row.status,
|
|
6268
6728
|
startedAt: row.started_at,
|
|
6269
|
-
...
|
|
6270
|
-
...
|
|
6271
|
-
...
|
|
6272
|
-
...
|
|
6273
|
-
...
|
|
6274
|
-
...
|
|
6729
|
+
...compact({ endedAt: row.ended_at ?? void 0 }),
|
|
6730
|
+
...compact({ durationMs: row.duration_ms ?? void 0 }),
|
|
6731
|
+
...compact({ output: row.output ?? void 0 }),
|
|
6732
|
+
...compact({ error }),
|
|
6733
|
+
...compact({ usage }),
|
|
6734
|
+
...compact({ metadata }),
|
|
6275
6735
|
observationCount: observations.length
|
|
6276
6736
|
};
|
|
6277
6737
|
}
|
|
@@ -6301,10 +6761,29 @@ function serializeJsonError2(error) {
|
|
|
6301
6761
|
}
|
|
6302
6762
|
return String(error);
|
|
6303
6763
|
}
|
|
6764
|
+
|
|
6765
|
+
// src/types.ts
|
|
6766
|
+
function traceSummary3(trace) {
|
|
6767
|
+
return compact({
|
|
6768
|
+
id: trace.id,
|
|
6769
|
+
sessionId: trace.sessionId,
|
|
6770
|
+
name: trace.name,
|
|
6771
|
+
status: trace.status,
|
|
6772
|
+
startedAt: trace.startedAt,
|
|
6773
|
+
endedAt: trace.endedAt,
|
|
6774
|
+
durationMs: trace.durationMs,
|
|
6775
|
+
output: trace.output,
|
|
6776
|
+
error: trace.error,
|
|
6777
|
+
usage: trace.usage,
|
|
6778
|
+
metadata: trace.metadata,
|
|
6779
|
+
observationCount: trace.observations.length
|
|
6780
|
+
});
|
|
6781
|
+
}
|
|
6304
6782
|
export {
|
|
6305
6783
|
Studio,
|
|
6306
6784
|
StudioTraceObserver,
|
|
6307
6785
|
createInMemoryStudioStore,
|
|
6308
|
-
createSqliteSessionStore
|
|
6786
|
+
createSqliteSessionStore,
|
|
6787
|
+
traceSummary3 as traceSummary
|
|
6309
6788
|
};
|
|
6310
6789
|
//# sourceMappingURL=index.js.map
|