@anvia/studio 0.6.0 → 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/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
- ...this.props.args.trace?.name === void 0 ? {} : { name: this.props.args.trace.name },
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
- ...result.output === void 0 ? {} : { output: result.output },
206
- ...result.error === void 0 ? {} : { error: result.error },
207
- ...result.usage === void 0 ? {} : { usage: result.usage },
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
- ...agentName === void 0 ? {} : { agentName }
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
- ...agentName === void 0 ? {} : { agentName },
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
- ...start?.input === void 0 ? {} : { input: start.input },
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
- ...agentName === void 0 ? {} : { agentName },
306
+ ...compact({ agentName }),
280
307
  childTurn,
281
308
  toolName,
282
- ...callId === void 0 ? {} : { toolCallId: callId },
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
- ...input === void 0 ? {} : { input },
331
+ ...compact({ input }),
305
332
  ...typeof child.result === "string" ? { output: parseOrString(child.result) } : {},
306
333
  metadata: {
307
334
  ...this.childMetadata(agentId, agentName, childTurn),
308
- ...toolCallId === void 0 ? {} : { toolCallId },
309
- ...internalCallId === void 0 ? {} : { internalCallId }
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
- ...props.input === void 0 ? {} : { input: props.input },
408
- ...props.output === void 0 ? {} : { output: props.output },
409
- ...props.error === void 0 ? {} : { error: props.error },
410
- ...props.metadata === void 0 ? {} : { metadata: props.metadata }
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,427 +851,413 @@ import {
824
851
  parseToolArgs
825
852
  } from "@anvia/core/tool";
826
853
 
827
- // src/runtime/transcript.ts
828
- function renumberTranscript(entries) {
829
- return entries.map((entry, entryId) => ({ ...entry, entryId }));
854
+ // src/runtime/type-guards.ts
855
+ function isObject(value) {
856
+ return typeof value === "object" && value !== null && !Array.isArray(value);
830
857
  }
831
- function transcriptFromMessages(messages) {
832
- const transcript = [];
833
- for (const message of messages) {
834
- if (message.role === "system") {
835
- continue;
836
- }
837
- if (message.role === "user") {
838
- const attachments = attachmentsFromMessage(message);
839
- let textEntryAdded = false;
840
- for (const content of message.content) {
841
- if (content.type === "text") {
842
- transcript.push({
843
- entryId: transcript.length,
844
- kind: "message",
845
- role: "user",
846
- text: content.text,
847
- ...attachments.length === 0 ? {} : { attachments }
848
- });
849
- textEntryAdded = true;
850
- }
851
- }
852
- if (!textEntryAdded && attachments.length > 0) {
853
- transcript.push({
854
- entryId: transcript.length,
855
- kind: "message",
856
- role: "user",
857
- text: "",
858
- attachments
859
- });
860
- }
861
- continue;
862
- }
863
- if (message.role === "tool") {
864
- for (const content of message.content) {
865
- transcript.push({
866
- entryId: transcript.length,
867
- kind: "tool",
868
- toolName: "tool_result",
869
- callId: content.callId ?? content.id,
870
- result: content.content.map(
871
- (item) => "text" in item ? item.text : `[image:${item.mediaType ?? "image/png"}]`
872
- ).join("\n"),
873
- structuredResult: content.content
874
- });
875
- }
876
- continue;
877
- }
878
- for (const content of message.content) {
879
- if (content.type === "text") {
880
- appendAssistantTranscriptText(transcript, content.text);
881
- } else if (content.type === "reasoning") {
882
- transcript.push({
883
- entryId: transcript.length,
884
- kind: "reasoning",
885
- ...content.id === void 0 ? {} : { reasoningId: content.id },
886
- text: content.text
887
- });
888
- } else if (content.type === "tool_call") {
889
- transcript.push({
890
- entryId: transcript.length,
891
- kind: "tool",
892
- toolName: content.function.name,
893
- callId: content.callId ?? content.id,
894
- args: formatJson(content.function.arguments)
895
- });
896
- }
897
- }
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;
898
864
  }
899
- return transcript;
865
+ if (Array.isArray(value)) {
866
+ return value.every(isJsonValue);
867
+ }
868
+ return isJsonObject(value);
900
869
  }
901
- function attachmentsFromMessage(message) {
902
- if (message.role !== "user" && message.role !== "assistant") {
903
- return [];
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;
904
876
  }
905
- return message.content.flatMap((content) => {
906
- if (content.type === "image") {
907
- return [
908
- {
909
- kind: "image",
910
- ...content.source.type === "base64" ? { data: content.source.data, mediaType: content.source.mediaType } : { url: content.source.url }
911
- }
912
- ];
913
- }
914
- if (content.type === "document") {
915
- return [
916
- {
917
- kind: "document",
918
- ...content.source.filename === void 0 ? {} : { name: content.source.filename },
919
- ...content.source.mediaType === void 0 ? {} : { mediaType: content.source.mediaType },
920
- ...content.source.type === "base64" ? { data: content.source.data } : content.source.type === "url" ? { url: content.source.url } : {}
921
- }
922
- ];
923
- }
924
- return [];
925
- });
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;
926
884
  }
927
- function appendAssistantTranscriptText(transcript, text) {
928
- const last = transcript.at(-1);
929
- if (last?.kind === "message" && last.role === "assistant") {
930
- last.text = `${last.text}${text}`;
931
- return;
885
+ function isAgentTraceOptions(value) {
886
+ if (!isObject(value)) {
887
+ return false;
932
888
  }
933
- transcript.push({
934
- entryId: transcript.length,
935
- kind: "message",
936
- role: "assistant",
937
- text
938
- });
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);
939
890
  }
940
- function formatJson(value) {
941
- try {
942
- return JSON.stringify(value, null, 2);
943
- } catch {
944
- return String(value);
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;
945
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);
946
934
  }
947
935
 
948
- // src/storage/memory-store.ts
949
- function createInMemoryStudioStore() {
950
- return new InMemoryStudioStore();
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;
951
940
  }
952
- var InMemoryStudioStore = class {
953
- kind = "memory";
954
- sessions = /* @__PURE__ */ new Map();
955
- traces = /* @__PURE__ */ new Map();
956
- pipelineLogs = /* @__PURE__ */ new Map();
957
- pipelineRuns = /* @__PURE__ */ new Map();
958
- listSessions(options) {
959
- 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;
960
944
  }
961
- createSession(input) {
962
- const now = (/* @__PURE__ */ new Date()).toISOString();
963
- const session = {
964
- id: input.id,
965
- agentId: input.agentId,
966
- ...input.title === void 0 ? {} : { title: input.title },
967
- createdAt: now,
968
- updatedAt: now,
969
- messageCount: 0,
970
- ...input.metadata === void 0 ? {} : { metadata: input.metadata },
971
- messages: [],
972
- runs: [],
973
- logs: []
974
- };
975
- this.sessions.set(input.id, session);
976
- return sessionSummary(session);
945
+ const limit = Number(value);
946
+ if (!Number.isInteger(limit) || limit <= 0) {
947
+ return void 0;
977
948
  }
978
- getSession(id) {
979
- const session = this.sessions.get(id);
980
- return session === void 0 ? void 0 : materializeSession(session);
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;
981
955
  }
982
- updateSessionMetadata(id, metadata) {
983
- const session = this.sessions.get(id);
984
- if (session === void 0) {
985
- return void 0;
986
- }
987
- if (metadata === void 0) {
988
- delete session.metadata;
989
- } else {
990
- session.metadata = metadata;
991
- }
992
- session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
993
- return materializeSession(session);
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;
994
961
  }
995
- load(context) {
996
- return Promise.resolve(this.sessions.get(context.sessionId)?.messages ?? []);
962
+ const after = Number(value);
963
+ if (!Number.isInteger(after) || after < 0) {
964
+ return false;
997
965
  }
998
- append(input) {
999
- const session = this.sessions.get(input.context.sessionId);
1000
- if (session !== void 0) {
1001
- session.messages.push(...input.messages);
1002
- session.messageCount = session.messages.length;
1003
- session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
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");
1004
975
  }
1005
- return Promise.resolve();
1006
- }
1007
- clear(context) {
1008
- const session = this.sessions.get(context.sessionId);
1009
- if (session !== void 0) {
1010
- session.messages = [];
1011
- session.runs = [];
1012
- session.messageCount = 0;
1013
- session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
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;
1014
982
  }
1015
- return Promise.resolve();
1016
- }
1017
- async recordError(input) {
1018
- await this.saveSessionRunTranscript({
1019
- id: input.context.sessionId,
1020
- runId: studioRunId(input.context) ?? input.runId,
1021
- transcript: transcriptFromMessages(input.messages),
1022
- status: "error",
1023
- error: serializeJsonError(input.error)
1024
- });
1025
- }
1026
- saveSessionRunTranscript(input) {
1027
- const session = this.sessions.get(input.id);
1028
- if (session === void 0) {
1029
- return void 0;
983
+ if (runId !== void 0) {
984
+ options.runId = runId;
1030
985
  }
1031
- const now = (/* @__PURE__ */ new Date()).toISOString();
1032
- const existingIndex = session.runs.findIndex((run2) => run2.runId === input.runId);
1033
- const run = {
1034
- ...input,
1035
- transcript: renumberTranscript(input.transcript),
1036
- createdAt: existingIndex === -1 ? now : session.runs[existingIndex]?.createdAt ?? now,
1037
- updatedAt: now
1038
- };
1039
- if (existingIndex === -1) {
1040
- session.runs.push(run);
1041
- } else {
1042
- session.runs[existingIndex] = run;
986
+ if (agentId !== void 0) {
987
+ options.agentId = agentId;
1043
988
  }
1044
- session.updatedAt = now;
1045
- return materializeSession(session);
1046
- }
1047
- appendSessionLog(input) {
1048
- const session = this.sessions.get(input.sessionId);
1049
- const logs = session?.logs ?? [];
1050
- const entry = {
1051
- id: globalThis.crypto.randomUUID(),
1052
- sessionId: input.sessionId,
1053
- ...input.runId === void 0 ? {} : { runId: input.runId },
1054
- sequence: logs.length,
1055
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1056
- level: input.level,
1057
- category: input.category,
1058
- event: input.event,
1059
- message: input.message,
1060
- ...input.metadata === void 0 ? {} : { metadata: input.metadata }
1061
- };
1062
- if (session !== void 0) {
1063
- session.logs.push(entry);
1064
- session.updatedAt = entry.timestamp;
989
+ if (sessionId !== void 0) {
990
+ options.sessionId = sessionId;
1065
991
  }
1066
- return entry;
1067
- }
1068
- listSessionLogs(options) {
1069
- return (this.sessions.get(options.sessionId)?.logs ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
1070
- }
1071
- deleteSession(id) {
1072
- for (const trace of this.traces.values()) {
1073
- if (trace.sessionId === id) {
1074
- this.traces.delete(trace.id);
1075
- }
992
+ return c.json({
993
+ approvals: approvals.list(options)
994
+ });
995
+ });
996
+ app.post("/approvals/:approvalId/decision", async (c) => {
997
+ const body = await parseApprovalDecisionRequest(c);
998
+ if ("error" in body) {
999
+ return body.error;
1076
1000
  }
1077
- return this.sessions.delete(id);
1078
- }
1079
- listTraces(options) {
1080
- 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);
1081
- }
1082
- listSessionTraces(options) {
1083
- return this.listTraces({ sessionId: options.sessionId, limit: options.limit });
1084
- }
1085
- getTrace(id) {
1086
- return this.traces.get(id);
1087
- }
1088
- saveTrace(trace) {
1089
- this.traces.set(trace.id, trace);
1090
- return trace;
1091
- }
1092
- appendPipelineLog(input) {
1093
- const logs = this.pipelineLogs.get(input.pipelineId) ?? [];
1094
- const entry = {
1095
- id: globalThis.crypto.randomUUID(),
1096
- pipelineId: input.pipelineId,
1097
- ...input.runId === void 0 ? {} : { runId: input.runId },
1098
- sequence: logs.length,
1099
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1100
- level: input.level,
1101
- category: input.category,
1102
- event: input.event,
1103
- message: input.message,
1104
- ...input.metadata === void 0 ? {} : { metadata: input.metadata }
1105
- };
1106
- this.pipelineLogs.set(input.pipelineId, [...logs, entry]);
1107
- return entry;
1108
- }
1109
- listPipelineLogs(options) {
1110
- return (this.pipelineLogs.get(options.pipelineId) ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
1111
- }
1112
- savePipelineRun(input) {
1113
- const record = {
1114
- runId: input.runId,
1115
- pipelineId: input.pipelineId,
1116
- status: input.status,
1117
- input: input.input,
1118
- ...input.output === void 0 ? {} : { output: input.output },
1119
- ...input.error === void 0 ? {} : { error: input.error },
1120
- ...input.metadata === void 0 ? {} : { metadata: input.metadata },
1121
- startedAt: input.startedAt,
1122
- ...input.endedAt === void 0 ? {} : { endedAt: input.endedAt },
1123
- ...input.durationMs === void 0 ? {} : { durationMs: input.durationMs }
1124
- };
1125
- this.pipelineRuns.set(input.runId, record);
1126
- return record;
1127
- }
1128
- getPipelineRun(options) {
1129
- const run = this.pipelineRuns.get(options.runId);
1130
- return run?.pipelineId === options.pipelineId ? run : void 0;
1131
- }
1132
- listPipelineRuns(options) {
1133
- 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);
1134
- }
1135
- };
1136
- function sessionSummary(session) {
1137
- return {
1138
- id: session.id,
1139
- agentId: session.agentId,
1140
- ...session.title === void 0 ? {} : { title: session.title },
1141
- createdAt: session.createdAt,
1142
- updatedAt: session.updatedAt,
1143
- messageCount: session.messages.length,
1144
- ...session.metadata === void 0 ? {} : { metadata: session.metadata }
1145
- };
1146
- }
1147
- function materializeSession(session) {
1148
- return {
1149
- ...sessionSummary(session),
1150
- messages: [...session.messages],
1151
- transcript: renumberTranscript(session.runs.flatMap((run) => run.transcript))
1152
- };
1153
- }
1154
- function traceSummary(trace) {
1155
- return {
1156
- id: trace.id,
1157
- sessionId: trace.sessionId,
1158
- ...trace.name === void 0 ? {} : { name: trace.name },
1159
- status: trace.status,
1160
- startedAt: trace.startedAt,
1161
- ...trace.endedAt === void 0 ? {} : { endedAt: trace.endedAt },
1162
- ...trace.durationMs === void 0 ? {} : { durationMs: trace.durationMs },
1163
- ...trace.output === void 0 ? {} : { output: trace.output },
1164
- ...trace.error === void 0 ? {} : { error: trace.error },
1165
- ...trace.usage === void 0 ? {} : { usage: trace.usage },
1166
- ...trace.metadata === void 0 ? {} : { metadata: trace.metadata },
1167
- observationCount: trace.observations.length
1168
- };
1169
- }
1170
- function traceAgentId(trace) {
1171
- const nestedMetadata = trace.metadata?.metadata;
1172
- return isJsonObject(nestedMetadata) && typeof nestedMetadata.agentId === "string" ? nestedMetadata.agentId : void 0;
1173
- }
1174
- function studioRunId(context) {
1175
- const value = context.metadata?.studioRunId;
1176
- return typeof value === "string" && value.length > 0 ? value : void 0;
1001
+ const result = approvals.decide(c.req.param("approvalId"), body);
1002
+ if (result === "missing") {
1003
+ return errorResponse(c, 404, "not_found", "Approval not found");
1004
+ }
1005
+ if (result === "resolved") {
1006
+ return errorResponse(c, 409, "conflict", "Approval is already resolved");
1007
+ }
1008
+ return c.json(result);
1009
+ });
1177
1010
  }
1178
- function serializeJsonError(error) {
1179
- if (error instanceof Error) {
1180
- return {
1181
- name: error.name,
1182
- message: error.message
1183
- };
1011
+ function parseApprovalStatus(value) {
1012
+ const status = optionalQueryString(value);
1013
+ if (status === void 0) {
1014
+ return void 0;
1184
1015
  }
1185
- return isJsonValue(error) ? error : String(error);
1186
- }
1187
- function isJsonObject(value) {
1188
- return typeof value === "object" && value !== null && !Array.isArray(value);
1016
+ return status === "pending" || status === "resolved" ? status : false;
1189
1017
  }
1190
- function isJsonValue(value) {
1191
- if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1192
- return true;
1018
+ async function parseApprovalDecisionRequest(c) {
1019
+ let body;
1020
+ try {
1021
+ body = await c.req.json();
1022
+ } catch {
1023
+ return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
1193
1024
  }
1194
- if (Array.isArray(value)) {
1195
- return value.every(isJsonValue);
1025
+ if (!isObject(body)) {
1026
+ return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
1196
1027
  }
1197
- return isJsonObject(value) && Object.values(value).every(isJsonValue);
1198
- }
1199
-
1200
- // src/runtime/models.ts
1201
- var STUDIO_MODEL_METADATA_KEY = "studioModel";
1202
- function createStudioModelRegistry(config) {
1203
- if (config === void 0) {
1204
- return void 0;
1028
+ if (typeof body.approved !== "boolean") {
1029
+ return { error: errorResponse(c, 400, "bad_request", "approved must be a boolean") };
1205
1030
  }
1206
- const providers = /* @__PURE__ */ new Map();
1207
- for (const provider of config.providers) {
1208
- const id = normalizeProviderId(provider.id);
1209
- if (providers.has(id)) {
1210
- throw new Error(`Duplicate Studio model provider id: ${id}`);
1211
- }
1212
- const staticModels = /* @__PURE__ */ new Map();
1213
- for (const model of provider.models ?? []) {
1214
- const modelId = normalizeModelId(model.id);
1215
- if (staticModels.has(modelId)) {
1216
- throw new Error(`Duplicate Studio model id for provider ${id}: ${modelId}`);
1217
- }
1218
- staticModels.set(modelId, { ...model, id: modelId });
1219
- }
1220
- providers.set(id, {
1221
- ...provider,
1222
- id,
1223
- ...provider.defaultModel === void 0 ? {} : { defaultModel: normalizeModelId(provider.defaultModel) },
1224
- staticModels
1225
- });
1031
+ if ("reason" in body && typeof body.reason !== "string") {
1032
+ return { error: errorResponse(c, 400, "bad_request", "reason must be a string") };
1226
1033
  }
1227
- return {
1228
- ...config.default === void 0 ? {} : { defaultModel: normalizeModelRef(config.default) },
1229
- providers,
1230
- agentPolicies: normalizeAgentPolicies(config.agents ?? {}),
1231
- modelCache: /* @__PURE__ */ new Map()
1232
- };
1034
+ return compact({
1035
+ approved: body.approved,
1036
+ reason: typeof body.reason === "string" && body.reason.trim().length > 0 ? body.reason.trim() : void 0
1037
+ });
1233
1038
  }
1234
- function studioModelsConfig(registry, agents) {
1235
- if (registry === void 0) {
1236
- return void 0;
1237
- }
1238
- const providers = [...registry.providers.values()].map((provider) => {
1239
- const models = [...provider.staticModels.values()].map(
1039
+ function createApprovalRuntime() {
1040
+ const approvals = /* @__PURE__ */ new Map();
1041
+ return {
1042
+ approvals,
1043
+ createHook(context) {
1044
+ const handleApprovalRequest = async ({ toolName, toolCallId, internalCallId, args, tool: control }, request) => {
1045
+ const decision = await requestApproval(approvals, context, compact({
1046
+ toolName,
1047
+ toolCallId,
1048
+ internalCallId,
1049
+ args,
1050
+ reason: request.reason,
1051
+ rejectMessage: request.rejectMessage
1052
+ }));
1053
+ return decision.approved ? control.run() : control.skip(decision.reason ?? request.rejectMessage ?? "Rejected in Anvia Studio.");
1054
+ };
1055
+ return {
1056
+ ...createHook({
1057
+ async onToolCall({ toolName, toolCallId, internalCallId, args, tool: control }) {
1058
+ const registeredTool = context.getTool(toolName);
1059
+ if (registeredTool?.approval === void 0) {
1060
+ return control.run();
1061
+ }
1062
+ const approval = registeredTool.approval;
1063
+ const rawParsedArgs = parseToolArgs(args);
1064
+ const parsedArgs = registeredTool.parseApprovalArgs?.(rawParsedArgs) ?? rawParsedArgs;
1065
+ const approvalContext = compact({
1066
+ toolName,
1067
+ args: parsedArgs,
1068
+ rawArgs: args,
1069
+ toolCallId,
1070
+ internalCallId,
1071
+ run: compact({
1072
+ agentId: context.agentId,
1073
+ runId: context.runId,
1074
+ sessionId: context.sessionId,
1075
+ metadata: context.metadata
1076
+ })
1077
+ });
1078
+ const required = await approval.when(approvalContext);
1079
+ if (!required) {
1080
+ return control.run();
1081
+ }
1082
+ const reason = await resolveApprovalText(approval.reason, approvalContext);
1083
+ const rejectMessage = await resolveApprovalText(
1084
+ approval.rejectMessage,
1085
+ approvalContext
1086
+ );
1087
+ const decision = await requestApproval(approvals, context, compact({
1088
+ toolName,
1089
+ toolCallId,
1090
+ internalCallId,
1091
+ args,
1092
+ reason,
1093
+ rejectMessage
1094
+ }));
1095
+ return decision.approved ? control.run() : control.skip(decision.reason ?? rejectMessage ?? "Rejected in Anvia Studio.");
1096
+ }
1097
+ }),
1098
+ handleApprovalRequest
1099
+ };
1100
+ },
1101
+ list(options) {
1102
+ return [...approvals.values()].filter((approval) => {
1103
+ if (options.status === "pending" && approval.status !== "pending") {
1104
+ return false;
1105
+ }
1106
+ if (options.status === "resolved" && approval.status === "pending") {
1107
+ return false;
1108
+ }
1109
+ if (options.runId !== void 0 && approval.runId !== options.runId) {
1110
+ return false;
1111
+ }
1112
+ if (options.agentId !== void 0 && approval.agentId !== options.agentId) {
1113
+ return false;
1114
+ }
1115
+ if (options.sessionId !== void 0 && approval.sessionId !== options.sessionId) {
1116
+ return false;
1117
+ }
1118
+ return true;
1119
+ }).map(publicApproval);
1120
+ },
1121
+ decide(id, decision) {
1122
+ const approval = approvals.get(id);
1123
+ if (approval === void 0) {
1124
+ return "missing";
1125
+ }
1126
+ if (!isPendingApproval(approval)) {
1127
+ return "resolved";
1128
+ }
1129
+ const reason = decision.approved ? decision.reason : decision.reason ?? approval.rejectMessage ?? "Rejected in Anvia Studio.";
1130
+ const resolved = resolveApproval(approval, decision.approved ? "approved" : "rejected", compact({ reason }));
1131
+ approvals.set(id, resolved);
1132
+ approval.emit?.({ type: "tool_approval_result", approval: resolved });
1133
+ approval.resolve(compact({
1134
+ approved: decision.approved,
1135
+ reason
1136
+ }));
1137
+ return publicApproval(resolved);
1138
+ }
1139
+ };
1140
+ }
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(
1240
1255
  (model) => modelSummary(provider, model.id, model)
1241
1256
  );
1242
1257
  return {
1243
1258
  id: provider.id,
1244
- ...provider.name === void 0 ? {} : { name: provider.name },
1245
- ...provider.defaultModel === void 0 ? {} : { defaultModel: provider.defaultModel },
1246
- models,
1247
- ...provider.metadata === void 0 ? {} : { metadata: provider.metadata }
1259
+ ...compact({ name: provider.name, defaultModel: provider.defaultModel, metadata: provider.metadata }),
1260
+ models
1248
1261
  };
1249
1262
  });
1250
1263
  const agentIds = new Set(agents.map((agent) => agent.id));
@@ -1253,7 +1266,7 @@ function studioModelsConfig(registry, agents) {
1253
1266
  );
1254
1267
  return {
1255
1268
  providers,
1256
- ...registry.defaultModel === void 0 ? {} : { default: registry.defaultModel },
1269
+ ...compact({ default: registry.defaultModel }),
1257
1270
  agents: agentsConfig
1258
1271
  };
1259
1272
  }
@@ -1267,7 +1280,7 @@ function registerModelRoutes(app, props) {
1267
1280
  );
1268
1281
  return c.json({
1269
1282
  providers,
1270
- ...props.registry.defaultModel === void 0 ? {} : { defaultModel: props.registry.defaultModel }
1283
+ ...compact({ defaultModel: props.registry.defaultModel })
1271
1284
  });
1272
1285
  });
1273
1286
  app.get("/models/:providerId", async (c) => {
@@ -1380,9 +1393,9 @@ async function agentModelsCatalog(registry, agent) {
1380
1393
  const defaultModel = policy?.default ?? registry.defaultModel;
1381
1394
  return {
1382
1395
  agentId: agent.id,
1383
- ...defaultModel === void 0 ? {} : { defaultModel },
1396
+ ...compact({ defaultModel }),
1384
1397
  models: [...models, ...exactPolicyModels],
1385
- ...warnings.length === 0 ? {} : { warnings }
1398
+ ...compact({ warnings: warnings.length === 0 ? void 0 : warnings })
1386
1399
  };
1387
1400
  }
1388
1401
  async function providerCatalog(provider) {
@@ -1400,14 +1413,15 @@ async function providerCatalog(provider) {
1400
1413
  model.id,
1401
1414
  modelSummary(provider, model.id, {
1402
1415
  id: model.id,
1403
- ...model.name === void 0 ? {} : { name: model.name },
1404
- ...model.description === void 0 ? {} : { description: model.description },
1416
+ ...compact({ name: model.name, description: model.description }),
1405
1417
  ...staticModel ?? {},
1406
1418
  metadata: {
1407
- ...model.type === void 0 ? {} : { type: model.type },
1408
- ...model.createdAt === void 0 ? {} : { createdAt: model.createdAt },
1409
- ...model.ownedBy === void 0 ? {} : { ownedBy: model.ownedBy },
1410
- ...model.contextLength === void 0 ? {} : { contextLength: model.contextLength },
1419
+ ...compact({
1420
+ type: model.type,
1421
+ createdAt: model.createdAt,
1422
+ ownedBy: model.ownedBy,
1423
+ contextLength: model.contextLength
1424
+ }),
1411
1425
  ...staticModel?.metadata ?? {}
1412
1426
  }
1413
1427
  })
@@ -1420,11 +1434,8 @@ async function providerCatalog(provider) {
1420
1434
  }
1421
1435
  return {
1422
1436
  id: provider.id,
1423
- ...provider.name === void 0 ? {} : { name: provider.name },
1424
- ...provider.defaultModel === void 0 ? {} : { defaultModel: provider.defaultModel },
1425
- models: [...models.values()].sort((left, right) => left.ref.localeCompare(right.ref)),
1426
- ...provider.metadata === void 0 ? {} : { metadata: provider.metadata },
1427
- ...warning === void 0 ? {} : { warning }
1437
+ ...compact({ name: provider.name, defaultModel: provider.defaultModel, metadata: provider.metadata, warning }),
1438
+ models: [...models.values()].sort((left, right) => left.ref.localeCompare(right.ref))
1428
1439
  };
1429
1440
  }
1430
1441
  function modelSummary(provider, modelId, model) {
@@ -1433,7 +1444,7 @@ function modelSummary(provider, modelId, model) {
1433
1444
  id: modelId,
1434
1445
  ref: `${provider.id}:${modelId}`,
1435
1446
  providerId: provider.id,
1436
- ...provider.name === void 0 ? {} : { providerName: provider.name }
1447
+ ...compact({ providerName: provider.name })
1437
1448
  };
1438
1449
  }
1439
1450
  function ensureModelAllowed(registry, agentId, ref) {
@@ -1456,21 +1467,18 @@ function normalizeAgentPolicies(policies) {
1456
1467
  Object.entries(policies).map(([agentId, policy]) => [
1457
1468
  agentId.trim(),
1458
1469
  {
1459
- ...policy.default === void 0 ? {} : { default: normalizeModelRef(policy.default) },
1460
- ...policy.allowed === void 0 ? {} : {
1461
- allowed: policy.allowed.map(
1470
+ ...compact({
1471
+ default: policy.default !== void 0 ? normalizeModelRef(policy.default) : void 0,
1472
+ allowed: policy.allowed?.map(
1462
1473
  (entry) => typeof entry === "string" && entry.trim().endsWith(":*") ? `${normalizeProviderId(entry.trim().slice(0, -2))}:*` : normalizeModelRef(entry)
1463
1474
  )
1464
- }
1475
+ })
1465
1476
  }
1466
1477
  ])
1467
1478
  );
1468
1479
  }
1469
1480
  function publicPolicy(policy) {
1470
- return {
1471
- ...policy.default === void 0 ? {} : { default: policy.default },
1472
- ...policy.allowed === void 0 ? {} : { allowed: policy.allowed }
1473
- };
1481
+ return compact({ default: policy.default, allowed: policy.allowed });
1474
1482
  }
1475
1483
  function modelWarnings(ref, model, request) {
1476
1484
  const warnings = [];
@@ -1572,126 +1580,69 @@ function agentHasMcpTools(agent) {
1572
1580
  return agentToolItems(agent).some(({ tool }) => mcpServerName(tool) !== void 0);
1573
1581
  }
1574
1582
 
1575
- // src/runtime/shared.ts
1576
- function resolveStores(options) {
1577
- const defaultStore = defaultStudioStore();
1578
- const sessions = resolveSessionStore(options, defaultStore);
1579
- const traces = resolveTraceStore(options, sessions, defaultStore);
1580
- const pipelineLogs = resolvePipelineLogStore(options, sessions, defaultStore);
1581
- const pipelineRuns = resolvePipelineRunStore(options, sessions, pipelineLogs, defaultStore);
1582
- return {
1583
- ...sessions === void 0 ? {} : { sessions },
1584
- ...traces === void 0 ? {} : { traces },
1585
- ...pipelineLogs === void 0 ? {} : { pipelineLogs },
1586
- ...pipelineRuns === void 0 ? {} : { pipelineRuns }
1587
- };
1588
- }
1589
- function defaultStudioStore() {
1590
- return createInMemoryStudioStore();
1583
+ // src/runtime/config.ts
1584
+ function runnerId(options) {
1585
+ return options.id ?? "anvia-studio";
1591
1586
  }
1592
- function resolveSessionStore(options, defaultStore) {
1593
- if (options.stores?.sessions === false) {
1594
- return void 0;
1595
- }
1596
- if (options.stores?.sessions !== void 0) {
1597
- return options.stores.sessions;
1598
- }
1599
- return defaultStore;
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
1596
+ });
1600
1597
  }
1601
- function resolveTraceStore(options, sessionStore, defaultStore) {
1602
- if (options.stores?.traces !== void 0) {
1603
- return options.stores.traces;
1604
- }
1605
- if (sessionStore === void 0) {
1606
- return void 0;
1607
- }
1608
- if (isTraceStore(sessionStore)) {
1609
- return sessionStore;
1610
- }
1611
- return defaultStore;
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
+ });
1612
1621
  }
1613
- function resolvePipelineLogStore(options, sessionStore, defaultStore) {
1614
- if (options.stores?.pipelineLogs === false) {
1615
- return void 0;
1616
- }
1617
- if (options.stores?.pipelineLogs !== void 0) {
1618
- return options.stores.pipelineLogs;
1619
- }
1620
- if (sessionStore !== void 0 && isPipelineLogStore(sessionStore)) {
1621
- return sessionStore;
1622
- }
1623
- return defaultStore;
1624
- }
1625
- function resolvePipelineRunStore(options, sessionStore, pipelineLogStore, defaultStore) {
1626
- if (options.stores?.pipelineRuns === false) {
1627
- return void 0;
1628
- }
1629
- if (options.stores?.pipelineRuns !== void 0) {
1630
- return options.stores.pipelineRuns;
1631
- }
1632
- if (sessionStore !== void 0 && isPipelineRunStore(sessionStore)) {
1633
- return sessionStore;
1634
- }
1635
- if (pipelineLogStore !== void 0 && isPipelineRunStore(pipelineLogStore)) {
1636
- return pipelineLogStore;
1637
- }
1638
- return defaultStore;
1639
- }
1640
- function isTraceStore(store) {
1641
- const candidate = store;
1642
- return typeof candidate.listSessionTraces === "function" && typeof candidate.getTrace === "function" && typeof candidate.saveTrace === "function";
1643
- }
1644
- function isPipelineLogStore(store) {
1645
- const candidate = store;
1646
- return typeof candidate.appendPipelineLog === "function" && typeof candidate.listPipelineLogs === "function";
1647
- }
1648
- function isPipelineRunStore(store) {
1649
- const candidate = store;
1650
- return typeof candidate.savePipelineRun === "function" && typeof candidate.getPipelineRun === "function" && typeof candidate.listPipelineRuns === "function";
1651
- }
1652
- function unsupportedCapabilities(stores) {
1653
- return [
1654
- ...stores.sessions === void 0 ? ["sessions"] : [],
1655
- ...stores.traces === void 0 ? ["traces"] : []
1656
- ];
1657
- }
1658
- function normalizeAgents(agents) {
1659
- const ids = /* @__PURE__ */ new Set();
1660
- return agents.map((agent) => {
1661
- const id = agent.id.trim();
1662
- if (id.length === 0) {
1663
- throw new Error("Studio agent id cannot be empty");
1664
- }
1665
- if (ids.has(id)) {
1666
- throw new Error(`Duplicate runner agent id: ${id}`);
1667
- }
1668
- ids.add(id);
1669
- return { ...agent, id };
1670
- });
1671
- }
1672
- function normalizePipelines(pipelines) {
1673
- const ids = /* @__PURE__ */ new Set();
1674
- return pipelines.map((pipeline) => {
1675
- const id = pipeline.id.trim();
1676
- if (id.length === 0) {
1677
- throw new Error("Studio pipeline id cannot be empty");
1678
- }
1679
- if (ids.has(id)) {
1680
- throw new Error(`Duplicate Studio pipeline id: ${id}`);
1681
- }
1682
- ids.add(id);
1683
- return { ...pipeline, id };
1684
- });
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
+ });
1685
1636
  }
1686
1637
  function buildConfig(options, agents, pipelines, stores) {
1687
1638
  const models = options.models === void 0 ? void 0 : studioModelsConfig(createStudioModelRegistry(options.models), agents);
1688
- return {
1639
+ return compact({
1689
1640
  id: runnerId(options),
1690
- ...options.name === void 0 ? {} : { name: options.name },
1691
- ...options.description === void 0 ? {} : { description: options.description },
1692
- ...options.version === void 0 ? {} : { version: options.version },
1641
+ name: options.name,
1642
+ description: options.description,
1643
+ version: options.version,
1693
1644
  agents: agents.map(agentConfig),
1694
- ...models === void 0 ? {} : { models },
1645
+ models,
1695
1646
  pipelines: pipelines.map(pipelineConfig),
1696
1647
  evals: options.evals.map(evalConfig),
1697
1648
  chat: {
@@ -1699,60 +1650,7 @@ function buildConfig(options, agents, pipelines, stores) {
1699
1650
  },
1700
1651
  capabilities: capabilityConfig(options, agents, pipelines, stores),
1701
1652
  unsupportedCapabilities: unsupportedCapabilities(stores)
1702
- };
1703
- }
1704
- function runnerId(options) {
1705
- return options.id ?? "anvia-studio";
1706
- }
1707
- function agentConfig(agent) {
1708
- const name = agent.name ?? agent.agent.name;
1709
- const description = agent.description ?? agent.agent.description;
1710
- return {
1711
- id: agent.id,
1712
- ...name === void 0 ? {} : { name },
1713
- ...description === void 0 ? {} : { description },
1714
- quickPrompts: agent.quickPrompts ?? [],
1715
- ...agent.metadata === void 0 ? {} : { metadata: agent.metadata }
1716
- };
1717
- }
1718
- function agentRuntimeSummary(agent) {
1719
- const tools = agentToolItems(agent);
1720
- const name = agent.name ?? agent.agent.name;
1721
- const description = agent.description ?? agent.agent.description;
1722
- return {
1723
- id: agent.id,
1724
- ...name === void 0 ? {} : { name },
1725
- ...description === void 0 ? {} : { description },
1726
- model: toJsonValue(agent.agent.model),
1727
- toolCount: tools.length,
1728
- staticToolCount: tools.filter((item) => item.source === "static").length,
1729
- dynamicToolCount: tools.filter((item) => item.source === "dynamic").length,
1730
- approvalToolCount: tools.filter((item) => item.tool.approval !== void 0).length,
1731
- mcpToolCount: tools.filter((item) => mcpServerName(item.tool) !== void 0).length,
1732
- staticContextCount: agent.agent.staticContext.length,
1733
- dynamicContextCount: agent.agent.dynamicContexts.length,
1734
- observerCount: agent.agent.observers.length,
1735
- hasMemory: agent.agent.memory !== void 0,
1736
- hasHook: agent.agent.hook !== void 0,
1737
- hasOutputSchema: agent.agent.outputSchema !== void 0,
1738
- ...agent.agent.defaultMaxTurns === void 0 ? {} : { defaultMaxTurns: agent.agent.defaultMaxTurns },
1739
- ...agent.metadata === void 0 ? {} : { metadata: agent.metadata }
1740
- };
1741
- }
1742
- function pipelineConfig(pipeline) {
1743
- const graph = pipeline.pipeline.graph();
1744
- const stageNodes = graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output");
1745
- return {
1746
- id: pipeline.id,
1747
- ...pipeline.name === void 0 ? {} : { name: pipeline.name },
1748
- ...pipeline.description === void 0 ? {} : { description: pipeline.description },
1749
- ...pipeline.metadata === void 0 ? {} : { metadata: pipeline.metadata },
1750
- stageCount: stageNodes.length,
1751
- edgeCount: graph.edges.length,
1752
- hasParallelStages: graph.nodes.some((node) => node.kind === "parallel"),
1753
- agentCount: graph.nodes.filter((node) => node.kind === "agent").length,
1754
- extractorCount: graph.nodes.filter((node) => node.kind === "extractor").length
1755
- };
1653
+ });
1756
1654
  }
1757
1655
  function capabilityConfig(_options, agents, pipelines, stores) {
1758
1656
  const capabilities = {
@@ -1794,848 +1692,508 @@ function capabilityConfig(_options, agents, pipelines, stores) {
1794
1692
  return capabilities;
1795
1693
  }
1796
1694
  function evalConfig(suite) {
1797
- return {
1695
+ return compact({
1798
1696
  id: suite.id ?? suite.name,
1799
1697
  name: suite.name,
1800
- ...suite.description === void 0 ? {} : { description: suite.description },
1698
+ description: suite.description,
1801
1699
  caseCount: suite.cases.length,
1802
1700
  metricNames: suite.metrics.map((metric) => metric.name),
1803
- ...suite.concurrency === void 0 ? {} : { concurrency: suite.concurrency },
1804
- ...suite.metadata === void 0 ? {} : { metadata: suite.metadata }
1805
- };
1806
- }
1807
- function optionalQueryString(value) {
1808
- const trimmed = value?.trim();
1809
- return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
1810
- }
1811
- function parseLimit(value) {
1812
- if (value === void 0 || value.trim().length === 0) {
1813
- return 50;
1814
- }
1815
- const limit = Number(value);
1816
- if (!Number.isInteger(limit) || limit <= 0) {
1817
- return void 0;
1818
- }
1819
- return Math.min(limit, 100);
1820
- }
1821
- function parseTraceStatus(value) {
1822
- const status = optionalQueryString(value);
1823
- if (status === void 0) {
1824
- return void 0;
1825
- }
1826
- return status === "running" || status === "success" || status === "error" ? status : false;
1827
- }
1828
- function isMessageInput(value) {
1829
- return typeof value === "string" || isMessage(value);
1701
+ concurrency: suite.concurrency,
1702
+ metadata: suite.metadata
1703
+ });
1830
1704
  }
1831
- function isMessage(value) {
1832
- if (!isObject(value) || typeof value.role !== "string") {
1833
- return false;
1834
- }
1835
- if (value.role === "system") {
1836
- return typeof value.content === "string";
1837
- }
1838
- if (value.role === "user" || value.role === "assistant" || value.role === "tool") {
1839
- return Array.isArray(value.content);
1840
- }
1841
- return false;
1705
+ function unsupportedCapabilities(stores) {
1706
+ return [
1707
+ ...stores.sessions === void 0 ? ["sessions"] : [],
1708
+ ...stores.traces === void 0 ? ["traces"] : []
1709
+ ];
1842
1710
  }
1843
- function isObject(value) {
1844
- return typeof value === "object" && value !== null && !Array.isArray(value);
1711
+ function toJsonValue2(value) {
1712
+ return serializeUnknown(value);
1845
1713
  }
1846
- function isJsonObject2(value) {
1847
- return isObject(value) && Object.values(value).every(isJsonValue2);
1714
+
1715
+ // src/runtime/evals.ts
1716
+ function registerEvalRoutes(app, props) {
1717
+ app.get(
1718
+ "/evals",
1719
+ (c) => c.json({
1720
+ evals: props.evals.map(evalConfig)
1721
+ })
1722
+ );
1723
+ app.get("/evals/:evalId", (c) => {
1724
+ const suite = props.evalMap.get(c.req.param("evalId"));
1725
+ if (suite === void 0) {
1726
+ return errorResponse(c, 404, "not_found", "Eval suite not found");
1727
+ }
1728
+ return c.json(evalConfig(suite));
1729
+ });
1730
+ app.post("/evals/:evalId/runs", async (c) => {
1731
+ const suite = props.evalMap.get(c.req.param("evalId"));
1732
+ if (suite === void 0) {
1733
+ return errorResponse(c, 404, "not_found", "Eval suite not found");
1734
+ }
1735
+ const body = await parseEvalRunRequest(c);
1736
+ if ("error" in body) {
1737
+ return body.error;
1738
+ }
1739
+ const runId = globalThis.crypto.randomUUID();
1740
+ const startedAt = Date.now();
1741
+ const result = await runEvalSuite({
1742
+ ...suite,
1743
+ ...compact({ concurrency: body.concurrency })
1744
+ });
1745
+ const endedAt = Date.now();
1746
+ const jsonResult = toJsonValue(result);
1747
+ const response = {
1748
+ runId,
1749
+ suiteId: suite.id ?? suite.name,
1750
+ startedAt: new Date(startedAt).toISOString(),
1751
+ endedAt: new Date(endedAt).toISOString(),
1752
+ durationMs: endedAt - startedAt,
1753
+ result: isJsonObject(jsonResult) ? jsonResult : { value: jsonResult }
1754
+ };
1755
+ return c.json(response);
1756
+ });
1848
1757
  }
1849
- function isJsonValue2(value) {
1850
- if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1851
- return true;
1852
- }
1853
- if (Array.isArray(value)) {
1854
- return value.every(isJsonValue2);
1758
+ async function parseEvalRunRequest(c) {
1759
+ let body = {};
1760
+ try {
1761
+ body = await c.req.json();
1762
+ } catch {
1763
+ body = {};
1855
1764
  }
1856
- return isJsonObject2(value);
1857
- }
1858
- function isAgentTraceOptions(value) {
1859
- if (!isObject(value)) {
1860
- return false;
1765
+ if (!isObject(body)) {
1766
+ return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
1861
1767
  }
1862
- 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);
1863
- }
1864
- function optionalString(value) {
1865
- return value === void 0 || typeof value === "string";
1866
- }
1867
- function optionalBoolean(value) {
1868
- return value === void 0 || typeof value === "boolean";
1869
- }
1870
- function optionalStringArray(value) {
1871
- return value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
1872
- }
1873
- function optionalObject(value) {
1874
- return value === void 0 || isObject(value);
1875
- }
1876
- function isNonNegativeInteger(value) {
1877
- return Number.isInteger(value) && typeof value === "number" && value >= 0;
1878
- }
1879
- function isPositiveInteger(value) {
1880
- return Number.isInteger(value) && typeof value === "number" && value > 0;
1881
- }
1882
- function unsupportedCapability(c, capability) {
1883
- return errorResponse(
1884
- c,
1885
- 501,
1886
- "unsupported_capability",
1887
- `Capability "${capability}" is not implemented by this runner`,
1888
- { capability }
1889
- );
1890
- }
1891
- function errorResponse(c, status, code, message, details) {
1892
- const body = {
1893
- error: {
1894
- code,
1895
- message
1768
+ const request = {};
1769
+ if ("concurrency" in body) {
1770
+ if (!isPositiveInteger(body.concurrency)) {
1771
+ return {
1772
+ error: errorResponse(c, 400, "bad_request", "concurrency must be a positive integer")
1773
+ };
1896
1774
  }
1897
- };
1898
- if (details !== void 0) {
1899
- body.error.details = details;
1775
+ request.concurrency = body.concurrency;
1900
1776
  }
1901
- return c.json(body, status);
1902
- }
1903
- function serializeError(error) {
1904
- return serializeUnknown(error);
1777
+ return request;
1905
1778
  }
1906
1779
 
1907
- // src/runtime/approvals.ts
1908
- function registerApprovalRoutes(app, approvals) {
1909
- app.get("/approvals", (c) => {
1910
- const status = parseApprovalStatus(c.req.query("status"));
1911
- if (status === false) {
1912
- return errorResponse(c, 400, "bad_request", "status must be pending or resolved");
1913
- }
1914
- const options = {};
1915
- const runId = optionalQueryString(c.req.query("runId"));
1916
- const agentId = optionalQueryString(c.req.query("agentId"));
1917
- const sessionId = optionalQueryString(c.req.query("sessionId"));
1918
- if (status !== void 0) {
1919
- options.status = status;
1780
+ // src/runtime/knowledge.ts
1781
+ function registerKnowledgeRoutes(app, props) {
1782
+ app.get("/knowledge", async (c) => {
1783
+ const limit = parseLimit(c.req.query("limit"));
1784
+ if (limit === void 0) {
1785
+ return errorResponse(c, 400, "bad_request", "Invalid limit");
1920
1786
  }
1921
- if (runId !== void 0) {
1922
- options.runId = runId;
1787
+ const summary = {
1788
+ agents: await Promise.all(props.agents.map(agentKnowledgeConfig)),
1789
+ evidence: await recentKnowledgeEvidence(props.traceStore, limit)
1790
+ };
1791
+ return c.json(summary);
1792
+ });
1793
+ app.get("/knowledge/items", async (c) => {
1794
+ const limit = parseLimit(c.req.query("limit"));
1795
+ if (limit === void 0) {
1796
+ return errorResponse(c, 400, "bad_request", "Invalid limit");
1923
1797
  }
1924
- if (agentId !== void 0) {
1925
- options.agentId = agentId;
1798
+ const agentId = optionalQueryString(c.req.query("agentId"));
1799
+ const sourceId = optionalQueryString(c.req.query("sourceId"));
1800
+ if (agentId === void 0 || sourceId === void 0) {
1801
+ return errorResponse(c, 400, "bad_request", "agentId and sourceId are required");
1926
1802
  }
1927
- if (sessionId !== void 0) {
1928
- options.sessionId = sessionId;
1803
+ const agent = props.agents.find((item) => item.id === agentId);
1804
+ if (agent === void 0) {
1805
+ return errorResponse(c, 404, "not_found", "Agent not found");
1929
1806
  }
1930
- return c.json({
1931
- approvals: approvals.list(options)
1807
+ const page = await knowledgeItemsPage(agent, sourceId, {
1808
+ limit,
1809
+ cursor: optionalQueryString(c.req.query("cursor"))
1932
1810
  });
1933
- });
1934
- app.post("/approvals/:approvalId/decision", async (c) => {
1935
- const body = await parseApprovalDecisionRequest(c);
1936
- if ("error" in body) {
1937
- return body.error;
1938
- }
1939
- const result = approvals.decide(c.req.param("approvalId"), body);
1940
- if (result === "missing") {
1941
- return errorResponse(c, 404, "not_found", "Approval not found");
1942
- }
1943
- if (result === "resolved") {
1944
- return errorResponse(c, 409, "conflict", "Approval is already resolved");
1811
+ if (page === void 0) {
1812
+ return errorResponse(c, 404, "not_found", "Knowledge source not found");
1945
1813
  }
1946
- return c.json(result);
1814
+ return c.json(page);
1947
1815
  });
1948
1816
  }
1949
- function parseApprovalStatus(value) {
1950
- const status = optionalQueryString(value);
1951
- if (status === void 0) {
1817
+ async function agentKnowledgeConfig(agent) {
1818
+ const agentName = agent.name ?? agent.agent.name;
1819
+ return {
1820
+ agentId: agent.id,
1821
+ ...compact({ agentName }),
1822
+ sources: await knowledgeSources(agent),
1823
+ staticContext: agent.agent.staticContext.map((document) => ({
1824
+ id: document.id,
1825
+ text: document.text,
1826
+ ...compact({ additionalProps: document.additionalProps !== void 0 ? jsonObjectFromRecord(document.additionalProps) : void 0 })
1827
+ }))
1828
+ };
1829
+ }
1830
+ async function knowledgeSources(agent) {
1831
+ const sources = [
1832
+ {
1833
+ sourceId: staticSourceId(),
1834
+ kind: "static_context",
1835
+ label: "Static context",
1836
+ count: agent.agent.staticContext.length,
1837
+ inspectable: true,
1838
+ itemCount: agent.agent.staticContext.length
1839
+ }
1840
+ ];
1841
+ const dynamicContextSources = await Promise.all(
1842
+ agent.agent.dynamicContexts.map(async (registration, index) => {
1843
+ const inspect = inspectFn(registration.index);
1844
+ const count = await inspectableCount(inspect, registration.options.filter);
1845
+ return {
1846
+ sourceId: dynamicContextSourceId(index),
1847
+ kind: "dynamic_context",
1848
+ label: `Dynamic context ${index + 1}`,
1849
+ count: 1,
1850
+ registrationIndex: index,
1851
+ topK: registration.options.topK,
1852
+ ...compact({ threshold: registration.options.threshold }),
1853
+ inspectable: inspect !== void 0,
1854
+ ...compact({ itemCount: count })
1855
+ };
1856
+ })
1857
+ );
1858
+ const dynamicToolSources = await Promise.all(
1859
+ agent.agent.dynamicTools.map(async (registration, index) => {
1860
+ const inspect = inspectFn(registration.index);
1861
+ const count = await inspectableCount(inspect, registration.options.filter);
1862
+ return {
1863
+ sourceId: dynamicToolsSourceId(index),
1864
+ kind: "dynamic_tools",
1865
+ label: `Dynamic tools ${index + 1}`,
1866
+ count: 1,
1867
+ registrationIndex: index,
1868
+ topK: registration.options.topK,
1869
+ ...compact({ threshold: registration.options.threshold }),
1870
+ inspectable: inspect !== void 0,
1871
+ ...compact({ itemCount: count })
1872
+ };
1873
+ })
1874
+ );
1875
+ return [...sources, ...dynamicContextSources, ...dynamicToolSources];
1876
+ }
1877
+ async function inspectableCount(inspect, filter) {
1878
+ if (inspect === void 0) {
1952
1879
  return void 0;
1953
1880
  }
1954
- return status === "pending" || status === "resolved" ? status : false;
1881
+ const page = await inspect({ limit: 1, filter });
1882
+ return page.totalCount;
1955
1883
  }
1956
- async function parseApprovalDecisionRequest(c) {
1957
- let body;
1958
- try {
1959
- body = await c.req.json();
1960
- } catch {
1961
- return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
1884
+ async function knowledgeItemsPage(agent, sourceId, request) {
1885
+ if (sourceId === staticSourceId()) {
1886
+ return staticKnowledgeItemsPage(agent, request);
1962
1887
  }
1963
- if (!isObject(body)) {
1964
- return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
1888
+ const dynamicContextIndex = dynamicSourceIndex(sourceId, "dynamic_context");
1889
+ if (dynamicContextIndex !== void 0) {
1890
+ const registration = agent.agent.dynamicContexts[dynamicContextIndex];
1891
+ if (registration === void 0) {
1892
+ return void 0;
1893
+ }
1894
+ const inspect = inspectFn(registration.index);
1895
+ if (inspect === void 0) {
1896
+ return nonInspectablePage(agent.id, sourceId, "dynamic_context");
1897
+ }
1898
+ const page = await inspect({
1899
+ limit: request.limit,
1900
+ cursor: request.cursor,
1901
+ filter: registration.options.filter
1902
+ });
1903
+ return {
1904
+ agentId: agent.id,
1905
+ sourceId,
1906
+ kind: "dynamic_context",
1907
+ inspectable: true,
1908
+ items: page.items.map((item) => dynamicContextItem(item)),
1909
+ ...compact({ nextCursor: page.nextCursor, totalCount: page.totalCount })
1910
+ };
1965
1911
  }
1966
- if (typeof body.approved !== "boolean") {
1967
- return { error: errorResponse(c, 400, "bad_request", "approved must be a boolean") };
1912
+ const dynamicToolsIndex = dynamicSourceIndex(sourceId, "dynamic_tools");
1913
+ if (dynamicToolsIndex !== void 0) {
1914
+ const registration = agent.agent.dynamicTools[dynamicToolsIndex];
1915
+ if (registration === void 0) {
1916
+ return void 0;
1917
+ }
1918
+ const inspect = inspectFn(registration.index);
1919
+ if (inspect === void 0) {
1920
+ return nonInspectablePage(agent.id, sourceId, "dynamic_tools");
1921
+ }
1922
+ const page = await inspect({
1923
+ limit: request.limit,
1924
+ cursor: request.cursor,
1925
+ filter: registration.options.filter
1926
+ });
1927
+ return {
1928
+ agentId: agent.id,
1929
+ sourceId,
1930
+ kind: "dynamic_tools",
1931
+ inspectable: true,
1932
+ items: page.items.map((item) => dynamicToolItem(item)),
1933
+ ...compact({ nextCursor: page.nextCursor, totalCount: page.totalCount })
1934
+ };
1968
1935
  }
1969
- if ("reason" in body && typeof body.reason !== "string") {
1970
- return { error: errorResponse(c, 400, "bad_request", "reason must be a string") };
1936
+ return void 0;
1937
+ }
1938
+ function inspectFn(index) {
1939
+ if (!isRecord2(index) || typeof index.inspect !== "function") {
1940
+ return void 0;
1971
1941
  }
1942
+ const inspect = index.inspect;
1943
+ return (request) => inspect.call(index, request);
1944
+ }
1945
+ function staticKnowledgeItemsPage(agent, request) {
1946
+ const start = Math.max(0, Math.trunc(Number(request.cursor ?? "0")));
1947
+ const page = agent.agent.staticContext.slice(start, start + request.limit);
1948
+ const nextOffset = start + page.length;
1972
1949
  return {
1973
- approved: body.approved,
1974
- ...typeof body.reason === "string" && body.reason.trim().length > 0 ? { reason: body.reason.trim() } : {}
1950
+ agentId: agent.id,
1951
+ sourceId: staticSourceId(),
1952
+ kind: "static_context",
1953
+ inspectable: true,
1954
+ items: page.map((document) => ({
1955
+ id: document.id,
1956
+ kind: "static_context",
1957
+ text: document.text,
1958
+ ...compact({ metadata: document.additionalProps !== void 0 ? jsonObjectFromRecord(document.additionalProps) : void 0 })
1959
+ })),
1960
+ ...compact({ nextCursor: nextOffset < agent.agent.staticContext.length ? String(nextOffset) : void 0 }),
1961
+ totalCount: agent.agent.staticContext.length
1975
1962
  };
1976
1963
  }
1977
- function createApprovalRuntime() {
1978
- const approvals = /* @__PURE__ */ new Map();
1964
+ function nonInspectablePage(agentId, sourceId, kind) {
1979
1965
  return {
1980
- approvals,
1981
- createHook(context) {
1982
- const handleApprovalRequest = async ({ toolName, toolCallId, internalCallId, args, tool: control }, request) => {
1983
- const decision = await requestApproval(approvals, context, {
1984
- toolName,
1985
- ...toolCallId === void 0 ? {} : { toolCallId },
1986
- internalCallId,
1987
- args,
1988
- ...request.reason === void 0 ? {} : { reason: request.reason },
1989
- ...request.rejectMessage === void 0 ? {} : { rejectMessage: request.rejectMessage }
1990
- });
1991
- return decision.approved ? control.run() : control.skip(decision.reason ?? request.rejectMessage ?? "Rejected in Anvia Studio.");
1992
- };
1993
- return {
1994
- ...createHook({
1995
- async onToolCall({ toolName, toolCallId, internalCallId, args, tool: control }) {
1996
- const registeredTool = context.getTool(toolName);
1997
- if (registeredTool?.approval === void 0) {
1998
- return control.run();
1999
- }
2000
- const approval = registeredTool.approval;
2001
- const rawParsedArgs = parseToolArgs(args);
2002
- const parsedArgs = registeredTool.parseApprovalArgs?.(rawParsedArgs) ?? rawParsedArgs;
2003
- const approvalContext = {
2004
- toolName,
2005
- args: parsedArgs,
2006
- rawArgs: args,
2007
- ...toolCallId === void 0 ? {} : { toolCallId },
2008
- internalCallId,
2009
- run: {
2010
- agentId: context.agentId,
2011
- runId: context.runId,
2012
- ...context.sessionId === void 0 ? {} : { sessionId: context.sessionId },
2013
- ...context.metadata === void 0 ? {} : { metadata: context.metadata }
2014
- }
2015
- };
2016
- const required = await approval.when(approvalContext);
2017
- if (!required) {
2018
- return control.run();
2019
- }
2020
- const reason = await resolveApprovalText(approval.reason, approvalContext);
2021
- const rejectMessage = await resolveApprovalText(
2022
- approval.rejectMessage,
2023
- approvalContext
2024
- );
2025
- const decision = await requestApproval(approvals, context, {
2026
- toolName,
2027
- ...toolCallId === void 0 ? {} : { toolCallId },
2028
- internalCallId,
2029
- args,
2030
- ...reason === void 0 ? {} : { reason },
2031
- ...rejectMessage === void 0 ? {} : { rejectMessage }
2032
- });
2033
- return decision.approved ? control.run() : control.skip(decision.reason ?? rejectMessage ?? "Rejected in Anvia Studio.");
2034
- }
2035
- }),
2036
- handleApprovalRequest
2037
- };
2038
- },
2039
- list(options) {
2040
- return [...approvals.values()].filter((approval) => {
2041
- if (options.status === "pending" && approval.status !== "pending") {
2042
- return false;
2043
- }
2044
- if (options.status === "resolved" && approval.status === "pending") {
2045
- return false;
2046
- }
2047
- if (options.runId !== void 0 && approval.runId !== options.runId) {
2048
- return false;
2049
- }
2050
- if (options.agentId !== void 0 && approval.agentId !== options.agentId) {
2051
- return false;
2052
- }
2053
- if (options.sessionId !== void 0 && approval.sessionId !== options.sessionId) {
2054
- return false;
2055
- }
2056
- return true;
2057
- }).map(publicApproval);
2058
- },
2059
- decide(id, decision) {
2060
- const approval = approvals.get(id);
2061
- if (approval === void 0) {
2062
- return "missing";
2063
- }
2064
- if (!isPendingApproval(approval)) {
2065
- return "resolved";
2066
- }
2067
- const reason = decision.approved ? decision.reason : decision.reason ?? approval.rejectMessage ?? "Rejected in Anvia Studio.";
2068
- const resolved = resolveApproval(approval, decision.approved ? "approved" : "rejected", {
2069
- ...reason === void 0 ? {} : { reason }
2070
- });
2071
- approvals.set(id, resolved);
2072
- approval.emit?.({ type: "tool_approval_result", approval: resolved });
2073
- approval.resolve({
2074
- approved: decision.approved,
2075
- ...reason === void 0 ? {} : { reason }
2076
- });
2077
- return publicApproval(resolved);
2078
- }
1966
+ agentId,
1967
+ sourceId,
1968
+ kind,
1969
+ inspectable: false,
1970
+ items: [],
1971
+ message: "This source can be searched at runtime, but it does not expose browseable chunks."
2079
1972
  };
2080
1973
  }
2081
- async function requestApproval(approvals, context, request) {
2082
- const id = globalThis.crypto.randomUUID();
2083
- const approval = {
2084
- id,
2085
- runId: context.runId,
2086
- agentId: context.agentId,
2087
- ...context.sessionId === void 0 ? {} : { sessionId: context.sessionId },
2088
- toolName: request.toolName,
2089
- ...request.toolCallId === void 0 ? {} : { callId: request.toolCallId },
2090
- internalCallId: request.internalCallId,
2091
- args: request.args,
2092
- status: "pending",
2093
- requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
2094
- ...request.reason === void 0 ? {} : { reason: request.reason },
2095
- ...request.rejectMessage === void 0 ? {} : { rejectMessage: request.rejectMessage },
2096
- ...context.emit === void 0 ? {} : { emit: context.emit },
2097
- resolve: () => {
2098
- }
1974
+ function dynamicContextItem(item) {
1975
+ const text = isRecord2(item.document) && typeof item.document.text === "string" ? item.document.text : typeof item.document === "string" ? item.document : void 0;
1976
+ return {
1977
+ id: item.id,
1978
+ kind: "dynamic_context",
1979
+ ...text === void 0 ? { document: toJsonValue(item.document) } : { text },
1980
+ ...compact({ metadata: item.metadata !== void 0 ? jsonObjectFromRecord(item.metadata) : void 0 })
2099
1981
  };
2100
- const decision = new Promise((resolve2) => {
2101
- approval.resolve = (decision2) => {
2102
- const current = approvals.get(id);
2103
- if (!isPendingApproval(current)) {
2104
- if (current !== void 0) {
2105
- resolve2({
2106
- approved: current.status === "approved",
2107
- ...current.reason === void 0 ? {} : { reason: current.reason }
2108
- });
2109
- }
2110
- return;
2111
- }
2112
- const reason = decision2.approved ? decision2.reason : decision2.reason ?? request.rejectMessage ?? "Rejected in Anvia Studio.";
2113
- const resolved = resolveApproval(current, decision2.approved ? "approved" : "rejected", {
2114
- ...reason === void 0 ? {} : { reason }
2115
- });
2116
- approvals.set(id, resolved);
2117
- context.emit?.({ type: "tool_approval_result", approval: resolved });
2118
- resolve2({
2119
- approved: decision2.approved,
2120
- ...reason === void 0 ? {} : { reason }
2121
- });
2122
- };
2123
- });
2124
- approvals.set(id, approval);
2125
- context.emit?.({ type: "tool_approval_request", approval: publicApproval(approval) });
2126
- return decision;
2127
1982
  }
2128
- async function resolveApprovalText(value, context) {
2129
- return typeof value === "function" ? value(context) : value;
1983
+ function dynamicToolItem(item) {
1984
+ const document = isRecord2(item.document) ? item.document : {};
1985
+ const definition = isRecord2(document.definition) ? document.definition : {};
1986
+ const toolName = typeof document.toolName === "string" ? document.toolName : typeof definition.name === "string" ? definition.name : item.id;
1987
+ const description = typeof definition.description === "string" ? definition.description : "";
1988
+ return {
1989
+ id: item.id,
1990
+ kind: "dynamic_tool",
1991
+ toolName,
1992
+ description,
1993
+ parameterKeys: parameterKeys(definition.parameters),
1994
+ document: toJsonValue(item.document),
1995
+ ...compact({ metadata: item.metadata !== void 0 ? jsonObjectFromRecord(item.metadata) : void 0 })
1996
+ };
2130
1997
  }
2131
- function isPendingApproval(approval) {
2132
- return approval !== void 0 && approval.status === "pending" && "resolve" in approval;
1998
+ function parameterKeys(parameters) {
1999
+ if (!isRecord2(parameters) || !isRecord2(parameters.properties)) {
2000
+ return [];
2001
+ }
2002
+ return Object.keys(parameters.properties);
2133
2003
  }
2134
- function resolveApproval(approval, status, options = {}) {
2135
- return publicApproval({
2136
- ...approval,
2137
- status,
2138
- resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
2139
- ...options.reason === void 0 ? {} : { reason: options.reason }
2140
- });
2004
+ function staticSourceId() {
2005
+ return "static-context";
2141
2006
  }
2142
- function publicApproval(approval) {
2143
- const { emit, rejectMessage, resolve: resolve2, ...rest } = approval;
2144
- void emit;
2145
- void rejectMessage;
2146
- void resolve2;
2147
- return rest;
2007
+ function dynamicContextSourceId(index) {
2008
+ return `dynamic-context-${index}`;
2148
2009
  }
2149
-
2150
- // src/runtime/evals.ts
2151
- import { runEvalSuite } from "@anvia/core/evals";
2152
- function registerEvalRoutes(app, props) {
2153
- app.get(
2154
- "/evals",
2155
- (c) => c.json({
2156
- evals: props.evals.map(evalConfig)
2157
- })
2010
+ function dynamicToolsSourceId(index) {
2011
+ return `dynamic-tools-${index}`;
2012
+ }
2013
+ function dynamicSourceIndex(sourceId, kind) {
2014
+ const prefix = kind === "dynamic_context" ? "dynamic-context-" : "dynamic-tools-";
2015
+ if (!sourceId.startsWith(prefix)) {
2016
+ return void 0;
2017
+ }
2018
+ const index = Number(sourceId.slice(prefix.length));
2019
+ return Number.isInteger(index) && index >= 0 ? index : void 0;
2020
+ }
2021
+ async function recentKnowledgeEvidence(traceStore, limit) {
2022
+ if (traceStore?.listTraces === void 0) {
2023
+ return [];
2024
+ }
2025
+ const store = traceStore;
2026
+ const listTraces = store.listTraces;
2027
+ if (listTraces === void 0) {
2028
+ return [];
2029
+ }
2030
+ const summaries = await listTraces.call(store, { limit });
2031
+ const traces = await Promise.all(
2032
+ summaries.map((summary) => Promise.resolve(store.getTrace(summary.id)).catch(() => void 0))
2158
2033
  );
2159
- app.get("/evals/:evalId", (c) => {
2160
- const suite = props.evalMap.get(c.req.param("evalId"));
2161
- if (suite === void 0) {
2162
- return errorResponse(c, 404, "not_found", "Eval suite not found");
2163
- }
2164
- return c.json(evalConfig(suite));
2165
- });
2166
- app.post("/evals/:evalId/runs", async (c) => {
2167
- const suite = props.evalMap.get(c.req.param("evalId"));
2168
- if (suite === void 0) {
2169
- return errorResponse(c, 404, "not_found", "Eval suite not found");
2034
+ return traces.flatMap(
2035
+ (trace) => trace === void 0 ? [] : evidenceFromTrace(trace)
2036
+ );
2037
+ }
2038
+ function evidenceFromTrace(trace) {
2039
+ return trace.observations.flatMap((observation) => {
2040
+ if (observation.kind !== "generation" || !isRecord2(observation.input)) {
2041
+ return [];
2170
2042
  }
2171
- const body = await parseEvalRunRequest(c);
2172
- if ("error" in body) {
2173
- return body.error;
2043
+ const documents = Array.isArray(observation.input.documents) ? observation.input.documents.flatMap((document) => evidenceDocument(document)) : [];
2044
+ const tools = Array.isArray(observation.input.tools) ? observation.input.tools.flatMap((tool) => evidenceToolName(tool)) : [];
2045
+ if (documents.length === 0 && tools.length === 0) {
2046
+ return [];
2174
2047
  }
2175
- const runId = globalThis.crypto.randomUUID();
2176
- const startedAt = Date.now();
2177
- const result = await runEvalSuite({
2178
- ...suite,
2179
- ...body.concurrency === void 0 ? {} : { concurrency: body.concurrency }
2180
- });
2181
- const endedAt = Date.now();
2182
- const jsonResult = toJsonValue(result);
2183
- const response = {
2184
- runId,
2185
- suiteId: suite.id ?? suite.name,
2186
- startedAt: new Date(startedAt).toISOString(),
2187
- endedAt: new Date(endedAt).toISOString(),
2188
- durationMs: endedAt - startedAt,
2189
- result: isJsonObject2(jsonResult) ? jsonResult : { value: jsonResult }
2190
- };
2191
- return c.json(response);
2048
+ const query = queryFromGenerationInput(observation.input);
2049
+ return [
2050
+ {
2051
+ traceId: trace.id,
2052
+ sessionId: trace.sessionId,
2053
+ observationId: observation.id,
2054
+ observationName: observation.name,
2055
+ turn: observation.turn,
2056
+ startedAt: observation.startedAt,
2057
+ ...compact({ query }),
2058
+ documentCount: documents.length,
2059
+ toolCount: tools.length,
2060
+ documents,
2061
+ tools
2062
+ }
2063
+ ];
2192
2064
  });
2193
2065
  }
2194
- async function parseEvalRunRequest(c) {
2195
- let body = {};
2196
- try {
2197
- body = await c.req.json();
2198
- } catch {
2199
- body = {};
2066
+ function queryFromGenerationInput(value) {
2067
+ const promptText = messageText(value.prompt);
2068
+ if (promptText.length > 0) {
2069
+ return promptText;
2200
2070
  }
2201
- if (!isObject(body)) {
2202
- return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
2071
+ if (Array.isArray(value.chatHistory)) {
2072
+ for (let index = value.chatHistory.length - 1; index >= 0; index -= 1) {
2073
+ const text = messageText(value.chatHistory[index]);
2074
+ if (text.length > 0) {
2075
+ return text;
2076
+ }
2077
+ }
2203
2078
  }
2204
- const request = {};
2205
- if ("concurrency" in body) {
2206
- if (!isPositiveInteger(body.concurrency)) {
2207
- return {
2208
- error: errorResponse(c, 400, "bad_request", "concurrency must be a positive integer")
2209
- };
2079
+ if (Array.isArray(value.history)) {
2080
+ for (let index = value.history.length - 1; index >= 0; index -= 1) {
2081
+ const text = messageText(value.history[index]);
2082
+ if (text.length > 0) {
2083
+ return text;
2084
+ }
2210
2085
  }
2211
- request.concurrency = body.concurrency;
2212
2086
  }
2213
- return request;
2087
+ return void 0;
2214
2088
  }
2215
-
2216
- // src/runtime/knowledge.ts
2217
- function registerKnowledgeRoutes(app, props) {
2218
- app.get("/knowledge", async (c) => {
2219
- const limit = parseLimit(c.req.query("limit"));
2220
- if (limit === void 0) {
2221
- return errorResponse(c, 400, "bad_request", "Invalid limit");
2222
- }
2223
- const summary = {
2224
- agents: await Promise.all(props.agents.map(agentKnowledgeConfig)),
2225
- evidence: await recentKnowledgeEvidence(props.traceStore, limit)
2226
- };
2227
- return c.json(summary);
2228
- });
2229
- app.get("/knowledge/items", async (c) => {
2230
- const limit = parseLimit(c.req.query("limit"));
2231
- if (limit === void 0) {
2232
- return errorResponse(c, 400, "bad_request", "Invalid limit");
2233
- }
2234
- const agentId = optionalQueryString(c.req.query("agentId"));
2235
- const sourceId = optionalQueryString(c.req.query("sourceId"));
2236
- if (agentId === void 0 || sourceId === void 0) {
2237
- return errorResponse(c, 400, "bad_request", "agentId and sourceId are required");
2238
- }
2239
- const agent = props.agents.find((item) => item.id === agentId);
2240
- if (agent === void 0) {
2241
- return errorResponse(c, 404, "not_found", "Agent not found");
2242
- }
2243
- const page = await knowledgeItemsPage(agent, sourceId, {
2244
- limit,
2245
- cursor: optionalQueryString(c.req.query("cursor"))
2246
- });
2247
- if (page === void 0) {
2248
- return errorResponse(c, 404, "not_found", "Knowledge source not found");
2249
- }
2250
- return c.json(page);
2251
- });
2089
+ function messageText(value) {
2090
+ if (typeof value === "string") {
2091
+ return value.trim();
2092
+ }
2093
+ if (!isRecord2(value)) {
2094
+ return "";
2095
+ }
2096
+ if (typeof value.text === "string") {
2097
+ return value.text.trim();
2098
+ }
2099
+ if (typeof value.content === "string") {
2100
+ return value.content.trim();
2101
+ }
2102
+ if (Array.isArray(value.content)) {
2103
+ return value.content.map(contentText).filter(Boolean).join("\n").trim();
2104
+ }
2105
+ return "";
2252
2106
  }
2253
- async function agentKnowledgeConfig(agent) {
2254
- const agentName = agent.name ?? agent.agent.name;
2255
- return {
2256
- agentId: agent.id,
2257
- ...agentName === void 0 ? {} : { agentName },
2258
- sources: await knowledgeSources(agent),
2259
- staticContext: agent.agent.staticContext.map((document) => ({
2260
- id: document.id,
2261
- text: document.text,
2262
- ...document.additionalProps === void 0 ? {} : { additionalProps: jsonObjectFromRecord(document.additionalProps) }
2263
- }))
2264
- };
2107
+ function contentText(value) {
2108
+ if (typeof value === "string") {
2109
+ return value.trim();
2110
+ }
2111
+ if (!isRecord2(value)) {
2112
+ return "";
2113
+ }
2114
+ if (typeof value.text === "string") {
2115
+ return value.text.trim();
2116
+ }
2117
+ return "";
2265
2118
  }
2266
- async function knowledgeSources(agent) {
2267
- const sources = [
2268
- {
2269
- sourceId: staticSourceId(),
2270
- kind: "static_context",
2271
- label: "Static context",
2272
- count: agent.agent.staticContext.length,
2273
- inspectable: true,
2274
- itemCount: agent.agent.staticContext.length
2275
- }
2119
+ function evidenceDocument(value) {
2120
+ if (!isRecord2(value)) {
2121
+ return [];
2122
+ }
2123
+ const id = typeof value.id === "string" ? value.id : void 0;
2124
+ const text = typeof value.text === "string" ? value.text : void 0;
2125
+ const additionalProps = isRecord2(value.additionalProps) ? jsonObjectFromRecord(value.additionalProps) : void 0;
2126
+ if (id === void 0 && text === void 0 && additionalProps === void 0) {
2127
+ return [];
2128
+ }
2129
+ return [
2130
+ compact({ id, text, additionalProps })
2276
2131
  ];
2277
- const dynamicContextSources = await Promise.all(
2278
- agent.agent.dynamicContexts.map(async (registration, index) => {
2279
- const inspect = inspectFn(registration.index);
2280
- const count = await inspectableCount(inspect, registration.options.filter);
2281
- return {
2282
- sourceId: dynamicContextSourceId(index),
2283
- kind: "dynamic_context",
2284
- label: `Dynamic context ${index + 1}`,
2285
- count: 1,
2286
- registrationIndex: index,
2287
- topK: registration.options.topK,
2288
- ...registration.options.threshold === void 0 ? {} : { threshold: registration.options.threshold },
2289
- inspectable: inspect !== void 0,
2290
- ...count === void 0 ? {} : { itemCount: count }
2291
- };
2292
- })
2293
- );
2294
- const dynamicToolSources = await Promise.all(
2295
- agent.agent.dynamicTools.map(async (registration, index) => {
2296
- const inspect = inspectFn(registration.index);
2297
- const count = await inspectableCount(inspect, registration.options.filter);
2298
- return {
2299
- sourceId: dynamicToolsSourceId(index),
2300
- kind: "dynamic_tools",
2301
- label: `Dynamic tools ${index + 1}`,
2302
- count: 1,
2303
- registrationIndex: index,
2304
- topK: registration.options.topK,
2305
- ...registration.options.threshold === void 0 ? {} : { threshold: registration.options.threshold },
2306
- inspectable: inspect !== void 0,
2307
- ...count === void 0 ? {} : { itemCount: count }
2308
- };
2309
- })
2310
- );
2311
- return [...sources, ...dynamicContextSources, ...dynamicToolSources];
2312
2132
  }
2313
- async function inspectableCount(inspect, filter) {
2314
- if (inspect === void 0) {
2315
- return void 0;
2133
+ function evidenceToolName(value) {
2134
+ if (!isRecord2(value) || typeof value.name !== "string") {
2135
+ return [];
2316
2136
  }
2317
- const page = await inspect({ limit: 1, filter });
2318
- return page.totalCount;
2137
+ return [value.name];
2319
2138
  }
2320
- async function knowledgeItemsPage(agent, sourceId, request) {
2321
- if (sourceId === staticSourceId()) {
2322
- return staticKnowledgeItemsPage(agent, request);
2323
- }
2324
- const dynamicContextIndex = dynamicSourceIndex(sourceId, "dynamic_context");
2325
- if (dynamicContextIndex !== void 0) {
2326
- const registration = agent.agent.dynamicContexts[dynamicContextIndex];
2327
- if (registration === void 0) {
2328
- return void 0;
2329
- }
2330
- const inspect = inspectFn(registration.index);
2331
- if (inspect === void 0) {
2332
- return nonInspectablePage(agent.id, sourceId, "dynamic_context");
2139
+ function jsonObjectFromRecord(value) {
2140
+ return compactJsonObject(value);
2141
+ }
2142
+ function isRecord2(value) {
2143
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2144
+ }
2145
+
2146
+ // src/runtime/mcps.ts
2147
+ function registerMcpRoutes(app, props) {
2148
+ app.get("/agents/:agentId/mcps", async (c) => {
2149
+ const agentId = c.req.param("agentId");
2150
+ const agent = props.agentMap.get(agentId);
2151
+ if (agent === void 0) {
2152
+ return errorResponse(c, 404, "not_found", "Agent not found");
2333
2153
  }
2334
- const page = await inspect({
2335
- limit: request.limit,
2336
- cursor: request.cursor,
2337
- filter: registration.options.filter
2154
+ return c.json({
2155
+ agentId,
2156
+ servers: await agentMcpMetadata(agent)
2338
2157
  });
2339
- return {
2340
- agentId: agent.id,
2341
- sourceId,
2342
- kind: "dynamic_context",
2343
- inspectable: true,
2344
- items: page.items.map((item) => dynamicContextItem(item)),
2345
- ...page.nextCursor === void 0 ? {} : { nextCursor: page.nextCursor },
2346
- ...page.totalCount === void 0 ? {} : { totalCount: page.totalCount }
2347
- };
2348
- }
2349
- const dynamicToolsIndex = dynamicSourceIndex(sourceId, "dynamic_tools");
2350
- if (dynamicToolsIndex !== void 0) {
2351
- const registration = agent.agent.dynamicTools[dynamicToolsIndex];
2352
- if (registration === void 0) {
2353
- return void 0;
2158
+ });
2159
+ }
2160
+ async function agentMcpMetadata(agent) {
2161
+ const servers = /* @__PURE__ */ new Map();
2162
+ const seen = /* @__PURE__ */ new Set();
2163
+ for (const { tool, source } of agentToolItems(agent)) {
2164
+ const serverName = mcpServerName(tool);
2165
+ if (serverName === void 0) {
2166
+ continue;
2354
2167
  }
2355
- const inspect = inspectFn(registration.index);
2356
- if (inspect === void 0) {
2357
- return nonInspectablePage(agent.id, sourceId, "dynamic_tools");
2168
+ const definition = await tool.definition("");
2169
+ const key = `${serverName}:${source}:${definition.name}`;
2170
+ if (seen.has(key)) {
2171
+ continue;
2358
2172
  }
2359
- const page = await inspect({
2360
- limit: request.limit,
2361
- cursor: request.cursor,
2362
- filter: registration.options.filter
2173
+ seen.add(key);
2174
+ const tools = servers.get(serverName) ?? [];
2175
+ tools.push({
2176
+ name: definition.name,
2177
+ description: definition.description,
2178
+ parameters: definition.parameters,
2179
+ source
2180
+ });
2181
+ servers.set(serverName, tools);
2182
+ }
2183
+ return [...servers.entries()].map(([name, tools]) => {
2184
+ const sortedTools = tools.sort((left, right) => {
2185
+ if (left.source !== right.source) {
2186
+ return left.source === "static" ? -1 : 1;
2187
+ }
2188
+ return left.name.localeCompare(right.name);
2363
2189
  });
2364
2190
  return {
2365
2191
  agentId: agent.id,
2366
- sourceId,
2367
- kind: "dynamic_tools",
2368
- inspectable: true,
2369
- items: page.items.map((item) => dynamicToolItem(item)),
2370
- ...page.nextCursor === void 0 ? {} : { nextCursor: page.nextCursor },
2371
- ...page.totalCount === void 0 ? {} : { totalCount: page.totalCount }
2192
+ name,
2193
+ toolCount: sortedTools.length,
2194
+ tools: sortedTools
2372
2195
  };
2373
- }
2374
- return void 0;
2375
- }
2376
- function inspectFn(index) {
2377
- if (!isRecord2(index) || typeof index.inspect !== "function") {
2378
- return void 0;
2379
- }
2380
- const inspect = index.inspect;
2381
- return (request) => inspect.call(index, request);
2382
- }
2383
- function staticKnowledgeItemsPage(agent, request) {
2384
- const start = Math.max(0, Math.trunc(Number(request.cursor ?? "0")));
2385
- const page = agent.agent.staticContext.slice(start, start + request.limit);
2386
- const nextOffset = start + page.length;
2387
- return {
2388
- agentId: agent.id,
2389
- sourceId: staticSourceId(),
2390
- kind: "static_context",
2391
- inspectable: true,
2392
- items: page.map((document) => ({
2393
- id: document.id,
2394
- kind: "static_context",
2395
- text: document.text,
2396
- ...document.additionalProps === void 0 ? {} : { metadata: jsonObjectFromRecord(document.additionalProps) }
2397
- })),
2398
- ...nextOffset < agent.agent.staticContext.length ? { nextCursor: String(nextOffset) } : {},
2399
- totalCount: agent.agent.staticContext.length
2400
- };
2401
- }
2402
- function nonInspectablePage(agentId, sourceId, kind) {
2403
- return {
2404
- agentId,
2405
- sourceId,
2406
- kind,
2407
- inspectable: false,
2408
- items: [],
2409
- message: "This source can be searched at runtime, but it does not expose browseable chunks."
2410
- };
2411
- }
2412
- function dynamicContextItem(item) {
2413
- const text = isRecord2(item.document) && typeof item.document.text === "string" ? item.document.text : typeof item.document === "string" ? item.document : void 0;
2414
- return {
2415
- id: item.id,
2416
- kind: "dynamic_context",
2417
- ...text === void 0 ? { document: toJsonValue(item.document) } : { text },
2418
- ...item.metadata === void 0 ? {} : { metadata: jsonObjectFromRecord(item.metadata) }
2419
- };
2420
- }
2421
- function dynamicToolItem(item) {
2422
- const document = isRecord2(item.document) ? item.document : {};
2423
- const definition = isRecord2(document.definition) ? document.definition : {};
2424
- const toolName = typeof document.toolName === "string" ? document.toolName : typeof definition.name === "string" ? definition.name : item.id;
2425
- const description = typeof definition.description === "string" ? definition.description : "";
2426
- return {
2427
- id: item.id,
2428
- kind: "dynamic_tool",
2429
- toolName,
2430
- description,
2431
- parameterKeys: parameterKeys(definition.parameters),
2432
- document: toJsonValue(item.document),
2433
- ...item.metadata === void 0 ? {} : { metadata: jsonObjectFromRecord(item.metadata) }
2434
- };
2435
- }
2436
- function parameterKeys(parameters) {
2437
- if (!isRecord2(parameters) || !isRecord2(parameters.properties)) {
2438
- return [];
2439
- }
2440
- return Object.keys(parameters.properties);
2441
- }
2442
- function staticSourceId() {
2443
- return "static-context";
2444
- }
2445
- function dynamicContextSourceId(index) {
2446
- return `dynamic-context-${index}`;
2447
- }
2448
- function dynamicToolsSourceId(index) {
2449
- return `dynamic-tools-${index}`;
2450
- }
2451
- function dynamicSourceIndex(sourceId, kind) {
2452
- const prefix = kind === "dynamic_context" ? "dynamic-context-" : "dynamic-tools-";
2453
- if (!sourceId.startsWith(prefix)) {
2454
- return void 0;
2455
- }
2456
- const index = Number(sourceId.slice(prefix.length));
2457
- return Number.isInteger(index) && index >= 0 ? index : void 0;
2458
- }
2459
- async function recentKnowledgeEvidence(traceStore, limit) {
2460
- if (traceStore?.listTraces === void 0) {
2461
- return [];
2462
- }
2463
- const store = traceStore;
2464
- const listTraces = store.listTraces;
2465
- if (listTraces === void 0) {
2466
- return [];
2467
- }
2468
- const summaries = await listTraces.call(store, { limit });
2469
- const traces = await Promise.all(
2470
- summaries.map((summary) => Promise.resolve(store.getTrace(summary.id)).catch(() => void 0))
2471
- );
2472
- return traces.flatMap(
2473
- (trace) => trace === void 0 ? [] : evidenceFromTrace(trace)
2474
- );
2475
- }
2476
- function evidenceFromTrace(trace) {
2477
- return trace.observations.flatMap((observation) => {
2478
- if (observation.kind !== "generation" || !isRecord2(observation.input)) {
2479
- return [];
2480
- }
2481
- const documents = Array.isArray(observation.input.documents) ? observation.input.documents.flatMap((document) => evidenceDocument(document)) : [];
2482
- const tools = Array.isArray(observation.input.tools) ? observation.input.tools.flatMap((tool) => evidenceToolName(tool)) : [];
2483
- if (documents.length === 0 && tools.length === 0) {
2484
- return [];
2485
- }
2486
- const query = queryFromGenerationInput(observation.input);
2487
- return [
2488
- {
2489
- traceId: trace.id,
2490
- sessionId: trace.sessionId,
2491
- observationId: observation.id,
2492
- observationName: observation.name,
2493
- turn: observation.turn,
2494
- startedAt: observation.startedAt,
2495
- ...query === void 0 ? {} : { query },
2496
- documentCount: documents.length,
2497
- toolCount: tools.length,
2498
- documents,
2499
- tools
2500
- }
2501
- ];
2502
- });
2503
- }
2504
- function queryFromGenerationInput(value) {
2505
- const promptText = messageText(value.prompt);
2506
- if (promptText.length > 0) {
2507
- return promptText;
2508
- }
2509
- if (Array.isArray(value.chatHistory)) {
2510
- for (let index = value.chatHistory.length - 1; index >= 0; index -= 1) {
2511
- const text = messageText(value.chatHistory[index]);
2512
- if (text.length > 0) {
2513
- return text;
2514
- }
2515
- }
2516
- }
2517
- if (Array.isArray(value.history)) {
2518
- for (let index = value.history.length - 1; index >= 0; index -= 1) {
2519
- const text = messageText(value.history[index]);
2520
- if (text.length > 0) {
2521
- return text;
2522
- }
2523
- }
2524
- }
2525
- return void 0;
2526
- }
2527
- function messageText(value) {
2528
- if (typeof value === "string") {
2529
- return value.trim();
2530
- }
2531
- if (!isRecord2(value)) {
2532
- return "";
2533
- }
2534
- if (typeof value.text === "string") {
2535
- return value.text.trim();
2536
- }
2537
- if (typeof value.content === "string") {
2538
- return value.content.trim();
2539
- }
2540
- if (Array.isArray(value.content)) {
2541
- return value.content.map(contentText).filter(Boolean).join("\n").trim();
2542
- }
2543
- return "";
2544
- }
2545
- function contentText(value) {
2546
- if (typeof value === "string") {
2547
- return value.trim();
2548
- }
2549
- if (!isRecord2(value)) {
2550
- return "";
2551
- }
2552
- if (typeof value.text === "string") {
2553
- return value.text.trim();
2554
- }
2555
- return "";
2556
- }
2557
- function evidenceDocument(value) {
2558
- if (!isRecord2(value)) {
2559
- return [];
2560
- }
2561
- const id = typeof value.id === "string" ? value.id : void 0;
2562
- const text = typeof value.text === "string" ? value.text : void 0;
2563
- const additionalProps = isRecord2(value.additionalProps) ? jsonObjectFromRecord(value.additionalProps) : void 0;
2564
- if (id === void 0 && text === void 0 && additionalProps === void 0) {
2565
- return [];
2566
- }
2567
- return [
2568
- {
2569
- ...id === void 0 ? {} : { id },
2570
- ...text === void 0 ? {} : { text },
2571
- ...additionalProps === void 0 ? {} : { additionalProps }
2572
- }
2573
- ];
2574
- }
2575
- function evidenceToolName(value) {
2576
- if (!isRecord2(value) || typeof value.name !== "string") {
2577
- return [];
2578
- }
2579
- return [value.name];
2580
- }
2581
- function jsonObjectFromRecord(value) {
2582
- return compactJsonObject(value);
2583
- }
2584
- function isRecord2(value) {
2585
- return typeof value === "object" && value !== null && !Array.isArray(value);
2586
- }
2587
-
2588
- // src/runtime/mcps.ts
2589
- function registerMcpRoutes(app, props) {
2590
- app.get("/agents/:agentId/mcps", async (c) => {
2591
- const agentId = c.req.param("agentId");
2592
- const agent = props.agentMap.get(agentId);
2593
- if (agent === void 0) {
2594
- return errorResponse(c, 404, "not_found", "Agent not found");
2595
- }
2596
- return c.json({
2597
- agentId,
2598
- servers: await agentMcpMetadata(agent)
2599
- });
2600
- });
2601
- }
2602
- async function agentMcpMetadata(agent) {
2603
- const servers = /* @__PURE__ */ new Map();
2604
- const seen = /* @__PURE__ */ new Set();
2605
- for (const { tool, source } of agentToolItems(agent)) {
2606
- const serverName = mcpServerName(tool);
2607
- if (serverName === void 0) {
2608
- continue;
2609
- }
2610
- const definition = await tool.definition("");
2611
- const key = `${serverName}:${source}:${definition.name}`;
2612
- if (seen.has(key)) {
2613
- continue;
2614
- }
2615
- seen.add(key);
2616
- const tools = servers.get(serverName) ?? [];
2617
- tools.push({
2618
- name: definition.name,
2619
- description: definition.description,
2620
- parameters: definition.parameters,
2621
- source
2622
- });
2623
- servers.set(serverName, tools);
2624
- }
2625
- return [...servers.entries()].map(([name, tools]) => {
2626
- const sortedTools = tools.sort((left, right) => {
2627
- if (left.source !== right.source) {
2628
- return left.source === "static" ? -1 : 1;
2629
- }
2630
- return left.name.localeCompare(right.name);
2631
- });
2632
- return {
2633
- agentId: agent.id,
2634
- name,
2635
- toolCount: sortedTools.length,
2636
- tools: sortedTools
2637
- };
2638
- }).sort((left, right) => left.name.localeCompare(right.name));
2196
+ }).sort((left, right) => left.name.localeCompare(right.name));
2639
2197
  }
2640
2198
 
2641
2199
  // src/runtime/memory.ts
@@ -2681,7 +2239,7 @@ function registerMemoryRoutes(app, props) {
2681
2239
  const agentId = optionalQueryString(c.req.query("agentId"));
2682
2240
  const userId = optionalQueryString(c.req.query("userId"));
2683
2241
  const sessions = await props.sessionStore.listSessions({
2684
- ...agentId === void 0 ? {} : { agentId },
2242
+ ...compact({ agentId }),
2685
2243
  limit: 100
2686
2244
  });
2687
2245
  const conversations = sessions.map(memoryConversationSummary).filter((session) => userId === void 0 || session.userId === userId).slice(0, limit);
@@ -2713,16 +2271,16 @@ function registerMemoryRoutes(app, props) {
2713
2271
  });
2714
2272
  }
2715
2273
  function memoryConversationSummary(session) {
2716
- return {
2274
+ return compact({
2717
2275
  id: session.id,
2718
2276
  userId: sessionUserId(session),
2719
2277
  agentId: session.agentId,
2720
- ...session.title === void 0 ? {} : { title: session.title },
2278
+ title: session.title,
2721
2279
  createdAt: session.createdAt,
2722
2280
  updatedAt: session.updatedAt,
2723
2281
  messageCount: session.messageCount,
2724
- ...session.metadata === void 0 ? {} : { metadata: session.metadata }
2725
- };
2282
+ metadata: session.metadata
2283
+ });
2726
2284
  }
2727
2285
  function sessionUserId(session) {
2728
2286
  const userId = session.metadata?.userId;
@@ -2809,9 +2367,11 @@ var StudioObservabilityHub = class {
2809
2367
  function observeStores(stores, hub) {
2810
2368
  return {
2811
2369
  ...stores,
2812
- ...stores.sessions === void 0 ? {} : { sessions: observeSessionStore(stores.sessions, hub) },
2813
- ...stores.traces === void 0 ? {} : { traces: observeTraceStore(stores.traces, hub) },
2814
- ...stores.pipelineLogs === void 0 ? {} : { pipelineLogs: observePipelineLogStore(stores.pipelineLogs, hub) }
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
+ })
2815
2375
  };
2816
2376
  }
2817
2377
  function registerObservabilityRoutes(app, hub) {
@@ -2832,7 +2392,7 @@ function registerObservabilityRoutes(app, hub) {
2832
2392
  });
2833
2393
  }
2834
2394
  function observabilityEvents(hub, types) {
2835
- const subscription = hub.subscribe(types === void 0 ? {} : { types });
2395
+ const subscription = hub.subscribe(compact({ types }));
2836
2396
  return {
2837
2397
  [Symbol.asyncIterator]() {
2838
2398
  return {
@@ -2924,7 +2484,7 @@ function observeTraceStore(store, hub) {
2924
2484
  const saveTrace = target.saveTrace.bind(target);
2925
2485
  return async (...args) => {
2926
2486
  const trace = await saveTrace(...args);
2927
- hub.emit({ type: "trace", trace: traceSummary2(trace) });
2487
+ hub.emit({ type: "trace", trace: traceSummary(trace) });
2928
2488
  return trace;
2929
2489
  };
2930
2490
  }
@@ -2951,20 +2511,22 @@ function parseEventTypes(value) {
2951
2511
  function isEventType(value) {
2952
2512
  return value === "session_log" || value === "pipeline_log" || value === "trace";
2953
2513
  }
2954
- function traceSummary2(trace) {
2514
+ function traceSummary(trace) {
2955
2515
  return {
2956
2516
  id: trace.id,
2957
2517
  sessionId: trace.sessionId,
2958
- ...trace.name === void 0 ? {} : { name: trace.name },
2959
2518
  status: trace.status,
2960
2519
  startedAt: trace.startedAt,
2961
- ...trace.endedAt === void 0 ? {} : { endedAt: trace.endedAt },
2962
- ...trace.durationMs === void 0 ? {} : { durationMs: trace.durationMs },
2963
- ...trace.output === void 0 ? {} : { output: trace.output },
2964
- ...trace.error === void 0 ? {} : { error: trace.error },
2965
- ...trace.usage === void 0 ? {} : { usage: trace.usage },
2966
- ...trace.metadata === void 0 ? {} : { metadata: trace.metadata },
2967
- observationCount: trace.observations.length
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
+ })
2968
2530
  };
2969
2531
  }
2970
2532
 
@@ -2986,7 +2548,7 @@ function pipelineRunReceivedLog(props) {
2986
2548
  category: "api",
2987
2549
  event: "pipeline.run_received",
2988
2550
  message: "Pipeline run request received",
2989
- metadata: cleanMetadata({
2551
+ metadata: compact({
2990
2552
  stream: props.stream,
2991
2553
  inputBytes: byteLength2(formatUnknown(props.input)),
2992
2554
  metadataKeys: Object.keys(props.metadata ?? {})
@@ -3002,7 +2564,7 @@ function pipelineRunStartedLog(pipeline, runId) {
3002
2564
  category: "run",
3003
2565
  event: "pipeline.run_started",
3004
2566
  message: "Pipeline run started",
3005
- metadata: cleanMetadata({
2567
+ metadata: compact({
3006
2568
  stageCount: graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output").length,
3007
2569
  edgeCount: graph.edges.length
3008
2570
  })
@@ -3016,7 +2578,7 @@ function pipelineRunCompletedLog(props) {
3016
2578
  category: "run",
3017
2579
  event: "pipeline.run_completed",
3018
2580
  message: "Pipeline run completed",
3019
- metadata: cleanMetadata({
2581
+ metadata: compact({
3020
2582
  durationMs: props.durationMs,
3021
2583
  outputBytes: byteLength2(formatUnknown(props.output))
3022
2584
  })
@@ -3030,7 +2592,7 @@ function pipelineRunFailedLog(pipelineId, runId, error, startedAt) {
3030
2592
  category: "run",
3031
2593
  event: "pipeline.run_failed",
3032
2594
  message: "Pipeline run failed",
3033
- metadata: cleanMetadata({
2595
+ metadata: compact({
3034
2596
  durationMs: Date.now() - startedAt,
3035
2597
  error: serializeError(error)
3036
2598
  })
@@ -3057,7 +2619,7 @@ function pipelineStageLog(pipelineId, runId, event) {
3057
2619
  category,
3058
2620
  event: `${event.node.kind}.completed`,
3059
2621
  message: `${event.node.label} completed`,
3060
- metadata: cleanMetadata({
2622
+ metadata: compact({
3061
2623
  ...nodeMetadata(event.node),
3062
2624
  durationMs: event.durationMs
3063
2625
  })
@@ -3070,7 +2632,7 @@ function pipelineStageLog(pipelineId, runId, event) {
3070
2632
  category,
3071
2633
  event: `${event.node.kind}.failed`,
3072
2634
  message: `${event.node.label} failed`,
3073
- metadata: cleanMetadata({
2635
+ metadata: compact({
3074
2636
  ...nodeMetadata(event.node),
3075
2637
  durationMs: event.durationMs,
3076
2638
  error: serializeError(event.error)
@@ -3090,7 +2652,7 @@ function stageCategory(node) {
3090
2652
  return "stage";
3091
2653
  }
3092
2654
  function nodeMetadata(node) {
3093
- return cleanMetadata({
2655
+ return compact({
3094
2656
  nodeId: node.id,
3095
2657
  kind: node.kind,
3096
2658
  label: node.label,
@@ -3099,50 +2661,153 @@ function nodeMetadata(node) {
3099
2661
  branchKey: node.branchKey
3100
2662
  });
3101
2663
  }
3102
- function cleanMetadata(value) {
3103
- return Object.fromEntries(
3104
- Object.entries(value).filter(([, item]) => item !== void 0)
3105
- );
3106
- }
3107
2664
  function byteLength2(value) {
3108
2665
  return value === void 0 ? void 0 : new TextEncoder().encode(value).length;
3109
2666
  }
3110
- function formatUnknown(value) {
3111
- try {
3112
- return JSON.stringify(value);
3113
- } catch {
3114
- return void 0;
3115
- }
3116
- }
3117
2667
 
3118
- // src/runtime/runs.ts
3119
- var AsyncEventQueue = class {
3120
- values = [];
3121
- resolvers = [];
3122
- closed = false;
3123
- push(value) {
3124
- if (this.closed) {
3125
- return;
3126
- }
3127
- const resolver = this.resolvers.shift();
3128
- if (resolver !== void 0) {
3129
- resolver({ done: false, value });
3130
- return;
3131
- }
3132
- this.values.push(value);
3133
- }
3134
- close() {
3135
- this.closed = true;
3136
- for (const resolver of this.resolvers.splice(0)) {
3137
- resolver({ done: true, value: void 0 });
3138
- }
3139
- }
3140
- next() {
3141
- const value = this.values.shift();
3142
- if (value !== void 0) {
3143
- return Promise.resolve({ done: false, value });
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;
3144
2677
  }
3145
- if (this.closed) {
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;
2774
+ }
2775
+ transcript.push({
2776
+ entryId: transcript.length,
2777
+ kind: "message",
2778
+ role: "assistant",
2779
+ text
2780
+ });
2781
+ }
2782
+
2783
+ // src/runtime/runs.ts
2784
+ var AsyncEventQueue = class {
2785
+ values = [];
2786
+ resolvers = [];
2787
+ closed = false;
2788
+ push(value) {
2789
+ if (this.closed) {
2790
+ return;
2791
+ }
2792
+ const resolver = this.resolvers.shift();
2793
+ if (resolver !== void 0) {
2794
+ resolver({ done: false, value });
2795
+ return;
2796
+ }
2797
+ this.values.push(value);
2798
+ }
2799
+ close() {
2800
+ this.closed = true;
2801
+ for (const resolver of this.resolvers.splice(0)) {
2802
+ resolver({ done: true, value: void 0 });
2803
+ }
2804
+ }
2805
+ next() {
2806
+ const value = this.values.shift();
2807
+ if (value !== void 0) {
2808
+ return Promise.resolve({ done: false, value });
2809
+ }
2810
+ if (this.closed) {
3146
2811
  return Promise.resolve({ done: true, value: void 0 });
3147
2812
  }
3148
2813
  return new Promise((resolve2) => this.resolvers.push(resolve2));
@@ -3263,21 +2928,21 @@ function acceptTranscriptStreamEvent(transcript, event) {
3263
2928
  kind: "tool",
3264
2929
  toolName: event.toolCall.function.name,
3265
2930
  callId: event.toolCall.callId ?? event.toolCall.id,
3266
- args: formatJson2(event.toolCall.function.arguments)
2931
+ args: formatJson(event.toolCall.function.arguments)
3267
2932
  });
3268
2933
  }
3269
2934
  if (event.type === "tool_result") {
3270
2935
  const matched = findTranscriptToolEntry(transcript, event.toolName, event.toolCallId);
3271
2936
  if (matched === void 0) {
3272
- transcript.push({
2937
+ transcript.push(compact({
3273
2938
  entryId: transcript.length,
3274
2939
  kind: "tool",
3275
2940
  toolName: event.toolName,
3276
- ...event.toolCallId === void 0 ? {} : { callId: event.toolCallId },
2941
+ callId: event.toolCallId,
3277
2942
  args: event.args,
3278
2943
  result: event.result,
3279
- ...event.structuredResult === void 0 ? {} : { structuredResult: event.structuredResult }
3280
- });
2944
+ structuredResult: event.structuredResult
2945
+ }));
3281
2946
  return;
3282
2947
  }
3283
2948
  matched.args = matched.args ?? event.args;
@@ -3289,15 +2954,15 @@ function acceptTranscriptStreamEvent(transcript, event) {
3289
2954
  if (event.type === "agent_tool_event") {
3290
2955
  const matched = findTranscriptToolEntry(transcript, event.toolName, event.toolCallId);
3291
2956
  if (matched === void 0) {
3292
- transcript.push({
2957
+ transcript.push(compact({
3293
2958
  entryId: transcript.length,
3294
2959
  kind: "tool",
3295
2960
  toolName: event.toolName,
3296
- ...event.toolCallId === void 0 ? {} : { callId: event.toolCallId },
2961
+ callId: event.toolCallId,
3297
2962
  childEvents: [childAgentTranscriptEvent(event)].filter(
3298
2963
  (childEvent) => childEvent !== void 0
3299
2964
  )
3300
- });
2965
+ }));
3301
2966
  return;
3302
2967
  }
3303
2968
  appendChildAgentTranscriptEvent(matched, event);
@@ -3323,13 +2988,13 @@ function acceptTranscriptStreamEvent(transcript, event) {
3323
2988
  approvalCallId(event.approval)
3324
2989
  );
3325
2990
  if (matched !== void 0) {
3326
- matched.approval = {
2991
+ matched.approval = compact({
3327
2992
  id: event.approval.id,
3328
2993
  status: event.approval.status,
3329
2994
  requestedAt: event.approval.requestedAt,
3330
- ...event.approval.resolvedAt === void 0 ? {} : { resolvedAt: event.approval.resolvedAt },
3331
- ...event.approval.reason === void 0 ? {} : { reason: event.approval.reason }
3332
- };
2995
+ resolvedAt: event.approval.resolvedAt,
2996
+ reason: event.approval.reason
2997
+ });
3333
2998
  }
3334
2999
  }
3335
3000
  if (event.type === "tool_question_request") {
@@ -3354,14 +3019,14 @@ function acceptTranscriptStreamEvent(transcript, event) {
3354
3019
  questionCallId(event.question)
3355
3020
  );
3356
3021
  if (matched !== void 0) {
3357
- matched.question = {
3022
+ matched.question = compact({
3358
3023
  id: event.question.id,
3359
3024
  status: event.question.status,
3360
3025
  requestedAt: event.question.requestedAt,
3361
- ...event.question.answeredAt === void 0 ? {} : { answeredAt: event.question.answeredAt },
3026
+ answeredAt: event.question.answeredAt,
3362
3027
  questions: event.question.questions,
3363
- ...event.question.answers === void 0 ? {} : { answers: event.question.answers }
3364
- };
3028
+ answers: event.question.answers
3029
+ });
3365
3030
  }
3366
3031
  }
3367
3032
  if (event.type === "final" && event.trace?.traceId !== void 0) {
@@ -3415,51 +3080,51 @@ function appendChildAgentTranscriptEvent(entry, event) {
3415
3080
  function childAgentTranscriptEvent(event) {
3416
3081
  const child = event.event;
3417
3082
  if (child.type === "text_delta") {
3418
- return {
3083
+ return compact({
3419
3084
  kind: "message",
3420
3085
  agentId: event.agentId,
3421
- ...event.agentName === void 0 ? {} : { agentName: event.agentName },
3086
+ agentName: event.agentName,
3422
3087
  text: child.delta
3423
- };
3088
+ });
3424
3089
  }
3425
3090
  if (child.type === "reasoning_delta") {
3426
- return {
3091
+ return compact({
3427
3092
  kind: "reasoning",
3428
3093
  agentId: event.agentId,
3429
- ...event.agentName === void 0 ? {} : { agentName: event.agentName },
3430
- ...child.id === void 0 ? {} : { reasoningId: child.id },
3094
+ agentName: event.agentName,
3095
+ reasoningId: child.id,
3431
3096
  text: child.delta
3432
- };
3097
+ });
3433
3098
  }
3434
3099
  if (child.type === "tool_call") {
3435
- return {
3100
+ return compact({
3436
3101
  kind: "tool",
3437
3102
  agentId: event.agentId,
3438
- ...event.agentName === void 0 ? {} : { agentName: event.agentName },
3103
+ agentName: event.agentName,
3439
3104
  toolName: child.toolCall.function.name,
3440
- ...child.toolCall.callId === void 0 && child.toolCall.id === void 0 ? {} : { callId: child.toolCall.callId ?? child.toolCall.id },
3441
- args: formatJson2(child.toolCall.function.arguments)
3442
- };
3105
+ callId: child.toolCall.callId ?? child.toolCall.id,
3106
+ args: formatJson(child.toolCall.function.arguments)
3107
+ });
3443
3108
  }
3444
3109
  if (child.type === "tool_result") {
3445
- return {
3110
+ return compact({
3446
3111
  kind: "tool",
3447
3112
  agentId: event.agentId,
3448
- ...event.agentName === void 0 ? {} : { agentName: event.agentName },
3113
+ agentName: event.agentName,
3449
3114
  toolName: child.toolName,
3450
- ...child.toolCallId === void 0 ? {} : { callId: child.toolCallId },
3115
+ callId: child.toolCallId,
3451
3116
  args: child.args,
3452
3117
  result: child.result,
3453
- ...child.structuredResult === void 0 ? {} : { structuredResult: child.structuredResult }
3454
- };
3118
+ structuredResult: child.structuredResult
3119
+ });
3455
3120
  }
3456
3121
  if (child.type === "error") {
3457
- return {
3122
+ return compact({
3458
3123
  kind: "message",
3459
3124
  agentId: event.agentId,
3460
- ...event.agentName === void 0 ? {} : { agentName: event.agentName },
3125
+ agentName: event.agentName,
3461
3126
  text: `Error: ${errorText(child.error)}`
3462
- };
3127
+ });
3463
3128
  }
3464
3129
  return void 0;
3465
3130
  }
@@ -3532,12 +3197,12 @@ function appendTranscriptReasoningText(transcript, delta, reasoningId) {
3532
3197
  last.text = `${last.text}${delta}`;
3533
3198
  return;
3534
3199
  }
3535
- transcript.push({
3200
+ transcript.push(compact({
3536
3201
  entryId: transcript.length,
3537
3202
  kind: "reasoning",
3538
- ...reasoningId === void 0 ? {} : { reasoningId },
3203
+ reasoningId,
3539
3204
  text: delta
3540
- });
3205
+ }));
3541
3206
  }
3542
3207
  function findTranscriptToolEntry(transcript, toolName, callId) {
3543
3208
  for (let index = transcript.length - 1; index >= 0; index -= 1) {
@@ -3574,7 +3239,7 @@ function extractMessageText(message) {
3574
3239
  return [item.text];
3575
3240
  }
3576
3241
  if (item.type === "tool_call") {
3577
- return [`${item.function.name}(${formatJson2(item.function.arguments)})`];
3242
+ return [`${item.function.name}(${formatJson(item.function.arguments)})`];
3578
3243
  }
3579
3244
  if (item.type === "tool_result") {
3580
3245
  return item.content.map(
@@ -3599,25 +3264,19 @@ function optionalTranscriptAttachments(message) {
3599
3264
  }
3600
3265
  if (content.type === "document") {
3601
3266
  return [
3602
- {
3267
+ compact({
3603
3268
  kind: "document",
3604
- ...content.source.filename === void 0 ? {} : { name: content.source.filename },
3605
- ...content.source.mediaType === void 0 ? {} : { mediaType: content.source.mediaType },
3606
- ...content.source.type === "base64" ? { data: content.source.data } : content.source.type === "url" ? { url: content.source.url } : {}
3607
- }
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
+ })
3608
3274
  ];
3609
3275
  }
3610
3276
  return [];
3611
3277
  });
3612
3278
  return attachments.length === 0 ? {} : { attachments };
3613
3279
  }
3614
- function formatJson2(value) {
3615
- try {
3616
- return JSON.stringify(value, null, 2);
3617
- } catch {
3618
- return String(value);
3619
- }
3620
- }
3621
3280
  async function parseRunRequest(c) {
3622
3281
  let body;
3623
3282
  try {
@@ -3695,7 +3354,7 @@ async function parseRunRequest(c) {
3695
3354
  }
3696
3355
  }
3697
3356
  if ("metadata" in body) {
3698
- if (!isJsonObject2(body.metadata)) {
3357
+ if (!isJsonObject(body.metadata)) {
3699
3358
  return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
3700
3359
  }
3701
3360
  request.metadata = body.metadata;
@@ -3751,7 +3410,7 @@ function registerPipelineRoutes(app, props) {
3751
3410
  const logs = await props.logStore.listPipelineLogs({
3752
3411
  pipelineId,
3753
3412
  limit,
3754
- ...after === void 0 ? {} : { after }
3413
+ ...compact({ after })
3755
3414
  });
3756
3415
  const last = logs.at(-1);
3757
3416
  return c.json({
@@ -3822,7 +3481,7 @@ function registerPipelineRoutes(app, props) {
3822
3481
  }
3823
3482
  return executePipelineRun(c, props, pipeline, {
3824
3483
  input: sourceRun.input,
3825
- ...body.stream === void 0 ? {} : { stream: body.stream },
3484
+ ...compact({ stream: body.stream }),
3826
3485
  metadata: replayMetadata(sourceRun.metadata, body.metadata, sourceRun.runId)
3827
3486
  });
3828
3487
  });
@@ -3838,7 +3497,7 @@ async function executePipelineRun(c, props, pipeline, body) {
3838
3497
  runId,
3839
3498
  stream: body.stream === true,
3840
3499
  input: body.input,
3841
- ...body.metadata === void 0 ? {} : { metadata: body.metadata }
3500
+ ...compact({ metadata: body.metadata })
3842
3501
  })
3843
3502
  );
3844
3503
  await savePipelineRun(props.runStore, {
@@ -3846,7 +3505,7 @@ async function executePipelineRun(c, props, pipeline, body) {
3846
3505
  pipelineId: pipeline.id,
3847
3506
  status: "running",
3848
3507
  input: body.input,
3849
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
3508
+ ...compact({ metadata: body.metadata }),
3850
3509
  startedAt: startedAtIso
3851
3510
  });
3852
3511
  if (body.stream === true) {
@@ -3856,9 +3515,8 @@ async function executePipelineRun(c, props, pipeline, body) {
3856
3515
  input: body.input,
3857
3516
  startedAt,
3858
3517
  startedAtIso,
3859
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
3860
- ...props.logStore === void 0 ? {} : { logStore: props.logStore },
3861
- ...props.runStore === void 0 ? {} : { runStore: props.runStore }
3518
+ ...compact({ metadata: body.metadata }),
3519
+ ...compact({ logStore: props.logStore, runStore: props.runStore })
3862
3520
  });
3863
3521
  }
3864
3522
  try {
@@ -3878,7 +3536,7 @@ async function executePipelineRun(c, props, pipeline, body) {
3878
3536
  status: "success",
3879
3537
  input: body.input,
3880
3538
  output: jsonOutput,
3881
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
3539
+ ...compact({ metadata: body.metadata }),
3882
3540
  startedAt: startedAtIso,
3883
3541
  endedAt: new Date(endedAt).toISOString(),
3884
3542
  durationMs: endedAt - startedAt
@@ -3906,7 +3564,7 @@ async function executePipelineRun(c, props, pipeline, body) {
3906
3564
  status: "error",
3907
3565
  input: body.input,
3908
3566
  error: serializeError(error),
3909
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
3567
+ ...compact({ metadata: body.metadata }),
3910
3568
  startedAt: startedAtIso,
3911
3569
  endedAt: new Date(endedAt).toISOString(),
3912
3570
  durationMs: endedAt - startedAt
@@ -3953,7 +3611,7 @@ async function* pipelineRunEvents(props) {
3953
3611
  status: "success",
3954
3612
  input: props.input,
3955
3613
  output: jsonOutput,
3956
- ...props.metadata === void 0 ? {} : { metadata: props.metadata },
3614
+ ...compact({ metadata: props.metadata }),
3957
3615
  startedAt: props.startedAtIso,
3958
3616
  endedAt: new Date(endedAt).toISOString(),
3959
3617
  durationMs: endedAt - props.startedAt
@@ -3984,7 +3642,7 @@ async function* pipelineRunEvents(props) {
3984
3642
  status: "error",
3985
3643
  input: props.input,
3986
3644
  error: serializeError(error),
3987
- ...props.metadata === void 0 ? {} : { metadata: props.metadata },
3645
+ ...compact({ metadata: props.metadata }),
3988
3646
  startedAt: props.startedAtIso,
3989
3647
  endedAt: new Date(endedAt).toISOString(),
3990
3648
  durationMs: endedAt - props.startedAt
@@ -4023,7 +3681,7 @@ async function parsePipelineRunRequest(c) {
4023
3681
  if (!isObject(body)) {
4024
3682
  return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
4025
3683
  }
4026
- if (!("input" in body) || !isJsonValue3(body.input)) {
3684
+ if (!("input" in body) || !isJsonValue2(body.input)) {
4027
3685
  return { error: errorResponse(c, 400, "bad_request", "input must be JSON-compatible") };
4028
3686
  }
4029
3687
  const request = {
@@ -4036,7 +3694,7 @@ async function parsePipelineRunRequest(c) {
4036
3694
  request.stream = body.stream;
4037
3695
  }
4038
3696
  if ("metadata" in body) {
4039
- if (!isJsonObject2(body.metadata)) {
3697
+ if (!isJsonObject(body.metadata)) {
4040
3698
  return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
4041
3699
  }
4042
3700
  request.metadata = body.metadata;
@@ -4061,7 +3719,7 @@ async function parsePipelineReplayRequest(c) {
4061
3719
  request.stream = body.stream;
4062
3720
  }
4063
3721
  if ("metadata" in body) {
4064
- if (!isJsonObject2(body.metadata)) {
3722
+ if (!isJsonObject(body.metadata)) {
4065
3723
  return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
4066
3724
  }
4067
3725
  request.metadata = body.metadata;
@@ -4095,15 +3753,15 @@ function parsePipelineLogAfter(value) {
4095
3753
  }
4096
3754
  return after;
4097
3755
  }
4098
- function isJsonValue3(value) {
3756
+ function isJsonValue2(value) {
4099
3757
  if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4100
3758
  return Number.isFinite(value) || typeof value !== "number";
4101
3759
  }
4102
3760
  if (Array.isArray(value)) {
4103
- return value.every(isJsonValue3);
3761
+ return value.every(isJsonValue2);
4104
3762
  }
4105
3763
  if (isObject(value)) {
4106
- return Object.values(value).every((item) => item === void 0 || isJsonValue3(item));
3764
+ return Object.values(value).every((item) => item === void 0 || isJsonValue2(item));
4107
3765
  }
4108
3766
  return false;
4109
3767
  }
@@ -4187,12 +3845,12 @@ async function parseQuestionAnswerRequest(c) {
4187
3845
  if ("custom" in answer && typeof answer.custom !== "boolean") {
4188
3846
  return { error: errorResponse(c, 400, "bad_request", "custom must be a boolean") };
4189
3847
  }
4190
- answers.push({
3848
+ answers.push(compact({
4191
3849
  questionId: answer.questionId.trim(),
4192
3850
  answer: answer.answer.trim(),
4193
- ...typeof answer.choice === "string" ? { choice: answer.choice } : {},
4194
- ...typeof answer.custom === "boolean" ? { custom: answer.custom } : {}
4195
- });
3851
+ choice: typeof answer.choice === "string" ? answer.choice : void 0,
3852
+ custom: typeof answer.custom === "boolean" ? answer.custom : void 0
3853
+ }));
4196
3854
  }
4197
3855
  return { answers };
4198
3856
  }
@@ -4210,13 +3868,13 @@ function createQuestionRuntime() {
4210
3868
  if ("error" in prompts) {
4211
3869
  return control.skip(prompts.error);
4212
3870
  }
4213
- const answers = await requestQuestion(questions, context, {
3871
+ const answers = await requestQuestion(questions, context, compact({
4214
3872
  toolName,
4215
- ...toolCallId === void 0 ? {} : { toolCallId },
3873
+ toolCallId,
4216
3874
  internalCallId,
4217
3875
  args,
4218
3876
  questions: prompts.questions
4219
- });
3877
+ }));
4220
3878
  return control.skip(JSON.stringify({ answers }));
4221
3879
  }
4222
3880
  });
@@ -4260,18 +3918,20 @@ function createQuestionRuntime() {
4260
3918
  async function requestQuestion(questions, context, request) {
4261
3919
  const id = globalThis.crypto.randomUUID();
4262
3920
  const question = {
4263
- id,
4264
- runId: context.runId,
4265
- agentId: context.agentId,
4266
- ...context.sessionId === void 0 ? {} : { sessionId: context.sessionId },
4267
- toolName: request.toolName,
4268
- ...request.toolCallId === void 0 ? {} : { callId: request.toolCallId },
4269
- internalCallId: request.internalCallId,
4270
- args: request.args,
4271
- questions: request.questions,
4272
- status: "pending",
4273
- requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
4274
- ...context.emit === void 0 ? {} : { emit: context.emit },
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
+ }),
4275
3935
  resolve: () => {
4276
3936
  }
4277
3937
  };
@@ -4382,7 +4042,7 @@ function sessionCreatedLog(session) {
4382
4042
  category: "session",
4383
4043
  event: "session.created",
4384
4044
  message: "Session created",
4385
- metadata: cleanMetadata2({
4045
+ metadata: compact({
4386
4046
  agentId: session.agentId,
4387
4047
  hasTitle: session.title !== void 0,
4388
4048
  titleLength: session.title?.length ?? 0
@@ -4397,7 +4057,7 @@ function runReceivedLog(props) {
4397
4057
  category: "api",
4398
4058
  event: "run.received",
4399
4059
  message: "Run request received",
4400
- metadata: cleanMetadata2({
4060
+ metadata: compact({
4401
4061
  agentId: props.agentId,
4402
4062
  stream: props.stream,
4403
4063
  message: messageSummary(props.message),
@@ -4416,7 +4076,7 @@ function runStartedLog(session, runId) {
4416
4076
  category: "run",
4417
4077
  event: "run.started",
4418
4078
  message: "Run started",
4419
- metadata: cleanMetadata2({
4079
+ metadata: compact({
4420
4080
  agentId: session.agentId,
4421
4081
  existingMessageCount: session.messageCount
4422
4082
  })
@@ -4430,7 +4090,7 @@ function memoryLoadedLog(session, runId) {
4430
4090
  category: "memory",
4431
4091
  event: "memory.loaded",
4432
4092
  message: "Session memory loaded",
4433
- metadata: cleanMetadata2({
4093
+ metadata: compact({
4434
4094
  messageCount: session.messageCount,
4435
4095
  transcriptEntries: session.transcript.length
4436
4096
  })
@@ -4444,7 +4104,7 @@ function runCompletedLog(props) {
4444
4104
  category: "run",
4445
4105
  event: "run.completed",
4446
4106
  message: "Run completed",
4447
- metadata: cleanMetadata2({
4107
+ metadata: compact({
4448
4108
  durationMs: props.durationMs,
4449
4109
  usage: usageSummary(props.usage),
4450
4110
  outputBytes: byteLength3(props.output),
@@ -4460,7 +4120,7 @@ function memorySavedLog(props) {
4460
4120
  category: "memory",
4461
4121
  event: "memory.saved",
4462
4122
  message: "Session memory saved",
4463
- metadata: cleanMetadata2({
4123
+ metadata: compact({
4464
4124
  messageCount: props.messageCount
4465
4125
  })
4466
4126
  };
@@ -4473,7 +4133,7 @@ function runFailedLog(sessionId, runId, error, startedAt) {
4473
4133
  category: "run",
4474
4134
  event: "run.failed",
4475
4135
  message: "Run failed",
4476
- metadata: cleanMetadata2({
4136
+ metadata: compact({
4477
4137
  durationMs: Date.now() - startedAt,
4478
4138
  error: serializeError(error)
4479
4139
  })
@@ -4490,7 +4150,7 @@ function logsFromStreamEvent(props) {
4490
4150
  category: "prompt",
4491
4151
  event: "prompt.prepared",
4492
4152
  message: `Turn ${event.turn} prompt prepared`,
4493
- metadata: cleanMetadata2({
4153
+ metadata: compact({
4494
4154
  turn: event.turn,
4495
4155
  prompt: messageSummary(event.prompt),
4496
4156
  historyCount: event.history.length
@@ -4507,11 +4167,11 @@ function logsFromStreamEvent(props) {
4507
4167
  category: "tool",
4508
4168
  event: "tool.called",
4509
4169
  message: `Tool ${event.toolCall.function.name} called`,
4510
- metadata: cleanMetadata2({
4170
+ metadata: compact({
4511
4171
  turn: event.turn,
4512
4172
  toolName: event.toolCall.function.name,
4513
4173
  callId: event.toolCall.callId ?? event.toolCall.id,
4514
- argumentBytes: byteLength3(formatUnknown2(event.toolCall.function.arguments))
4174
+ argumentBytes: byteLength3(formatUnknown(event.toolCall.function.arguments))
4515
4175
  })
4516
4176
  }
4517
4177
  ];
@@ -4525,7 +4185,7 @@ function logsFromStreamEvent(props) {
4525
4185
  category: "tool",
4526
4186
  event: "tool.completed",
4527
4187
  message: `Tool ${event.toolName} completed`,
4528
- metadata: cleanMetadata2({
4188
+ metadata: compact({
4529
4189
  turn: event.turn,
4530
4190
  toolName: event.toolName,
4531
4191
  callId: event.toolCallId,
@@ -4546,7 +4206,7 @@ function logsFromStreamEvent(props) {
4546
4206
  category: "model",
4547
4207
  event: "model.turn.completed",
4548
4208
  message: `Model turn ${event.turn} completed`,
4549
- metadata: cleanMetadata2({
4209
+ metadata: compact({
4550
4210
  turn: event.turn,
4551
4211
  contentCount: event.response.choice.length,
4552
4212
  usage: usageSummary(event.response.usage)
@@ -4579,7 +4239,7 @@ function logsFromStreamEvent(props) {
4579
4239
  category: "approval",
4580
4240
  event: "approval.requested",
4581
4241
  message: `Approval requested for ${event.approval.toolName}`,
4582
- metadata: cleanMetadata2({
4242
+ metadata: compact({
4583
4243
  approvalId: event.approval.id,
4584
4244
  toolName: event.approval.toolName,
4585
4245
  callId: event.approval.callId,
@@ -4590,411 +4250,715 @@ function logsFromStreamEvent(props) {
4590
4250
  }
4591
4251
  ];
4592
4252
  }
4593
- if (event.type === "tool_approval_result") {
4594
- return [
4595
- {
4596
- sessionId,
4597
- runId,
4598
- level: event.approval.status === "approved" ? "info" : "warn",
4599
- category: "approval",
4600
- event: "approval.resolved",
4601
- message: `Approval ${event.approval.status} for ${event.approval.toolName}`,
4602
- metadata: cleanMetadata2({
4603
- approvalId: event.approval.id,
4604
- toolName: event.approval.toolName,
4605
- callId: event.approval.callId,
4606
- status: event.approval.status,
4607
- hasReason: event.approval.reason !== void 0
4608
- })
4609
- }
4610
- ];
4253
+ if (event.type === "tool_approval_result") {
4254
+ return [
4255
+ {
4256
+ sessionId,
4257
+ runId,
4258
+ level: event.approval.status === "approved" ? "info" : "warn",
4259
+ category: "approval",
4260
+ event: "approval.resolved",
4261
+ message: `Approval ${event.approval.status} for ${event.approval.toolName}`,
4262
+ metadata: compact({
4263
+ approvalId: event.approval.id,
4264
+ toolName: event.approval.toolName,
4265
+ callId: event.approval.callId,
4266
+ status: event.approval.status,
4267
+ hasReason: event.approval.reason !== void 0
4268
+ })
4269
+ }
4270
+ ];
4271
+ }
4272
+ if (event.type === "tool_question_request") {
4273
+ return [
4274
+ {
4275
+ sessionId,
4276
+ runId,
4277
+ level: "info",
4278
+ category: "question",
4279
+ event: "question.requested",
4280
+ message: `Question requested by ${event.question.toolName}`,
4281
+ metadata: compact({
4282
+ questionId: event.question.id,
4283
+ toolName: event.question.toolName,
4284
+ callId: event.question.callId,
4285
+ status: event.question.status,
4286
+ questionCount: event.question.questions.length,
4287
+ argumentBytes: byteLength3(event.question.args)
4288
+ })
4289
+ }
4290
+ ];
4291
+ }
4292
+ if (event.type === "tool_question_result") {
4293
+ return [
4294
+ {
4295
+ sessionId,
4296
+ runId,
4297
+ level: "info",
4298
+ category: "question",
4299
+ event: "question.answered",
4300
+ message: `Question answered for ${event.question.toolName}`,
4301
+ metadata: compact({
4302
+ questionId: event.question.id,
4303
+ toolName: event.question.toolName,
4304
+ callId: event.question.callId,
4305
+ status: event.question.status,
4306
+ answerCount: event.question.answers?.length ?? 0
4307
+ })
4308
+ }
4309
+ ];
4310
+ }
4311
+ if (event.type === "agent_tool_event") {
4312
+ return childAgentLog(event, sessionId, runId);
4313
+ }
4314
+ return [];
4315
+ }
4316
+ async function* emitLog(store, input) {
4317
+ const log = await appendSessionLog(store, input);
4318
+ if (log !== void 0) {
4319
+ yield { type: "session_log", log };
4320
+ }
4321
+ }
4322
+ function childAgentLog(event, sessionId, runId) {
4323
+ const child = event.event;
4324
+ if (child.type === "tool_call") {
4325
+ return [
4326
+ {
4327
+ sessionId,
4328
+ runId,
4329
+ level: "debug",
4330
+ category: "tool",
4331
+ event: "child_tool.called",
4332
+ message: `Child agent ${event.agentName ?? event.agentId} called ${child.toolCall.function.name}`,
4333
+ metadata: compact({
4334
+ parentToolName: event.toolName,
4335
+ agentId: event.agentId,
4336
+ hasAgentName: event.agentName !== void 0,
4337
+ turn: event.turn,
4338
+ childTurn: child.turn,
4339
+ toolName: child.toolCall.function.name,
4340
+ callId: child.toolCall.callId ?? child.toolCall.id,
4341
+ argumentBytes: byteLength3(formatUnknown(child.toolCall.function.arguments))
4342
+ })
4343
+ }
4344
+ ];
4345
+ }
4346
+ if (child.type === "tool_result") {
4347
+ return [
4348
+ {
4349
+ sessionId,
4350
+ runId,
4351
+ level: "debug",
4352
+ category: "tool",
4353
+ event: "child_tool.completed",
4354
+ message: `Child agent ${event.agentName ?? event.agentId} completed ${child.toolName}`,
4355
+ metadata: compact({
4356
+ parentToolName: event.toolName,
4357
+ agentId: event.agentId,
4358
+ hasAgentName: event.agentName !== void 0,
4359
+ turn: event.turn,
4360
+ childTurn: child.turn,
4361
+ toolName: child.toolName,
4362
+ callId: child.toolCallId,
4363
+ resultBytes: byteLength3(child.result),
4364
+ structuredResultBytes: child.structuredResult === void 0 ? void 0 : byteLength3(JSON.stringify(child.structuredResult))
4365
+ })
4366
+ }
4367
+ ];
4368
+ }
4369
+ if (child.type === "turn_start") {
4370
+ return [
4371
+ {
4372
+ sessionId,
4373
+ runId,
4374
+ level: "debug",
4375
+ category: "run",
4376
+ event: "child_agent.turn_started",
4377
+ message: `Child agent ${event.agentName ?? event.agentId} turn ${child.turn} started`,
4378
+ metadata: compact({
4379
+ parentToolName: event.toolName,
4380
+ agentId: event.agentId,
4381
+ hasAgentName: event.agentName !== void 0,
4382
+ childTurn: child.turn,
4383
+ historyCount: child.history.length
4384
+ })
4385
+ }
4386
+ ];
4387
+ }
4388
+ if (child.type === "final") {
4389
+ return [
4390
+ {
4391
+ sessionId,
4392
+ runId,
4393
+ level: "debug",
4394
+ category: "run",
4395
+ event: "child_agent.completed",
4396
+ message: `Child agent ${event.agentName ?? event.agentId} completed`,
4397
+ metadata: compact({
4398
+ parentToolName: event.toolName,
4399
+ agentId: event.agentId,
4400
+ hasAgentName: event.agentName !== void 0,
4401
+ usage: usageSummary(child.usage),
4402
+ outputBytes: byteLength3(child.output),
4403
+ messageCount: child.messages.length
4404
+ })
4405
+ }
4406
+ ];
4407
+ }
4408
+ if (child.type === "error") {
4409
+ return [
4410
+ {
4411
+ sessionId,
4412
+ runId,
4413
+ level: "error",
4414
+ category: "run",
4415
+ event: "child_agent.failed",
4416
+ message: `Child agent ${event.agentName ?? event.agentId} failed`,
4417
+ metadata: compact({
4418
+ parentToolName: event.toolName,
4419
+ agentId: event.agentId,
4420
+ hasAgentName: event.agentName !== void 0,
4421
+ error: serializeError(child.error)
4422
+ })
4423
+ }
4424
+ ];
4425
+ }
4426
+ return [];
4427
+ }
4428
+ function messageSummary(message) {
4429
+ if (typeof message === "string") {
4430
+ return {
4431
+ role: "user",
4432
+ contentKind: "text",
4433
+ byteLength: byteLength3(message)
4434
+ };
4435
+ }
4436
+ return {
4437
+ role: message.role,
4438
+ contentKind: Array.isArray(message.content) ? "parts" : "text",
4439
+ partCount: Array.isArray(message.content) ? message.content.length : 1,
4440
+ byteLength: byteLength3(formatUnknown(message.content))
4441
+ };
4442
+ }
4443
+ function usageSummary(value) {
4444
+ if (value === void 0 || value === null || typeof value !== "object") {
4445
+ return void 0;
4446
+ }
4447
+ const record = value;
4448
+ return compact({
4449
+ inputTokens: numericValue(record.inputTokens),
4450
+ outputTokens: numericValue(record.outputTokens),
4451
+ totalTokens: numericValue(record.totalTokens),
4452
+ cachedInputTokens: numericValue(record.cachedInputTokens),
4453
+ cacheCreationInputTokens: numericValue(record.cacheCreationInputTokens)
4454
+ });
4455
+ }
4456
+ function numericValue(value) {
4457
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
4458
+ }
4459
+ function byteLength3(value) {
4460
+ return value === void 0 ? 0 : new TextEncoder().encode(value).byteLength;
4461
+ }
4462
+
4463
+ // src/runtime/sessions.ts
4464
+ function registerSessionRoutes(app, props) {
4465
+ app.get("/sessions", async (c) => {
4466
+ const agentId = optionalQueryString(c.req.query("agentId"));
4467
+ if (agentId !== void 0 && !props.agentMap.has(agentId)) {
4468
+ return errorResponse(c, 404, "not_found", "Agent not found");
4469
+ }
4470
+ const limit = parseLimit(c.req.query("limit"));
4471
+ if (limit === void 0) {
4472
+ return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
4473
+ }
4474
+ const sessions = await props.sessionStore.listSessions({
4475
+ ...compact({ agentId }),
4476
+ limit
4477
+ });
4478
+ return c.json({ sessions });
4479
+ });
4480
+ app.post("/sessions", async (c) => {
4481
+ const body = await parseCreateSessionRequest(c);
4482
+ if ("error" in body) {
4483
+ return body.error;
4484
+ }
4485
+ if (!props.agentMap.has(body.agentId)) {
4486
+ return errorResponse(c, 404, "not_found", "Agent not found");
4487
+ }
4488
+ const session = await props.sessionStore.createSession({
4489
+ id: globalThis.crypto.randomUUID(),
4490
+ agentId: body.agentId,
4491
+ ...compact({ title: body.title, metadata: body.metadata })
4492
+ });
4493
+ await appendSessionLog(props.sessionStore, sessionCreatedLog(session));
4494
+ return c.json(session, 201);
4495
+ });
4496
+ app.get("/sessions/:sessionId", async (c) => {
4497
+ const session = await props.sessionStore.getSession(c.req.param("sessionId"));
4498
+ if (session === void 0) {
4499
+ return errorResponse(c, 404, "not_found", "Session not found");
4500
+ }
4501
+ return c.json(session);
4502
+ });
4503
+ app.get("/sessions/:sessionId/logs", async (c) => {
4504
+ const sessionId = c.req.param("sessionId");
4505
+ const session = await props.sessionStore.getSession(sessionId);
4506
+ if (session === void 0) {
4507
+ return errorResponse(c, 404, "not_found", "Session not found");
4508
+ }
4509
+ if (props.sessionStore.listSessionLogs === void 0) {
4510
+ return errorResponse(
4511
+ c,
4512
+ 501,
4513
+ "unsupported_capability",
4514
+ 'Capability "sessions.logs" is not implemented by this runner',
4515
+ { capability: "sessions", operation: "logs" }
4516
+ );
4517
+ }
4518
+ const limit = parseLimit(c.req.query("limit"), 200, 1e3);
4519
+ if (limit === void 0) {
4520
+ return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
4521
+ }
4522
+ const after = parseAfter(c.req.query("after"));
4523
+ if (after === false) {
4524
+ return errorResponse(c, 400, "bad_request", "after must be a non-negative integer");
4525
+ }
4526
+ const logs = await props.sessionStore.listSessionLogs({
4527
+ sessionId,
4528
+ limit,
4529
+ ...compact({ after })
4530
+ });
4531
+ const last = logs.at(-1);
4532
+ return c.json({
4533
+ logs,
4534
+ ...logs.length === limit && last !== void 0 ? { nextCursor: last.sequence } : {}
4535
+ });
4536
+ });
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);
4611
4728
  }
4612
- if (event.type === "tool_question_request") {
4613
- return [
4614
- {
4615
- sessionId,
4616
- runId,
4617
- level: "info",
4618
- category: "question",
4619
- event: "question.requested",
4620
- message: `Question requested by ${event.question.toolName}`,
4621
- metadata: cleanMetadata2({
4622
- questionId: event.question.id,
4623
- toolName: event.question.toolName,
4624
- callId: event.question.callId,
4625
- status: event.question.status,
4626
- questionCount: event.question.questions.length,
4627
- argumentBytes: byteLength3(event.question.args)
4628
- })
4729
+ deleteSession(id) {
4730
+ for (const trace of this.traces.values()) {
4731
+ if (trace.sessionId === id) {
4732
+ this.traces.delete(trace.id);
4629
4733
  }
4630
- ];
4734
+ }
4735
+ return this.sessions.delete(id);
4631
4736
  }
4632
- if (event.type === "tool_question_result") {
4633
- return [
4634
- {
4635
- sessionId,
4636
- runId,
4637
- level: "info",
4638
- category: "question",
4639
- event: "question.answered",
4640
- message: `Question answered for ${event.question.toolName}`,
4641
- metadata: cleanMetadata2({
4642
- questionId: event.question.id,
4643
- toolName: event.question.toolName,
4644
- callId: event.question.callId,
4645
- status: event.question.status,
4646
- answerCount: event.question.answers?.length ?? 0
4647
- })
4648
- }
4649
- ];
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);
4650
4739
  }
4651
- if (event.type === "agent_tool_event") {
4652
- return childAgentLog(event, sessionId, runId);
4740
+ listSessionTraces(options) {
4741
+ return this.listTraces({ sessionId: options.sessionId, limit: options.limit });
4653
4742
  }
4654
- return [];
4655
- }
4656
- async function* emitLog(store, input) {
4657
- const log = await appendSessionLog(store, input);
4658
- if (log !== void 0) {
4659
- yield { type: "session_log", log };
4743
+ getTrace(id) {
4744
+ return this.traces.get(id);
4660
4745
  }
4661
- }
4662
- function childAgentLog(event, sessionId, runId) {
4663
- const child = event.event;
4664
- if (child.type === "tool_call") {
4665
- return [
4666
- {
4667
- sessionId,
4668
- runId,
4669
- level: "debug",
4670
- category: "tool",
4671
- event: "child_tool.called",
4672
- message: `Child agent ${event.agentName ?? event.agentId} called ${child.toolCall.function.name}`,
4673
- metadata: cleanMetadata2({
4674
- parentToolName: event.toolName,
4675
- agentId: event.agentId,
4676
- hasAgentName: event.agentName !== void 0,
4677
- turn: event.turn,
4678
- childTurn: child.turn,
4679
- toolName: child.toolCall.function.name,
4680
- callId: child.toolCall.callId ?? child.toolCall.id,
4681
- argumentBytes: byteLength3(formatUnknown2(child.toolCall.function.arguments))
4682
- })
4683
- }
4684
- ];
4746
+ saveTrace(trace) {
4747
+ this.traces.set(trace.id, trace);
4748
+ return trace;
4685
4749
  }
4686
- if (child.type === "tool_result") {
4687
- return [
4688
- {
4689
- sessionId,
4690
- runId,
4691
- level: "debug",
4692
- category: "tool",
4693
- event: "child_tool.completed",
4694
- message: `Child agent ${event.agentName ?? event.agentId} completed ${child.toolName}`,
4695
- metadata: cleanMetadata2({
4696
- parentToolName: event.toolName,
4697
- agentId: event.agentId,
4698
- hasAgentName: event.agentName !== void 0,
4699
- turn: event.turn,
4700
- childTurn: child.turn,
4701
- toolName: child.toolName,
4702
- callId: child.toolCallId,
4703
- resultBytes: byteLength3(child.result),
4704
- structuredResultBytes: child.structuredResult === void 0 ? void 0 : byteLength3(JSON.stringify(child.structuredResult))
4705
- })
4706
- }
4707
- ];
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;
4708
4766
  }
4709
- if (child.type === "turn_start") {
4710
- return [
4711
- {
4712
- sessionId,
4713
- runId,
4714
- level: "debug",
4715
- category: "run",
4716
- event: "child_agent.turn_started",
4717
- message: `Child agent ${event.agentName ?? event.agentId} turn ${child.turn} started`,
4718
- metadata: cleanMetadata2({
4719
- parentToolName: event.toolName,
4720
- agentId: event.agentId,
4721
- hasAgentName: event.agentName !== void 0,
4722
- childTurn: child.turn,
4723
- historyCount: child.history.length
4724
- })
4725
- }
4726
- ];
4767
+ listPipelineLogs(options) {
4768
+ return (this.pipelineLogs.get(options.pipelineId) ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
4727
4769
  }
4728
- if (child.type === "final") {
4729
- return [
4730
- {
4731
- sessionId,
4732
- runId,
4733
- level: "debug",
4734
- category: "run",
4735
- event: "child_agent.completed",
4736
- message: `Child agent ${event.agentName ?? event.agentId} completed`,
4737
- metadata: cleanMetadata2({
4738
- parentToolName: event.toolName,
4739
- agentId: event.agentId,
4740
- hasAgentName: event.agentName !== void 0,
4741
- usage: usageSummary(child.usage),
4742
- outputBytes: byteLength3(child.output),
4743
- messageCount: child.messages.length
4744
- })
4745
- }
4746
- ];
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;
4747
4785
  }
4748
- if (child.type === "error") {
4749
- return [
4750
- {
4751
- sessionId,
4752
- runId,
4753
- level: "error",
4754
- category: "run",
4755
- event: "child_agent.failed",
4756
- message: `Child agent ${event.agentName ?? event.agentId} failed`,
4757
- metadata: cleanMetadata2({
4758
- parentToolName: event.toolName,
4759
- agentId: event.agentId,
4760
- hasAgentName: event.agentName !== void 0,
4761
- error: serializeError(child.error)
4762
- })
4763
- }
4764
- ];
4786
+ getPipelineRun(options) {
4787
+ const run = this.pipelineRuns.get(options.runId);
4788
+ return run?.pipelineId === options.pipelineId ? run : void 0;
4765
4789
  }
4766
- return [];
4767
- }
4768
- function messageSummary(message) {
4769
- if (typeof message === "string") {
4770
- return {
4771
- role: "user",
4772
- contentKind: "text",
4773
- byteLength: byteLength3(message)
4774
- };
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);
4775
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) {
4776
4806
  return {
4777
- role: message.role,
4778
- contentKind: Array.isArray(message.content) ? "parts" : "text",
4779
- partCount: Array.isArray(message.content) ? message.content.length : 1,
4780
- byteLength: byteLength3(formatUnknown2(message.content))
4807
+ ...sessionSummary(session),
4808
+ messages: [...session.messages],
4809
+ transcript: renumberTranscript(session.runs.flatMap((run) => run.transcript))
4781
4810
  };
4782
4811
  }
4783
- function usageSummary(value) {
4784
- if (value === void 0 || value === null || typeof value !== "object") {
4785
- return void 0;
4786
- }
4787
- const record = value;
4788
- return cleanMetadata2({
4789
- inputTokens: numericValue(record.inputTokens),
4790
- outputTokens: numericValue(record.outputTokens),
4791
- totalTokens: numericValue(record.totalTokens),
4792
- cachedInputTokens: numericValue(record.cachedInputTokens),
4793
- cacheCreationInputTokens: numericValue(record.cacheCreationInputTokens)
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
4794
4826
  });
4795
4827
  }
4796
- function cleanMetadata2(value) {
4797
- const cleaned = {};
4798
- for (const [key, item] of Object.entries(value)) {
4799
- if (item === void 0) {
4800
- continue;
4801
- }
4802
- const jsonValue = cleanJsonValue(item);
4803
- if (jsonValue !== void 0) {
4804
- cleaned[key] = jsonValue;
4805
- }
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
+ };
4806
4842
  }
4807
- return cleaned;
4843
+ return isJsonValue3(error) ? error : String(error);
4844
+ }
4845
+ function isJsonObject2(value) {
4846
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4808
4847
  }
4809
- function cleanJsonValue(value) {
4848
+ function isJsonValue3(value) {
4810
4849
  if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4811
- return value;
4850
+ return true;
4812
4851
  }
4813
4852
  if (Array.isArray(value)) {
4814
- return value.map((item) => cleanJsonValue(item)).filter((item) => item !== void 0);
4815
- }
4816
- if (typeof value === "object" && value !== null) {
4817
- return cleanMetadata2(value);
4853
+ return value.every(isJsonValue3);
4818
4854
  }
4819
- return void 0;
4855
+ return isJsonObject2(value) && Object.values(value).every(isJsonValue3);
4820
4856
  }
4821
- function numericValue(value) {
4822
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
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
4870
+ });
4823
4871
  }
4824
- function byteLength3(value) {
4825
- return value === void 0 ? 0 : new TextEncoder().encode(value).byteLength;
4872
+ function defaultStudioStore() {
4873
+ return createInMemoryStudioStore();
4826
4874
  }
4827
- function formatUnknown2(value) {
4828
- if (typeof value === "string") {
4829
- return value;
4875
+ function resolveSessionStore(options, defaultStore) {
4876
+ if (options.stores?.sessions === false) {
4877
+ return void 0;
4830
4878
  }
4831
- try {
4832
- return JSON.stringify(value);
4833
- } catch {
4834
- return String(value);
4879
+ if (options.stores?.sessions !== void 0) {
4880
+ return options.stores.sessions;
4835
4881
  }
4882
+ return defaultStore;
4836
4883
  }
4837
-
4838
- // src/runtime/sessions.ts
4839
- function registerSessionRoutes(app, props) {
4840
- app.get("/sessions", async (c) => {
4841
- const agentId = optionalQueryString(c.req.query("agentId"));
4842
- if (agentId !== void 0 && !props.agentMap.has(agentId)) {
4843
- return errorResponse(c, 404, "not_found", "Agent not found");
4844
- }
4845
- const limit = parseLimit(c.req.query("limit"));
4846
- if (limit === void 0) {
4847
- return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
4848
- }
4849
- const sessions = await props.sessionStore.listSessions({
4850
- ...agentId === void 0 ? {} : { agentId },
4851
- limit
4852
- });
4853
- return c.json({ sessions });
4854
- });
4855
- app.post("/sessions", async (c) => {
4856
- const body = await parseCreateSessionRequest(c);
4857
- if ("error" in body) {
4858
- return body.error;
4859
- }
4860
- if (!props.agentMap.has(body.agentId)) {
4861
- return errorResponse(c, 404, "not_found", "Agent not found");
4862
- }
4863
- const session = await props.sessionStore.createSession({
4864
- id: globalThis.crypto.randomUUID(),
4865
- agentId: body.agentId,
4866
- ...body.title === void 0 ? {} : { title: body.title },
4867
- ...body.metadata === void 0 ? {} : { metadata: body.metadata }
4868
- });
4869
- await appendSessionLog(props.sessionStore, sessionCreatedLog(session));
4870
- return c.json(session, 201);
4871
- });
4872
- app.get("/sessions/:sessionId", async (c) => {
4873
- const session = await props.sessionStore.getSession(c.req.param("sessionId"));
4874
- if (session === void 0) {
4875
- return errorResponse(c, 404, "not_found", "Session not found");
4876
- }
4877
- return c.json(session);
4878
- });
4879
- app.get("/sessions/:sessionId/logs", async (c) => {
4880
- const sessionId = c.req.param("sessionId");
4881
- const session = await props.sessionStore.getSession(sessionId);
4882
- if (session === void 0) {
4883
- return errorResponse(c, 404, "not_found", "Session not found");
4884
- }
4885
- if (props.sessionStore.listSessionLogs === void 0) {
4886
- return errorResponse(
4887
- c,
4888
- 501,
4889
- "unsupported_capability",
4890
- 'Capability "sessions.logs" is not implemented by this runner',
4891
- { capability: "sessions", operation: "logs" }
4892
- );
4893
- }
4894
- const limit = parseSessionLogLimit(c.req.query("limit"));
4895
- if (limit === void 0) {
4896
- return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
4897
- }
4898
- const after = parseSessionLogAfter(c.req.query("after"));
4899
- if (after === false) {
4900
- return errorResponse(c, 400, "bad_request", "after must be a non-negative integer");
4901
- }
4902
- const logs = await props.sessionStore.listSessionLogs({
4903
- sessionId,
4904
- limit,
4905
- ...after === void 0 ? {} : { after }
4906
- });
4907
- const last = logs.at(-1);
4908
- return c.json({
4909
- logs,
4910
- ...logs.length === limit && last !== void 0 ? { nextCursor: last.sequence } : {}
4911
- });
4912
- });
4913
- app.delete("/sessions/:sessionId", async (c) => {
4914
- if (props.sessionStore.deleteSession === void 0) {
4915
- return errorResponse(
4916
- c,
4917
- 501,
4918
- "unsupported_capability",
4919
- 'Capability "sessions.delete" is not implemented by this runner',
4920
- { capability: "sessions", operation: "delete" }
4921
- );
4922
- }
4923
- const deleted = await props.sessionStore.deleteSession(c.req.param("sessionId"));
4924
- if (!deleted) {
4925
- return errorResponse(c, 404, "not_found", "Session not found");
4926
- }
4927
- return c.body(null, 204);
4928
- });
4929
- app.get("/sessions/:sessionId/traces", async (c) => {
4930
- if (props.traceStore === void 0) {
4931
- return unsupportedCapability(c, "traces");
4932
- }
4933
- const sessionId = c.req.param("sessionId");
4934
- const session = await props.sessionStore.getSession(sessionId);
4935
- if (session === void 0) {
4936
- return errorResponse(c, 404, "not_found", "Session not found");
4937
- }
4938
- const limit = parseLimit(c.req.query("limit"));
4939
- if (limit === void 0) {
4940
- return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
4941
- }
4942
- const traces = await props.traceStore.listSessionTraces({ sessionId, limit });
4943
- return c.json({ traces });
4944
- });
4945
- }
4946
- function parseSessionLogLimit(value) {
4947
- if (value === void 0 || value.trim().length === 0) {
4948
- return 200;
4884
+ function resolveTraceStore(options, sessionStore, defaultStore) {
4885
+ if (options.stores?.traces !== void 0) {
4886
+ return options.stores.traces;
4949
4887
  }
4950
- const limit = Number(value);
4951
- if (!Number.isInteger(limit) || limit <= 0) {
4888
+ if (sessionStore === void 0) {
4952
4889
  return void 0;
4953
4890
  }
4954
- return Math.min(limit, 1e3);
4891
+ if (isTraceStore(sessionStore)) {
4892
+ return sessionStore;
4893
+ }
4894
+ return defaultStore;
4955
4895
  }
4956
- function parseSessionLogAfter(value) {
4957
- if (value === void 0 || value.trim().length === 0) {
4896
+ function resolvePipelineLogStore(options, sessionStore, defaultStore) {
4897
+ if (options.stores?.pipelineLogs === false) {
4958
4898
  return void 0;
4959
4899
  }
4960
- const after = Number(value);
4961
- if (!Number.isInteger(after) || after < 0) {
4962
- return false;
4900
+ if (options.stores?.pipelineLogs !== void 0) {
4901
+ return options.stores.pipelineLogs;
4963
4902
  }
4964
- return after;
4903
+ if (sessionStore !== void 0 && isPipelineLogStore(sessionStore)) {
4904
+ return sessionStore;
4905
+ }
4906
+ return defaultStore;
4965
4907
  }
4966
- async function parseCreateSessionRequest(c) {
4967
- let body;
4968
- try {
4969
- body = await c.req.json();
4970
- } catch {
4971
- 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;
4972
4911
  }
4973
- if (!isObject(body)) {
4974
- return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
4912
+ if (options.stores?.pipelineRuns !== void 0) {
4913
+ return options.stores.pipelineRuns;
4975
4914
  }
4976
- if (typeof body.agentId !== "string" || body.agentId.trim().length === 0) {
4977
- return { error: errorResponse(c, 400, "bad_request", "agentId must be a string") };
4915
+ if (sessionStore !== void 0 && isPipelineRunStore(sessionStore)) {
4916
+ return sessionStore;
4978
4917
  }
4979
- const request = {
4980
- agentId: body.agentId.trim()
4981
- };
4982
- if ("title" in body) {
4983
- if (typeof body.title !== "string") {
4984
- return { error: errorResponse(c, 400, "bad_request", "title must be a string") };
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");
4985
4941
  }
4986
- const title = body.title.trim();
4987
- if (title.length > 0) {
4988
- request.title = title;
4942
+ if (ids.has(id)) {
4943
+ throw new Error(`Duplicate runner agent id: ${id}`);
4989
4944
  }
4990
- }
4991
- if ("metadata" in body) {
4992
- if (!isJsonObject2(body.metadata)) {
4993
- return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
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");
4994
4955
  }
4995
- request.metadata = body.metadata;
4996
- }
4997
- return request;
4956
+ if (ids.has(id)) {
4957
+ throw new Error(`Duplicate Studio pipeline id: ${id}`);
4958
+ }
4959
+ ids.add(id);
4960
+ return { ...pipeline, id };
4961
+ });
4998
4962
  }
4999
4963
 
5000
4964
  // src/runtime/status.ts
@@ -5003,30 +4967,31 @@ function registerStatusRoutes(app, props) {
5003
4967
  const summary = {
5004
4968
  runner: {
5005
4969
  id: runnerId(props.options),
5006
- ...props.options.name === void 0 ? {} : { name: props.options.name },
5007
- ...props.options.version === void 0 ? {} : { version: props.options.version }
4970
+ ...compact({ name: props.options.name, version: props.options.version })
5008
4971
  },
5009
4972
  storage: {
5010
- ...props.stores.sessions?.kind === void 0 ? {} : { sessions: props.stores.sessions.kind },
5011
- ...props.stores.traces?.kind === void 0 ? {} : { traces: props.stores.traces.kind },
5012
- ...props.stores.pipelineLogs === void 0 ? {} : { pipelineLogs: "available" },
5013
- ...props.stores.pipelineRuns === void 0 ? {} : { pipelineRuns: "available" }
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
+ })
5014
4979
  },
5015
4980
  counts: {
5016
4981
  agents: props.agents.length,
5017
4982
  pipelines: props.pipelines.length,
5018
- ...props.stores.sessions === void 0 ? {} : { sessions: (await props.stores.sessions.listSessions({ limit: 100 })).length },
5019
- ...props.stores.traces?.listTraces === void 0 ? {} : { traces: (await props.stores.traces.listTraces({ limit: 100 })).length },
5020
- ...props.stores.pipelineRuns === void 0 || props.pipelines.length === 0 ? {} : {
5021
- 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(
5022
4987
  props.pipelines.map(
5023
4988
  (pipeline) => props.stores.pipelineRuns?.listPipelineRuns({
5024
4989
  pipelineId: pipeline.id,
5025
4990
  limit: 100
5026
4991
  })
5027
4992
  )
5028
- )).reduce((sum, runs) => sum + (runs?.length ?? 0), 0)
5029
- }
4993
+ )).reduce((sum, runs) => sum + (runs?.length ?? 0), 0) : void 0
4994
+ })
5030
4995
  },
5031
4996
  capabilities: capabilityConfig(props.options, props.agents, props.pipelines, props.stores),
5032
4997
  generatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -5110,16 +5075,16 @@ async function parseToolRunRequest(c) {
5110
5075
  if (body === void 0 || body === null) {
5111
5076
  return { args: {} };
5112
5077
  }
5113
- if (!isJsonObject2(body)) {
5078
+ if (!isJsonObject(body)) {
5114
5079
  return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
5115
5080
  }
5116
5081
  const args = Object.hasOwn(body, "args") ? body.args : {};
5117
- if (!isJsonValue2(args)) {
5082
+ if (!isJsonValue(args)) {
5118
5083
  return { error: errorResponse(c, 400, "bad_request", "args must be JSON-compatible") };
5119
5084
  }
5120
5085
  const request = { args };
5121
5086
  if (Object.hasOwn(body, "context")) {
5122
- if (!isJsonObject2(body.context)) {
5087
+ if (!isJsonObject(body.context)) {
5123
5088
  return { error: errorResponse(c, 400, "bad_request", "context must be an object") };
5124
5089
  }
5125
5090
  request.context = body.context;
@@ -5177,9 +5142,7 @@ function registerTraceRoutes(app, traceStore) {
5177
5142
  const sessionId = optionalQueryString(c.req.query("sessionId"));
5178
5143
  const traces = await traceStore.listTraces({
5179
5144
  limit,
5180
- ...agentId === void 0 ? {} : { agentId },
5181
- ...sessionId === void 0 ? {} : { sessionId },
5182
- ...status === void 0 ? {} : { status }
5145
+ ...compact({ agentId, sessionId, status })
5183
5146
  });
5184
5147
  return c.json({ traces });
5185
5148
  });
@@ -5222,7 +5185,7 @@ var Studio = class {
5222
5185
  const port = serveOptions.port ?? Number(process.env.RUNNER_PORT ?? 4021);
5223
5186
  this.server = serve({
5224
5187
  fetch: (request) => this.fetch(request),
5225
- ...serveOptions.hostname === void 0 ? {} : { hostname: serveOptions.hostname },
5188
+ ...compact({ hostname: serveOptions.hostname }),
5226
5189
  port
5227
5190
  });
5228
5191
  const log = serveOptions.log ?? true;
@@ -5262,9 +5225,9 @@ function studioOptionsFromTargets(targets, options) {
5262
5225
  agents: inferStudioAgents(agents, options.quickPrompts ?? {}),
5263
5226
  pipelines: inferStudioPipelines(pipelines),
5264
5227
  evals: options.evals ?? [],
5265
- ...options.models === void 0 ? {} : { models: options.models },
5266
- ...options.stores === void 0 ? {} : { stores: options.stores },
5267
- ...options.ui === void 0 ? {} : { ui: options.ui }
5228
+ ...compact({ models: options.models }),
5229
+ ...compact({ stores: options.stores }),
5230
+ ...compact({ ui: options.ui })
5268
5231
  };
5269
5232
  }
5270
5233
  function inferStudioAgents(agents, quickPrompts) {
@@ -5286,9 +5249,9 @@ function inferStudioPipelines(pipelines) {
5286
5249
  return {
5287
5250
  id,
5288
5251
  pipeline,
5289
- ...pipeline.name === void 0 ? {} : { name: pipeline.name },
5290
- ...pipeline.description === void 0 ? {} : { description: pipeline.description },
5291
- ...pipeline.metadata === void 0 ? {} : { metadata: pipeline.metadata }
5252
+ ...compact({ name: pipeline.name }),
5253
+ ...compact({ description: pipeline.description }),
5254
+ ...compact({ metadata: pipeline.metadata })
5292
5255
  };
5293
5256
  });
5294
5257
  }
@@ -5304,7 +5267,7 @@ function uniqueAgentId(baseId, ids) {
5304
5267
  }
5305
5268
  function agentMetadata(agent) {
5306
5269
  return {
5307
- ...agent.defaultMaxTurns === void 0 ? {} : { defaultMaxTurns: agent.defaultMaxTurns },
5270
+ ...compact({ defaultMaxTurns: agent.defaultMaxTurns }),
5308
5271
  staticContextCount: agent.staticContext.length,
5309
5272
  dynamicContextCount: agent.dynamicContexts.length,
5310
5273
  dynamicToolCount: agent.dynamicTools.length,
@@ -5375,13 +5338,13 @@ function createStudioApp(options) {
5375
5338
  });
5376
5339
  registerKnowledgeRoutes(app, {
5377
5340
  agents,
5378
- ...stores.traces === void 0 ? {} : { traceStore: stores.traces }
5341
+ ...compact({ traceStore: stores.traces })
5379
5342
  });
5380
5343
  registerPipelineRoutes(app, {
5381
5344
  pipelines,
5382
5345
  pipelineMap,
5383
- ...stores.pipelineLogs === void 0 ? {} : { logStore: stores.pipelineLogs },
5384
- ...stores.pipelineRuns === void 0 ? {} : { runStore: stores.pipelineRuns }
5346
+ ...compact({ logStore: stores.pipelineLogs }),
5347
+ ...compact({ runStore: stores.pipelineRuns })
5385
5348
  });
5386
5349
  app.post("/agents/:agentId/runs", async (c) => {
5387
5350
  const agentId = c.req.param("agentId");
@@ -5428,8 +5391,8 @@ function createStudioApp(options) {
5428
5391
  agentId,
5429
5392
  message: body.message,
5430
5393
  stream: body.stream === true,
5431
- ...body.maxTurns === void 0 ? {} : { maxTurns: body.maxTurns },
5432
- ...body.toolConcurrency === void 0 ? {} : { toolConcurrency: body.toolConcurrency },
5394
+ ...compact({ maxTurns: body.maxTurns }),
5395
+ ...compact({ toolConcurrency: body.toolConcurrency }),
5433
5396
  hasTrace: body.trace !== void 0,
5434
5397
  ...body.metadata === void 0 && selectedModel.ref === void 0 ? {} : {
5435
5398
  metadata: {
@@ -5498,8 +5461,8 @@ function createStudioApp(options) {
5498
5461
  approvalRuntime.createHook({
5499
5462
  runId,
5500
5463
  agentId,
5501
- ...session?.id === void 0 ? {} : { sessionId: session.id },
5502
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
5464
+ ...compact({ sessionId: session?.id }),
5465
+ ...compact({ metadata: body.metadata }),
5503
5466
  getTool: (toolName) => runAgent.getTool(toolName),
5504
5467
  emit: (event) => runtimeEvents.push(event)
5505
5468
  })
@@ -5507,8 +5470,8 @@ function createStudioApp(options) {
5507
5470
  questionRuntime.createHook({
5508
5471
  runId,
5509
5472
  agentId,
5510
- ...session?.id === void 0 ? {} : { sessionId: session.id },
5511
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
5473
+ ...compact({ sessionId: session?.id }),
5474
+ ...compact({ metadata: body.metadata }),
5512
5475
  emit: (event) => runtimeEvents.push(event)
5513
5476
  })
5514
5477
  );
@@ -5543,16 +5506,16 @@ function createStudioApp(options) {
5543
5506
  approvalRuntime.createHook({
5544
5507
  runId,
5545
5508
  agentId,
5546
- ...session?.id === void 0 ? {} : { sessionId: session.id },
5547
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
5509
+ ...compact({ sessionId: session?.id }),
5510
+ ...compact({ metadata: body.metadata }),
5548
5511
  getTool: (toolName) => runAgent.getTool(toolName)
5549
5512
  })
5550
5513
  ),
5551
5514
  questionRuntime.createHook({
5552
5515
  runId,
5553
5516
  agentId,
5554
- ...session?.id === void 0 ? {} : { sessionId: session.id },
5555
- ...body.metadata === void 0 ? {} : { metadata: body.metadata }
5517
+ ...compact({ sessionId: session?.id }),
5518
+ ...compact({ metadata: body.metadata })
5556
5519
  })
5557
5520
  );
5558
5521
  if (effectiveHook !== void 0) {
@@ -5625,7 +5588,7 @@ function createStudioApp(options) {
5625
5588
  registerSessionRoutes(app, {
5626
5589
  agentMap,
5627
5590
  sessionStore: stores.sessions,
5628
- ...stores.traces === void 0 ? {} : { traceStore: stores.traces }
5591
+ ...compact({ traceStore: stores.traces })
5629
5592
  });
5630
5593
  }
5631
5594
  if (stores.traces !== void 0) {
@@ -5645,8 +5608,8 @@ function createStudioApp(options) {
5645
5608
  },
5646
5609
  close() {
5647
5610
  },
5648
- ...stores.sessions === void 0 ? {} : { sessionStore: stores.sessions },
5649
- ...stores.traces === void 0 ? {} : { traceStore: stores.traces }
5611
+ ...compact({ sessionStore: stores.sessions }),
5612
+ ...compact({ traceStore: stores.traces })
5650
5613
  };
5651
5614
  }
5652
5615
  function normalizePromptMessage(message) {
@@ -5790,11 +5753,11 @@ var SqliteSessionStore = class {
5790
5753
  return {
5791
5754
  id: input.id,
5792
5755
  agentId: input.agentId,
5793
- ...input.title === void 0 ? {} : { title: input.title },
5756
+ ...compact({ title: input.title }),
5794
5757
  createdAt: now,
5795
5758
  updatedAt: now,
5796
5759
  messageCount: 0,
5797
- ...input.metadata === void 0 ? {} : { metadata: input.metadata }
5760
+ ...compact({ metadata: input.metadata })
5798
5761
  };
5799
5762
  }
5800
5763
  getSession(id) {
@@ -5980,14 +5943,14 @@ var SqliteSessionStore = class {
5980
5943
  const entry = {
5981
5944
  id: globalThis.crypto.randomUUID(),
5982
5945
  sessionId: input.sessionId,
5983
- ...input.runId === void 0 ? {} : { runId: input.runId },
5946
+ ...compact({ runId: input.runId }),
5984
5947
  sequence,
5985
5948
  timestamp: now,
5986
5949
  level: input.level,
5987
5950
  category: input.category,
5988
5951
  event: input.event,
5989
5952
  message: input.message,
5990
- ...input.metadata === void 0 ? {} : { metadata: input.metadata }
5953
+ ...compact({ metadata: input.metadata })
5991
5954
  };
5992
5955
  db.prepare(
5993
5956
  `INSERT INTO anvia_studio_session_logs (
@@ -6061,14 +6024,14 @@ var SqliteSessionStore = class {
6061
6024
  const entry = {
6062
6025
  id: globalThis.crypto.randomUUID(),
6063
6026
  pipelineId: input.pipelineId,
6064
- ...input.runId === void 0 ? {} : { runId: input.runId },
6027
+ ...compact({ runId: input.runId }),
6065
6028
  sequence,
6066
6029
  timestamp: now,
6067
6030
  level: input.level,
6068
6031
  category: input.category,
6069
6032
  event: input.event,
6070
6033
  message: input.message,
6071
- ...input.metadata === void 0 ? {} : { metadata: input.metadata }
6034
+ ...compact({ metadata: input.metadata })
6072
6035
  };
6073
6036
  db.prepare(
6074
6037
  `INSERT INTO anvia_studio_pipeline_logs (
@@ -6186,12 +6149,12 @@ var SqliteSessionStore = class {
6186
6149
  pipelineId: input.pipelineId,
6187
6150
  status: input.status,
6188
6151
  input: input.input,
6189
- ...input.output === void 0 ? {} : { output: input.output },
6190
- ...input.error === void 0 ? {} : { error: input.error },
6191
- ...input.metadata === void 0 ? {} : { metadata: input.metadata },
6152
+ ...compact({ output: input.output }),
6153
+ ...compact({ error: input.error }),
6154
+ ...compact({ metadata: input.metadata }),
6192
6155
  startedAt: input.startedAt,
6193
- ...input.endedAt === void 0 ? {} : { endedAt: input.endedAt },
6194
- ...input.durationMs === void 0 ? {} : { durationMs: input.durationMs }
6156
+ ...compact({ endedAt: input.endedAt }),
6157
+ ...compact({ durationMs: input.durationMs })
6195
6158
  };
6196
6159
  }
6197
6160
  getPipelineRun(options) {
@@ -6622,11 +6585,11 @@ function toSessionSummary(row) {
6622
6585
  return {
6623
6586
  id: row.id,
6624
6587
  agentId: row.agent_id,
6625
- ...row.title === null ? {} : { title: row.title },
6588
+ ...compact({ title: row.title ?? void 0 }),
6626
6589
  createdAt: row.created_at,
6627
6590
  updatedAt: row.updated_at,
6628
6591
  messageCount: row.message_count,
6629
- ...metadata === void 0 ? {} : { metadata }
6592
+ ...compact({ metadata })
6630
6593
  };
6631
6594
  }
6632
6595
  function toSessionLog(row) {
@@ -6634,14 +6597,14 @@ function toSessionLog(row) {
6634
6597
  return {
6635
6598
  id: row.id,
6636
6599
  sessionId: row.session_id,
6637
- ...row.run_id === null ? {} : { runId: row.run_id },
6600
+ ...compact({ runId: row.run_id ?? void 0 }),
6638
6601
  sequence: row.sequence,
6639
6602
  timestamp: row.timestamp,
6640
6603
  level: row.level,
6641
6604
  category: row.category,
6642
6605
  event: row.event,
6643
6606
  message: row.message,
6644
- ...metadata === void 0 ? {} : { metadata }
6607
+ ...compact({ metadata })
6645
6608
  };
6646
6609
  }
6647
6610
  function toPipelineLog(row) {
@@ -6649,14 +6612,14 @@ function toPipelineLog(row) {
6649
6612
  return {
6650
6613
  id: row.id,
6651
6614
  pipelineId: row.pipeline_id,
6652
- ...row.run_id === null ? {} : { runId: row.run_id },
6615
+ ...compact({ runId: row.run_id ?? void 0 }),
6653
6616
  sequence: row.sequence,
6654
6617
  timestamp: row.timestamp,
6655
6618
  level: row.level,
6656
6619
  category: row.category,
6657
6620
  event: row.event,
6658
6621
  message: row.message,
6659
- ...metadata === void 0 ? {} : { metadata }
6622
+ ...compact({ metadata })
6660
6623
  };
6661
6624
  }
6662
6625
  function toPipelineRun(row) {
@@ -6668,12 +6631,12 @@ function toPipelineRun(row) {
6668
6631
  pipelineId: row.pipeline_id,
6669
6632
  status: row.status,
6670
6633
  input: JSON.parse(row.input_json),
6671
- ...output === void 0 ? {} : { output },
6672
- ...error === void 0 ? {} : { error },
6673
- ...metadata === void 0 ? {} : { metadata },
6634
+ ...compact({ output }),
6635
+ ...compact({ error }),
6636
+ ...compact({ metadata }),
6674
6637
  startedAt: row.started_at,
6675
- ...row.ended_at === null ? {} : { endedAt: row.ended_at },
6676
- ...row.duration_ms === null ? {} : { durationMs: row.duration_ms }
6638
+ ...compact({ endedAt: row.ended_at ?? void 0 }),
6639
+ ...compact({ durationMs: row.duration_ms ?? void 0 })
6677
6640
  };
6678
6641
  }
6679
6642
  function messageParts(message) {
@@ -6699,7 +6662,7 @@ function messageFromRows(row, partRows) {
6699
6662
  if (row.role === "assistant") {
6700
6663
  return {
6701
6664
  role: "assistant",
6702
- ...row.message_id === null ? {} : { id: row.message_id },
6665
+ ...compact({ id: row.message_id ?? void 0 }),
6703
6666
  content: parts
6704
6667
  };
6705
6668
  }
@@ -6747,8 +6710,8 @@ function toTrace(row) {
6747
6710
  const input = parseJsonValue(row.input_json);
6748
6711
  return {
6749
6712
  ...toTraceSummary(row),
6750
- ...trace === void 0 ? {} : { trace },
6751
- ...input === void 0 ? {} : { input },
6713
+ ...compact({ trace }),
6714
+ ...compact({ input }),
6752
6715
  observations: parseJsonArray(row.observations_json)
6753
6716
  };
6754
6717
  }
@@ -6760,15 +6723,15 @@ function toTraceSummary(row) {
6760
6723
  return {
6761
6724
  id: row.id,
6762
6725
  sessionId: row.session_id,
6763
- ...row.name === null ? {} : { name: row.name },
6726
+ ...compact({ name: row.name ?? void 0 }),
6764
6727
  status: row.status,
6765
6728
  startedAt: row.started_at,
6766
- ...row.ended_at === null ? {} : { endedAt: row.ended_at },
6767
- ...row.duration_ms === null ? {} : { durationMs: row.duration_ms },
6768
- ...row.output === null ? {} : { output: row.output },
6769
- ...error === void 0 ? {} : { error },
6770
- ...usage === void 0 ? {} : { usage },
6771
- ...metadata === void 0 ? {} : { metadata },
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 }),
6772
6735
  observationCount: observations.length
6773
6736
  };
6774
6737
  }
@@ -6798,10 +6761,29 @@ function serializeJsonError2(error) {
6798
6761
  }
6799
6762
  return String(error);
6800
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
+ }
6801
6782
  export {
6802
6783
  Studio,
6803
6784
  StudioTraceObserver,
6804
6785
  createInMemoryStudioStore,
6805
- createSqliteSessionStore
6786
+ createSqliteSessionStore,
6787
+ traceSummary3 as traceSummary
6806
6788
  };
6807
6789
  //# sourceMappingURL=index.js.map