@anvia/studio 0.2.11 → 0.4.0
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 +14 -7
- package/dist/index.d.ts +140 -5
- package/dist/index.js +1126 -247
- package/dist/index.js.map +1 -1
- package/dist/ui/assets/index-B0bCx2Nv.js +100 -0
- package/dist/ui/assets/index-B0bCx2Nv.js.map +1 -0
- package/dist/ui/assets/index-BiMI9T3_.css +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/index-DfSrZD9A.js +0 -100
- package/dist/ui/assets/index-DfSrZD9A.js.map +0 -1
- package/dist/ui/assets/index-Dx2LlqO-.css +0 -1
package/dist/index.js
CHANGED
|
@@ -586,6 +586,11 @@ function registerStudioUi(app, options) {
|
|
|
586
586
|
app.get(`${options.path}/tracing/*`, async (c) => c.html(await renderShell()));
|
|
587
587
|
app.get(`${options.path}/sessions`, async (c) => c.html(await renderShell()));
|
|
588
588
|
app.get(`${options.path}/agents`, async (c) => c.html(await renderShell()));
|
|
589
|
+
app.get(`${options.path}/tools`, async (c) => c.html(await renderShell()));
|
|
590
|
+
app.get(`${options.path}/mcps`, async (c) => c.html(await renderShell()));
|
|
591
|
+
app.get(`${options.path}/pipelines`, async (c) => c.html(await renderShell()));
|
|
592
|
+
app.get(`${options.path}/memory`, async (c) => c.html(await renderShell()));
|
|
593
|
+
app.get(`${options.path}/status`, async (c) => c.html(await renderShell()));
|
|
589
594
|
app.get(`${options.path}/knowledge`, async (c) => c.html(await renderShell()));
|
|
590
595
|
app.get(`${options.path}/knowledge/:tab`, async (c) => c.html(await renderShell()));
|
|
591
596
|
app.get(`${options.path}/knowledge/*`, async (c) => c.html(await renderShell()));
|
|
@@ -787,8 +792,277 @@ function escapeHtml(value) {
|
|
|
787
792
|
// src/runtime/approvals.ts
|
|
788
793
|
import { createHook, parseToolArgs } from "@anvia/core";
|
|
789
794
|
|
|
790
|
-
// src/
|
|
791
|
-
|
|
795
|
+
// src/storage/memory-store.ts
|
|
796
|
+
function createInMemoryStudioStore() {
|
|
797
|
+
return new InMemoryStudioStore();
|
|
798
|
+
}
|
|
799
|
+
var InMemoryStudioStore = class {
|
|
800
|
+
kind = "memory";
|
|
801
|
+
sessions = /* @__PURE__ */ new Map();
|
|
802
|
+
traces = /* @__PURE__ */ new Map();
|
|
803
|
+
pipelineLogs = /* @__PURE__ */ new Map();
|
|
804
|
+
pipelineRuns = /* @__PURE__ */ new Map();
|
|
805
|
+
listSessions(options) {
|
|
806
|
+
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);
|
|
807
|
+
}
|
|
808
|
+
createSession(input) {
|
|
809
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
810
|
+
const session = {
|
|
811
|
+
id: input.id,
|
|
812
|
+
agentId: input.agentId,
|
|
813
|
+
...input.title === void 0 ? {} : { title: input.title },
|
|
814
|
+
createdAt: now,
|
|
815
|
+
updatedAt: now,
|
|
816
|
+
messageCount: 0,
|
|
817
|
+
...input.metadata === void 0 ? {} : { metadata: input.metadata },
|
|
818
|
+
messages: [],
|
|
819
|
+
runs: [],
|
|
820
|
+
logs: []
|
|
821
|
+
};
|
|
822
|
+
this.sessions.set(input.id, session);
|
|
823
|
+
return sessionSummary(session);
|
|
824
|
+
}
|
|
825
|
+
getSession(id) {
|
|
826
|
+
const session = this.sessions.get(id);
|
|
827
|
+
return session === void 0 ? void 0 : materializeSession(session);
|
|
828
|
+
}
|
|
829
|
+
load(context) {
|
|
830
|
+
return Promise.resolve(this.sessions.get(context.sessionId)?.messages ?? []);
|
|
831
|
+
}
|
|
832
|
+
append(input) {
|
|
833
|
+
const session = this.sessions.get(input.context.sessionId);
|
|
834
|
+
if (session !== void 0) {
|
|
835
|
+
session.messages.push(...input.messages);
|
|
836
|
+
session.messageCount = session.messages.length;
|
|
837
|
+
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
838
|
+
}
|
|
839
|
+
return Promise.resolve();
|
|
840
|
+
}
|
|
841
|
+
clear(context) {
|
|
842
|
+
const session = this.sessions.get(context.sessionId);
|
|
843
|
+
if (session !== void 0) {
|
|
844
|
+
session.messages = [];
|
|
845
|
+
session.runs = [];
|
|
846
|
+
session.messageCount = 0;
|
|
847
|
+
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
848
|
+
}
|
|
849
|
+
return Promise.resolve();
|
|
850
|
+
}
|
|
851
|
+
async recordError(input) {
|
|
852
|
+
await this.saveSessionRunTranscript({
|
|
853
|
+
id: input.context.sessionId,
|
|
854
|
+
runId: studioRunId(input.context) ?? input.runId,
|
|
855
|
+
transcript: transcriptFromMessagesFallback(input.messages),
|
|
856
|
+
status: "error",
|
|
857
|
+
error: serializeJsonError(input.error)
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
saveSessionRunTranscript(input) {
|
|
861
|
+
const session = this.sessions.get(input.id);
|
|
862
|
+
if (session === void 0) {
|
|
863
|
+
return void 0;
|
|
864
|
+
}
|
|
865
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
866
|
+
const existingIndex = session.runs.findIndex((run2) => run2.runId === input.runId);
|
|
867
|
+
const run = {
|
|
868
|
+
...input,
|
|
869
|
+
transcript: renumberTranscript(input.transcript),
|
|
870
|
+
createdAt: existingIndex === -1 ? now : session.runs[existingIndex]?.createdAt ?? now,
|
|
871
|
+
updatedAt: now
|
|
872
|
+
};
|
|
873
|
+
if (existingIndex === -1) {
|
|
874
|
+
session.runs.push(run);
|
|
875
|
+
} else {
|
|
876
|
+
session.runs[existingIndex] = run;
|
|
877
|
+
}
|
|
878
|
+
session.updatedAt = now;
|
|
879
|
+
return materializeSession(session);
|
|
880
|
+
}
|
|
881
|
+
appendSessionLog(input) {
|
|
882
|
+
const session = this.sessions.get(input.sessionId);
|
|
883
|
+
const logs = session?.logs ?? [];
|
|
884
|
+
const entry = {
|
|
885
|
+
id: globalThis.crypto.randomUUID(),
|
|
886
|
+
sessionId: input.sessionId,
|
|
887
|
+
...input.runId === void 0 ? {} : { runId: input.runId },
|
|
888
|
+
sequence: logs.length,
|
|
889
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
890
|
+
level: input.level,
|
|
891
|
+
category: input.category,
|
|
892
|
+
event: input.event,
|
|
893
|
+
message: input.message,
|
|
894
|
+
...input.metadata === void 0 ? {} : { metadata: input.metadata }
|
|
895
|
+
};
|
|
896
|
+
if (session !== void 0) {
|
|
897
|
+
session.logs.push(entry);
|
|
898
|
+
session.updatedAt = entry.timestamp;
|
|
899
|
+
}
|
|
900
|
+
return entry;
|
|
901
|
+
}
|
|
902
|
+
listSessionLogs(options) {
|
|
903
|
+
return (this.sessions.get(options.sessionId)?.logs ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
|
|
904
|
+
}
|
|
905
|
+
deleteSession(id) {
|
|
906
|
+
for (const trace of this.traces.values()) {
|
|
907
|
+
if (trace.sessionId === id) {
|
|
908
|
+
this.traces.delete(trace.id);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return this.sessions.delete(id);
|
|
912
|
+
}
|
|
913
|
+
listTraces(options) {
|
|
914
|
+
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);
|
|
915
|
+
}
|
|
916
|
+
listSessionTraces(options) {
|
|
917
|
+
return this.listTraces({ sessionId: options.sessionId, limit: options.limit });
|
|
918
|
+
}
|
|
919
|
+
getTrace(id) {
|
|
920
|
+
return this.traces.get(id);
|
|
921
|
+
}
|
|
922
|
+
saveTrace(trace) {
|
|
923
|
+
this.traces.set(trace.id, trace);
|
|
924
|
+
return trace;
|
|
925
|
+
}
|
|
926
|
+
appendPipelineLog(input) {
|
|
927
|
+
const logs = this.pipelineLogs.get(input.pipelineId) ?? [];
|
|
928
|
+
const entry = {
|
|
929
|
+
id: globalThis.crypto.randomUUID(),
|
|
930
|
+
pipelineId: input.pipelineId,
|
|
931
|
+
...input.runId === void 0 ? {} : { runId: input.runId },
|
|
932
|
+
sequence: logs.length,
|
|
933
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
934
|
+
level: input.level,
|
|
935
|
+
category: input.category,
|
|
936
|
+
event: input.event,
|
|
937
|
+
message: input.message,
|
|
938
|
+
...input.metadata === void 0 ? {} : { metadata: input.metadata }
|
|
939
|
+
};
|
|
940
|
+
this.pipelineLogs.set(input.pipelineId, [...logs, entry]);
|
|
941
|
+
return entry;
|
|
942
|
+
}
|
|
943
|
+
listPipelineLogs(options) {
|
|
944
|
+
return (this.pipelineLogs.get(options.pipelineId) ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
|
|
945
|
+
}
|
|
946
|
+
savePipelineRun(input) {
|
|
947
|
+
const record = {
|
|
948
|
+
runId: input.runId,
|
|
949
|
+
pipelineId: input.pipelineId,
|
|
950
|
+
status: input.status,
|
|
951
|
+
input: input.input,
|
|
952
|
+
...input.output === void 0 ? {} : { output: input.output },
|
|
953
|
+
...input.error === void 0 ? {} : { error: input.error },
|
|
954
|
+
...input.metadata === void 0 ? {} : { metadata: input.metadata },
|
|
955
|
+
startedAt: input.startedAt,
|
|
956
|
+
...input.endedAt === void 0 ? {} : { endedAt: input.endedAt },
|
|
957
|
+
...input.durationMs === void 0 ? {} : { durationMs: input.durationMs }
|
|
958
|
+
};
|
|
959
|
+
this.pipelineRuns.set(input.runId, record);
|
|
960
|
+
return record;
|
|
961
|
+
}
|
|
962
|
+
listPipelineRuns(options) {
|
|
963
|
+
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);
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
function sessionSummary(session) {
|
|
967
|
+
return {
|
|
968
|
+
id: session.id,
|
|
969
|
+
agentId: session.agentId,
|
|
970
|
+
...session.title === void 0 ? {} : { title: session.title },
|
|
971
|
+
createdAt: session.createdAt,
|
|
972
|
+
updatedAt: session.updatedAt,
|
|
973
|
+
messageCount: session.messages.length,
|
|
974
|
+
...session.metadata === void 0 ? {} : { metadata: session.metadata }
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
function materializeSession(session) {
|
|
978
|
+
return {
|
|
979
|
+
...sessionSummary(session),
|
|
980
|
+
messages: [...session.messages],
|
|
981
|
+
transcript: renumberTranscript(session.runs.flatMap((run) => run.transcript))
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
function traceSummary(trace) {
|
|
985
|
+
return {
|
|
986
|
+
id: trace.id,
|
|
987
|
+
sessionId: trace.sessionId,
|
|
988
|
+
...trace.name === void 0 ? {} : { name: trace.name },
|
|
989
|
+
status: trace.status,
|
|
990
|
+
startedAt: trace.startedAt,
|
|
991
|
+
...trace.endedAt === void 0 ? {} : { endedAt: trace.endedAt },
|
|
992
|
+
...trace.durationMs === void 0 ? {} : { durationMs: trace.durationMs },
|
|
993
|
+
...trace.output === void 0 ? {} : { output: trace.output },
|
|
994
|
+
...trace.error === void 0 ? {} : { error: trace.error },
|
|
995
|
+
...trace.usage === void 0 ? {} : { usage: trace.usage },
|
|
996
|
+
...trace.metadata === void 0 ? {} : { metadata: trace.metadata },
|
|
997
|
+
observationCount: trace.observations.length
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
function traceAgentId(trace) {
|
|
1001
|
+
const nestedMetadata = trace.metadata?.metadata;
|
|
1002
|
+
return isJsonObject(nestedMetadata) && typeof nestedMetadata.agentId === "string" ? nestedMetadata.agentId : void 0;
|
|
1003
|
+
}
|
|
1004
|
+
function renumberTranscript(entries) {
|
|
1005
|
+
return entries.map((entry, entryId) => ({ ...entry, entryId }));
|
|
1006
|
+
}
|
|
1007
|
+
function studioRunId(context) {
|
|
1008
|
+
const value = context.metadata?.studioRunId;
|
|
1009
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1010
|
+
}
|
|
1011
|
+
function serializeJsonError(error) {
|
|
1012
|
+
if (error instanceof Error) {
|
|
1013
|
+
return {
|
|
1014
|
+
name: error.name,
|
|
1015
|
+
message: error.message
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
return isJsonValue(error) ? error : String(error);
|
|
1019
|
+
}
|
|
1020
|
+
function transcriptFromMessagesFallback(messages) {
|
|
1021
|
+
const transcript = [];
|
|
1022
|
+
for (const message of messages) {
|
|
1023
|
+
if (message.role === "system") {
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
if (message.role === "user") {
|
|
1027
|
+
for (const content of message.content) {
|
|
1028
|
+
if (content.type === "text") {
|
|
1029
|
+
transcript.push({
|
|
1030
|
+
entryId: transcript.length,
|
|
1031
|
+
kind: "message",
|
|
1032
|
+
role: "user",
|
|
1033
|
+
text: content.text
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
continue;
|
|
1038
|
+
}
|
|
1039
|
+
if (message.role === "assistant") {
|
|
1040
|
+
for (const content of message.content) {
|
|
1041
|
+
if (content.type === "text") {
|
|
1042
|
+
transcript.push({
|
|
1043
|
+
entryId: transcript.length,
|
|
1044
|
+
kind: "message",
|
|
1045
|
+
role: "assistant",
|
|
1046
|
+
text: content.text
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
return transcript;
|
|
1053
|
+
}
|
|
1054
|
+
function isJsonObject(value) {
|
|
1055
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1056
|
+
}
|
|
1057
|
+
function isJsonValue(value) {
|
|
1058
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1059
|
+
return true;
|
|
1060
|
+
}
|
|
1061
|
+
if (Array.isArray(value)) {
|
|
1062
|
+
return value.every(isJsonValue);
|
|
1063
|
+
}
|
|
1064
|
+
return isJsonObject(value) && Object.values(value).every(isJsonValue);
|
|
1065
|
+
}
|
|
792
1066
|
|
|
793
1067
|
// src/storage/sqlite-store.ts
|
|
794
1068
|
import { mkdirSync } from "fs";
|
|
@@ -811,8 +1085,8 @@ var SqliteSessionStore = class {
|
|
|
811
1085
|
const rows = db.prepare(
|
|
812
1086
|
`SELECT s.id, s.agent_id, s.title, s.metadata_json, s.created_at, s.updated_at,
|
|
813
1087
|
COUNT(m.message_index) AS message_count
|
|
814
|
-
FROM
|
|
815
|
-
LEFT JOIN
|
|
1088
|
+
FROM anvia_studio_sessions s
|
|
1089
|
+
LEFT JOIN anvia_studio_session_messages m ON m.session_id = s.id
|
|
816
1090
|
${agentClause}
|
|
817
1091
|
GROUP BY s.id, s.agent_id, s.title, s.metadata_json, s.created_at, s.updated_at
|
|
818
1092
|
ORDER BY s.updated_at DESC
|
|
@@ -827,7 +1101,7 @@ var SqliteSessionStore = class {
|
|
|
827
1101
|
const db = this.database();
|
|
828
1102
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
829
1103
|
db.prepare(
|
|
830
|
-
`INSERT INTO
|
|
1104
|
+
`INSERT INTO anvia_studio_sessions (
|
|
831
1105
|
id,
|
|
832
1106
|
agent_id,
|
|
833
1107
|
title,
|
|
@@ -866,7 +1140,7 @@ var SqliteSessionStore = class {
|
|
|
866
1140
|
db.exec("BEGIN IMMEDIATE");
|
|
867
1141
|
const row = db.prepare(
|
|
868
1142
|
`SELECT id, agent_id, title, metadata_json, created_at, updated_at
|
|
869
|
-
FROM
|
|
1143
|
+
FROM anvia_studio_sessions
|
|
870
1144
|
WHERE id = $id`
|
|
871
1145
|
).get({ $id: input.context.sessionId });
|
|
872
1146
|
if (row === void 0) {
|
|
@@ -877,7 +1151,7 @@ var SqliteSessionStore = class {
|
|
|
877
1151
|
const nextIndex = this.nextMessageIndex(input.context.sessionId);
|
|
878
1152
|
this.insertMessages(input.context.sessionId, input.messages, nextIndex, updatedAt);
|
|
879
1153
|
db.prepare(
|
|
880
|
-
`UPDATE
|
|
1154
|
+
`UPDATE anvia_studio_sessions
|
|
881
1155
|
SET updated_at = $updatedAt
|
|
882
1156
|
WHERE id = $id`
|
|
883
1157
|
).run({
|
|
@@ -899,17 +1173,17 @@ var SqliteSessionStore = class {
|
|
|
899
1173
|
try {
|
|
900
1174
|
db.exec("BEGIN IMMEDIATE");
|
|
901
1175
|
db.prepare(
|
|
902
|
-
`UPDATE
|
|
1176
|
+
`UPDATE anvia_studio_sessions
|
|
903
1177
|
SET updated_at = $updatedAt
|
|
904
1178
|
WHERE id = $id`
|
|
905
1179
|
).run({
|
|
906
1180
|
$id: context.sessionId,
|
|
907
1181
|
$updatedAt: updatedAt
|
|
908
1182
|
});
|
|
909
|
-
db.prepare("DELETE FROM
|
|
1183
|
+
db.prepare("DELETE FROM anvia_studio_session_messages WHERE session_id = $id").run({
|
|
910
1184
|
$id: context.sessionId
|
|
911
1185
|
});
|
|
912
|
-
db.prepare("DELETE FROM
|
|
1186
|
+
db.prepare("DELETE FROM anvia_studio_session_runs WHERE session_id = $id").run({
|
|
913
1187
|
$id: context.sessionId
|
|
914
1188
|
});
|
|
915
1189
|
db.exec("COMMIT");
|
|
@@ -922,15 +1196,15 @@ var SqliteSessionStore = class {
|
|
|
922
1196
|
}
|
|
923
1197
|
}
|
|
924
1198
|
async recordError(input) {
|
|
925
|
-
const runId =
|
|
1199
|
+
const runId = studioRunId2(input.context) ?? input.runId;
|
|
926
1200
|
const existing = this.getSessionRun(input.context.sessionId, runId);
|
|
927
|
-
const transcript = existing === void 0 || parseJsonArray(existing.transcript_json).length === 0 ?
|
|
1201
|
+
const transcript = existing === void 0 || parseJsonArray(existing.transcript_json).length === 0 ? transcriptFromMessagesFallback2(input.messages) : parseJsonArray(existing.transcript_json);
|
|
928
1202
|
await this.saveSessionRunTranscript({
|
|
929
1203
|
id: input.context.sessionId,
|
|
930
1204
|
runId,
|
|
931
1205
|
transcript,
|
|
932
1206
|
status: "error",
|
|
933
|
-
error:
|
|
1207
|
+
error: serializeJsonError2(input.error)
|
|
934
1208
|
});
|
|
935
1209
|
}
|
|
936
1210
|
saveSessionRunTranscript(input) {
|
|
@@ -950,7 +1224,7 @@ var SqliteSessionStore = class {
|
|
|
950
1224
|
);
|
|
951
1225
|
const title = current.title ?? input.title;
|
|
952
1226
|
db.prepare(
|
|
953
|
-
`INSERT INTO
|
|
1227
|
+
`INSERT INTO anvia_studio_session_runs (
|
|
954
1228
|
run_id,
|
|
955
1229
|
session_id,
|
|
956
1230
|
status,
|
|
@@ -971,7 +1245,7 @@ var SqliteSessionStore = class {
|
|
|
971
1245
|
)
|
|
972
1246
|
ON CONFLICT(run_id) DO UPDATE SET
|
|
973
1247
|
status = excluded.status,
|
|
974
|
-
title = COALESCE(
|
|
1248
|
+
title = COALESCE(anvia_studio_session_runs.title, excluded.title),
|
|
975
1249
|
transcript_json = excluded.transcript_json,
|
|
976
1250
|
error_json = excluded.error_json,
|
|
977
1251
|
updated_at = excluded.updated_at`
|
|
@@ -980,12 +1254,12 @@ var SqliteSessionStore = class {
|
|
|
980
1254
|
$sessionId: input.id,
|
|
981
1255
|
$status: input.status,
|
|
982
1256
|
$title: input.title ?? null,
|
|
983
|
-
$transcript: JSON.stringify(
|
|
1257
|
+
$transcript: JSON.stringify(renumberTranscript2(input.transcript)),
|
|
984
1258
|
$error: input.error === void 0 ? null : JSON.stringify(input.error),
|
|
985
1259
|
$now: now
|
|
986
1260
|
});
|
|
987
1261
|
db.prepare(
|
|
988
|
-
`UPDATE
|
|
1262
|
+
`UPDATE anvia_studio_sessions
|
|
989
1263
|
SET title = $title,
|
|
990
1264
|
updated_at = $updatedAt
|
|
991
1265
|
WHERE id = $id`
|
|
@@ -1027,7 +1301,7 @@ var SqliteSessionStore = class {
|
|
|
1027
1301
|
...input.metadata === void 0 ? {} : { metadata: input.metadata }
|
|
1028
1302
|
};
|
|
1029
1303
|
db.prepare(
|
|
1030
|
-
`INSERT INTO
|
|
1304
|
+
`INSERT INTO anvia_studio_session_logs (
|
|
1031
1305
|
id,
|
|
1032
1306
|
session_id,
|
|
1033
1307
|
run_id,
|
|
@@ -1077,7 +1351,7 @@ var SqliteSessionStore = class {
|
|
|
1077
1351
|
const rows = db.prepare(
|
|
1078
1352
|
`SELECT id, session_id, run_id, sequence, timestamp, level, category, event, message,
|
|
1079
1353
|
metadata_json
|
|
1080
|
-
FROM
|
|
1354
|
+
FROM anvia_studio_session_logs
|
|
1081
1355
|
WHERE session_id = $sessionId
|
|
1082
1356
|
${afterClause}
|
|
1083
1357
|
ORDER BY sequence ASC
|
|
@@ -1108,7 +1382,7 @@ var SqliteSessionStore = class {
|
|
|
1108
1382
|
...input.metadata === void 0 ? {} : { metadata: input.metadata }
|
|
1109
1383
|
};
|
|
1110
1384
|
db.prepare(
|
|
1111
|
-
`INSERT INTO
|
|
1385
|
+
`INSERT INTO anvia_studio_pipeline_logs (
|
|
1112
1386
|
id,
|
|
1113
1387
|
pipeline_id,
|
|
1114
1388
|
run_id,
|
|
@@ -1158,7 +1432,7 @@ var SqliteSessionStore = class {
|
|
|
1158
1432
|
const rows = db.prepare(
|
|
1159
1433
|
`SELECT id, pipeline_id, run_id, sequence, timestamp, level, category, event, message,
|
|
1160
1434
|
metadata_json
|
|
1161
|
-
FROM
|
|
1435
|
+
FROM anvia_studio_pipeline_logs
|
|
1162
1436
|
WHERE pipeline_id = $pipelineId
|
|
1163
1437
|
${afterClause}
|
|
1164
1438
|
ORDER BY sequence ASC
|
|
@@ -1173,7 +1447,7 @@ var SqliteSessionStore = class {
|
|
|
1173
1447
|
savePipelineRun(input) {
|
|
1174
1448
|
const db = this.database();
|
|
1175
1449
|
db.prepare(
|
|
1176
|
-
`INSERT INTO
|
|
1450
|
+
`INSERT INTO anvia_studio_pipeline_runs (
|
|
1177
1451
|
run_id,
|
|
1178
1452
|
pipeline_id,
|
|
1179
1453
|
status,
|
|
@@ -1236,7 +1510,7 @@ var SqliteSessionStore = class {
|
|
|
1236
1510
|
const rows = db.prepare(
|
|
1237
1511
|
`SELECT run_id, pipeline_id, status, input_json, output_json, error_json,
|
|
1238
1512
|
metadata_json, started_at, ended_at, duration_ms
|
|
1239
|
-
FROM
|
|
1513
|
+
FROM anvia_studio_pipeline_runs
|
|
1240
1514
|
WHERE pipeline_id = $pipelineId
|
|
1241
1515
|
ORDER BY started_at DESC
|
|
1242
1516
|
LIMIT $limit`
|
|
@@ -1250,10 +1524,10 @@ var SqliteSessionStore = class {
|
|
|
1250
1524
|
const db = this.database();
|
|
1251
1525
|
try {
|
|
1252
1526
|
db.exec("BEGIN IMMEDIATE");
|
|
1253
|
-
db.prepare("DELETE FROM
|
|
1254
|
-
db.prepare("DELETE FROM
|
|
1255
|
-
db.prepare("DELETE FROM
|
|
1256
|
-
const result = db.prepare("DELETE FROM
|
|
1527
|
+
db.prepare("DELETE FROM anvia_studio_traces WHERE session_id = $id").run({ $id: id });
|
|
1528
|
+
db.prepare("DELETE FROM anvia_studio_session_runs WHERE session_id = $id").run({ $id: id });
|
|
1529
|
+
db.prepare("DELETE FROM anvia_studio_session_logs WHERE session_id = $id").run({ $id: id });
|
|
1530
|
+
const result = db.prepare("DELETE FROM anvia_studio_sessions WHERE id = $id").run({ $id: id });
|
|
1257
1531
|
db.exec("COMMIT");
|
|
1258
1532
|
return Number(result.changes) > 0;
|
|
1259
1533
|
} catch (error) {
|
|
@@ -1288,8 +1562,8 @@ var SqliteSessionStore = class {
|
|
|
1288
1562
|
`SELECT t.id, t.session_id, t.name, t.status, t.trace_json, t.input_json, t.output,
|
|
1289
1563
|
t.error_json, t.usage_json, t.metadata_json, t.observations_json,
|
|
1290
1564
|
t.started_at, t.ended_at, t.duration_ms
|
|
1291
|
-
FROM
|
|
1292
|
-
LEFT JOIN
|
|
1565
|
+
FROM anvia_studio_traces t
|
|
1566
|
+
LEFT JOIN anvia_studio_sessions s ON s.id = t.session_id
|
|
1293
1567
|
${whereClause}
|
|
1294
1568
|
ORDER BY t.started_at DESC
|
|
1295
1569
|
LIMIT $limit`
|
|
@@ -1301,7 +1575,7 @@ var SqliteSessionStore = class {
|
|
|
1301
1575
|
const rows = db.prepare(
|
|
1302
1576
|
`SELECT id, session_id, name, status, trace_json, input_json, output, error_json,
|
|
1303
1577
|
usage_json, metadata_json, observations_json, started_at, ended_at, duration_ms
|
|
1304
|
-
FROM
|
|
1578
|
+
FROM anvia_studio_traces
|
|
1305
1579
|
WHERE session_id = $sessionId
|
|
1306
1580
|
ORDER BY started_at DESC
|
|
1307
1581
|
LIMIT $limit`
|
|
@@ -1316,7 +1590,7 @@ var SqliteSessionStore = class {
|
|
|
1316
1590
|
const row = db.prepare(
|
|
1317
1591
|
`SELECT id, session_id, name, status, trace_json, input_json, output, error_json,
|
|
1318
1592
|
usage_json, metadata_json, observations_json, started_at, ended_at, duration_ms
|
|
1319
|
-
FROM
|
|
1593
|
+
FROM anvia_studio_traces
|
|
1320
1594
|
WHERE id = $id`
|
|
1321
1595
|
).get({ $id: id });
|
|
1322
1596
|
return row === void 0 ? void 0 : toTrace(row);
|
|
@@ -1324,7 +1598,7 @@ var SqliteSessionStore = class {
|
|
|
1324
1598
|
saveTrace(trace) {
|
|
1325
1599
|
const db = this.database();
|
|
1326
1600
|
db.prepare(
|
|
1327
|
-
`INSERT INTO
|
|
1601
|
+
`INSERT INTO anvia_studio_traces (
|
|
1328
1602
|
id,
|
|
1329
1603
|
session_id,
|
|
1330
1604
|
name,
|
|
@@ -1404,7 +1678,7 @@ var SqliteSessionStore = class {
|
|
|
1404
1678
|
`);
|
|
1405
1679
|
guardAgainstLegacySessionSchema(db);
|
|
1406
1680
|
db.exec(`
|
|
1407
|
-
CREATE TABLE IF NOT EXISTS
|
|
1681
|
+
CREATE TABLE IF NOT EXISTS anvia_studio_sessions (
|
|
1408
1682
|
id TEXT PRIMARY KEY,
|
|
1409
1683
|
agent_id TEXT NOT NULL,
|
|
1410
1684
|
title TEXT,
|
|
@@ -1412,20 +1686,20 @@ var SqliteSessionStore = class {
|
|
|
1412
1686
|
created_at TEXT NOT NULL,
|
|
1413
1687
|
updated_at TEXT NOT NULL
|
|
1414
1688
|
) STRICT;
|
|
1415
|
-
CREATE INDEX IF NOT EXISTS
|
|
1416
|
-
ON
|
|
1417
|
-
CREATE TABLE IF NOT EXISTS
|
|
1689
|
+
CREATE INDEX IF NOT EXISTS anvia_studio_sessions_agent_updated_idx
|
|
1690
|
+
ON anvia_studio_sessions(agent_id, updated_at DESC);
|
|
1691
|
+
CREATE TABLE IF NOT EXISTS anvia_studio_session_messages (
|
|
1418
1692
|
session_id TEXT NOT NULL,
|
|
1419
1693
|
message_index INTEGER NOT NULL,
|
|
1420
1694
|
role TEXT NOT NULL,
|
|
1421
1695
|
message_id TEXT,
|
|
1422
1696
|
created_at TEXT NOT NULL,
|
|
1423
1697
|
PRIMARY KEY(session_id, message_index),
|
|
1424
|
-
FOREIGN KEY(session_id) REFERENCES
|
|
1698
|
+
FOREIGN KEY(session_id) REFERENCES anvia_studio_sessions(id) ON DELETE CASCADE
|
|
1425
1699
|
) STRICT;
|
|
1426
|
-
CREATE INDEX IF NOT EXISTS
|
|
1427
|
-
ON
|
|
1428
|
-
CREATE TABLE IF NOT EXISTS
|
|
1700
|
+
CREATE INDEX IF NOT EXISTS anvia_studio_session_messages_session_idx
|
|
1701
|
+
ON anvia_studio_session_messages(session_id, message_index ASC);
|
|
1702
|
+
CREATE TABLE IF NOT EXISTS anvia_studio_session_message_parts (
|
|
1429
1703
|
session_id TEXT NOT NULL,
|
|
1430
1704
|
message_index INTEGER NOT NULL,
|
|
1431
1705
|
part_index INTEGER NOT NULL,
|
|
@@ -1433,10 +1707,10 @@ var SqliteSessionStore = class {
|
|
|
1433
1707
|
part_json TEXT NOT NULL,
|
|
1434
1708
|
PRIMARY KEY(session_id, message_index, part_index),
|
|
1435
1709
|
FOREIGN KEY(session_id, message_index)
|
|
1436
|
-
REFERENCES
|
|
1710
|
+
REFERENCES anvia_studio_session_messages(session_id, message_index)
|
|
1437
1711
|
ON DELETE CASCADE
|
|
1438
1712
|
) STRICT;
|
|
1439
|
-
CREATE TABLE IF NOT EXISTS
|
|
1713
|
+
CREATE TABLE IF NOT EXISTS anvia_studio_session_runs (
|
|
1440
1714
|
run_id TEXT PRIMARY KEY,
|
|
1441
1715
|
session_id TEXT NOT NULL,
|
|
1442
1716
|
status TEXT NOT NULL,
|
|
@@ -1445,11 +1719,11 @@ var SqliteSessionStore = class {
|
|
|
1445
1719
|
error_json TEXT,
|
|
1446
1720
|
created_at TEXT NOT NULL,
|
|
1447
1721
|
updated_at TEXT NOT NULL,
|
|
1448
|
-
FOREIGN KEY(session_id) REFERENCES
|
|
1722
|
+
FOREIGN KEY(session_id) REFERENCES anvia_studio_sessions(id) ON DELETE CASCADE
|
|
1449
1723
|
) STRICT;
|
|
1450
|
-
CREATE INDEX IF NOT EXISTS
|
|
1451
|
-
ON
|
|
1452
|
-
CREATE TABLE IF NOT EXISTS
|
|
1724
|
+
CREATE INDEX IF NOT EXISTS anvia_studio_session_runs_session_created_idx
|
|
1725
|
+
ON anvia_studio_session_runs(session_id, created_at ASC);
|
|
1726
|
+
CREATE TABLE IF NOT EXISTS anvia_studio_session_logs (
|
|
1453
1727
|
id TEXT PRIMARY KEY,
|
|
1454
1728
|
session_id TEXT NOT NULL,
|
|
1455
1729
|
run_id TEXT,
|
|
@@ -1461,11 +1735,11 @@ var SqliteSessionStore = class {
|
|
|
1461
1735
|
message TEXT NOT NULL,
|
|
1462
1736
|
metadata_json TEXT,
|
|
1463
1737
|
UNIQUE(session_id, sequence),
|
|
1464
|
-
FOREIGN KEY(session_id) REFERENCES
|
|
1738
|
+
FOREIGN KEY(session_id) REFERENCES anvia_studio_sessions(id) ON DELETE CASCADE
|
|
1465
1739
|
) STRICT;
|
|
1466
|
-
CREATE INDEX IF NOT EXISTS
|
|
1467
|
-
ON
|
|
1468
|
-
CREATE TABLE IF NOT EXISTS
|
|
1740
|
+
CREATE INDEX IF NOT EXISTS anvia_studio_session_logs_session_sequence_idx
|
|
1741
|
+
ON anvia_studio_session_logs(session_id, sequence ASC);
|
|
1742
|
+
CREATE TABLE IF NOT EXISTS anvia_studio_pipeline_logs (
|
|
1469
1743
|
id TEXT PRIMARY KEY,
|
|
1470
1744
|
pipeline_id TEXT NOT NULL,
|
|
1471
1745
|
run_id TEXT,
|
|
@@ -1478,9 +1752,9 @@ var SqliteSessionStore = class {
|
|
|
1478
1752
|
metadata_json TEXT,
|
|
1479
1753
|
UNIQUE(pipeline_id, sequence)
|
|
1480
1754
|
) STRICT;
|
|
1481
|
-
CREATE INDEX IF NOT EXISTS
|
|
1482
|
-
ON
|
|
1483
|
-
CREATE TABLE IF NOT EXISTS
|
|
1755
|
+
CREATE INDEX IF NOT EXISTS anvia_studio_pipeline_logs_pipeline_sequence_idx
|
|
1756
|
+
ON anvia_studio_pipeline_logs(pipeline_id, sequence ASC);
|
|
1757
|
+
CREATE TABLE IF NOT EXISTS anvia_studio_pipeline_runs (
|
|
1484
1758
|
run_id TEXT PRIMARY KEY,
|
|
1485
1759
|
pipeline_id TEXT NOT NULL,
|
|
1486
1760
|
status TEXT NOT NULL,
|
|
@@ -1492,9 +1766,9 @@ var SqliteSessionStore = class {
|
|
|
1492
1766
|
ended_at TEXT,
|
|
1493
1767
|
duration_ms INTEGER
|
|
1494
1768
|
) STRICT;
|
|
1495
|
-
CREATE INDEX IF NOT EXISTS
|
|
1496
|
-
ON
|
|
1497
|
-
CREATE TABLE IF NOT EXISTS
|
|
1769
|
+
CREATE INDEX IF NOT EXISTS anvia_studio_pipeline_runs_pipeline_started_idx
|
|
1770
|
+
ON anvia_studio_pipeline_runs(pipeline_id, started_at DESC);
|
|
1771
|
+
CREATE TABLE IF NOT EXISTS anvia_studio_traces (
|
|
1498
1772
|
id TEXT PRIMARY KEY,
|
|
1499
1773
|
session_id TEXT NOT NULL,
|
|
1500
1774
|
name TEXT,
|
|
@@ -1510,8 +1784,8 @@ var SqliteSessionStore = class {
|
|
|
1510
1784
|
ended_at TEXT,
|
|
1511
1785
|
duration_ms INTEGER
|
|
1512
1786
|
) STRICT;
|
|
1513
|
-
CREATE INDEX IF NOT EXISTS
|
|
1514
|
-
ON
|
|
1787
|
+
CREATE INDEX IF NOT EXISTS anvia_studio_traces_session_started_idx
|
|
1788
|
+
ON anvia_studio_traces(session_id, started_at DESC);
|
|
1515
1789
|
`);
|
|
1516
1790
|
this.db = db;
|
|
1517
1791
|
return db;
|
|
@@ -1519,21 +1793,21 @@ var SqliteSessionStore = class {
|
|
|
1519
1793
|
getSessionRow(id) {
|
|
1520
1794
|
return this.database().prepare(
|
|
1521
1795
|
`SELECT id, agent_id, title, metadata_json, created_at, updated_at
|
|
1522
|
-
FROM
|
|
1796
|
+
FROM anvia_studio_sessions
|
|
1523
1797
|
WHERE id = $id`
|
|
1524
1798
|
).get({ $id: id });
|
|
1525
1799
|
}
|
|
1526
1800
|
getSessionRun(sessionId, runId) {
|
|
1527
1801
|
return this.database().prepare(
|
|
1528
1802
|
`SELECT run_id, session_id, status, title, transcript_json, error_json, created_at, updated_at
|
|
1529
|
-
FROM
|
|
1803
|
+
FROM anvia_studio_session_runs
|
|
1530
1804
|
WHERE session_id = $sessionId AND run_id = $runId`
|
|
1531
1805
|
).get({ $sessionId: sessionId, $runId: runId });
|
|
1532
1806
|
}
|
|
1533
1807
|
listSessionRunRows(sessionId) {
|
|
1534
1808
|
return this.database().prepare(
|
|
1535
1809
|
`SELECT run_id, session_id, status, title, transcript_json, error_json, created_at, updated_at
|
|
1536
|
-
FROM
|
|
1810
|
+
FROM anvia_studio_session_runs
|
|
1537
1811
|
WHERE session_id = $sessionId
|
|
1538
1812
|
ORDER BY created_at ASC`
|
|
1539
1813
|
).all({ $sessionId: sessionId });
|
|
@@ -1541,7 +1815,7 @@ var SqliteSessionStore = class {
|
|
|
1541
1815
|
nextSessionLogSequence(sessionId) {
|
|
1542
1816
|
const row = this.database().prepare(
|
|
1543
1817
|
`SELECT COALESCE(MAX(sequence) + 1, 0) AS next_sequence
|
|
1544
|
-
FROM
|
|
1818
|
+
FROM anvia_studio_session_logs
|
|
1545
1819
|
WHERE session_id = $sessionId`
|
|
1546
1820
|
).get({ $sessionId: sessionId });
|
|
1547
1821
|
return row.next_sequence;
|
|
@@ -1549,7 +1823,7 @@ var SqliteSessionStore = class {
|
|
|
1549
1823
|
nextPipelineLogSequence(pipelineId) {
|
|
1550
1824
|
const row = this.database().prepare(
|
|
1551
1825
|
`SELECT COALESCE(MAX(sequence) + 1, 0) AS next_sequence
|
|
1552
|
-
FROM
|
|
1826
|
+
FROM anvia_studio_pipeline_logs
|
|
1553
1827
|
WHERE pipeline_id = $pipelineId`
|
|
1554
1828
|
).get({ $pipelineId: pipelineId });
|
|
1555
1829
|
return row.next_sequence;
|
|
@@ -1558,7 +1832,7 @@ var SqliteSessionStore = class {
|
|
|
1558
1832
|
const db = this.database();
|
|
1559
1833
|
const messageRows = db.prepare(
|
|
1560
1834
|
`SELECT session_id, message_index, role, message_id, created_at
|
|
1561
|
-
FROM
|
|
1835
|
+
FROM anvia_studio_session_messages
|
|
1562
1836
|
WHERE session_id = $sessionId
|
|
1563
1837
|
ORDER BY message_index ASC`
|
|
1564
1838
|
).all({ $sessionId: sessionId });
|
|
@@ -1567,7 +1841,7 @@ var SqliteSessionStore = class {
|
|
|
1567
1841
|
}
|
|
1568
1842
|
const partRows = db.prepare(
|
|
1569
1843
|
`SELECT session_id, message_index, part_index, type, part_json
|
|
1570
|
-
FROM
|
|
1844
|
+
FROM anvia_studio_session_message_parts
|
|
1571
1845
|
WHERE session_id = $sessionId
|
|
1572
1846
|
ORDER BY message_index ASC, part_index ASC`
|
|
1573
1847
|
).all({ $sessionId: sessionId });
|
|
@@ -1584,7 +1858,7 @@ var SqliteSessionStore = class {
|
|
|
1584
1858
|
nextMessageIndex(sessionId) {
|
|
1585
1859
|
const row = this.database().prepare(
|
|
1586
1860
|
`SELECT COALESCE(MAX(message_index) + 1, 0) AS next_index
|
|
1587
|
-
FROM
|
|
1861
|
+
FROM anvia_studio_session_messages
|
|
1588
1862
|
WHERE session_id = $sessionId`
|
|
1589
1863
|
).get({ $sessionId: sessionId });
|
|
1590
1864
|
return row.next_index;
|
|
@@ -1592,7 +1866,7 @@ var SqliteSessionStore = class {
|
|
|
1592
1866
|
insertMessages(sessionId, messages, startIndex, createdAt) {
|
|
1593
1867
|
const db = this.database();
|
|
1594
1868
|
const insertMessage = db.prepare(
|
|
1595
|
-
`INSERT INTO
|
|
1869
|
+
`INSERT INTO anvia_studio_session_messages (
|
|
1596
1870
|
session_id,
|
|
1597
1871
|
message_index,
|
|
1598
1872
|
role,
|
|
@@ -1601,7 +1875,7 @@ var SqliteSessionStore = class {
|
|
|
1601
1875
|
) VALUES ($sessionId, $messageIndex, $role, $messageId, $createdAt)`
|
|
1602
1876
|
);
|
|
1603
1877
|
const insertPart = db.prepare(
|
|
1604
|
-
`INSERT INTO
|
|
1878
|
+
`INSERT INTO anvia_studio_session_message_parts (
|
|
1605
1879
|
session_id,
|
|
1606
1880
|
message_index,
|
|
1607
1881
|
part_index,
|
|
@@ -1638,7 +1912,7 @@ function toSession(row, messages, runRows = []) {
|
|
|
1638
1912
|
return {
|
|
1639
1913
|
...summary,
|
|
1640
1914
|
messages,
|
|
1641
|
-
transcript:
|
|
1915
|
+
transcript: renumberTranscript2(runTranscript)
|
|
1642
1916
|
};
|
|
1643
1917
|
}
|
|
1644
1918
|
function toSessionSummary(row) {
|
|
@@ -1743,7 +2017,7 @@ function systemContentFromParts(parts) {
|
|
|
1743
2017
|
return "";
|
|
1744
2018
|
}
|
|
1745
2019
|
function guardAgainstLegacySessionSchema(db) {
|
|
1746
|
-
const columns = db.prepare("PRAGMA table_info('
|
|
2020
|
+
const columns = db.prepare("PRAGMA table_info('anvia_studio_sessions')").all();
|
|
1747
2021
|
if (columns.some((column) => column.name === "messages_json")) {
|
|
1748
2022
|
throw new Error(
|
|
1749
2023
|
"Existing Studio SQLite DB uses the legacy messages_json schema. Delete or recreate the Studio SQLite DB to use normalized session messages."
|
|
@@ -1806,14 +2080,14 @@ function parseJsonValue(value) {
|
|
|
1806
2080
|
}
|
|
1807
2081
|
return JSON.parse(value);
|
|
1808
2082
|
}
|
|
1809
|
-
function
|
|
2083
|
+
function renumberTranscript2(entries) {
|
|
1810
2084
|
return entries.map((entry, entryId) => ({ ...entry, entryId }));
|
|
1811
2085
|
}
|
|
1812
|
-
function
|
|
2086
|
+
function studioRunId2(context) {
|
|
1813
2087
|
const value = context.metadata?.studioRunId;
|
|
1814
2088
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1815
2089
|
}
|
|
1816
|
-
function
|
|
2090
|
+
function serializeJsonError2(error) {
|
|
1817
2091
|
if (error instanceof Error) {
|
|
1818
2092
|
return {
|
|
1819
2093
|
name: error.name,
|
|
@@ -1825,7 +2099,7 @@ function serializeJsonError(error) {
|
|
|
1825
2099
|
}
|
|
1826
2100
|
return String(error);
|
|
1827
2101
|
}
|
|
1828
|
-
function
|
|
2102
|
+
function transcriptFromMessagesFallback2(messages) {
|
|
1829
2103
|
const transcript = [];
|
|
1830
2104
|
for (const message of messages) {
|
|
1831
2105
|
if (message.role === "system") {
|
|
@@ -1903,6 +2177,39 @@ function formatJson(value) {
|
|
|
1903
2177
|
}
|
|
1904
2178
|
}
|
|
1905
2179
|
|
|
2180
|
+
// src/runtime/json.ts
|
|
2181
|
+
function toJsonValue2(value) {
|
|
2182
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
2183
|
+
return value;
|
|
2184
|
+
}
|
|
2185
|
+
if (value === void 0) {
|
|
2186
|
+
return null;
|
|
2187
|
+
}
|
|
2188
|
+
if (Array.isArray(value)) {
|
|
2189
|
+
return value.map((item) => toJsonValue2(item));
|
|
2190
|
+
}
|
|
2191
|
+
if (typeof value === "object") {
|
|
2192
|
+
return compactJsonObject2(value);
|
|
2193
|
+
}
|
|
2194
|
+
return String(value);
|
|
2195
|
+
}
|
|
2196
|
+
function compactJsonObject2(values) {
|
|
2197
|
+
const entries = Object.entries(values).flatMap(
|
|
2198
|
+
([key, value]) => value === void 0 ? [] : [[key, toJsonValue2(value)]]
|
|
2199
|
+
);
|
|
2200
|
+
return Object.fromEntries(entries);
|
|
2201
|
+
}
|
|
2202
|
+
function serializeUnknown(error) {
|
|
2203
|
+
if (error instanceof Error) {
|
|
2204
|
+
return compactJsonObject2({
|
|
2205
|
+
name: error.name,
|
|
2206
|
+
message: error.message,
|
|
2207
|
+
stack: error.stack
|
|
2208
|
+
});
|
|
2209
|
+
}
|
|
2210
|
+
return toJsonValue2(error);
|
|
2211
|
+
}
|
|
2212
|
+
|
|
1906
2213
|
// src/runtime/tool-metadata.ts
|
|
1907
2214
|
import { ToolSet } from "@anvia/core";
|
|
1908
2215
|
var MCP_TOOL_METADATA_KEY = /* @__PURE__ */ Symbol.for("anvia.mcp.tool.metadata");
|
|
@@ -1944,8 +2251,7 @@ function agentHasMcpTools(agent) {
|
|
|
1944
2251
|
|
|
1945
2252
|
// src/runtime/shared.ts
|
|
1946
2253
|
function resolveStores(options) {
|
|
1947
|
-
const
|
|
1948
|
-
const defaultStore = createSqliteSessionStore({ path: defaultPath });
|
|
2254
|
+
const defaultStore = defaultStudioStore();
|
|
1949
2255
|
const sessions = resolveSessionStore(options, defaultStore);
|
|
1950
2256
|
const traces = resolveTraceStore(options, sessions, defaultStore);
|
|
1951
2257
|
const pipelineLogs = resolvePipelineLogStore(options, sessions, defaultStore);
|
|
@@ -1957,6 +2263,10 @@ function resolveStores(options) {
|
|
|
1957
2263
|
...pipelineRuns === void 0 ? {} : { pipelineRuns }
|
|
1958
2264
|
};
|
|
1959
2265
|
}
|
|
2266
|
+
function defaultStudioStore() {
|
|
2267
|
+
const sqlitePath = process.env.ANVIA_STUDIO_DB ?? process.env.AION_STUDIO_DB;
|
|
2268
|
+
return sqlitePath === void 0 ? createInMemoryStudioStore() : createSqliteSessionStore({ path: sqlitePath });
|
|
2269
|
+
}
|
|
1960
2270
|
function resolveSessionStore(options, defaultStore) {
|
|
1961
2271
|
if (options.stores?.sessions === false) {
|
|
1962
2272
|
return void 0;
|
|
@@ -2059,6 +2369,7 @@ function buildConfig(options, agents, pipelines, stores) {
|
|
|
2059
2369
|
...options.version === void 0 ? {} : { version: options.version },
|
|
2060
2370
|
agents: agents.map(agentConfig),
|
|
2061
2371
|
pipelines: pipelines.map(pipelineConfig),
|
|
2372
|
+
evals: options.evals.map(evalConfig),
|
|
2062
2373
|
chat: {
|
|
2063
2374
|
quickPrompts: Object.fromEntries(agents.map((agent) => [agent.id, agent.quickPrompts ?? []]))
|
|
2064
2375
|
},
|
|
@@ -2080,6 +2391,30 @@ function agentConfig(agent) {
|
|
|
2080
2391
|
...agent.metadata === void 0 ? {} : { metadata: agent.metadata }
|
|
2081
2392
|
};
|
|
2082
2393
|
}
|
|
2394
|
+
function agentRuntimeSummary(agent) {
|
|
2395
|
+
const tools = agentToolItems(agent);
|
|
2396
|
+
const name = agent.name ?? agent.agent.name;
|
|
2397
|
+
const description = agent.description ?? agent.agent.description;
|
|
2398
|
+
return {
|
|
2399
|
+
id: agent.id,
|
|
2400
|
+
...name === void 0 ? {} : { name },
|
|
2401
|
+
...description === void 0 ? {} : { description },
|
|
2402
|
+
model: toJsonValue2(agent.agent.model),
|
|
2403
|
+
toolCount: tools.length,
|
|
2404
|
+
staticToolCount: tools.filter((item) => item.source === "static").length,
|
|
2405
|
+
dynamicToolCount: tools.filter((item) => item.source === "dynamic").length,
|
|
2406
|
+
approvalToolCount: tools.filter((item) => item.tool.approval !== void 0).length,
|
|
2407
|
+
mcpToolCount: tools.filter((item) => mcpServerName(item.tool) !== void 0).length,
|
|
2408
|
+
staticContextCount: agent.agent.staticContext.length,
|
|
2409
|
+
dynamicContextCount: agent.agent.dynamicContexts.length,
|
|
2410
|
+
observerCount: agent.agent.observers.length,
|
|
2411
|
+
hasMemory: agent.agent.memory !== void 0,
|
|
2412
|
+
hasHook: agent.agent.hook !== void 0,
|
|
2413
|
+
hasOutputSchema: agent.agent.outputSchema !== void 0,
|
|
2414
|
+
...agent.agent.defaultMaxTurns === void 0 ? {} : { defaultMaxTurns: agent.agent.defaultMaxTurns },
|
|
2415
|
+
...agent.metadata === void 0 ? {} : { metadata: agent.metadata }
|
|
2416
|
+
};
|
|
2417
|
+
}
|
|
2083
2418
|
function pipelineConfig(pipeline) {
|
|
2084
2419
|
const graph = pipeline.pipeline.graph();
|
|
2085
2420
|
const stageNodes = graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output");
|
|
@@ -2097,10 +2432,13 @@ function pipelineConfig(pipeline) {
|
|
|
2097
2432
|
}
|
|
2098
2433
|
function capabilityConfig(_options, agents, pipelines, stores) {
|
|
2099
2434
|
const capabilities = {
|
|
2100
|
-
agents: { enabled: true }
|
|
2435
|
+
agents: { enabled: true },
|
|
2436
|
+
observability: { enabled: true },
|
|
2437
|
+
status: { enabled: true }
|
|
2101
2438
|
};
|
|
2102
2439
|
if (stores.sessions !== void 0) {
|
|
2103
2440
|
capabilities.sessions = { enabled: true };
|
|
2441
|
+
capabilities.memory = { enabled: true };
|
|
2104
2442
|
}
|
|
2105
2443
|
if (stores.traces !== void 0) {
|
|
2106
2444
|
capabilities.traces = { enabled: true };
|
|
@@ -2108,6 +2446,9 @@ function capabilityConfig(_options, agents, pipelines, stores) {
|
|
|
2108
2446
|
if (pipelines.length > 0) {
|
|
2109
2447
|
capabilities.pipelines = { enabled: true };
|
|
2110
2448
|
}
|
|
2449
|
+
if (_options.evals.length > 0) {
|
|
2450
|
+
capabilities.evals = { enabled: true };
|
|
2451
|
+
}
|
|
2111
2452
|
if (agents.some(
|
|
2112
2453
|
(agent) => agent.agent.toolSet.values().length > 0 || agent.agent.dynamicTools.length > 0
|
|
2113
2454
|
)) {
|
|
@@ -2116,9 +2457,6 @@ function capabilityConfig(_options, agents, pipelines, stores) {
|
|
|
2116
2457
|
if (agents.some(agentHasMcpTools)) {
|
|
2117
2458
|
capabilities.mcps = { enabled: true };
|
|
2118
2459
|
}
|
|
2119
|
-
if (agents.some((agent) => agent.agent.observers.length > 0)) {
|
|
2120
|
-
capabilities.observability = { enabled: true };
|
|
2121
|
-
}
|
|
2122
2460
|
if (agents.some(
|
|
2123
2461
|
(agent) => agent.agent.hook !== void 0 || agent.agent.toolSet.values().some((tool) => tool.approval)
|
|
2124
2462
|
)) {
|
|
@@ -2131,6 +2469,17 @@ function capabilityConfig(_options, agents, pipelines, stores) {
|
|
|
2131
2469
|
}
|
|
2132
2470
|
return capabilities;
|
|
2133
2471
|
}
|
|
2472
|
+
function evalConfig(suite) {
|
|
2473
|
+
return {
|
|
2474
|
+
id: suite.id ?? suite.name,
|
|
2475
|
+
name: suite.name,
|
|
2476
|
+
...suite.description === void 0 ? {} : { description: suite.description },
|
|
2477
|
+
caseCount: suite.cases.length,
|
|
2478
|
+
metricNames: suite.metrics.map((metric) => metric.name),
|
|
2479
|
+
...suite.concurrency === void 0 ? {} : { concurrency: suite.concurrency },
|
|
2480
|
+
...suite.metadata === void 0 ? {} : { metadata: suite.metadata }
|
|
2481
|
+
};
|
|
2482
|
+
}
|
|
2134
2483
|
function optionalQueryString(value) {
|
|
2135
2484
|
const trimmed = value?.trim();
|
|
2136
2485
|
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
@@ -2152,9 +2501,6 @@ function parseTraceStatus(value) {
|
|
|
2152
2501
|
}
|
|
2153
2502
|
return status === "running" || status === "success" || status === "error" ? status : false;
|
|
2154
2503
|
}
|
|
2155
|
-
function safeFileName(value) {
|
|
2156
|
-
return value.replace(/[^a-zA-Z0-9._-]+/g, "_") || "anvia-studio";
|
|
2157
|
-
}
|
|
2158
2504
|
function isMessageInput(value) {
|
|
2159
2505
|
return typeof value === "string" || isMessage(value);
|
|
2160
2506
|
}
|
|
@@ -2173,17 +2519,17 @@ function isMessage(value) {
|
|
|
2173
2519
|
function isObject(value) {
|
|
2174
2520
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2175
2521
|
}
|
|
2176
|
-
function
|
|
2177
|
-
return isObject(value) && Object.values(value).every(
|
|
2522
|
+
function isJsonObject2(value) {
|
|
2523
|
+
return isObject(value) && Object.values(value).every(isJsonValue2);
|
|
2178
2524
|
}
|
|
2179
|
-
function
|
|
2525
|
+
function isJsonValue2(value) {
|
|
2180
2526
|
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
2181
2527
|
return true;
|
|
2182
2528
|
}
|
|
2183
2529
|
if (Array.isArray(value)) {
|
|
2184
|
-
return value.every(
|
|
2530
|
+
return value.every(isJsonValue2);
|
|
2185
2531
|
}
|
|
2186
|
-
return
|
|
2532
|
+
return isJsonObject2(value);
|
|
2187
2533
|
}
|
|
2188
2534
|
function isAgentTraceOptions(value) {
|
|
2189
2535
|
if (!isObject(value)) {
|
|
@@ -2238,7 +2584,7 @@ function serializeError2(error) {
|
|
|
2238
2584
|
...error.stack === void 0 ? {} : { stack: error.stack }
|
|
2239
2585
|
};
|
|
2240
2586
|
}
|
|
2241
|
-
return
|
|
2587
|
+
return isJsonValue2(error) ? error : String(error);
|
|
2242
2588
|
}
|
|
2243
2589
|
|
|
2244
2590
|
// src/runtime/approvals.ts
|
|
@@ -2484,27 +2830,70 @@ function publicApproval(approval) {
|
|
|
2484
2830
|
return rest;
|
|
2485
2831
|
}
|
|
2486
2832
|
|
|
2487
|
-
// src/runtime/
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2833
|
+
// src/runtime/evals.ts
|
|
2834
|
+
import { runEvalSuite } from "@anvia/core";
|
|
2835
|
+
function registerEvalRoutes(app, props) {
|
|
2836
|
+
app.get(
|
|
2837
|
+
"/evals",
|
|
2838
|
+
(c) => c.json({
|
|
2839
|
+
evals: props.evals.map(evalConfig)
|
|
2840
|
+
})
|
|
2841
|
+
);
|
|
2842
|
+
app.get("/evals/:evalId", (c) => {
|
|
2843
|
+
const suite = props.evalMap.get(c.req.param("evalId"));
|
|
2844
|
+
if (suite === void 0) {
|
|
2845
|
+
return errorResponse(c, 404, "not_found", "Eval suite not found");
|
|
2846
|
+
}
|
|
2847
|
+
return c.json(evalConfig(suite));
|
|
2848
|
+
});
|
|
2849
|
+
app.post("/evals/:evalId/runs", async (c) => {
|
|
2850
|
+
const suite = props.evalMap.get(c.req.param("evalId"));
|
|
2851
|
+
if (suite === void 0) {
|
|
2852
|
+
return errorResponse(c, 404, "not_found", "Eval suite not found");
|
|
2853
|
+
}
|
|
2854
|
+
const body = await parseEvalRunRequest(c);
|
|
2855
|
+
if ("error" in body) {
|
|
2856
|
+
return body.error;
|
|
2857
|
+
}
|
|
2858
|
+
const runId = globalThis.crypto.randomUUID();
|
|
2859
|
+
const startedAt = Date.now();
|
|
2860
|
+
const result = await runEvalSuite({
|
|
2861
|
+
...suite,
|
|
2862
|
+
...body.concurrency === void 0 ? {} : { concurrency: body.concurrency }
|
|
2863
|
+
});
|
|
2864
|
+
const endedAt = Date.now();
|
|
2865
|
+
const jsonResult = toJsonValue2(result);
|
|
2866
|
+
const response = {
|
|
2867
|
+
runId,
|
|
2868
|
+
suiteId: suite.id ?? suite.name,
|
|
2869
|
+
startedAt: new Date(startedAt).toISOString(),
|
|
2870
|
+
endedAt: new Date(endedAt).toISOString(),
|
|
2871
|
+
durationMs: endedAt - startedAt,
|
|
2872
|
+
result: isJsonObject2(jsonResult) ? jsonResult : { value: jsonResult }
|
|
2873
|
+
};
|
|
2874
|
+
return c.json(response);
|
|
2875
|
+
});
|
|
2876
|
+
}
|
|
2877
|
+
async function parseEvalRunRequest(c) {
|
|
2878
|
+
let body = {};
|
|
2879
|
+
try {
|
|
2880
|
+
body = await c.req.json();
|
|
2881
|
+
} catch {
|
|
2882
|
+
body = {};
|
|
2494
2883
|
}
|
|
2495
|
-
if (
|
|
2496
|
-
return
|
|
2884
|
+
if (!isObject(body)) {
|
|
2885
|
+
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
2497
2886
|
}
|
|
2498
|
-
|
|
2499
|
-
|
|
2887
|
+
const request = {};
|
|
2888
|
+
if ("concurrency" in body) {
|
|
2889
|
+
if (!isPositiveInteger(body.concurrency)) {
|
|
2890
|
+
return {
|
|
2891
|
+
error: errorResponse(c, 400, "bad_request", "concurrency must be a positive integer")
|
|
2892
|
+
};
|
|
2893
|
+
}
|
|
2894
|
+
request.concurrency = body.concurrency;
|
|
2500
2895
|
}
|
|
2501
|
-
return
|
|
2502
|
-
}
|
|
2503
|
-
function compactJsonObject2(values) {
|
|
2504
|
-
const entries = Object.entries(values).flatMap(
|
|
2505
|
-
([key, value]) => value === void 0 ? [] : [[key, toJsonValue2(value)]]
|
|
2506
|
-
);
|
|
2507
|
-
return Object.fromEntries(entries);
|
|
2896
|
+
return request;
|
|
2508
2897
|
}
|
|
2509
2898
|
|
|
2510
2899
|
// src/runtime/knowledge.ts
|
|
@@ -2878,62 +3267,343 @@ function jsonObjectFromRecord(value) {
|
|
|
2878
3267
|
function isRecord2(value) {
|
|
2879
3268
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2880
3269
|
}
|
|
2881
|
-
|
|
2882
|
-
// src/runtime/mcps.ts
|
|
2883
|
-
function registerMcpRoutes(app, props) {
|
|
2884
|
-
app.get("/agents/:agentId/mcps", async (c) => {
|
|
2885
|
-
const agentId = c.req.param("agentId");
|
|
2886
|
-
const agent = props.agentMap.get(agentId);
|
|
2887
|
-
if (agent === void 0) {
|
|
2888
|
-
return errorResponse(c, 404, "not_found", "Agent not found");
|
|
3270
|
+
|
|
3271
|
+
// src/runtime/mcps.ts
|
|
3272
|
+
function registerMcpRoutes(app, props) {
|
|
3273
|
+
app.get("/agents/:agentId/mcps", async (c) => {
|
|
3274
|
+
const agentId = c.req.param("agentId");
|
|
3275
|
+
const agent = props.agentMap.get(agentId);
|
|
3276
|
+
if (agent === void 0) {
|
|
3277
|
+
return errorResponse(c, 404, "not_found", "Agent not found");
|
|
3278
|
+
}
|
|
3279
|
+
return c.json({
|
|
3280
|
+
agentId,
|
|
3281
|
+
servers: await agentMcpMetadata(agent)
|
|
3282
|
+
});
|
|
3283
|
+
});
|
|
3284
|
+
}
|
|
3285
|
+
async function agentMcpMetadata(agent) {
|
|
3286
|
+
const servers = /* @__PURE__ */ new Map();
|
|
3287
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3288
|
+
for (const { tool, source } of agentToolItems(agent)) {
|
|
3289
|
+
const serverName = mcpServerName(tool);
|
|
3290
|
+
if (serverName === void 0) {
|
|
3291
|
+
continue;
|
|
3292
|
+
}
|
|
3293
|
+
const definition = await tool.definition("");
|
|
3294
|
+
const key = `${serverName}:${source}:${definition.name}`;
|
|
3295
|
+
if (seen.has(key)) {
|
|
3296
|
+
continue;
|
|
3297
|
+
}
|
|
3298
|
+
seen.add(key);
|
|
3299
|
+
const tools = servers.get(serverName) ?? [];
|
|
3300
|
+
tools.push({
|
|
3301
|
+
name: definition.name,
|
|
3302
|
+
description: definition.description,
|
|
3303
|
+
parameters: definition.parameters,
|
|
3304
|
+
source
|
|
3305
|
+
});
|
|
3306
|
+
servers.set(serverName, tools);
|
|
3307
|
+
}
|
|
3308
|
+
return [...servers.entries()].map(([name, tools]) => {
|
|
3309
|
+
const sortedTools = tools.sort((left, right) => {
|
|
3310
|
+
if (left.source !== right.source) {
|
|
3311
|
+
return left.source === "static" ? -1 : 1;
|
|
3312
|
+
}
|
|
3313
|
+
return left.name.localeCompare(right.name);
|
|
3314
|
+
});
|
|
3315
|
+
return {
|
|
3316
|
+
agentId: agent.id,
|
|
3317
|
+
name,
|
|
3318
|
+
toolCount: sortedTools.length,
|
|
3319
|
+
tools: sortedTools
|
|
3320
|
+
};
|
|
3321
|
+
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
3322
|
+
}
|
|
3323
|
+
|
|
3324
|
+
// src/runtime/memory.ts
|
|
3325
|
+
var DEFAULT_USER_ID = "default";
|
|
3326
|
+
function registerMemoryRoutes(app, props) {
|
|
3327
|
+
app.get("/memory/users", async (c) => {
|
|
3328
|
+
const limit = parseLimit(c.req.query("limit"));
|
|
3329
|
+
if (limit === void 0) {
|
|
3330
|
+
return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
|
|
3331
|
+
}
|
|
3332
|
+
const sessions = await props.sessionStore.listSessions({ limit: 100 });
|
|
3333
|
+
const users = /* @__PURE__ */ new Map();
|
|
3334
|
+
for (const session of sessions) {
|
|
3335
|
+
const userId = sessionUserId(session);
|
|
3336
|
+
const existing = users.get(userId);
|
|
3337
|
+
if (existing === void 0) {
|
|
3338
|
+
users.set(userId, {
|
|
3339
|
+
userId,
|
|
3340
|
+
conversationCount: 1,
|
|
3341
|
+
agentIds: [session.agentId],
|
|
3342
|
+
lastInteractionAt: session.updatedAt
|
|
3343
|
+
});
|
|
3344
|
+
continue;
|
|
3345
|
+
}
|
|
3346
|
+
existing.conversationCount += 1;
|
|
3347
|
+
if (!existing.agentIds.includes(session.agentId)) {
|
|
3348
|
+
existing.agentIds.push(session.agentId);
|
|
3349
|
+
}
|
|
3350
|
+
if (new Date(session.updatedAt).getTime() > new Date(existing.lastInteractionAt).getTime()) {
|
|
3351
|
+
existing.lastInteractionAt = session.updatedAt;
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
const page = [...users.values()].sort(
|
|
3355
|
+
(left, right) => new Date(right.lastInteractionAt).getTime() - new Date(left.lastInteractionAt).getTime()
|
|
3356
|
+
).slice(0, limit);
|
|
3357
|
+
return c.json({ users: page, total: users.size });
|
|
3358
|
+
});
|
|
3359
|
+
app.get("/memory/conversations", async (c) => {
|
|
3360
|
+
const limit = parseLimit(c.req.query("limit"));
|
|
3361
|
+
if (limit === void 0) {
|
|
3362
|
+
return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
|
|
3363
|
+
}
|
|
3364
|
+
const agentId = optionalQueryString(c.req.query("agentId"));
|
|
3365
|
+
const userId = optionalQueryString(c.req.query("userId"));
|
|
3366
|
+
const sessions = await props.sessionStore.listSessions({
|
|
3367
|
+
...agentId === void 0 ? {} : { agentId },
|
|
3368
|
+
limit: 100
|
|
3369
|
+
});
|
|
3370
|
+
const conversations = sessions.map(memoryConversationSummary).filter((session) => userId === void 0 || session.userId === userId).slice(0, limit);
|
|
3371
|
+
return c.json({
|
|
3372
|
+
conversations,
|
|
3373
|
+
total: conversations.length
|
|
3374
|
+
});
|
|
3375
|
+
});
|
|
3376
|
+
app.get("/memory/conversations/:conversationId/messages", async (c) => {
|
|
3377
|
+
const session = await props.sessionStore.getSession(c.req.param("conversationId"));
|
|
3378
|
+
if (session === void 0) {
|
|
3379
|
+
return errorResponse(c, 404, "not_found", "Conversation not found");
|
|
3380
|
+
}
|
|
3381
|
+
return c.json({
|
|
3382
|
+
conversation: memoryConversationSummary(session),
|
|
3383
|
+
messages: session.messages,
|
|
3384
|
+
transcript: session.transcript
|
|
3385
|
+
});
|
|
3386
|
+
});
|
|
3387
|
+
app.get("/memory/conversations/:conversationId/steps", async (c) => {
|
|
3388
|
+
const session = await props.sessionStore.getSession(c.req.param("conversationId"));
|
|
3389
|
+
if (session === void 0) {
|
|
3390
|
+
return errorResponse(c, 404, "not_found", "Conversation not found");
|
|
3391
|
+
}
|
|
3392
|
+
return c.json({
|
|
3393
|
+
conversation: memoryConversationSummary(session),
|
|
3394
|
+
steps: session.transcript
|
|
3395
|
+
});
|
|
3396
|
+
});
|
|
3397
|
+
}
|
|
3398
|
+
function memoryConversationSummary(session) {
|
|
3399
|
+
return {
|
|
3400
|
+
id: session.id,
|
|
3401
|
+
userId: sessionUserId(session),
|
|
3402
|
+
agentId: session.agentId,
|
|
3403
|
+
...session.title === void 0 ? {} : { title: session.title },
|
|
3404
|
+
createdAt: session.createdAt,
|
|
3405
|
+
updatedAt: session.updatedAt,
|
|
3406
|
+
messageCount: session.messageCount,
|
|
3407
|
+
...session.metadata === void 0 ? {} : { metadata: session.metadata }
|
|
3408
|
+
};
|
|
3409
|
+
}
|
|
3410
|
+
function sessionUserId(session) {
|
|
3411
|
+
const userId = session.metadata?.userId;
|
|
3412
|
+
return typeof userId === "string" && userId.trim().length > 0 ? userId : DEFAULT_USER_ID;
|
|
3413
|
+
}
|
|
3414
|
+
|
|
3415
|
+
// src/runtime/observability.ts
|
|
3416
|
+
import { stream as streamResponse } from "hono/streaming";
|
|
3417
|
+
var defaultBufferSize = 1e3;
|
|
3418
|
+
var StudioObservabilityHub = class {
|
|
3419
|
+
subscriptions = /* @__PURE__ */ new Set();
|
|
3420
|
+
emit(event) {
|
|
3421
|
+
for (const subscription of this.subscriptions) {
|
|
3422
|
+
subscription.push(event);
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
subscribe(options = {}) {
|
|
3426
|
+
const subscription = createSubscription(options.types);
|
|
3427
|
+
this.subscriptions.add(subscription);
|
|
3428
|
+
return {
|
|
3429
|
+
close: () => {
|
|
3430
|
+
subscription.close();
|
|
3431
|
+
this.subscriptions.delete(subscription);
|
|
3432
|
+
},
|
|
3433
|
+
next: subscription.next,
|
|
3434
|
+
push: subscription.push
|
|
3435
|
+
};
|
|
3436
|
+
}
|
|
3437
|
+
};
|
|
3438
|
+
function observeStores(stores, hub) {
|
|
3439
|
+
return {
|
|
3440
|
+
...stores,
|
|
3441
|
+
...stores.sessions === void 0 ? {} : { sessions: observeSessionStore(stores.sessions, hub) },
|
|
3442
|
+
...stores.traces === void 0 ? {} : { traces: observeTraceStore(stores.traces, hub) },
|
|
3443
|
+
...stores.pipelineLogs === void 0 ? {} : { pipelineLogs: observePipelineLogStore(stores.pipelineLogs, hub) }
|
|
3444
|
+
};
|
|
3445
|
+
}
|
|
3446
|
+
function registerObservabilityRoutes(app, hub) {
|
|
3447
|
+
app.get("/observability/events", (c) => {
|
|
3448
|
+
const types = parseEventTypes(c.req.query("type"));
|
|
3449
|
+
if (types === false) {
|
|
3450
|
+
return c.json(
|
|
3451
|
+
{
|
|
3452
|
+
error: {
|
|
3453
|
+
code: "bad_request",
|
|
3454
|
+
message: "type must include session_log, pipeline_log, or trace"
|
|
3455
|
+
}
|
|
3456
|
+
},
|
|
3457
|
+
400
|
|
3458
|
+
);
|
|
3459
|
+
}
|
|
3460
|
+
c.header("content-type", "application/x-ndjson; charset=utf-8");
|
|
3461
|
+
c.header("cache-control", "no-cache, no-transform");
|
|
3462
|
+
c.header("connection", "keep-alive");
|
|
3463
|
+
c.header("transfer-encoding", "chunked");
|
|
3464
|
+
c.header("x-accel-buffering", "no");
|
|
3465
|
+
return streamResponse(c, async (stream) => {
|
|
3466
|
+
const subscription = hub.subscribe(types === void 0 ? {} : { types });
|
|
3467
|
+
try {
|
|
3468
|
+
while (true) {
|
|
3469
|
+
const next = await subscription.next();
|
|
3470
|
+
if (next.done === true) {
|
|
3471
|
+
break;
|
|
3472
|
+
}
|
|
3473
|
+
await stream.write(`${JSON.stringify(next.value)}
|
|
3474
|
+
`);
|
|
3475
|
+
}
|
|
3476
|
+
} finally {
|
|
3477
|
+
subscription.close();
|
|
3478
|
+
}
|
|
3479
|
+
});
|
|
3480
|
+
});
|
|
3481
|
+
}
|
|
3482
|
+
function createSubscription(types) {
|
|
3483
|
+
const values = [];
|
|
3484
|
+
const resolvers = [];
|
|
3485
|
+
let closed = false;
|
|
3486
|
+
return {
|
|
3487
|
+
close() {
|
|
3488
|
+
closed = true;
|
|
3489
|
+
for (const resolve2 of resolvers.splice(0)) {
|
|
3490
|
+
resolve2({ done: true, value: void 0 });
|
|
3491
|
+
}
|
|
3492
|
+
},
|
|
3493
|
+
next() {
|
|
3494
|
+
const value = values.shift();
|
|
3495
|
+
if (value !== void 0) {
|
|
3496
|
+
return Promise.resolve({ done: false, value });
|
|
3497
|
+
}
|
|
3498
|
+
if (closed) {
|
|
3499
|
+
return Promise.resolve({ done: true, value: void 0 });
|
|
3500
|
+
}
|
|
3501
|
+
return new Promise((resolve2) => resolvers.push(resolve2));
|
|
3502
|
+
},
|
|
3503
|
+
push(event) {
|
|
3504
|
+
if (closed || types !== void 0 && !types.has(event.type)) {
|
|
3505
|
+
return;
|
|
3506
|
+
}
|
|
3507
|
+
const resolve2 = resolvers.shift();
|
|
3508
|
+
if (resolve2 !== void 0) {
|
|
3509
|
+
resolve2({ done: false, value: event });
|
|
3510
|
+
return;
|
|
3511
|
+
}
|
|
3512
|
+
if (values.length >= defaultBufferSize) {
|
|
3513
|
+
values.shift();
|
|
3514
|
+
}
|
|
3515
|
+
values.push(event);
|
|
3516
|
+
}
|
|
3517
|
+
};
|
|
3518
|
+
}
|
|
3519
|
+
function observeSessionStore(store, hub) {
|
|
3520
|
+
return new Proxy(store, {
|
|
3521
|
+
get(target, property, receiver) {
|
|
3522
|
+
if (property !== "appendSessionLog") {
|
|
3523
|
+
return boundProperty(target, property, receiver);
|
|
3524
|
+
}
|
|
3525
|
+
const appendSessionLog2 = target.appendSessionLog?.bind(target);
|
|
3526
|
+
if (appendSessionLog2 === void 0) {
|
|
3527
|
+
return void 0;
|
|
3528
|
+
}
|
|
3529
|
+
return async (...args) => {
|
|
3530
|
+
const log = await appendSessionLog2(...args);
|
|
3531
|
+
hub.emit({ type: "session_log", log });
|
|
3532
|
+
return log;
|
|
3533
|
+
};
|
|
2889
3534
|
}
|
|
2890
|
-
return c.json({
|
|
2891
|
-
agentId,
|
|
2892
|
-
servers: await agentMcpMetadata(agent)
|
|
2893
|
-
});
|
|
2894
3535
|
});
|
|
2895
3536
|
}
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
3537
|
+
function observePipelineLogStore(store, hub) {
|
|
3538
|
+
return new Proxy(store, {
|
|
3539
|
+
get(target, property, receiver) {
|
|
3540
|
+
if (property !== "appendPipelineLog") {
|
|
3541
|
+
return boundProperty(target, property, receiver);
|
|
3542
|
+
}
|
|
3543
|
+
const appendPipelineLog2 = target.appendPipelineLog.bind(target);
|
|
3544
|
+
return async (...args) => {
|
|
3545
|
+
const log = await appendPipelineLog2(...args);
|
|
3546
|
+
hub.emit({ type: "pipeline_log", log });
|
|
3547
|
+
return log;
|
|
3548
|
+
};
|
|
2903
3549
|
}
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
3550
|
+
});
|
|
3551
|
+
}
|
|
3552
|
+
function observeTraceStore(store, hub) {
|
|
3553
|
+
return new Proxy(store, {
|
|
3554
|
+
get(target, property, receiver) {
|
|
3555
|
+
if (property !== "saveTrace") {
|
|
3556
|
+
return boundProperty(target, property, receiver);
|
|
3557
|
+
}
|
|
3558
|
+
const saveTrace = target.saveTrace.bind(target);
|
|
3559
|
+
return async (...args) => {
|
|
3560
|
+
const trace = await saveTrace(...args);
|
|
3561
|
+
hub.emit({ type: "trace", trace: traceSummary2(trace) });
|
|
3562
|
+
return trace;
|
|
3563
|
+
};
|
|
2908
3564
|
}
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
3565
|
+
});
|
|
3566
|
+
}
|
|
3567
|
+
function boundProperty(target, property, receiver) {
|
|
3568
|
+
const value = Reflect.get(target, property, receiver);
|
|
3569
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
3570
|
+
}
|
|
3571
|
+
function parseEventTypes(value) {
|
|
3572
|
+
if (value === void 0 || value.trim().length === 0) {
|
|
3573
|
+
return void 0;
|
|
2918
3574
|
}
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
3575
|
+
const types = /* @__PURE__ */ new Set();
|
|
3576
|
+
for (const type of value.split(",")) {
|
|
3577
|
+
const trimmed = type.trim();
|
|
3578
|
+
if (!isEventType(trimmed)) {
|
|
3579
|
+
return false;
|
|
3580
|
+
}
|
|
3581
|
+
types.add(trimmed);
|
|
3582
|
+
}
|
|
3583
|
+
return types;
|
|
3584
|
+
}
|
|
3585
|
+
function isEventType(value) {
|
|
3586
|
+
return value === "session_log" || value === "pipeline_log" || value === "trace";
|
|
3587
|
+
}
|
|
3588
|
+
function traceSummary2(trace) {
|
|
3589
|
+
return {
|
|
3590
|
+
id: trace.id,
|
|
3591
|
+
sessionId: trace.sessionId,
|
|
3592
|
+
...trace.name === void 0 ? {} : { name: trace.name },
|
|
3593
|
+
status: trace.status,
|
|
3594
|
+
startedAt: trace.startedAt,
|
|
3595
|
+
...trace.endedAt === void 0 ? {} : { endedAt: trace.endedAt },
|
|
3596
|
+
...trace.durationMs === void 0 ? {} : { durationMs: trace.durationMs },
|
|
3597
|
+
...trace.output === void 0 ? {} : { output: trace.output },
|
|
3598
|
+
...trace.error === void 0 ? {} : { error: trace.error },
|
|
3599
|
+
...trace.usage === void 0 ? {} : { usage: trace.usage },
|
|
3600
|
+
...trace.metadata === void 0 ? {} : { metadata: trace.metadata },
|
|
3601
|
+
observationCount: trace.observations.length
|
|
3602
|
+
};
|
|
2933
3603
|
}
|
|
2934
3604
|
|
|
2935
3605
|
// src/runtime/pipelines.ts
|
|
2936
|
-
import { stream as
|
|
3606
|
+
import { stream as streamResponse3 } from "hono/streaming";
|
|
2937
3607
|
|
|
2938
3608
|
// src/runtime/pipeline-logs.ts
|
|
2939
3609
|
async function appendPipelineLog(store, input) {
|
|
@@ -3083,7 +3753,7 @@ function formatUnknown(value) {
|
|
|
3083
3753
|
}
|
|
3084
3754
|
|
|
3085
3755
|
// src/runtime/runs.ts
|
|
3086
|
-
import { stream as
|
|
3756
|
+
import { stream as streamResponse2 } from "hono/streaming";
|
|
3087
3757
|
var AsyncEventQueue = class {
|
|
3088
3758
|
values = [];
|
|
3089
3759
|
resolvers = [];
|
|
@@ -3162,7 +3832,7 @@ function streamAgentRunEvents(c, events) {
|
|
|
3162
3832
|
c.header("connection", "keep-alive");
|
|
3163
3833
|
c.header("transfer-encoding", "chunked");
|
|
3164
3834
|
c.header("x-accel-buffering", "no");
|
|
3165
|
-
return
|
|
3835
|
+
return streamResponse2(
|
|
3166
3836
|
c,
|
|
3167
3837
|
async (stream) => {
|
|
3168
3838
|
for await (const event of events) {
|
|
@@ -3662,7 +4332,7 @@ async function parseRunRequest(c) {
|
|
|
3662
4332
|
request.toolConcurrency = body.toolConcurrency;
|
|
3663
4333
|
}
|
|
3664
4334
|
if ("metadata" in body) {
|
|
3665
|
-
if (!
|
|
4335
|
+
if (!isJsonObject2(body.metadata)) {
|
|
3666
4336
|
return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
|
|
3667
4337
|
}
|
|
3668
4338
|
request.metadata = body.metadata;
|
|
@@ -3756,96 +4426,135 @@ function registerPipelineRoutes(app, props) {
|
|
|
3756
4426
|
if ("error" in body) {
|
|
3757
4427
|
return body.error;
|
|
3758
4428
|
}
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
4429
|
+
return executePipelineRun(c, props, pipeline, body);
|
|
4430
|
+
});
|
|
4431
|
+
app.post("/pipelines/:pipelineId/runs/:runId/replay", async (c) => {
|
|
4432
|
+
const pipeline = props.pipelineMap.get(c.req.param("pipelineId"));
|
|
4433
|
+
if (pipeline === void 0) {
|
|
4434
|
+
return errorResponse(c, 404, "not_found", "Pipeline not found");
|
|
4435
|
+
}
|
|
4436
|
+
if (props.runStore === void 0) {
|
|
4437
|
+
return errorResponse(
|
|
4438
|
+
c,
|
|
4439
|
+
501,
|
|
4440
|
+
"unsupported_capability",
|
|
4441
|
+
'Capability "pipelines.runs" is not implemented by this runner',
|
|
4442
|
+
{ capability: "pipelines", operation: "runs" }
|
|
4443
|
+
);
|
|
4444
|
+
}
|
|
4445
|
+
const body = await parsePipelineReplayRequest(c);
|
|
4446
|
+
if ("error" in body) {
|
|
4447
|
+
return body.error;
|
|
4448
|
+
}
|
|
4449
|
+
const sourceRunId = c.req.param("runId");
|
|
4450
|
+
const runs = await props.runStore.listPipelineRuns({
|
|
4451
|
+
pipelineId: pipeline.id,
|
|
4452
|
+
limit: 1e3
|
|
4453
|
+
});
|
|
4454
|
+
const sourceRun = runs.find((run) => run.runId === sourceRunId);
|
|
4455
|
+
if (sourceRun === void 0) {
|
|
4456
|
+
return errorResponse(c, 404, "not_found", "Pipeline run not found");
|
|
4457
|
+
}
|
|
4458
|
+
if (sourceRun.status === "running") {
|
|
4459
|
+
return errorResponse(c, 409, "conflict", "Cannot replay a running pipeline run");
|
|
4460
|
+
}
|
|
4461
|
+
return executePipelineRun(c, props, pipeline, {
|
|
4462
|
+
input: sourceRun.input,
|
|
4463
|
+
...body.stream === void 0 ? {} : { stream: body.stream },
|
|
4464
|
+
metadata: replayMetadata(sourceRun.metadata, body.metadata, sourceRun.runId)
|
|
4465
|
+
});
|
|
4466
|
+
});
|
|
4467
|
+
}
|
|
4468
|
+
async function executePipelineRun(c, props, pipeline, body) {
|
|
4469
|
+
const runId = globalThis.crypto.randomUUID();
|
|
4470
|
+
const startedAt = Date.now();
|
|
4471
|
+
const startedAtIso = new Date(startedAt).toISOString();
|
|
4472
|
+
await appendPipelineLog(
|
|
4473
|
+
props.logStore,
|
|
4474
|
+
pipelineRunReceivedLog({
|
|
4475
|
+
pipeline,
|
|
4476
|
+
runId,
|
|
4477
|
+
stream: body.stream === true,
|
|
4478
|
+
input: body.input,
|
|
4479
|
+
...body.metadata === void 0 ? {} : { metadata: body.metadata }
|
|
4480
|
+
})
|
|
4481
|
+
);
|
|
4482
|
+
await savePipelineRun(props.runStore, {
|
|
4483
|
+
runId,
|
|
4484
|
+
pipelineId: pipeline.id,
|
|
4485
|
+
status: "running",
|
|
4486
|
+
input: body.input,
|
|
4487
|
+
...body.metadata === void 0 ? {} : { metadata: body.metadata },
|
|
4488
|
+
startedAt: startedAtIso
|
|
4489
|
+
});
|
|
4490
|
+
if (body.stream === true) {
|
|
4491
|
+
return streamPipelineRun(c, {
|
|
4492
|
+
pipeline,
|
|
4493
|
+
runId,
|
|
4494
|
+
input: body.input,
|
|
4495
|
+
startedAt,
|
|
4496
|
+
startedAtIso,
|
|
4497
|
+
...body.metadata === void 0 ? {} : { metadata: body.metadata },
|
|
4498
|
+
...props.logStore === void 0 ? {} : { logStore: props.logStore },
|
|
4499
|
+
...props.runStore === void 0 ? {} : { runStore: props.runStore }
|
|
4500
|
+
});
|
|
4501
|
+
}
|
|
4502
|
+
try {
|
|
4503
|
+
await appendPipelineLog(props.logStore, pipelineRunStartedLog(pipeline, runId));
|
|
4504
|
+
const output = await pipeline.pipeline.run(body.input, {
|
|
4505
|
+
observer: {
|
|
4506
|
+
async onEvent(event) {
|
|
4507
|
+
await appendPipelineLog(props.logStore, pipelineStageLog(pipeline.id, runId, event));
|
|
4508
|
+
}
|
|
4509
|
+
}
|
|
4510
|
+
});
|
|
4511
|
+
const jsonOutput = toJsonValue3(output);
|
|
4512
|
+
const endedAt = Date.now();
|
|
4513
|
+
await savePipelineRun(props.runStore, {
|
|
4514
|
+
runId,
|
|
4515
|
+
pipelineId: pipeline.id,
|
|
4516
|
+
status: "success",
|
|
4517
|
+
input: body.input,
|
|
4518
|
+
output: jsonOutput,
|
|
4519
|
+
...body.metadata === void 0 ? {} : { metadata: body.metadata },
|
|
4520
|
+
startedAt: startedAtIso,
|
|
4521
|
+
endedAt: new Date(endedAt).toISOString(),
|
|
4522
|
+
durationMs: endedAt - startedAt
|
|
4523
|
+
});
|
|
3762
4524
|
await appendPipelineLog(
|
|
3763
4525
|
props.logStore,
|
|
3764
|
-
|
|
3765
|
-
pipeline,
|
|
4526
|
+
pipelineRunCompletedLog({
|
|
4527
|
+
pipelineId: pipeline.id,
|
|
3766
4528
|
runId,
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
...body.metadata === void 0 ? {} : { metadata: body.metadata }
|
|
4529
|
+
durationMs: endedAt - startedAt,
|
|
4530
|
+
output: jsonOutput
|
|
3770
4531
|
})
|
|
3771
4532
|
);
|
|
4533
|
+
const response = {
|
|
4534
|
+
runId,
|
|
4535
|
+
pipelineId: pipeline.id,
|
|
4536
|
+
output: jsonOutput
|
|
4537
|
+
};
|
|
4538
|
+
return c.json(response);
|
|
4539
|
+
} catch (error) {
|
|
4540
|
+
const endedAt = Date.now();
|
|
3772
4541
|
await savePipelineRun(props.runStore, {
|
|
3773
4542
|
runId,
|
|
3774
4543
|
pipelineId: pipeline.id,
|
|
3775
|
-
status: "
|
|
4544
|
+
status: "error",
|
|
3776
4545
|
input: body.input,
|
|
4546
|
+
error: serializeError2(error),
|
|
3777
4547
|
...body.metadata === void 0 ? {} : { metadata: body.metadata },
|
|
3778
|
-
startedAt: startedAtIso
|
|
4548
|
+
startedAt: startedAtIso,
|
|
4549
|
+
endedAt: new Date(endedAt).toISOString(),
|
|
4550
|
+
durationMs: endedAt - startedAt
|
|
3779
4551
|
});
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
startedAtIso,
|
|
3787
|
-
...body.metadata === void 0 ? {} : { metadata: body.metadata },
|
|
3788
|
-
...props.logStore === void 0 ? {} : { logStore: props.logStore },
|
|
3789
|
-
...props.runStore === void 0 ? {} : { runStore: props.runStore }
|
|
3790
|
-
});
|
|
3791
|
-
}
|
|
3792
|
-
try {
|
|
3793
|
-
await appendPipelineLog(props.logStore, pipelineRunStartedLog(pipeline, runId));
|
|
3794
|
-
const output = await pipeline.pipeline.run(body.input, {
|
|
3795
|
-
observer: {
|
|
3796
|
-
async onEvent(event) {
|
|
3797
|
-
await appendPipelineLog(props.logStore, pipelineStageLog(pipeline.id, runId, event));
|
|
3798
|
-
}
|
|
3799
|
-
}
|
|
3800
|
-
});
|
|
3801
|
-
const jsonOutput = toJsonValue3(output);
|
|
3802
|
-
const endedAt = Date.now();
|
|
3803
|
-
await savePipelineRun(props.runStore, {
|
|
3804
|
-
runId,
|
|
3805
|
-
pipelineId: pipeline.id,
|
|
3806
|
-
status: "success",
|
|
3807
|
-
input: body.input,
|
|
3808
|
-
output: jsonOutput,
|
|
3809
|
-
...body.metadata === void 0 ? {} : { metadata: body.metadata },
|
|
3810
|
-
startedAt: startedAtIso,
|
|
3811
|
-
endedAt: new Date(endedAt).toISOString(),
|
|
3812
|
-
durationMs: endedAt - startedAt
|
|
3813
|
-
});
|
|
3814
|
-
await appendPipelineLog(
|
|
3815
|
-
props.logStore,
|
|
3816
|
-
pipelineRunCompletedLog({
|
|
3817
|
-
pipelineId: pipeline.id,
|
|
3818
|
-
runId,
|
|
3819
|
-
durationMs: endedAt - startedAt,
|
|
3820
|
-
output: jsonOutput
|
|
3821
|
-
})
|
|
3822
|
-
);
|
|
3823
|
-
const response = {
|
|
3824
|
-
runId,
|
|
3825
|
-
pipelineId: pipeline.id,
|
|
3826
|
-
output: jsonOutput
|
|
3827
|
-
};
|
|
3828
|
-
return c.json(response);
|
|
3829
|
-
} catch (error) {
|
|
3830
|
-
const endedAt = Date.now();
|
|
3831
|
-
await savePipelineRun(props.runStore, {
|
|
3832
|
-
runId,
|
|
3833
|
-
pipelineId: pipeline.id,
|
|
3834
|
-
status: "error",
|
|
3835
|
-
input: body.input,
|
|
3836
|
-
error: serializeError2(error),
|
|
3837
|
-
...body.metadata === void 0 ? {} : { metadata: body.metadata },
|
|
3838
|
-
startedAt: startedAtIso,
|
|
3839
|
-
endedAt: new Date(endedAt).toISOString(),
|
|
3840
|
-
durationMs: endedAt - startedAt
|
|
3841
|
-
});
|
|
3842
|
-
await appendPipelineLog(
|
|
3843
|
-
props.logStore,
|
|
3844
|
-
pipelineRunFailedLog(pipeline.id, runId, error, startedAt)
|
|
3845
|
-
);
|
|
3846
|
-
return errorResponse(c, 500, "internal_error", "Pipeline run failed", serializeError2(error));
|
|
3847
|
-
}
|
|
3848
|
-
});
|
|
4552
|
+
await appendPipelineLog(
|
|
4553
|
+
props.logStore,
|
|
4554
|
+
pipelineRunFailedLog(pipeline.id, runId, error, startedAt)
|
|
4555
|
+
);
|
|
4556
|
+
return errorResponse(c, 500, "internal_error", "Pipeline run failed", serializeError2(error));
|
|
4557
|
+
}
|
|
3849
4558
|
}
|
|
3850
4559
|
function pipelineDetail(pipeline) {
|
|
3851
4560
|
const graph = pipeline.pipeline.graph();
|
|
@@ -3861,7 +4570,7 @@ function streamPipelineRun(c, props) {
|
|
|
3861
4570
|
c.header("connection", "keep-alive");
|
|
3862
4571
|
c.header("transfer-encoding", "chunked");
|
|
3863
4572
|
c.header("x-accel-buffering", "no");
|
|
3864
|
-
return
|
|
4573
|
+
return streamResponse3(
|
|
3865
4574
|
c,
|
|
3866
4575
|
async (stream) => {
|
|
3867
4576
|
for await (const event of pipelineRunEvents(props)) {
|
|
@@ -3969,7 +4678,7 @@ async function parsePipelineRunRequest(c) {
|
|
|
3969
4678
|
if (!isObject(body)) {
|
|
3970
4679
|
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
3971
4680
|
}
|
|
3972
|
-
if (!("input" in body) || !
|
|
4681
|
+
if (!("input" in body) || !isJsonValue3(body.input)) {
|
|
3973
4682
|
return { error: errorResponse(c, 400, "bad_request", "input must be JSON-compatible") };
|
|
3974
4683
|
}
|
|
3975
4684
|
const request = {
|
|
@@ -3982,13 +4691,45 @@ async function parsePipelineRunRequest(c) {
|
|
|
3982
4691
|
request.stream = body.stream;
|
|
3983
4692
|
}
|
|
3984
4693
|
if ("metadata" in body) {
|
|
3985
|
-
if (!
|
|
4694
|
+
if (!isJsonObject2(body.metadata)) {
|
|
4695
|
+
return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
|
|
4696
|
+
}
|
|
4697
|
+
request.metadata = body.metadata;
|
|
4698
|
+
}
|
|
4699
|
+
return request;
|
|
4700
|
+
}
|
|
4701
|
+
async function parsePipelineReplayRequest(c) {
|
|
4702
|
+
let body;
|
|
4703
|
+
try {
|
|
4704
|
+
body = await c.req.json();
|
|
4705
|
+
} catch {
|
|
4706
|
+
return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
|
|
4707
|
+
}
|
|
4708
|
+
if (!isObject(body)) {
|
|
4709
|
+
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
4710
|
+
}
|
|
4711
|
+
const request = {};
|
|
4712
|
+
if ("stream" in body) {
|
|
4713
|
+
if (typeof body.stream !== "boolean") {
|
|
4714
|
+
return { error: errorResponse(c, 400, "bad_request", "stream must be a boolean") };
|
|
4715
|
+
}
|
|
4716
|
+
request.stream = body.stream;
|
|
4717
|
+
}
|
|
4718
|
+
if ("metadata" in body) {
|
|
4719
|
+
if (!isJsonObject2(body.metadata)) {
|
|
3986
4720
|
return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
|
|
3987
4721
|
}
|
|
3988
4722
|
request.metadata = body.metadata;
|
|
3989
4723
|
}
|
|
3990
4724
|
return request;
|
|
3991
4725
|
}
|
|
4726
|
+
function replayMetadata(sourceMetadata, requestMetadata, sourceRunId) {
|
|
4727
|
+
return {
|
|
4728
|
+
...sourceMetadata ?? {},
|
|
4729
|
+
...requestMetadata ?? {},
|
|
4730
|
+
replayOf: sourceRunId
|
|
4731
|
+
};
|
|
4732
|
+
}
|
|
3992
4733
|
function parsePipelineLogLimit(value) {
|
|
3993
4734
|
if (value === void 0 || value.trim().length === 0) {
|
|
3994
4735
|
return 200;
|
|
@@ -4009,20 +4750,20 @@ function parsePipelineLogAfter(value) {
|
|
|
4009
4750
|
}
|
|
4010
4751
|
return after;
|
|
4011
4752
|
}
|
|
4012
|
-
function
|
|
4753
|
+
function isJsonValue3(value) {
|
|
4013
4754
|
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
4014
4755
|
return Number.isFinite(value) || typeof value !== "number";
|
|
4015
4756
|
}
|
|
4016
4757
|
if (Array.isArray(value)) {
|
|
4017
|
-
return value.every(
|
|
4758
|
+
return value.every(isJsonValue3);
|
|
4018
4759
|
}
|
|
4019
4760
|
if (isObject(value)) {
|
|
4020
|
-
return Object.values(value).every((item) => item === void 0 ||
|
|
4761
|
+
return Object.values(value).every((item) => item === void 0 || isJsonValue3(item));
|
|
4021
4762
|
}
|
|
4022
4763
|
return false;
|
|
4023
4764
|
}
|
|
4024
4765
|
function toJsonValue3(value) {
|
|
4025
|
-
if (
|
|
4766
|
+
if (isJsonValue3(value)) {
|
|
4026
4767
|
return value;
|
|
4027
4768
|
}
|
|
4028
4769
|
if (value === void 0) {
|
|
@@ -4030,7 +4771,7 @@ function toJsonValue3(value) {
|
|
|
4030
4771
|
}
|
|
4031
4772
|
try {
|
|
4032
4773
|
const parsed = JSON.parse(JSON.stringify(value));
|
|
4033
|
-
return
|
|
4774
|
+
return isJsonValue3(parsed) ? parsed : String(value);
|
|
4034
4775
|
} catch {
|
|
4035
4776
|
return String(value);
|
|
4036
4777
|
}
|
|
@@ -4916,7 +5657,7 @@ async function parseCreateSessionRequest(c) {
|
|
|
4916
5657
|
}
|
|
4917
5658
|
}
|
|
4918
5659
|
if ("metadata" in body) {
|
|
4919
|
-
if (!
|
|
5660
|
+
if (!isJsonObject2(body.metadata)) {
|
|
4920
5661
|
return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
|
|
4921
5662
|
}
|
|
4922
5663
|
request.metadata = body.metadata;
|
|
@@ -4924,6 +5665,44 @@ async function parseCreateSessionRequest(c) {
|
|
|
4924
5665
|
return request;
|
|
4925
5666
|
}
|
|
4926
5667
|
|
|
5668
|
+
// src/runtime/status.ts
|
|
5669
|
+
function registerStatusRoutes(app, props) {
|
|
5670
|
+
app.get("/status", async (c) => {
|
|
5671
|
+
const summary = {
|
|
5672
|
+
runner: {
|
|
5673
|
+
id: runnerId(props.options),
|
|
5674
|
+
...props.options.name === void 0 ? {} : { name: props.options.name },
|
|
5675
|
+
...props.options.version === void 0 ? {} : { version: props.options.version }
|
|
5676
|
+
},
|
|
5677
|
+
storage: {
|
|
5678
|
+
...props.stores.sessions?.kind === void 0 ? {} : { sessions: props.stores.sessions.kind },
|
|
5679
|
+
...props.stores.traces?.kind === void 0 ? {} : { traces: props.stores.traces.kind },
|
|
5680
|
+
...props.stores.pipelineLogs === void 0 ? {} : { pipelineLogs: "available" },
|
|
5681
|
+
...props.stores.pipelineRuns === void 0 ? {} : { pipelineRuns: "available" }
|
|
5682
|
+
},
|
|
5683
|
+
counts: {
|
|
5684
|
+
agents: props.agents.length,
|
|
5685
|
+
pipelines: props.pipelines.length,
|
|
5686
|
+
...props.stores.sessions === void 0 ? {} : { sessions: (await props.stores.sessions.listSessions({ limit: 100 })).length },
|
|
5687
|
+
...props.stores.traces?.listTraces === void 0 ? {} : { traces: (await props.stores.traces.listTraces({ limit: 100 })).length },
|
|
5688
|
+
...props.stores.pipelineRuns === void 0 || props.pipelines.length === 0 ? {} : {
|
|
5689
|
+
pipelineRuns: (await Promise.all(
|
|
5690
|
+
props.pipelines.map(
|
|
5691
|
+
(pipeline) => props.stores.pipelineRuns?.listPipelineRuns({
|
|
5692
|
+
pipelineId: pipeline.id,
|
|
5693
|
+
limit: 100
|
|
5694
|
+
})
|
|
5695
|
+
)
|
|
5696
|
+
)).reduce((sum, runs) => sum + (runs?.length ?? 0), 0)
|
|
5697
|
+
}
|
|
5698
|
+
},
|
|
5699
|
+
capabilities: capabilityConfig(props.options, props.agents, props.pipelines, props.stores),
|
|
5700
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5701
|
+
};
|
|
5702
|
+
return c.json(summary);
|
|
5703
|
+
});
|
|
5704
|
+
}
|
|
5705
|
+
|
|
4927
5706
|
// src/runtime/tools.ts
|
|
4928
5707
|
function registerToolRoutes(app, props) {
|
|
4929
5708
|
app.get("/agents/:agentId/tools", async (c) => {
|
|
@@ -4937,6 +5716,83 @@ function registerToolRoutes(app, props) {
|
|
|
4937
5716
|
tools: await agentToolMetadata(agent)
|
|
4938
5717
|
});
|
|
4939
5718
|
});
|
|
5719
|
+
app.post("/agents/:agentId/tools/:toolName/runs", async (c) => {
|
|
5720
|
+
const agentId = c.req.param("agentId");
|
|
5721
|
+
const toolName = c.req.param("toolName");
|
|
5722
|
+
const agent = props.agentMap.get(agentId);
|
|
5723
|
+
if (agent === void 0) {
|
|
5724
|
+
return errorResponse(c, 404, "not_found", "Agent not found");
|
|
5725
|
+
}
|
|
5726
|
+
if (agent.agent.getTool(toolName) === void 0) {
|
|
5727
|
+
return errorResponse(c, 404, "not_found", "Tool not found");
|
|
5728
|
+
}
|
|
5729
|
+
const body = await parseToolRunRequest(c);
|
|
5730
|
+
if ("error" in body) {
|
|
5731
|
+
return body.error;
|
|
5732
|
+
}
|
|
5733
|
+
const started = Date.now();
|
|
5734
|
+
const startedAt = new Date(started).toISOString();
|
|
5735
|
+
const events = [];
|
|
5736
|
+
try {
|
|
5737
|
+
const result = await agent.agent.callTool(toolName, JSON.stringify(body.args), {
|
|
5738
|
+
emitStreamEvent(event) {
|
|
5739
|
+
events.push(event);
|
|
5740
|
+
}
|
|
5741
|
+
});
|
|
5742
|
+
const ended = Date.now();
|
|
5743
|
+
return c.json({
|
|
5744
|
+
agentId,
|
|
5745
|
+
toolName,
|
|
5746
|
+
status: "success",
|
|
5747
|
+
result: toJsonValue2(result),
|
|
5748
|
+
durationMs: ended - started,
|
|
5749
|
+
startedAt,
|
|
5750
|
+
endedAt: new Date(ended).toISOString(),
|
|
5751
|
+
events: events.map(toJsonValue2)
|
|
5752
|
+
});
|
|
5753
|
+
} catch (error) {
|
|
5754
|
+
const ended = Date.now();
|
|
5755
|
+
return c.json(
|
|
5756
|
+
{
|
|
5757
|
+
agentId,
|
|
5758
|
+
toolName,
|
|
5759
|
+
status: "error",
|
|
5760
|
+
error: serializeUnknown(error),
|
|
5761
|
+
durationMs: ended - started,
|
|
5762
|
+
startedAt,
|
|
5763
|
+
endedAt: new Date(ended).toISOString(),
|
|
5764
|
+
events: events.map(toJsonValue2)
|
|
5765
|
+
},
|
|
5766
|
+
500
|
|
5767
|
+
);
|
|
5768
|
+
}
|
|
5769
|
+
});
|
|
5770
|
+
}
|
|
5771
|
+
async function parseToolRunRequest(c) {
|
|
5772
|
+
let body;
|
|
5773
|
+
try {
|
|
5774
|
+
body = await c.req.json();
|
|
5775
|
+
} catch {
|
|
5776
|
+
return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
|
|
5777
|
+
}
|
|
5778
|
+
if (body === void 0 || body === null) {
|
|
5779
|
+
return { args: {} };
|
|
5780
|
+
}
|
|
5781
|
+
if (!isJsonObject2(body)) {
|
|
5782
|
+
return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
|
|
5783
|
+
}
|
|
5784
|
+
const args = Object.hasOwn(body, "args") ? body.args : {};
|
|
5785
|
+
if (!isJsonValue2(args)) {
|
|
5786
|
+
return { error: errorResponse(c, 400, "bad_request", "args must be JSON-compatible") };
|
|
5787
|
+
}
|
|
5788
|
+
const request = { args };
|
|
5789
|
+
if (Object.hasOwn(body, "context")) {
|
|
5790
|
+
if (!isJsonObject2(body.context)) {
|
|
5791
|
+
return { error: errorResponse(c, 400, "bad_request", "context must be an object") };
|
|
5792
|
+
}
|
|
5793
|
+
request.context = body.context;
|
|
5794
|
+
}
|
|
5795
|
+
return request;
|
|
4940
5796
|
}
|
|
4941
5797
|
async function agentToolMetadata(agent) {
|
|
4942
5798
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -5067,11 +5923,15 @@ var Studio = class {
|
|
|
5067
5923
|
function studioOptionsFromTargets(targets, options) {
|
|
5068
5924
|
const agents = targets.filter((target) => target instanceof Agent);
|
|
5069
5925
|
const pipelines = targets.filter(
|
|
5926
|
+
// biome-ignore lint/suspicious/noExplicitAny: Studio accepts heterogeneous user pipelines.
|
|
5070
5927
|
(target) => target instanceof Pipeline
|
|
5071
5928
|
);
|
|
5072
5929
|
return {
|
|
5073
5930
|
agents: inferStudioAgents(agents, options.quickPrompts ?? {}),
|
|
5074
|
-
pipelines: inferStudioPipelines(pipelines)
|
|
5931
|
+
pipelines: inferStudioPipelines(pipelines),
|
|
5932
|
+
evals: options.evals ?? [],
|
|
5933
|
+
...options.stores === void 0 ? {} : { stores: options.stores },
|
|
5934
|
+
...options.ui === void 0 ? {} : { ui: options.ui }
|
|
5075
5935
|
};
|
|
5076
5936
|
}
|
|
5077
5937
|
function inferStudioAgents(agents, quickPrompts) {
|
|
@@ -5122,11 +5982,13 @@ function agentMetadata(agent) {
|
|
|
5122
5982
|
};
|
|
5123
5983
|
}
|
|
5124
5984
|
function createStudioApp(options) {
|
|
5125
|
-
const
|
|
5985
|
+
const observabilityHub = new StudioObservabilityHub();
|
|
5986
|
+
const stores = observeStores(resolveStores(options), observabilityHub);
|
|
5126
5987
|
const agents = normalizeAgents(options.agents).map((agent) => withStudioSessionMemory(agent, stores.sessions)).map((agent) => withStudioTraceObserver(agent, stores.traces));
|
|
5127
5988
|
const pipelines = normalizePipelines(options.pipelines);
|
|
5128
5989
|
const agentMap = new Map(agents.map((agent) => [agent.id, agent]));
|
|
5129
5990
|
const pipelineMap = new Map(pipelines.map((pipeline) => [pipeline.id, pipeline]));
|
|
5991
|
+
const evalMap = new Map(options.evals.map((suite) => [suite.id ?? suite.name, suite]));
|
|
5130
5992
|
const approvalRuntime = createApprovalRuntime();
|
|
5131
5993
|
const questionRuntime = createQuestionRuntime();
|
|
5132
5994
|
const app = new HonoApp();
|
|
@@ -5149,6 +6011,7 @@ function createStudioApp(options) {
|
|
|
5149
6011
|
})
|
|
5150
6012
|
);
|
|
5151
6013
|
app.get("/config", (c) => c.json(buildConfig(options, agents, pipelines, stores)));
|
|
6014
|
+
registerStatusRoutes(app, { options, agents, pipelines, stores });
|
|
5152
6015
|
app.get("/agents", (c) => c.json({ agents: agents.map(agentConfig) }));
|
|
5153
6016
|
app.get("/agents/:agentId", (c) => {
|
|
5154
6017
|
const agent = agentMap.get(c.req.param("agentId"));
|
|
@@ -5157,10 +6020,22 @@ function createStudioApp(options) {
|
|
|
5157
6020
|
}
|
|
5158
6021
|
return c.json(agentConfig(agent));
|
|
5159
6022
|
});
|
|
6023
|
+
app.get("/agents/:agentId/runtime", (c) => {
|
|
6024
|
+
const agent = agentMap.get(c.req.param("agentId"));
|
|
6025
|
+
if (agent === void 0) {
|
|
6026
|
+
return errorResponse(c, 404, "not_found", "Agent not found");
|
|
6027
|
+
}
|
|
6028
|
+
return c.json(agentRuntimeSummary(agent));
|
|
6029
|
+
});
|
|
5160
6030
|
registerMcpRoutes(app, { agentMap });
|
|
5161
6031
|
registerToolRoutes(app, { agentMap });
|
|
5162
6032
|
registerApprovalRoutes(app, approvalRuntime);
|
|
5163
6033
|
registerQuestionRoutes(app, questionRuntime);
|
|
6034
|
+
registerObservabilityRoutes(app, observabilityHub);
|
|
6035
|
+
registerEvalRoutes(app, {
|
|
6036
|
+
evals: options.evals,
|
|
6037
|
+
evalMap
|
|
6038
|
+
});
|
|
5164
6039
|
registerKnowledgeRoutes(app, {
|
|
5165
6040
|
agents,
|
|
5166
6041
|
...stores.traces === void 0 ? {} : { traceStore: stores.traces }
|
|
@@ -5348,6 +6223,9 @@ function createStudioApp(options) {
|
|
|
5348
6223
|
}
|
|
5349
6224
|
});
|
|
5350
6225
|
if (stores.sessions !== void 0) {
|
|
6226
|
+
registerMemoryRoutes(app, {
|
|
6227
|
+
sessionStore: stores.sessions
|
|
6228
|
+
});
|
|
5351
6229
|
registerSessionRoutes(app, {
|
|
5352
6230
|
agentMap,
|
|
5353
6231
|
sessionStore: stores.sessions,
|
|
@@ -5474,6 +6352,7 @@ function approvalRequestHandler(hook) {
|
|
|
5474
6352
|
export {
|
|
5475
6353
|
Studio,
|
|
5476
6354
|
StudioTraceObserver,
|
|
6355
|
+
createInMemoryStudioStore,
|
|
5477
6356
|
createSqliteSessionStore
|
|
5478
6357
|
};
|
|
5479
6358
|
//# sourceMappingURL=index.js.map
|