@anvia/studio 0.5.14 → 0.6.1

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