@anvia/studio 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.js +1455 -1522
  3. package/dist/index.js.map +1 -1
  4. package/dist/ui/assets/{ArrowClockwise.es-BA79KX3F.js → ArrowClockwise.es-CdkDSmVV.js} +2 -2
  5. package/dist/ui/assets/{ArrowClockwise.es-BA79KX3F.js.map → ArrowClockwise.es-CdkDSmVV.js.map} +1 -1
  6. package/dist/ui/assets/{Path.es-DTZ3zsLn.js → Path.es-CAqZdUXu.js} +2 -2
  7. package/dist/ui/assets/{Path.es-DTZ3zsLn.js.map → Path.es-CAqZdUXu.js.map} +1 -1
  8. package/dist/ui/assets/{Play.es-CJTRfv9R.js → Play.es-D9AQgyVC.js} +2 -2
  9. package/dist/ui/assets/{Play.es-CJTRfv9R.js.map → Play.es-D9AQgyVC.js.map} +1 -1
  10. package/dist/ui/assets/{evals-page-rS-P7eLF.js → evals-page-GEsRKWxr.js} +2 -2
  11. package/dist/ui/assets/{evals-page-rS-P7eLF.js.map → evals-page-GEsRKWxr.js.map} +1 -1
  12. package/dist/ui/assets/index-DW3P6_Qc.js +54 -0
  13. package/dist/ui/assets/index-DW3P6_Qc.js.map +1 -0
  14. package/dist/ui/assets/{knowledge-page-CR0JUneq.js → knowledge-page-CQJNZ8fA.js} +2 -2
  15. package/dist/ui/assets/{knowledge-page-CR0JUneq.js.map → knowledge-page-CQJNZ8fA.js.map} +1 -1
  16. package/dist/ui/assets/{mcps-page-D3P0UAWf.js → mcps-page-BRCLJmEX.js} +2 -2
  17. package/dist/ui/assets/{mcps-page-D3P0UAWf.js.map → mcps-page-BRCLJmEX.js.map} +1 -1
  18. package/dist/ui/assets/{memory-page-kVDqOAOd.js → memory-page-DsITtAok.js} +2 -2
  19. package/dist/ui/assets/{memory-page-kVDqOAOd.js.map → memory-page-DsITtAok.js.map} +1 -1
  20. package/dist/ui/assets/{pipelines-page-lMfsVNRy.js → pipelines-page-vBUhZ5x2.js} +2 -2
  21. package/dist/ui/assets/{pipelines-page-lMfsVNRy.js.map → pipelines-page-vBUhZ5x2.js.map} +1 -1
  22. package/dist/ui/assets/{renderers-Bc89UGTN.js → renderers-hYnJAoYZ.js} +2 -2
  23. package/dist/ui/assets/{renderers-Bc89UGTN.js.map → renderers-hYnJAoYZ.js.map} +1 -1
  24. package/dist/ui/assets/{sessions-page-CVlkRPfT.js → sessions-page-BYhPHSQS.js} +2 -2
  25. package/dist/ui/assets/{sessions-page-CVlkRPfT.js.map → sessions-page-BYhPHSQS.js.map} +1 -1
  26. package/dist/ui/assets/{status-page-XKvTGruQ.js → status-page-B16drVrZ.js} +2 -2
  27. package/dist/ui/assets/{status-page-XKvTGruQ.js.map → status-page-B16drVrZ.js.map} +1 -1
  28. package/dist/ui/assets/{tools-page-DJt_QdDe.js → tools-page-DwgbeCMm.js} +2 -2
  29. package/dist/ui/assets/{tools-page-DJt_QdDe.js.map → tools-page-DwgbeCMm.js.map} +1 -1
  30. package/dist/ui/assets/{trace-browser-BBITQELO.js → trace-browser-DLB0mURK.js} +2 -2
  31. package/dist/ui/assets/{trace-browser-BBITQELO.js.map → trace-browser-DLB0mURK.js.map} +1 -1
  32. package/dist/ui/assets/{transcript-item-BvaA1PBu.js → transcript-item-DM71m6Mp.js} +2 -2
  33. package/dist/ui/assets/{transcript-item-BvaA1PBu.js.map → transcript-item-DM71m6Mp.js.map} +1 -1
  34. package/dist/ui/index.html +1 -1
  35. package/package.json +4 -4
  36. package/dist/ui/assets/index-ChlKOnbD.js +0 -54
  37. package/dist/ui/assets/index-ChlKOnbD.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/runtime/studio.ts
2
2
  import {
3
- createHook as createHook3
3
+ createHook as createHook2
4
4
  } from "@anvia/core/agent";
5
5
  import { Message } from "@anvia/core/completion";
6
6
  import { Agent } from "@anvia/core/internal/agent";
@@ -8,6 +8,17 @@ import { Pipeline } from "@anvia/core/pipeline";
8
8
  import { serve } from "@hono/node-server";
9
9
  import { Hono as HonoApp } from "hono";
10
10
 
11
+ // src/runtime/compact.ts
12
+ function compact(obj) {
13
+ const result = {};
14
+ for (const [key, value] of Object.entries(obj)) {
15
+ if (value !== void 0) {
16
+ result[key] = value;
17
+ }
18
+ }
19
+ return result;
20
+ }
21
+
11
22
  // src/runtime/json.ts
12
23
  function toJsonValue(value) {
13
24
  return toJsonValueInternal(value, /* @__PURE__ */ new WeakSet());
@@ -65,6 +76,20 @@ function serializeUnknown(error) {
65
76
  }
66
77
  return toJsonValue(error);
67
78
  }
79
+ function formatJson(value) {
80
+ try {
81
+ return JSON.stringify(value, null, 2);
82
+ } catch {
83
+ return String(value);
84
+ }
85
+ }
86
+ function formatUnknown(value) {
87
+ try {
88
+ return JSON.stringify(value);
89
+ } catch {
90
+ return void 0;
91
+ }
92
+ }
68
93
 
69
94
  // src/traces/trace-observer.ts
70
95
  var StudioTraceObserver = class {
@@ -191,7 +216,7 @@ var StudioRunTraceObserver = class {
191
216
  const trace = {
192
217
  id: this.props.id,
193
218
  sessionId,
194
- ...this.props.args.trace?.name === void 0 ? {} : { name: this.props.args.trace.name },
219
+ ...compact({ name: this.props.args.trace?.name }),
195
220
  status,
196
221
  trace: this.trace,
197
222
  startedAt: this.startedAt.toISOString(),
@@ -202,9 +227,9 @@ var StudioRunTraceObserver = class {
202
227
  prompt: this.props.args.prompt,
203
228
  history: this.props.args.history
204
229
  }),
205
- ...result.output === void 0 ? {} : { output: result.output },
206
- ...result.error === void 0 ? {} : { error: result.error },
207
- ...result.usage === void 0 ? {} : { usage: result.usage },
230
+ ...compact({ output: result.output }),
231
+ ...compact({ error: result.error }),
232
+ ...compact({ usage: result.usage }),
208
233
  metadata,
209
234
  observations: this.observations,
210
235
  observationCount: this.observations.length
@@ -234,7 +259,7 @@ var ChildAgentToolTraceAccumulator = class {
234
259
  this.agentStarts.set(agentId, {
235
260
  startedAt: /* @__PURE__ */ new Date(),
236
261
  agentId,
237
- ...agentName === void 0 ? {} : { agentName }
262
+ ...compact({ agentName })
238
263
  });
239
264
  }
240
265
  if (child.type === "turn_start") {
@@ -245,7 +270,7 @@ var ChildAgentToolTraceAccumulator = class {
245
270
  history: child.history
246
271
  }),
247
272
  agentId,
248
- ...agentName === void 0 ? {} : { agentName },
273
+ ...compact({ agentName }),
249
274
  childTurn
250
275
  });
251
276
  return;
@@ -261,7 +286,7 @@ var ChildAgentToolTraceAccumulator = class {
261
286
  status: "success",
262
287
  turn: this.parent.turn,
263
288
  startedAt: start?.startedAt ?? /* @__PURE__ */ new Date(),
264
- ...start?.input === void 0 ? {} : { input: start.input },
289
+ ...compact({ input: start?.input }),
265
290
  output: toJsonValue(child.response),
266
291
  metadata: this.childMetadata(agentId, agentName, childTurn)
267
292
  })
@@ -276,10 +301,10 @@ var ChildAgentToolTraceAccumulator = class {
276
301
  this.toolStarts.push({
277
302
  startedAt: /* @__PURE__ */ new Date(),
278
303
  agentId,
279
- ...agentName === void 0 ? {} : { agentName },
304
+ ...compact({ agentName }),
280
305
  childTurn,
281
306
  toolName,
282
- ...callId === void 0 ? {} : { toolCallId: callId },
307
+ ...compact({ toolCallId: callId }),
283
308
  input: toJsonValue(toolCallFunction?.arguments ?? {}),
284
309
  completed: false
285
310
  });
@@ -301,12 +326,12 @@ var ChildAgentToolTraceAccumulator = class {
301
326
  status: "success",
302
327
  turn: this.parent.turn,
303
328
  startedAt: start?.startedAt ?? /* @__PURE__ */ new Date(),
304
- ...input === void 0 ? {} : { input },
329
+ ...compact({ input }),
305
330
  ...typeof child.result === "string" ? { output: parseOrString(child.result) } : {},
306
331
  metadata: {
307
332
  ...this.childMetadata(agentId, agentName, childTurn),
308
- ...toolCallId === void 0 ? {} : { toolCallId },
309
- ...internalCallId === void 0 ? {} : { internalCallId }
333
+ ...compact({ toolCallId }),
334
+ ...compact({ internalCallId })
310
335
  }
311
336
  })
312
337
  );
@@ -404,10 +429,10 @@ function traceObservation(props) {
404
429
  startedAt: props.startedAt.toISOString(),
405
430
  endedAt: endedAt.toISOString(),
406
431
  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 }
432
+ ...compact({ input: props.input }),
433
+ ...compact({ output: props.output }),
434
+ ...compact({ error: props.error }),
435
+ ...compact({ metadata: props.metadata })
411
436
  };
412
437
  }
413
438
  function traceMetadata(args, messages) {
@@ -816,385 +841,334 @@ function escapeHtml(value) {
816
841
  return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
817
842
  }
818
843
 
819
- // src/runtime/approvals.ts
820
- import {
821
- createHook
822
- } from "@anvia/core/agent";
823
- import {
824
- parseToolArgs
825
- } from "@anvia/core/tool";
826
-
827
- // src/runtime/transcript.ts
828
- function renumberTranscript(entries) {
829
- return entries.map((entry, entryId) => ({ ...entry, entryId }));
844
+ // src/runtime/type-guards.ts
845
+ function isObject(value) {
846
+ return typeof value === "object" && value !== null && !Array.isArray(value);
830
847
  }
831
- function transcriptFromMessages(messages) {
832
- const transcript = [];
833
- for (const message of messages) {
834
- if (message.role === "system") {
835
- continue;
836
- }
837
- if (message.role === "user") {
838
- const attachments = attachmentsFromMessage(message);
839
- let textEntryAdded = false;
840
- for (const content of message.content) {
841
- if (content.type === "text") {
842
- transcript.push({
843
- entryId: transcript.length,
844
- kind: "message",
845
- role: "user",
846
- text: content.text,
847
- ...attachments.length === 0 ? {} : { attachments }
848
- });
849
- textEntryAdded = true;
850
- }
851
- }
852
- if (!textEntryAdded && attachments.length > 0) {
853
- transcript.push({
854
- entryId: transcript.length,
855
- kind: "message",
856
- role: "user",
857
- text: "",
858
- attachments
859
- });
860
- }
861
- continue;
862
- }
863
- if (message.role === "tool") {
864
- for (const content of message.content) {
865
- transcript.push({
866
- entryId: transcript.length,
867
- kind: "tool",
868
- toolName: "tool_result",
869
- callId: content.callId ?? content.id,
870
- result: content.content.map(
871
- (item) => "text" in item ? item.text : `[image:${item.mediaType ?? "image/png"}]`
872
- ).join("\n"),
873
- structuredResult: content.content
874
- });
875
- }
876
- continue;
877
- }
878
- for (const content of message.content) {
879
- if (content.type === "text") {
880
- appendAssistantTranscriptText(transcript, content.text);
881
- } else if (content.type === "reasoning") {
882
- transcript.push({
883
- entryId: transcript.length,
884
- kind: "reasoning",
885
- ...content.id === void 0 ? {} : { reasoningId: content.id },
886
- text: content.text
887
- });
888
- } else if (content.type === "tool_call") {
889
- transcript.push({
890
- entryId: transcript.length,
891
- kind: "tool",
892
- toolName: content.function.name,
893
- callId: content.callId ?? content.id,
894
- args: formatJson(content.function.arguments)
895
- });
896
- }
897
- }
848
+ function isJsonObject(value) {
849
+ return isObject(value) && Object.values(value).every(isJsonValue);
850
+ }
851
+ function isJsonValue(value) {
852
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
853
+ return true;
898
854
  }
899
- return transcript;
855
+ if (Array.isArray(value)) {
856
+ return value.every(isJsonValue);
857
+ }
858
+ return isJsonObject(value);
900
859
  }
901
- function attachmentsFromMessage(message) {
902
- if (message.role !== "user" && message.role !== "assistant") {
903
- return [];
860
+ function isMessageInput(value) {
861
+ return typeof value === "string" || isMessage(value);
862
+ }
863
+ function isMessage(value) {
864
+ if (!isObject(value) || typeof value.role !== "string") {
865
+ return false;
904
866
  }
905
- return message.content.flatMap((content) => {
906
- if (content.type === "image") {
907
- return [
908
- {
909
- kind: "image",
910
- ...content.source.type === "base64" ? { data: content.source.data, mediaType: content.source.mediaType } : { url: content.source.url }
911
- }
912
- ];
913
- }
914
- if (content.type === "document") {
915
- return [
916
- {
917
- kind: "document",
918
- ...content.source.filename === void 0 ? {} : { name: content.source.filename },
919
- ...content.source.mediaType === void 0 ? {} : { mediaType: content.source.mediaType },
920
- ...content.source.type === "base64" ? { data: content.source.data } : content.source.type === "url" ? { url: content.source.url } : {}
921
- }
922
- ];
923
- }
924
- return [];
925
- });
867
+ if (value.role === "system") {
868
+ return typeof value.content === "string";
869
+ }
870
+ if (value.role === "user" || value.role === "assistant" || value.role === "tool") {
871
+ return Array.isArray(value.content);
872
+ }
873
+ return false;
926
874
  }
927
- function appendAssistantTranscriptText(transcript, text) {
928
- const last = transcript.at(-1);
929
- if (last?.kind === "message" && last.role === "assistant") {
930
- last.text = `${last.text}${text}`;
931
- return;
875
+ function isAgentTraceOptions(value) {
876
+ if (!isObject(value)) {
877
+ return false;
932
878
  }
933
- transcript.push({
934
- entryId: transcript.length,
935
- kind: "message",
936
- role: "assistant",
937
- text
938
- });
879
+ return optionalString(value.name) && optionalString(value.userId) && optionalString(value.sessionId) && optionalString(value.version) && optionalString(value.traceId) && optionalBoolean(value.failOnObserverError) && optionalStringArray(value.tags) && optionalObject(value.metadata);
939
880
  }
940
- function formatJson(value) {
941
- try {
942
- return JSON.stringify(value, null, 2);
943
- } catch {
944
- return String(value);
881
+ function isNonNegativeInteger(value) {
882
+ return Number.isInteger(value) && typeof value === "number" && value >= 0;
883
+ }
884
+ function isPositiveInteger(value) {
885
+ return Number.isInteger(value) && typeof value === "number" && value > 0;
886
+ }
887
+ function optionalString(value) {
888
+ return value === void 0 || typeof value === "string";
889
+ }
890
+ function optionalBoolean(value) {
891
+ return value === void 0 || typeof value === "boolean";
892
+ }
893
+ function optionalStringArray(value) {
894
+ return value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
895
+ }
896
+ function optionalObject(value) {
897
+ return value === void 0 || isObject(value);
898
+ }
899
+
900
+ // src/runtime/http.ts
901
+ function errorResponse(c, status, code, message, details) {
902
+ const body = {
903
+ error: {
904
+ code,
905
+ message
906
+ }
907
+ };
908
+ if (details !== void 0) {
909
+ body.error.details = details;
945
910
  }
911
+ return c.json(body, status);
912
+ }
913
+ function unsupportedCapability(c, capability) {
914
+ return errorResponse(
915
+ c,
916
+ 501,
917
+ "unsupported_capability",
918
+ `Capability "${capability}" is not implemented by this runner`,
919
+ { capability }
920
+ );
921
+ }
922
+ function serializeError(error) {
923
+ return serializeUnknown(error);
946
924
  }
947
925
 
948
- // src/storage/memory-store.ts
949
- function createInMemoryStudioStore() {
950
- return new InMemoryStudioStore();
926
+ // src/runtime/query.ts
927
+ function optionalQueryString(value) {
928
+ const trimmed = value?.trim();
929
+ return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
951
930
  }
952
- var InMemoryStudioStore = class {
953
- kind = "memory";
954
- sessions = /* @__PURE__ */ new Map();
955
- traces = /* @__PURE__ */ new Map();
956
- pipelineLogs = /* @__PURE__ */ new Map();
957
- pipelineRuns = /* @__PURE__ */ new Map();
958
- listSessions(options) {
959
- return [...this.sessions.values()].filter((session) => options.agentId === void 0 || session.agentId === options.agentId).sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt)).slice(0, options.limit).map(sessionSummary);
960
- }
961
- createSession(input) {
962
- const now = (/* @__PURE__ */ new Date()).toISOString();
963
- const session = {
964
- id: input.id,
965
- agentId: input.agentId,
966
- ...input.title === void 0 ? {} : { title: input.title },
967
- createdAt: now,
968
- updatedAt: now,
969
- messageCount: 0,
970
- ...input.metadata === void 0 ? {} : { metadata: input.metadata },
971
- messages: [],
972
- runs: [],
973
- logs: []
974
- };
975
- this.sessions.set(input.id, session);
976
- return sessionSummary(session);
931
+ function parseLimit(value, defaultMax = 50, max = 100) {
932
+ if (value === void 0 || value.trim().length === 0) {
933
+ return defaultMax;
977
934
  }
978
- getSession(id) {
979
- const session = this.sessions.get(id);
980
- return session === void 0 ? void 0 : materializeSession(session);
935
+ const limit = Number(value);
936
+ if (!Number.isInteger(limit) || limit <= 0) {
937
+ return void 0;
981
938
  }
982
- updateSessionMetadata(id, metadata) {
983
- const session = this.sessions.get(id);
984
- if (session === void 0) {
985
- return void 0;
986
- }
987
- if (metadata === void 0) {
988
- delete session.metadata;
989
- } else {
990
- session.metadata = metadata;
991
- }
992
- session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
993
- return materializeSession(session);
939
+ return Math.min(limit, max);
940
+ }
941
+ function parseTraceStatus(value) {
942
+ const status = optionalQueryString(value);
943
+ if (status === void 0) {
944
+ return void 0;
994
945
  }
995
- load(context) {
996
- return Promise.resolve(this.sessions.get(context.sessionId)?.messages ?? []);
946
+ return status === "running" || status === "success" || status === "error" ? status : false;
947
+ }
948
+ function parseAfter(value) {
949
+ if (value === void 0 || value.trim().length === 0) {
950
+ return void 0;
997
951
  }
998
- append(input) {
999
- const session = this.sessions.get(input.context.sessionId);
1000
- if (session !== void 0) {
1001
- session.messages.push(...input.messages);
1002
- session.messageCount = session.messages.length;
1003
- session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1004
- }
1005
- return Promise.resolve();
952
+ const after = Number(value);
953
+ if (!Number.isInteger(after) || after < 0) {
954
+ return false;
1006
955
  }
1007
- clear(context) {
1008
- const session = this.sessions.get(context.sessionId);
1009
- if (session !== void 0) {
1010
- session.messages = [];
1011
- session.runs = [];
1012
- session.messageCount = 0;
1013
- session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
956
+ return after;
957
+ }
958
+
959
+ // src/runtime/approvals.ts
960
+ function registerApprovalRoutes(app, approvals) {
961
+ app.get("/approvals", (c) => {
962
+ const status = parseApprovalStatus(c.req.query("status"));
963
+ if (status === false) {
964
+ return errorResponse(c, 400, "bad_request", "status must be pending or resolved");
1014
965
  }
1015
- return Promise.resolve();
1016
- }
1017
- async recordError(input) {
1018
- await this.saveSessionRunTranscript({
1019
- id: input.context.sessionId,
1020
- runId: studioRunId(input.context) ?? input.runId,
1021
- transcript: transcriptFromMessages(input.messages),
1022
- status: "error",
1023
- error: serializeJsonError(input.error)
1024
- });
1025
- }
1026
- saveSessionRunTranscript(input) {
1027
- const session = this.sessions.get(input.id);
1028
- if (session === void 0) {
1029
- return void 0;
966
+ const options = {};
967
+ const runId = optionalQueryString(c.req.query("runId"));
968
+ const agentId = optionalQueryString(c.req.query("agentId"));
969
+ const sessionId = optionalQueryString(c.req.query("sessionId"));
970
+ if (status !== void 0) {
971
+ options.status = status;
1030
972
  }
1031
- const now = (/* @__PURE__ */ new Date()).toISOString();
1032
- const existingIndex = session.runs.findIndex((run2) => run2.runId === input.runId);
1033
- const run = {
1034
- ...input,
1035
- transcript: renumberTranscript(input.transcript),
1036
- createdAt: existingIndex === -1 ? now : session.runs[existingIndex]?.createdAt ?? now,
1037
- updatedAt: now
1038
- };
1039
- if (existingIndex === -1) {
1040
- session.runs.push(run);
1041
- } else {
1042
- session.runs[existingIndex] = run;
973
+ if (runId !== void 0) {
974
+ options.runId = runId;
1043
975
  }
1044
- session.updatedAt = now;
1045
- return materializeSession(session);
1046
- }
1047
- appendSessionLog(input) {
1048
- const session = this.sessions.get(input.sessionId);
1049
- const logs = session?.logs ?? [];
1050
- const entry = {
1051
- id: globalThis.crypto.randomUUID(),
1052
- sessionId: input.sessionId,
1053
- ...input.runId === void 0 ? {} : { runId: input.runId },
1054
- sequence: logs.length,
1055
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1056
- level: input.level,
1057
- category: input.category,
1058
- event: input.event,
1059
- message: input.message,
1060
- ...input.metadata === void 0 ? {} : { metadata: input.metadata }
1061
- };
1062
- if (session !== void 0) {
1063
- session.logs.push(entry);
1064
- session.updatedAt = entry.timestamp;
976
+ if (agentId !== void 0) {
977
+ options.agentId = agentId;
1065
978
  }
1066
- return entry;
1067
- }
1068
- listSessionLogs(options) {
1069
- return (this.sessions.get(options.sessionId)?.logs ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
1070
- }
1071
- deleteSession(id) {
1072
- for (const trace of this.traces.values()) {
1073
- if (trace.sessionId === id) {
1074
- this.traces.delete(trace.id);
1075
- }
979
+ if (sessionId !== void 0) {
980
+ options.sessionId = sessionId;
1076
981
  }
1077
- return this.sessions.delete(id);
1078
- }
1079
- listTraces(options) {
1080
- return [...this.traces.values()].filter((trace) => options.sessionId === void 0 || trace.sessionId === options.sessionId).filter((trace) => options.status === void 0 || trace.status === options.status).filter((trace) => options.agentId === void 0 || traceAgentId(trace) === options.agentId).sort((left, right) => Date.parse(right.startedAt) - Date.parse(left.startedAt)).slice(0, options.limit).map(traceSummary);
1081
- }
1082
- listSessionTraces(options) {
1083
- return this.listTraces({ sessionId: options.sessionId, limit: options.limit });
1084
- }
1085
- getTrace(id) {
1086
- return this.traces.get(id);
1087
- }
1088
- saveTrace(trace) {
1089
- this.traces.set(trace.id, trace);
1090
- return trace;
1091
- }
1092
- appendPipelineLog(input) {
1093
- const logs = this.pipelineLogs.get(input.pipelineId) ?? [];
1094
- const entry = {
1095
- id: globalThis.crypto.randomUUID(),
1096
- pipelineId: input.pipelineId,
1097
- ...input.runId === void 0 ? {} : { runId: input.runId },
1098
- sequence: logs.length,
1099
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1100
- level: input.level,
1101
- category: input.category,
1102
- event: input.event,
1103
- message: input.message,
1104
- ...input.metadata === void 0 ? {} : { metadata: input.metadata }
1105
- };
1106
- this.pipelineLogs.set(input.pipelineId, [...logs, entry]);
1107
- return entry;
982
+ return c.json({
983
+ approvals: approvals.list(options)
984
+ });
985
+ });
986
+ app.post("/approvals/:approvalId/decision", async (c) => {
987
+ const body = await parseApprovalDecisionRequest(c);
988
+ if ("error" in body) {
989
+ return body.error;
990
+ }
991
+ const result = approvals.decide(c.req.param("approvalId"), body);
992
+ if (result === "missing") {
993
+ return errorResponse(c, 404, "not_found", "Approval not found");
994
+ }
995
+ if (result === "resolved") {
996
+ return errorResponse(c, 409, "conflict", "Approval is already resolved");
997
+ }
998
+ return c.json(result);
999
+ });
1000
+ }
1001
+ function parseApprovalStatus(value) {
1002
+ const status = optionalQueryString(value);
1003
+ if (status === void 0) {
1004
+ return void 0;
1108
1005
  }
1109
- listPipelineLogs(options) {
1110
- return (this.pipelineLogs.get(options.pipelineId) ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
1006
+ return status === "pending" || status === "resolved" ? status : false;
1007
+ }
1008
+ async function parseApprovalDecisionRequest(c) {
1009
+ let body;
1010
+ try {
1011
+ body = await c.req.json();
1012
+ } catch {
1013
+ return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
1111
1014
  }
1112
- savePipelineRun(input) {
1113
- const record = {
1114
- runId: input.runId,
1115
- pipelineId: input.pipelineId,
1116
- status: input.status,
1117
- input: input.input,
1118
- ...input.output === void 0 ? {} : { output: input.output },
1119
- ...input.error === void 0 ? {} : { error: input.error },
1120
- ...input.metadata === void 0 ? {} : { metadata: input.metadata },
1121
- startedAt: input.startedAt,
1122
- ...input.endedAt === void 0 ? {} : { endedAt: input.endedAt },
1123
- ...input.durationMs === void 0 ? {} : { durationMs: input.durationMs }
1124
- };
1125
- this.pipelineRuns.set(input.runId, record);
1126
- return record;
1015
+ if (!isObject(body)) {
1016
+ return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
1127
1017
  }
1128
- getPipelineRun(options) {
1129
- const run = this.pipelineRuns.get(options.runId);
1130
- return run?.pipelineId === options.pipelineId ? run : void 0;
1018
+ if (typeof body.approved !== "boolean") {
1019
+ return { error: errorResponse(c, 400, "bad_request", "approved must be a boolean") };
1131
1020
  }
1132
- listPipelineRuns(options) {
1133
- return [...this.pipelineRuns.values()].filter((run) => run.pipelineId === options.pipelineId).sort((left, right) => Date.parse(right.startedAt) - Date.parse(left.startedAt)).slice(0, options.limit);
1021
+ if ("reason" in body && typeof body.reason !== "string") {
1022
+ return { error: errorResponse(c, 400, "bad_request", "reason must be a string") };
1134
1023
  }
1135
- };
1136
- function sessionSummary(session) {
1137
- return {
1138
- id: session.id,
1139
- agentId: session.agentId,
1140
- ...session.title === void 0 ? {} : { title: session.title },
1141
- createdAt: session.createdAt,
1142
- updatedAt: session.updatedAt,
1143
- messageCount: session.messages.length,
1144
- ...session.metadata === void 0 ? {} : { metadata: session.metadata }
1145
- };
1024
+ return compact({
1025
+ approved: body.approved,
1026
+ reason: typeof body.reason === "string" && body.reason.trim().length > 0 ? body.reason.trim() : void 0
1027
+ });
1146
1028
  }
1147
- function materializeSession(session) {
1029
+ function createApprovalRuntime() {
1030
+ const approvals = /* @__PURE__ */ new Map();
1148
1031
  return {
1149
- ...sessionSummary(session),
1150
- messages: [...session.messages],
1151
- transcript: renumberTranscript(session.runs.flatMap((run) => run.transcript))
1032
+ approvals,
1033
+ createApprovals(context) {
1034
+ return {
1035
+ async handler(request) {
1036
+ const decision = await requestApproval(
1037
+ approvals,
1038
+ context,
1039
+ compact({
1040
+ toolName: request.toolName,
1041
+ toolCallId: request.toolCallId,
1042
+ internalCallId: request.internalCallId,
1043
+ args: request.rawArgs,
1044
+ reason: request.reason,
1045
+ rejectMessage: request.rejectMessage
1046
+ })
1047
+ );
1048
+ return decision.approved ? compact({ approved: true, reason: decision.reason }) : compact({ approved: false, reason: decision.reason });
1049
+ }
1050
+ };
1051
+ },
1052
+ list(options) {
1053
+ return [...approvals.values()].filter((approval) => {
1054
+ if (options.status === "pending" && approval.status !== "pending") {
1055
+ return false;
1056
+ }
1057
+ if (options.status === "resolved" && approval.status === "pending") {
1058
+ return false;
1059
+ }
1060
+ if (options.runId !== void 0 && approval.runId !== options.runId) {
1061
+ return false;
1062
+ }
1063
+ if (options.agentId !== void 0 && approval.agentId !== options.agentId) {
1064
+ return false;
1065
+ }
1066
+ if (options.sessionId !== void 0 && approval.sessionId !== options.sessionId) {
1067
+ return false;
1068
+ }
1069
+ return true;
1070
+ }).map(publicApproval);
1071
+ },
1072
+ decide(id, decision) {
1073
+ const approval = approvals.get(id);
1074
+ if (approval === void 0) {
1075
+ return "missing";
1076
+ }
1077
+ if (!isPendingApproval(approval)) {
1078
+ return "resolved";
1079
+ }
1080
+ const reason = decision.approved ? decision.reason : decision.reason ?? approval.rejectMessage ?? "Rejected in Anvia Studio.";
1081
+ const resolved = resolveApproval(
1082
+ approval,
1083
+ decision.approved ? "approved" : "rejected",
1084
+ compact({ reason })
1085
+ );
1086
+ approvals.set(id, resolved);
1087
+ approval.emit?.({ type: "tool_approval_result", approval: resolved });
1088
+ approval.resolve(
1089
+ compact({
1090
+ approved: decision.approved,
1091
+ reason
1092
+ })
1093
+ );
1094
+ return publicApproval(resolved);
1095
+ }
1152
1096
  };
1153
1097
  }
1154
- function traceSummary(trace) {
1155
- return {
1156
- id: trace.id,
1157
- sessionId: trace.sessionId,
1158
- ...trace.name === void 0 ? {} : { name: trace.name },
1159
- status: trace.status,
1160
- startedAt: trace.startedAt,
1161
- ...trace.endedAt === void 0 ? {} : { endedAt: trace.endedAt },
1162
- ...trace.durationMs === void 0 ? {} : { durationMs: trace.durationMs },
1163
- ...trace.output === void 0 ? {} : { output: trace.output },
1164
- ...trace.error === void 0 ? {} : { error: trace.error },
1165
- ...trace.usage === void 0 ? {} : { usage: trace.usage },
1166
- ...trace.metadata === void 0 ? {} : { metadata: trace.metadata },
1167
- observationCount: trace.observations.length
1098
+ async function requestApproval(approvals, context, request) {
1099
+ const id = globalThis.crypto.randomUUID();
1100
+ const approval = {
1101
+ ...compact({
1102
+ id,
1103
+ runId: context.runId,
1104
+ agentId: context.agentId,
1105
+ sessionId: context.sessionId,
1106
+ toolName: request.toolName,
1107
+ callId: request.toolCallId,
1108
+ internalCallId: request.internalCallId,
1109
+ args: request.args,
1110
+ status: "pending",
1111
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
1112
+ reason: request.reason,
1113
+ rejectMessage: request.rejectMessage,
1114
+ emit: context.emit
1115
+ }),
1116
+ resolve: () => {
1117
+ }
1168
1118
  };
1169
- }
1170
- function traceAgentId(trace) {
1171
- const nestedMetadata = trace.metadata?.metadata;
1172
- return isJsonObject(nestedMetadata) && typeof nestedMetadata.agentId === "string" ? nestedMetadata.agentId : void 0;
1173
- }
1174
- function studioRunId(context) {
1175
- const value = context.metadata?.studioRunId;
1176
- return typeof value === "string" && value.length > 0 ? value : void 0;
1177
- }
1178
- function serializeJsonError(error) {
1179
- if (error instanceof Error) {
1180
- return {
1181
- name: error.name,
1182
- message: error.message
1119
+ const decision = new Promise((resolve2) => {
1120
+ approval.resolve = (decision2) => {
1121
+ const current = approvals.get(id);
1122
+ if (!isPendingApproval(current)) {
1123
+ if (current !== void 0) {
1124
+ resolve2(
1125
+ compact({
1126
+ approved: current.status === "approved",
1127
+ reason: current.reason
1128
+ })
1129
+ );
1130
+ }
1131
+ return;
1132
+ }
1133
+ const reason = decision2.approved ? decision2.reason : decision2.reason ?? request.rejectMessage ?? "Rejected in Anvia Studio.";
1134
+ const resolved = resolveApproval(
1135
+ current,
1136
+ decision2.approved ? "approved" : "rejected",
1137
+ compact({ reason })
1138
+ );
1139
+ approvals.set(id, resolved);
1140
+ context.emit?.({ type: "tool_approval_result", approval: resolved });
1141
+ resolve2(
1142
+ compact({
1143
+ approved: decision2.approved,
1144
+ reason
1145
+ })
1146
+ );
1183
1147
  };
1184
- }
1185
- return isJsonValue(error) ? error : String(error);
1148
+ });
1149
+ approvals.set(id, approval);
1150
+ context.emit?.({ type: "tool_approval_request", approval: publicApproval(approval) });
1151
+ return decision;
1186
1152
  }
1187
- function isJsonObject(value) {
1188
- return typeof value === "object" && value !== null && !Array.isArray(value);
1153
+ function isPendingApproval(approval) {
1154
+ return approval !== void 0 && approval.status === "pending" && "resolve" in approval;
1189
1155
  }
1190
- function isJsonValue(value) {
1191
- if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1192
- return true;
1193
- }
1194
- if (Array.isArray(value)) {
1195
- return value.every(isJsonValue);
1196
- }
1197
- return isJsonObject(value) && Object.values(value).every(isJsonValue);
1156
+ function resolveApproval(approval, status, options = {}) {
1157
+ return publicApproval({
1158
+ ...approval,
1159
+ ...compact({
1160
+ status,
1161
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
1162
+ reason: options.reason
1163
+ })
1164
+ });
1165
+ }
1166
+ function publicApproval(approval) {
1167
+ const { emit, rejectMessage, resolve: resolve2, ...rest } = approval;
1168
+ void emit;
1169
+ void rejectMessage;
1170
+ void resolve2;
1171
+ return rest;
1198
1172
  }
1199
1173
 
1200
1174
  // src/runtime/models.ts
@@ -1220,12 +1194,12 @@ function createStudioModelRegistry(config) {
1220
1194
  providers.set(id, {
1221
1195
  ...provider,
1222
1196
  id,
1223
- ...provider.defaultModel === void 0 ? {} : { defaultModel: normalizeModelId(provider.defaultModel) },
1197
+ ...compact({ defaultModel: provider.defaultModel !== void 0 ? normalizeModelId(provider.defaultModel) : void 0 }),
1224
1198
  staticModels
1225
1199
  });
1226
1200
  }
1227
1201
  return {
1228
- ...config.default === void 0 ? {} : { defaultModel: normalizeModelRef(config.default) },
1202
+ ...compact({ defaultModel: config.default !== void 0 ? normalizeModelRef(config.default) : void 0 }),
1229
1203
  providers,
1230
1204
  agentPolicies: normalizeAgentPolicies(config.agents ?? {}),
1231
1205
  modelCache: /* @__PURE__ */ new Map()
@@ -1241,10 +1215,8 @@ function studioModelsConfig(registry, agents) {
1241
1215
  );
1242
1216
  return {
1243
1217
  id: provider.id,
1244
- ...provider.name === void 0 ? {} : { name: provider.name },
1245
- ...provider.defaultModel === void 0 ? {} : { defaultModel: provider.defaultModel },
1246
- models,
1247
- ...provider.metadata === void 0 ? {} : { metadata: provider.metadata }
1218
+ ...compact({ name: provider.name, defaultModel: provider.defaultModel, metadata: provider.metadata }),
1219
+ models
1248
1220
  };
1249
1221
  });
1250
1222
  const agentIds = new Set(agents.map((agent) => agent.id));
@@ -1253,7 +1225,7 @@ function studioModelsConfig(registry, agents) {
1253
1225
  );
1254
1226
  return {
1255
1227
  providers,
1256
- ...registry.defaultModel === void 0 ? {} : { default: registry.defaultModel },
1228
+ ...compact({ default: registry.defaultModel }),
1257
1229
  agents: agentsConfig
1258
1230
  };
1259
1231
  }
@@ -1267,7 +1239,7 @@ function registerModelRoutes(app, props) {
1267
1239
  );
1268
1240
  return c.json({
1269
1241
  providers,
1270
- ...props.registry.defaultModel === void 0 ? {} : { defaultModel: props.registry.defaultModel }
1242
+ ...compact({ defaultModel: props.registry.defaultModel })
1271
1243
  });
1272
1244
  });
1273
1245
  app.get("/models/:providerId", async (c) => {
@@ -1380,9 +1352,9 @@ async function agentModelsCatalog(registry, agent) {
1380
1352
  const defaultModel = policy?.default ?? registry.defaultModel;
1381
1353
  return {
1382
1354
  agentId: agent.id,
1383
- ...defaultModel === void 0 ? {} : { defaultModel },
1355
+ ...compact({ defaultModel }),
1384
1356
  models: [...models, ...exactPolicyModels],
1385
- ...warnings.length === 0 ? {} : { warnings }
1357
+ ...compact({ warnings: warnings.length === 0 ? void 0 : warnings })
1386
1358
  };
1387
1359
  }
1388
1360
  async function providerCatalog(provider) {
@@ -1400,14 +1372,15 @@ async function providerCatalog(provider) {
1400
1372
  model.id,
1401
1373
  modelSummary(provider, model.id, {
1402
1374
  id: model.id,
1403
- ...model.name === void 0 ? {} : { name: model.name },
1404
- ...model.description === void 0 ? {} : { description: model.description },
1375
+ ...compact({ name: model.name, description: model.description }),
1405
1376
  ...staticModel ?? {},
1406
1377
  metadata: {
1407
- ...model.type === void 0 ? {} : { type: model.type },
1408
- ...model.createdAt === void 0 ? {} : { createdAt: model.createdAt },
1409
- ...model.ownedBy === void 0 ? {} : { ownedBy: model.ownedBy },
1410
- ...model.contextLength === void 0 ? {} : { contextLength: model.contextLength },
1378
+ ...compact({
1379
+ type: model.type,
1380
+ createdAt: model.createdAt,
1381
+ ownedBy: model.ownedBy,
1382
+ contextLength: model.contextLength
1383
+ }),
1411
1384
  ...staticModel?.metadata ?? {}
1412
1385
  }
1413
1386
  })
@@ -1420,11 +1393,8 @@ async function providerCatalog(provider) {
1420
1393
  }
1421
1394
  return {
1422
1395
  id: provider.id,
1423
- ...provider.name === void 0 ? {} : { name: provider.name },
1424
- ...provider.defaultModel === void 0 ? {} : { defaultModel: provider.defaultModel },
1425
- models: [...models.values()].sort((left, right) => left.ref.localeCompare(right.ref)),
1426
- ...provider.metadata === void 0 ? {} : { metadata: provider.metadata },
1427
- ...warning === void 0 ? {} : { warning }
1396
+ ...compact({ name: provider.name, defaultModel: provider.defaultModel, metadata: provider.metadata, warning }),
1397
+ models: [...models.values()].sort((left, right) => left.ref.localeCompare(right.ref))
1428
1398
  };
1429
1399
  }
1430
1400
  function modelSummary(provider, modelId, model) {
@@ -1433,7 +1403,7 @@ function modelSummary(provider, modelId, model) {
1433
1403
  id: modelId,
1434
1404
  ref: `${provider.id}:${modelId}`,
1435
1405
  providerId: provider.id,
1436
- ...provider.name === void 0 ? {} : { providerName: provider.name }
1406
+ ...compact({ providerName: provider.name })
1437
1407
  };
1438
1408
  }
1439
1409
  function ensureModelAllowed(registry, agentId, ref) {
@@ -1456,21 +1426,18 @@ function normalizeAgentPolicies(policies) {
1456
1426
  Object.entries(policies).map(([agentId, policy]) => [
1457
1427
  agentId.trim(),
1458
1428
  {
1459
- ...policy.default === void 0 ? {} : { default: normalizeModelRef(policy.default) },
1460
- ...policy.allowed === void 0 ? {} : {
1461
- allowed: policy.allowed.map(
1429
+ ...compact({
1430
+ default: policy.default !== void 0 ? normalizeModelRef(policy.default) : void 0,
1431
+ allowed: policy.allowed?.map(
1462
1432
  (entry) => typeof entry === "string" && entry.trim().endsWith(":*") ? `${normalizeProviderId(entry.trim().slice(0, -2))}:*` : normalizeModelRef(entry)
1463
1433
  )
1464
- }
1434
+ })
1465
1435
  }
1466
1436
  ])
1467
1437
  );
1468
1438
  }
1469
1439
  function publicPolicy(policy) {
1470
- return {
1471
- ...policy.default === void 0 ? {} : { default: policy.default },
1472
- ...policy.allowed === void 0 ? {} : { allowed: policy.allowed }
1473
- };
1440
+ return compact({ default: policy.default, allowed: policy.allowed });
1474
1441
  }
1475
1442
  function modelWarnings(ref, model, request) {
1476
1443
  const warnings = [];
@@ -1572,158 +1539,30 @@ function agentHasMcpTools(agent) {
1572
1539
  return agentToolItems(agent).some(({ tool }) => mcpServerName(tool) !== void 0);
1573
1540
  }
1574
1541
 
1575
- // src/runtime/shared.ts
1576
- function resolveStores(options) {
1577
- const defaultStore = defaultStudioStore();
1578
- const sessions = resolveSessionStore(options, defaultStore);
1579
- const traces = resolveTraceStore(options, sessions, defaultStore);
1580
- const pipelineLogs = resolvePipelineLogStore(options, sessions, defaultStore);
1581
- const pipelineRuns = resolvePipelineRunStore(options, sessions, pipelineLogs, defaultStore);
1582
- return {
1583
- ...sessions === void 0 ? {} : { sessions },
1584
- ...traces === void 0 ? {} : { traces },
1585
- ...pipelineLogs === void 0 ? {} : { pipelineLogs },
1586
- ...pipelineRuns === void 0 ? {} : { pipelineRuns }
1587
- };
1588
- }
1589
- function defaultStudioStore() {
1590
- return createInMemoryStudioStore();
1591
- }
1592
- function resolveSessionStore(options, defaultStore) {
1593
- if (options.stores?.sessions === false) {
1594
- return void 0;
1595
- }
1596
- if (options.stores?.sessions !== void 0) {
1597
- return options.stores.sessions;
1598
- }
1599
- return defaultStore;
1600
- }
1601
- function resolveTraceStore(options, sessionStore, defaultStore) {
1602
- if (options.stores?.traces !== void 0) {
1603
- return options.stores.traces;
1604
- }
1605
- if (sessionStore === void 0) {
1606
- return void 0;
1607
- }
1608
- if (isTraceStore(sessionStore)) {
1609
- return sessionStore;
1610
- }
1611
- return defaultStore;
1612
- }
1613
- function resolvePipelineLogStore(options, sessionStore, defaultStore) {
1614
- if (options.stores?.pipelineLogs === false) {
1615
- return void 0;
1616
- }
1617
- if (options.stores?.pipelineLogs !== void 0) {
1618
- return options.stores.pipelineLogs;
1619
- }
1620
- if (sessionStore !== void 0 && isPipelineLogStore(sessionStore)) {
1621
- return sessionStore;
1622
- }
1623
- return defaultStore;
1624
- }
1625
- function resolvePipelineRunStore(options, sessionStore, pipelineLogStore, defaultStore) {
1626
- if (options.stores?.pipelineRuns === false) {
1627
- return void 0;
1628
- }
1629
- if (options.stores?.pipelineRuns !== void 0) {
1630
- return options.stores.pipelineRuns;
1631
- }
1632
- if (sessionStore !== void 0 && isPipelineRunStore(sessionStore)) {
1633
- return sessionStore;
1634
- }
1635
- if (pipelineLogStore !== void 0 && isPipelineRunStore(pipelineLogStore)) {
1636
- return pipelineLogStore;
1637
- }
1638
- return defaultStore;
1639
- }
1640
- function isTraceStore(store) {
1641
- const candidate = store;
1642
- return typeof candidate.listSessionTraces === "function" && typeof candidate.getTrace === "function" && typeof candidate.saveTrace === "function";
1643
- }
1644
- function isPipelineLogStore(store) {
1645
- const candidate = store;
1646
- return typeof candidate.appendPipelineLog === "function" && typeof candidate.listPipelineLogs === "function";
1647
- }
1648
- function isPipelineRunStore(store) {
1649
- const candidate = store;
1650
- return typeof candidate.savePipelineRun === "function" && typeof candidate.getPipelineRun === "function" && typeof candidate.listPipelineRuns === "function";
1651
- }
1652
- function unsupportedCapabilities(stores) {
1653
- return [
1654
- ...stores.sessions === void 0 ? ["sessions"] : [],
1655
- ...stores.traces === void 0 ? ["traces"] : []
1656
- ];
1657
- }
1658
- function normalizeAgents(agents) {
1659
- const ids = /* @__PURE__ */ new Set();
1660
- return agents.map((agent) => {
1661
- const id = agent.id.trim();
1662
- if (id.length === 0) {
1663
- throw new Error("Studio agent id cannot be empty");
1664
- }
1665
- if (ids.has(id)) {
1666
- throw new Error(`Duplicate runner agent id: ${id}`);
1667
- }
1668
- ids.add(id);
1669
- return { ...agent, id };
1670
- });
1671
- }
1672
- function normalizePipelines(pipelines) {
1673
- const ids = /* @__PURE__ */ new Set();
1674
- return pipelines.map((pipeline) => {
1675
- const id = pipeline.id.trim();
1676
- if (id.length === 0) {
1677
- throw new Error("Studio pipeline id cannot be empty");
1678
- }
1679
- if (ids.has(id)) {
1680
- throw new Error(`Duplicate Studio pipeline id: ${id}`);
1681
- }
1682
- ids.add(id);
1683
- return { ...pipeline, id };
1684
- });
1685
- }
1686
- function buildConfig(options, agents, pipelines, stores) {
1687
- const models = options.models === void 0 ? void 0 : studioModelsConfig(createStudioModelRegistry(options.models), agents);
1688
- return {
1689
- id: runnerId(options),
1690
- ...options.name === void 0 ? {} : { name: options.name },
1691
- ...options.description === void 0 ? {} : { description: options.description },
1692
- ...options.version === void 0 ? {} : { version: options.version },
1693
- agents: agents.map(agentConfig),
1694
- ...models === void 0 ? {} : { models },
1695
- pipelines: pipelines.map(pipelineConfig),
1696
- evals: options.evals.map(evalConfig),
1697
- chat: {
1698
- quickPrompts: Object.fromEntries(agents.map((agent) => [agent.id, agent.quickPrompts ?? []]))
1699
- },
1700
- capabilities: capabilityConfig(options, agents, pipelines, stores),
1701
- unsupportedCapabilities: unsupportedCapabilities(stores)
1702
- };
1703
- }
1542
+ // src/runtime/config.ts
1704
1543
  function runnerId(options) {
1705
1544
  return options.id ?? "anvia-studio";
1706
1545
  }
1707
1546
  function agentConfig(agent) {
1708
1547
  const name = agent.name ?? agent.agent.name;
1709
1548
  const description = agent.description ?? agent.agent.description;
1710
- return {
1549
+ return compact({
1711
1550
  id: agent.id,
1712
- ...name === void 0 ? {} : { name },
1713
- ...description === void 0 ? {} : { description },
1551
+ name,
1552
+ description,
1714
1553
  quickPrompts: agent.quickPrompts ?? [],
1715
- ...agent.metadata === void 0 ? {} : { metadata: agent.metadata }
1716
- };
1554
+ metadata: agent.metadata
1555
+ });
1717
1556
  }
1718
1557
  function agentRuntimeSummary(agent) {
1719
1558
  const tools = agentToolItems(agent);
1720
1559
  const name = agent.name ?? agent.agent.name;
1721
1560
  const description = agent.description ?? agent.agent.description;
1722
- return {
1561
+ return compact({
1723
1562
  id: agent.id,
1724
- ...name === void 0 ? {} : { name },
1725
- ...description === void 0 ? {} : { description },
1726
- model: toJsonValue(agent.agent.model),
1563
+ name,
1564
+ description,
1565
+ model: toJsonValue2(agent.agent.model),
1727
1566
  toolCount: tools.length,
1728
1567
  staticToolCount: tools.filter((item) => item.source === "static").length,
1729
1568
  dynamicToolCount: tools.filter((item) => item.source === "dynamic").length,
@@ -1735,24 +1574,42 @@ function agentRuntimeSummary(agent) {
1735
1574
  hasMemory: agent.agent.memory !== void 0,
1736
1575
  hasHook: agent.agent.hook !== void 0,
1737
1576
  hasOutputSchema: agent.agent.outputSchema !== void 0,
1738
- ...agent.agent.defaultMaxTurns === void 0 ? {} : { defaultMaxTurns: agent.agent.defaultMaxTurns },
1739
- ...agent.metadata === void 0 ? {} : { metadata: agent.metadata }
1740
- };
1577
+ defaultMaxTurns: agent.agent.defaultMaxTurns,
1578
+ metadata: agent.metadata
1579
+ });
1741
1580
  }
1742
1581
  function pipelineConfig(pipeline) {
1743
1582
  const graph = pipeline.pipeline.graph();
1744
1583
  const stageNodes = graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output");
1745
- return {
1584
+ return compact({
1746
1585
  id: pipeline.id,
1747
- ...pipeline.name === void 0 ? {} : { name: pipeline.name },
1748
- ...pipeline.description === void 0 ? {} : { description: pipeline.description },
1749
- ...pipeline.metadata === void 0 ? {} : { metadata: pipeline.metadata },
1586
+ name: pipeline.name,
1587
+ description: pipeline.description,
1588
+ metadata: pipeline.metadata,
1750
1589
  stageCount: stageNodes.length,
1751
1590
  edgeCount: graph.edges.length,
1752
1591
  hasParallelStages: graph.nodes.some((node) => node.kind === "parallel"),
1753
1592
  agentCount: graph.nodes.filter((node) => node.kind === "agent").length,
1754
1593
  extractorCount: graph.nodes.filter((node) => node.kind === "extractor").length
1755
- };
1594
+ });
1595
+ }
1596
+ function buildConfig(options, agents, pipelines, stores) {
1597
+ const models = options.models === void 0 ? void 0 : studioModelsConfig(createStudioModelRegistry(options.models), agents);
1598
+ return compact({
1599
+ id: runnerId(options),
1600
+ name: options.name,
1601
+ description: options.description,
1602
+ version: options.version,
1603
+ agents: agents.map(agentConfig),
1604
+ models,
1605
+ pipelines: pipelines.map(pipelineConfig),
1606
+ evals: options.evals.map(evalConfig),
1607
+ chat: {
1608
+ quickPrompts: Object.fromEntries(agents.map((agent) => [agent.id, agent.quickPrompts ?? []]))
1609
+ },
1610
+ capabilities: capabilityConfig(options, agents, pipelines, stores),
1611
+ unsupportedCapabilities: unsupportedCapabilities(stores)
1612
+ });
1756
1613
  }
1757
1614
  function capabilityConfig(_options, agents, pipelines, stores) {
1758
1615
  const capabilities = {
@@ -1794,357 +1651,24 @@ function capabilityConfig(_options, agents, pipelines, stores) {
1794
1651
  return capabilities;
1795
1652
  }
1796
1653
  function evalConfig(suite) {
1797
- return {
1654
+ return compact({
1798
1655
  id: suite.id ?? suite.name,
1799
1656
  name: suite.name,
1800
- ...suite.description === void 0 ? {} : { description: suite.description },
1657
+ description: suite.description,
1801
1658
  caseCount: suite.cases.length,
1802
1659
  metricNames: suite.metrics.map((metric) => metric.name),
1803
- ...suite.concurrency === void 0 ? {} : { concurrency: suite.concurrency },
1804
- ...suite.metadata === void 0 ? {} : { metadata: suite.metadata }
1805
- };
1806
- }
1807
- function optionalQueryString(value) {
1808
- const trimmed = value?.trim();
1809
- return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
1810
- }
1811
- function parseLimit(value) {
1812
- if (value === void 0 || value.trim().length === 0) {
1813
- return 50;
1814
- }
1815
- const limit = Number(value);
1816
- if (!Number.isInteger(limit) || limit <= 0) {
1817
- return void 0;
1818
- }
1819
- return Math.min(limit, 100);
1820
- }
1821
- function parseTraceStatus(value) {
1822
- const status = optionalQueryString(value);
1823
- if (status === void 0) {
1824
- return void 0;
1825
- }
1826
- return status === "running" || status === "success" || status === "error" ? status : false;
1827
- }
1828
- function isMessageInput(value) {
1829
- return typeof value === "string" || isMessage(value);
1830
- }
1831
- function isMessage(value) {
1832
- if (!isObject(value) || typeof value.role !== "string") {
1833
- return false;
1834
- }
1835
- if (value.role === "system") {
1836
- return typeof value.content === "string";
1837
- }
1838
- if (value.role === "user" || value.role === "assistant" || value.role === "tool") {
1839
- return Array.isArray(value.content);
1840
- }
1841
- return false;
1842
- }
1843
- function isObject(value) {
1844
- return typeof value === "object" && value !== null && !Array.isArray(value);
1845
- }
1846
- function isJsonObject2(value) {
1847
- return isObject(value) && Object.values(value).every(isJsonValue2);
1848
- }
1849
- function isJsonValue2(value) {
1850
- if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1851
- return true;
1852
- }
1853
- if (Array.isArray(value)) {
1854
- return value.every(isJsonValue2);
1855
- }
1856
- return isJsonObject2(value);
1660
+ concurrency: suite.concurrency,
1661
+ metadata: suite.metadata
1662
+ });
1857
1663
  }
1858
- function isAgentTraceOptions(value) {
1859
- if (!isObject(value)) {
1860
- return false;
1861
- }
1862
- return optionalString(value.name) && optionalString(value.userId) && optionalString(value.sessionId) && optionalString(value.version) && optionalString(value.traceId) && optionalBoolean(value.failOnObserverError) && optionalStringArray(value.tags) && optionalObject(value.metadata);
1664
+ function unsupportedCapabilities(stores) {
1665
+ return [
1666
+ ...stores.sessions === void 0 ? ["sessions"] : [],
1667
+ ...stores.traces === void 0 ? ["traces"] : []
1668
+ ];
1863
1669
  }
1864
- function optionalString(value) {
1865
- return value === void 0 || typeof value === "string";
1866
- }
1867
- function optionalBoolean(value) {
1868
- return value === void 0 || typeof value === "boolean";
1869
- }
1870
- function optionalStringArray(value) {
1871
- return value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
1872
- }
1873
- function optionalObject(value) {
1874
- return value === void 0 || isObject(value);
1875
- }
1876
- function isNonNegativeInteger(value) {
1877
- return Number.isInteger(value) && typeof value === "number" && value >= 0;
1878
- }
1879
- function isPositiveInteger(value) {
1880
- return Number.isInteger(value) && typeof value === "number" && value > 0;
1881
- }
1882
- function unsupportedCapability(c, capability) {
1883
- return errorResponse(
1884
- c,
1885
- 501,
1886
- "unsupported_capability",
1887
- `Capability "${capability}" is not implemented by this runner`,
1888
- { capability }
1889
- );
1890
- }
1891
- function errorResponse(c, status, code, message, details) {
1892
- const body = {
1893
- error: {
1894
- code,
1895
- message
1896
- }
1897
- };
1898
- if (details !== void 0) {
1899
- body.error.details = details;
1900
- }
1901
- return c.json(body, status);
1902
- }
1903
- function serializeError(error) {
1904
- return serializeUnknown(error);
1905
- }
1906
-
1907
- // src/runtime/approvals.ts
1908
- function registerApprovalRoutes(app, approvals) {
1909
- app.get("/approvals", (c) => {
1910
- const status = parseApprovalStatus(c.req.query("status"));
1911
- if (status === false) {
1912
- return errorResponse(c, 400, "bad_request", "status must be pending or resolved");
1913
- }
1914
- const options = {};
1915
- const runId = optionalQueryString(c.req.query("runId"));
1916
- const agentId = optionalQueryString(c.req.query("agentId"));
1917
- const sessionId = optionalQueryString(c.req.query("sessionId"));
1918
- if (status !== void 0) {
1919
- options.status = status;
1920
- }
1921
- if (runId !== void 0) {
1922
- options.runId = runId;
1923
- }
1924
- if (agentId !== void 0) {
1925
- options.agentId = agentId;
1926
- }
1927
- if (sessionId !== void 0) {
1928
- options.sessionId = sessionId;
1929
- }
1930
- return c.json({
1931
- approvals: approvals.list(options)
1932
- });
1933
- });
1934
- app.post("/approvals/:approvalId/decision", async (c) => {
1935
- const body = await parseApprovalDecisionRequest(c);
1936
- if ("error" in body) {
1937
- return body.error;
1938
- }
1939
- const result = approvals.decide(c.req.param("approvalId"), body);
1940
- if (result === "missing") {
1941
- return errorResponse(c, 404, "not_found", "Approval not found");
1942
- }
1943
- if (result === "resolved") {
1944
- return errorResponse(c, 409, "conflict", "Approval is already resolved");
1945
- }
1946
- return c.json(result);
1947
- });
1948
- }
1949
- function parseApprovalStatus(value) {
1950
- const status = optionalQueryString(value);
1951
- if (status === void 0) {
1952
- return void 0;
1953
- }
1954
- return status === "pending" || status === "resolved" ? status : false;
1955
- }
1956
- async function parseApprovalDecisionRequest(c) {
1957
- let body;
1958
- try {
1959
- body = await c.req.json();
1960
- } catch {
1961
- return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
1962
- }
1963
- if (!isObject(body)) {
1964
- return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
1965
- }
1966
- if (typeof body.approved !== "boolean") {
1967
- return { error: errorResponse(c, 400, "bad_request", "approved must be a boolean") };
1968
- }
1969
- if ("reason" in body && typeof body.reason !== "string") {
1970
- return { error: errorResponse(c, 400, "bad_request", "reason must be a string") };
1971
- }
1972
- return {
1973
- approved: body.approved,
1974
- ...typeof body.reason === "string" && body.reason.trim().length > 0 ? { reason: body.reason.trim() } : {}
1975
- };
1976
- }
1977
- function createApprovalRuntime() {
1978
- const approvals = /* @__PURE__ */ new Map();
1979
- return {
1980
- approvals,
1981
- createHook(context) {
1982
- const handleApprovalRequest = async ({ toolName, toolCallId, internalCallId, args, tool: control }, request) => {
1983
- const decision = await requestApproval(approvals, context, {
1984
- toolName,
1985
- ...toolCallId === void 0 ? {} : { toolCallId },
1986
- internalCallId,
1987
- args,
1988
- ...request.reason === void 0 ? {} : { reason: request.reason },
1989
- ...request.rejectMessage === void 0 ? {} : { rejectMessage: request.rejectMessage }
1990
- });
1991
- return decision.approved ? control.run() : control.skip(decision.reason ?? request.rejectMessage ?? "Rejected in Anvia Studio.");
1992
- };
1993
- return {
1994
- ...createHook({
1995
- async onToolCall({ toolName, toolCallId, internalCallId, args, tool: control }) {
1996
- const registeredTool = context.getTool(toolName);
1997
- if (registeredTool?.approval === void 0) {
1998
- return control.run();
1999
- }
2000
- const approval = registeredTool.approval;
2001
- const rawParsedArgs = parseToolArgs(args);
2002
- const parsedArgs = registeredTool.parseApprovalArgs?.(rawParsedArgs) ?? rawParsedArgs;
2003
- const approvalContext = {
2004
- toolName,
2005
- args: parsedArgs,
2006
- rawArgs: args,
2007
- ...toolCallId === void 0 ? {} : { toolCallId },
2008
- internalCallId,
2009
- run: {
2010
- agentId: context.agentId,
2011
- runId: context.runId,
2012
- ...context.sessionId === void 0 ? {} : { sessionId: context.sessionId },
2013
- ...context.metadata === void 0 ? {} : { metadata: context.metadata }
2014
- }
2015
- };
2016
- const required = await approval.when(approvalContext);
2017
- if (!required) {
2018
- return control.run();
2019
- }
2020
- const reason = await resolveApprovalText(approval.reason, approvalContext);
2021
- const rejectMessage = await resolveApprovalText(
2022
- approval.rejectMessage,
2023
- approvalContext
2024
- );
2025
- const decision = await requestApproval(approvals, context, {
2026
- toolName,
2027
- ...toolCallId === void 0 ? {} : { toolCallId },
2028
- internalCallId,
2029
- args,
2030
- ...reason === void 0 ? {} : { reason },
2031
- ...rejectMessage === void 0 ? {} : { rejectMessage }
2032
- });
2033
- return decision.approved ? control.run() : control.skip(decision.reason ?? rejectMessage ?? "Rejected in Anvia Studio.");
2034
- }
2035
- }),
2036
- handleApprovalRequest
2037
- };
2038
- },
2039
- list(options) {
2040
- return [...approvals.values()].filter((approval) => {
2041
- if (options.status === "pending" && approval.status !== "pending") {
2042
- return false;
2043
- }
2044
- if (options.status === "resolved" && approval.status === "pending") {
2045
- return false;
2046
- }
2047
- if (options.runId !== void 0 && approval.runId !== options.runId) {
2048
- return false;
2049
- }
2050
- if (options.agentId !== void 0 && approval.agentId !== options.agentId) {
2051
- return false;
2052
- }
2053
- if (options.sessionId !== void 0 && approval.sessionId !== options.sessionId) {
2054
- return false;
2055
- }
2056
- return true;
2057
- }).map(publicApproval);
2058
- },
2059
- decide(id, decision) {
2060
- const approval = approvals.get(id);
2061
- if (approval === void 0) {
2062
- return "missing";
2063
- }
2064
- if (!isPendingApproval(approval)) {
2065
- return "resolved";
2066
- }
2067
- const reason = decision.approved ? decision.reason : decision.reason ?? approval.rejectMessage ?? "Rejected in Anvia Studio.";
2068
- const resolved = resolveApproval(approval, decision.approved ? "approved" : "rejected", {
2069
- ...reason === void 0 ? {} : { reason }
2070
- });
2071
- approvals.set(id, resolved);
2072
- approval.emit?.({ type: "tool_approval_result", approval: resolved });
2073
- approval.resolve({
2074
- approved: decision.approved,
2075
- ...reason === void 0 ? {} : { reason }
2076
- });
2077
- return publicApproval(resolved);
2078
- }
2079
- };
2080
- }
2081
- async function requestApproval(approvals, context, request) {
2082
- const id = globalThis.crypto.randomUUID();
2083
- const approval = {
2084
- id,
2085
- runId: context.runId,
2086
- agentId: context.agentId,
2087
- ...context.sessionId === void 0 ? {} : { sessionId: context.sessionId },
2088
- toolName: request.toolName,
2089
- ...request.toolCallId === void 0 ? {} : { callId: request.toolCallId },
2090
- internalCallId: request.internalCallId,
2091
- args: request.args,
2092
- status: "pending",
2093
- requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
2094
- ...request.reason === void 0 ? {} : { reason: request.reason },
2095
- ...request.rejectMessage === void 0 ? {} : { rejectMessage: request.rejectMessage },
2096
- ...context.emit === void 0 ? {} : { emit: context.emit },
2097
- resolve: () => {
2098
- }
2099
- };
2100
- const decision = new Promise((resolve2) => {
2101
- approval.resolve = (decision2) => {
2102
- const current = approvals.get(id);
2103
- if (!isPendingApproval(current)) {
2104
- if (current !== void 0) {
2105
- resolve2({
2106
- approved: current.status === "approved",
2107
- ...current.reason === void 0 ? {} : { reason: current.reason }
2108
- });
2109
- }
2110
- return;
2111
- }
2112
- const reason = decision2.approved ? decision2.reason : decision2.reason ?? request.rejectMessage ?? "Rejected in Anvia Studio.";
2113
- const resolved = resolveApproval(current, decision2.approved ? "approved" : "rejected", {
2114
- ...reason === void 0 ? {} : { reason }
2115
- });
2116
- approvals.set(id, resolved);
2117
- context.emit?.({ type: "tool_approval_result", approval: resolved });
2118
- resolve2({
2119
- approved: decision2.approved,
2120
- ...reason === void 0 ? {} : { reason }
2121
- });
2122
- };
2123
- });
2124
- approvals.set(id, approval);
2125
- context.emit?.({ type: "tool_approval_request", approval: publicApproval(approval) });
2126
- return decision;
2127
- }
2128
- async function resolveApprovalText(value, context) {
2129
- return typeof value === "function" ? value(context) : value;
2130
- }
2131
- function isPendingApproval(approval) {
2132
- return approval !== void 0 && approval.status === "pending" && "resolve" in approval;
2133
- }
2134
- function resolveApproval(approval, status, options = {}) {
2135
- return publicApproval({
2136
- ...approval,
2137
- status,
2138
- resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
2139
- ...options.reason === void 0 ? {} : { reason: options.reason }
2140
- });
2141
- }
2142
- function publicApproval(approval) {
2143
- const { emit, rejectMessage, resolve: resolve2, ...rest } = approval;
2144
- void emit;
2145
- void rejectMessage;
2146
- void resolve2;
2147
- return rest;
1670
+ function toJsonValue2(value) {
1671
+ return serializeUnknown(value);
2148
1672
  }
2149
1673
 
2150
1674
  // src/runtime/evals.ts
@@ -2176,7 +1700,7 @@ function registerEvalRoutes(app, props) {
2176
1700
  const startedAt = Date.now();
2177
1701
  const result = await runEvalSuite({
2178
1702
  ...suite,
2179
- ...body.concurrency === void 0 ? {} : { concurrency: body.concurrency }
1703
+ ...compact({ concurrency: body.concurrency })
2180
1704
  });
2181
1705
  const endedAt = Date.now();
2182
1706
  const jsonResult = toJsonValue(result);
@@ -2186,7 +1710,7 @@ function registerEvalRoutes(app, props) {
2186
1710
  startedAt: new Date(startedAt).toISOString(),
2187
1711
  endedAt: new Date(endedAt).toISOString(),
2188
1712
  durationMs: endedAt - startedAt,
2189
- result: isJsonObject2(jsonResult) ? jsonResult : { value: jsonResult }
1713
+ result: isJsonObject(jsonResult) ? jsonResult : { value: jsonResult }
2190
1714
  };
2191
1715
  return c.json(response);
2192
1716
  });
@@ -2254,12 +1778,12 @@ async function agentKnowledgeConfig(agent) {
2254
1778
  const agentName = agent.name ?? agent.agent.name;
2255
1779
  return {
2256
1780
  agentId: agent.id,
2257
- ...agentName === void 0 ? {} : { agentName },
1781
+ ...compact({ agentName }),
2258
1782
  sources: await knowledgeSources(agent),
2259
1783
  staticContext: agent.agent.staticContext.map((document) => ({
2260
1784
  id: document.id,
2261
1785
  text: document.text,
2262
- ...document.additionalProps === void 0 ? {} : { additionalProps: jsonObjectFromRecord(document.additionalProps) }
1786
+ ...compact({ additionalProps: document.additionalProps !== void 0 ? jsonObjectFromRecord(document.additionalProps) : void 0 })
2263
1787
  }))
2264
1788
  };
2265
1789
  }
@@ -2285,9 +1809,9 @@ async function knowledgeSources(agent) {
2285
1809
  count: 1,
2286
1810
  registrationIndex: index,
2287
1811
  topK: registration.options.topK,
2288
- ...registration.options.threshold === void 0 ? {} : { threshold: registration.options.threshold },
1812
+ ...compact({ threshold: registration.options.threshold }),
2289
1813
  inspectable: inspect !== void 0,
2290
- ...count === void 0 ? {} : { itemCount: count }
1814
+ ...compact({ itemCount: count })
2291
1815
  };
2292
1816
  })
2293
1817
  );
@@ -2302,9 +1826,9 @@ async function knowledgeSources(agent) {
2302
1826
  count: 1,
2303
1827
  registrationIndex: index,
2304
1828
  topK: registration.options.topK,
2305
- ...registration.options.threshold === void 0 ? {} : { threshold: registration.options.threshold },
1829
+ ...compact({ threshold: registration.options.threshold }),
2306
1830
  inspectable: inspect !== void 0,
2307
- ...count === void 0 ? {} : { itemCount: count }
1831
+ ...compact({ itemCount: count })
2308
1832
  };
2309
1833
  })
2310
1834
  );
@@ -2342,8 +1866,7 @@ async function knowledgeItemsPage(agent, sourceId, request) {
2342
1866
  kind: "dynamic_context",
2343
1867
  inspectable: true,
2344
1868
  items: page.items.map((item) => dynamicContextItem(item)),
2345
- ...page.nextCursor === void 0 ? {} : { nextCursor: page.nextCursor },
2346
- ...page.totalCount === void 0 ? {} : { totalCount: page.totalCount }
1869
+ ...compact({ nextCursor: page.nextCursor, totalCount: page.totalCount })
2347
1870
  };
2348
1871
  }
2349
1872
  const dynamicToolsIndex = dynamicSourceIndex(sourceId, "dynamic_tools");
@@ -2367,8 +1890,7 @@ async function knowledgeItemsPage(agent, sourceId, request) {
2367
1890
  kind: "dynamic_tools",
2368
1891
  inspectable: true,
2369
1892
  items: page.items.map((item) => dynamicToolItem(item)),
2370
- ...page.nextCursor === void 0 ? {} : { nextCursor: page.nextCursor },
2371
- ...page.totalCount === void 0 ? {} : { totalCount: page.totalCount }
1893
+ ...compact({ nextCursor: page.nextCursor, totalCount: page.totalCount })
2372
1894
  };
2373
1895
  }
2374
1896
  return void 0;
@@ -2393,9 +1915,9 @@ function staticKnowledgeItemsPage(agent, request) {
2393
1915
  id: document.id,
2394
1916
  kind: "static_context",
2395
1917
  text: document.text,
2396
- ...document.additionalProps === void 0 ? {} : { metadata: jsonObjectFromRecord(document.additionalProps) }
1918
+ ...compact({ metadata: document.additionalProps !== void 0 ? jsonObjectFromRecord(document.additionalProps) : void 0 })
2397
1919
  })),
2398
- ...nextOffset < agent.agent.staticContext.length ? { nextCursor: String(nextOffset) } : {},
1920
+ ...compact({ nextCursor: nextOffset < agent.agent.staticContext.length ? String(nextOffset) : void 0 }),
2399
1921
  totalCount: agent.agent.staticContext.length
2400
1922
  };
2401
1923
  }
@@ -2415,7 +1937,7 @@ function dynamicContextItem(item) {
2415
1937
  id: item.id,
2416
1938
  kind: "dynamic_context",
2417
1939
  ...text === void 0 ? { document: toJsonValue(item.document) } : { text },
2418
- ...item.metadata === void 0 ? {} : { metadata: jsonObjectFromRecord(item.metadata) }
1940
+ ...compact({ metadata: item.metadata !== void 0 ? jsonObjectFromRecord(item.metadata) : void 0 })
2419
1941
  };
2420
1942
  }
2421
1943
  function dynamicToolItem(item) {
@@ -2430,7 +1952,7 @@ function dynamicToolItem(item) {
2430
1952
  description,
2431
1953
  parameterKeys: parameterKeys(definition.parameters),
2432
1954
  document: toJsonValue(item.document),
2433
- ...item.metadata === void 0 ? {} : { metadata: jsonObjectFromRecord(item.metadata) }
1955
+ ...compact({ metadata: item.metadata !== void 0 ? jsonObjectFromRecord(item.metadata) : void 0 })
2434
1956
  };
2435
1957
  }
2436
1958
  function parameterKeys(parameters) {
@@ -2492,7 +2014,7 @@ function evidenceFromTrace(trace) {
2492
2014
  observationName: observation.name,
2493
2015
  turn: observation.turn,
2494
2016
  startedAt: observation.startedAt,
2495
- ...query === void 0 ? {} : { query },
2017
+ ...compact({ query }),
2496
2018
  documentCount: documents.length,
2497
2019
  toolCount: tools.length,
2498
2020
  documents,
@@ -2565,11 +2087,7 @@ function evidenceDocument(value) {
2565
2087
  return [];
2566
2088
  }
2567
2089
  return [
2568
- {
2569
- ...id === void 0 ? {} : { id },
2570
- ...text === void 0 ? {} : { text },
2571
- ...additionalProps === void 0 ? {} : { additionalProps }
2572
- }
2090
+ compact({ id, text, additionalProps })
2573
2091
  ];
2574
2092
  }
2575
2093
  function evidenceToolName(value) {
@@ -2681,7 +2199,7 @@ function registerMemoryRoutes(app, props) {
2681
2199
  const agentId = optionalQueryString(c.req.query("agentId"));
2682
2200
  const userId = optionalQueryString(c.req.query("userId"));
2683
2201
  const sessions = await props.sessionStore.listSessions({
2684
- ...agentId === void 0 ? {} : { agentId },
2202
+ ...compact({ agentId }),
2685
2203
  limit: 100
2686
2204
  });
2687
2205
  const conversations = sessions.map(memoryConversationSummary).filter((session) => userId === void 0 || session.userId === userId).slice(0, limit);
@@ -2713,16 +2231,16 @@ function registerMemoryRoutes(app, props) {
2713
2231
  });
2714
2232
  }
2715
2233
  function memoryConversationSummary(session) {
2716
- return {
2234
+ return compact({
2717
2235
  id: session.id,
2718
2236
  userId: sessionUserId(session),
2719
2237
  agentId: session.agentId,
2720
- ...session.title === void 0 ? {} : { title: session.title },
2238
+ title: session.title,
2721
2239
  createdAt: session.createdAt,
2722
2240
  updatedAt: session.updatedAt,
2723
2241
  messageCount: session.messageCount,
2724
- ...session.metadata === void 0 ? {} : { metadata: session.metadata }
2725
- };
2242
+ metadata: session.metadata
2243
+ });
2726
2244
  }
2727
2245
  function sessionUserId(session) {
2728
2246
  const userId = session.metadata?.userId;
@@ -2809,9 +2327,11 @@ var StudioObservabilityHub = class {
2809
2327
  function observeStores(stores, hub) {
2810
2328
  return {
2811
2329
  ...stores,
2812
- ...stores.sessions === void 0 ? {} : { sessions: observeSessionStore(stores.sessions, hub) },
2813
- ...stores.traces === void 0 ? {} : { traces: observeTraceStore(stores.traces, hub) },
2814
- ...stores.pipelineLogs === void 0 ? {} : { pipelineLogs: observePipelineLogStore(stores.pipelineLogs, hub) }
2330
+ ...compact({
2331
+ sessions: stores.sessions !== void 0 ? observeSessionStore(stores.sessions, hub) : void 0,
2332
+ traces: stores.traces !== void 0 ? observeTraceStore(stores.traces, hub) : void 0,
2333
+ pipelineLogs: stores.pipelineLogs !== void 0 ? observePipelineLogStore(stores.pipelineLogs, hub) : void 0
2334
+ })
2815
2335
  };
2816
2336
  }
2817
2337
  function registerObservabilityRoutes(app, hub) {
@@ -2832,7 +2352,7 @@ function registerObservabilityRoutes(app, hub) {
2832
2352
  });
2833
2353
  }
2834
2354
  function observabilityEvents(hub, types) {
2835
- const subscription = hub.subscribe(types === void 0 ? {} : { types });
2355
+ const subscription = hub.subscribe(compact({ types }));
2836
2356
  return {
2837
2357
  [Symbol.asyncIterator]() {
2838
2358
  return {
@@ -2924,7 +2444,7 @@ function observeTraceStore(store, hub) {
2924
2444
  const saveTrace = target.saveTrace.bind(target);
2925
2445
  return async (...args) => {
2926
2446
  const trace = await saveTrace(...args);
2927
- hub.emit({ type: "trace", trace: traceSummary2(trace) });
2447
+ hub.emit({ type: "trace", trace: traceSummary(trace) });
2928
2448
  return trace;
2929
2449
  };
2930
2450
  }
@@ -2951,20 +2471,22 @@ function parseEventTypes(value) {
2951
2471
  function isEventType(value) {
2952
2472
  return value === "session_log" || value === "pipeline_log" || value === "trace";
2953
2473
  }
2954
- function traceSummary2(trace) {
2474
+ function traceSummary(trace) {
2955
2475
  return {
2956
2476
  id: trace.id,
2957
2477
  sessionId: trace.sessionId,
2958
- ...trace.name === void 0 ? {} : { name: trace.name },
2959
2478
  status: trace.status,
2960
2479
  startedAt: trace.startedAt,
2961
- ...trace.endedAt === void 0 ? {} : { endedAt: trace.endedAt },
2962
- ...trace.durationMs === void 0 ? {} : { durationMs: trace.durationMs },
2963
- ...trace.output === void 0 ? {} : { output: trace.output },
2964
- ...trace.error === void 0 ? {} : { error: trace.error },
2965
- ...trace.usage === void 0 ? {} : { usage: trace.usage },
2966
- ...trace.metadata === void 0 ? {} : { metadata: trace.metadata },
2967
- observationCount: trace.observations.length
2480
+ observationCount: trace.observations.length,
2481
+ ...compact({
2482
+ name: trace.name,
2483
+ endedAt: trace.endedAt,
2484
+ durationMs: trace.durationMs,
2485
+ output: trace.output,
2486
+ error: trace.error,
2487
+ usage: trace.usage,
2488
+ metadata: trace.metadata
2489
+ })
2968
2490
  };
2969
2491
  }
2970
2492
 
@@ -2986,7 +2508,7 @@ function pipelineRunReceivedLog(props) {
2986
2508
  category: "api",
2987
2509
  event: "pipeline.run_received",
2988
2510
  message: "Pipeline run request received",
2989
- metadata: cleanMetadata({
2511
+ metadata: compact({
2990
2512
  stream: props.stream,
2991
2513
  inputBytes: byteLength2(formatUnknown(props.input)),
2992
2514
  metadataKeys: Object.keys(props.metadata ?? {})
@@ -3002,7 +2524,7 @@ function pipelineRunStartedLog(pipeline, runId) {
3002
2524
  category: "run",
3003
2525
  event: "pipeline.run_started",
3004
2526
  message: "Pipeline run started",
3005
- metadata: cleanMetadata({
2527
+ metadata: compact({
3006
2528
  stageCount: graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output").length,
3007
2529
  edgeCount: graph.edges.length
3008
2530
  })
@@ -3016,7 +2538,7 @@ function pipelineRunCompletedLog(props) {
3016
2538
  category: "run",
3017
2539
  event: "pipeline.run_completed",
3018
2540
  message: "Pipeline run completed",
3019
- metadata: cleanMetadata({
2541
+ metadata: compact({
3020
2542
  durationMs: props.durationMs,
3021
2543
  outputBytes: byteLength2(formatUnknown(props.output))
3022
2544
  })
@@ -3030,7 +2552,7 @@ function pipelineRunFailedLog(pipelineId, runId, error, startedAt) {
3030
2552
  category: "run",
3031
2553
  event: "pipeline.run_failed",
3032
2554
  message: "Pipeline run failed",
3033
- metadata: cleanMetadata({
2555
+ metadata: compact({
3034
2556
  durationMs: Date.now() - startedAt,
3035
2557
  error: serializeError(error)
3036
2558
  })
@@ -3057,7 +2579,7 @@ function pipelineStageLog(pipelineId, runId, event) {
3057
2579
  category,
3058
2580
  event: `${event.node.kind}.completed`,
3059
2581
  message: `${event.node.label} completed`,
3060
- metadata: cleanMetadata({
2582
+ metadata: compact({
3061
2583
  ...nodeMetadata(event.node),
3062
2584
  durationMs: event.durationMs
3063
2585
  })
@@ -3070,7 +2592,7 @@ function pipelineStageLog(pipelineId, runId, event) {
3070
2592
  category,
3071
2593
  event: `${event.node.kind}.failed`,
3072
2594
  message: `${event.node.label} failed`,
3073
- metadata: cleanMetadata({
2595
+ metadata: compact({
3074
2596
  ...nodeMetadata(event.node),
3075
2597
  durationMs: event.durationMs,
3076
2598
  error: serializeError(event.error)
@@ -3090,7 +2612,7 @@ function stageCategory(node) {
3090
2612
  return "stage";
3091
2613
  }
3092
2614
  function nodeMetadata(node) {
3093
- return cleanMetadata({
2615
+ return compact({
3094
2616
  nodeId: node.id,
3095
2617
  kind: node.kind,
3096
2618
  label: node.label,
@@ -3099,48 +2621,151 @@ function nodeMetadata(node) {
3099
2621
  branchKey: node.branchKey
3100
2622
  });
3101
2623
  }
3102
- function cleanMetadata(value) {
3103
- return Object.fromEntries(
3104
- Object.entries(value).filter(([, item]) => item !== void 0)
3105
- );
3106
- }
3107
2624
  function byteLength2(value) {
3108
2625
  return value === void 0 ? void 0 : new TextEncoder().encode(value).length;
3109
2626
  }
3110
- function formatUnknown(value) {
3111
- try {
3112
- return JSON.stringify(value);
3113
- } catch {
3114
- return void 0;
3115
- }
3116
- }
3117
2627
 
3118
- // src/runtime/runs.ts
3119
- var AsyncEventQueue = class {
3120
- values = [];
3121
- resolvers = [];
3122
- closed = false;
3123
- push(value) {
3124
- if (this.closed) {
3125
- return;
3126
- }
3127
- const resolver = this.resolvers.shift();
3128
- if (resolver !== void 0) {
3129
- resolver({ done: false, value });
3130
- return;
3131
- }
3132
- this.values.push(value);
3133
- }
3134
- close() {
3135
- this.closed = true;
3136
- for (const resolver of this.resolvers.splice(0)) {
3137
- resolver({ done: true, value: void 0 });
2628
+ // src/runtime/transcript.ts
2629
+ function renumberTranscript(entries) {
2630
+ return entries.map((entry, entryId) => ({ ...entry, entryId }));
2631
+ }
2632
+ function transcriptFromMessages(messages) {
2633
+ const transcript = [];
2634
+ for (const message of messages) {
2635
+ if (message.role === "system") {
2636
+ continue;
3138
2637
  }
3139
- }
3140
- next() {
3141
- const value = this.values.shift();
3142
- if (value !== void 0) {
3143
- return Promise.resolve({ done: false, value });
2638
+ if (message.role === "user") {
2639
+ const attachments = attachmentsFromMessage(message);
2640
+ let textEntryAdded = false;
2641
+ for (const content of message.content) {
2642
+ if (content.type === "text") {
2643
+ transcript.push(compact({
2644
+ entryId: transcript.length,
2645
+ kind: "message",
2646
+ role: "user",
2647
+ text: content.text,
2648
+ attachments: attachments.length === 0 ? void 0 : attachments
2649
+ }));
2650
+ textEntryAdded = true;
2651
+ }
2652
+ }
2653
+ if (!textEntryAdded && attachments.length > 0) {
2654
+ transcript.push({
2655
+ entryId: transcript.length,
2656
+ kind: "message",
2657
+ role: "user",
2658
+ text: "",
2659
+ attachments
2660
+ });
2661
+ }
2662
+ continue;
2663
+ }
2664
+ if (message.role === "tool") {
2665
+ for (const content of message.content) {
2666
+ transcript.push({
2667
+ entryId: transcript.length,
2668
+ kind: "tool",
2669
+ toolName: "tool_result",
2670
+ callId: content.callId ?? content.id,
2671
+ result: content.content.map(
2672
+ (item) => "text" in item ? item.text : `[image:${item.mediaType ?? "image/png"}]`
2673
+ ).join("\n"),
2674
+ structuredResult: content.content
2675
+ });
2676
+ }
2677
+ continue;
2678
+ }
2679
+ for (const content of message.content) {
2680
+ if (content.type === "text") {
2681
+ appendAssistantTranscriptText(transcript, content.text);
2682
+ } else if (content.type === "reasoning") {
2683
+ transcript.push(compact({
2684
+ entryId: transcript.length,
2685
+ kind: "reasoning",
2686
+ reasoningId: content.id,
2687
+ text: content.text
2688
+ }));
2689
+ } else if (content.type === "tool_call") {
2690
+ transcript.push({
2691
+ entryId: transcript.length,
2692
+ kind: "tool",
2693
+ toolName: content.function.name,
2694
+ callId: content.callId ?? content.id,
2695
+ args: formatJson(content.function.arguments)
2696
+ });
2697
+ }
2698
+ }
2699
+ }
2700
+ return transcript;
2701
+ }
2702
+ function attachmentsFromMessage(message) {
2703
+ if (message.role !== "user" && message.role !== "assistant") {
2704
+ return [];
2705
+ }
2706
+ return message.content.flatMap((content) => {
2707
+ if (content.type === "image") {
2708
+ return [
2709
+ {
2710
+ kind: "image",
2711
+ ...content.source.type === "base64" ? { data: content.source.data, mediaType: content.source.mediaType } : { url: content.source.url }
2712
+ }
2713
+ ];
2714
+ }
2715
+ if (content.type === "document") {
2716
+ return [
2717
+ compact({
2718
+ kind: "document",
2719
+ name: content.source.filename,
2720
+ mediaType: content.source.mediaType,
2721
+ data: content.source.type === "base64" ? content.source.data : void 0,
2722
+ url: content.source.type === "url" ? content.source.url : void 0
2723
+ })
2724
+ ];
2725
+ }
2726
+ return [];
2727
+ });
2728
+ }
2729
+ function appendAssistantTranscriptText(transcript, text) {
2730
+ const last = transcript.at(-1);
2731
+ if (last?.kind === "message" && last.role === "assistant") {
2732
+ last.text = `${last.text}${text}`;
2733
+ return;
2734
+ }
2735
+ transcript.push({
2736
+ entryId: transcript.length,
2737
+ kind: "message",
2738
+ role: "assistant",
2739
+ text
2740
+ });
2741
+ }
2742
+
2743
+ // src/runtime/runs.ts
2744
+ var AsyncEventQueue = class {
2745
+ values = [];
2746
+ resolvers = [];
2747
+ closed = false;
2748
+ push(value) {
2749
+ if (this.closed) {
2750
+ return;
2751
+ }
2752
+ const resolver = this.resolvers.shift();
2753
+ if (resolver !== void 0) {
2754
+ resolver({ done: false, value });
2755
+ return;
2756
+ }
2757
+ this.values.push(value);
2758
+ }
2759
+ close() {
2760
+ this.closed = true;
2761
+ for (const resolver of this.resolvers.splice(0)) {
2762
+ resolver({ done: true, value: void 0 });
2763
+ }
2764
+ }
2765
+ next() {
2766
+ const value = this.values.shift();
2767
+ if (value !== void 0) {
2768
+ return Promise.resolve({ done: false, value });
3144
2769
  }
3145
2770
  if (this.closed) {
3146
2771
  return Promise.resolve({ done: true, value: void 0 });
@@ -3263,21 +2888,21 @@ function acceptTranscriptStreamEvent(transcript, event) {
3263
2888
  kind: "tool",
3264
2889
  toolName: event.toolCall.function.name,
3265
2890
  callId: event.toolCall.callId ?? event.toolCall.id,
3266
- args: formatJson2(event.toolCall.function.arguments)
2891
+ args: formatJson(event.toolCall.function.arguments)
3267
2892
  });
3268
2893
  }
3269
2894
  if (event.type === "tool_result") {
3270
2895
  const matched = findTranscriptToolEntry(transcript, event.toolName, event.toolCallId);
3271
2896
  if (matched === void 0) {
3272
- transcript.push({
2897
+ transcript.push(compact({
3273
2898
  entryId: transcript.length,
3274
2899
  kind: "tool",
3275
2900
  toolName: event.toolName,
3276
- ...event.toolCallId === void 0 ? {} : { callId: event.toolCallId },
2901
+ callId: event.toolCallId,
3277
2902
  args: event.args,
3278
2903
  result: event.result,
3279
- ...event.structuredResult === void 0 ? {} : { structuredResult: event.structuredResult }
3280
- });
2904
+ structuredResult: event.structuredResult
2905
+ }));
3281
2906
  return;
3282
2907
  }
3283
2908
  matched.args = matched.args ?? event.args;
@@ -3289,15 +2914,15 @@ function acceptTranscriptStreamEvent(transcript, event) {
3289
2914
  if (event.type === "agent_tool_event") {
3290
2915
  const matched = findTranscriptToolEntry(transcript, event.toolName, event.toolCallId);
3291
2916
  if (matched === void 0) {
3292
- transcript.push({
2917
+ transcript.push(compact({
3293
2918
  entryId: transcript.length,
3294
2919
  kind: "tool",
3295
2920
  toolName: event.toolName,
3296
- ...event.toolCallId === void 0 ? {} : { callId: event.toolCallId },
2921
+ callId: event.toolCallId,
3297
2922
  childEvents: [childAgentTranscriptEvent(event)].filter(
3298
2923
  (childEvent) => childEvent !== void 0
3299
2924
  )
3300
- });
2925
+ }));
3301
2926
  return;
3302
2927
  }
3303
2928
  appendChildAgentTranscriptEvent(matched, event);
@@ -3323,13 +2948,13 @@ function acceptTranscriptStreamEvent(transcript, event) {
3323
2948
  approvalCallId(event.approval)
3324
2949
  );
3325
2950
  if (matched !== void 0) {
3326
- matched.approval = {
2951
+ matched.approval = compact({
3327
2952
  id: event.approval.id,
3328
2953
  status: event.approval.status,
3329
2954
  requestedAt: event.approval.requestedAt,
3330
- ...event.approval.resolvedAt === void 0 ? {} : { resolvedAt: event.approval.resolvedAt },
3331
- ...event.approval.reason === void 0 ? {} : { reason: event.approval.reason }
3332
- };
2955
+ resolvedAt: event.approval.resolvedAt,
2956
+ reason: event.approval.reason
2957
+ });
3333
2958
  }
3334
2959
  }
3335
2960
  if (event.type === "tool_question_request") {
@@ -3354,14 +2979,14 @@ function acceptTranscriptStreamEvent(transcript, event) {
3354
2979
  questionCallId(event.question)
3355
2980
  );
3356
2981
  if (matched !== void 0) {
3357
- matched.question = {
2982
+ matched.question = compact({
3358
2983
  id: event.question.id,
3359
2984
  status: event.question.status,
3360
2985
  requestedAt: event.question.requestedAt,
3361
- ...event.question.answeredAt === void 0 ? {} : { answeredAt: event.question.answeredAt },
2986
+ answeredAt: event.question.answeredAt,
3362
2987
  questions: event.question.questions,
3363
- ...event.question.answers === void 0 ? {} : { answers: event.question.answers }
3364
- };
2988
+ answers: event.question.answers
2989
+ });
3365
2990
  }
3366
2991
  }
3367
2992
  if (event.type === "final" && event.trace?.traceId !== void 0) {
@@ -3415,51 +3040,51 @@ function appendChildAgentTranscriptEvent(entry, event) {
3415
3040
  function childAgentTranscriptEvent(event) {
3416
3041
  const child = event.event;
3417
3042
  if (child.type === "text_delta") {
3418
- return {
3043
+ return compact({
3419
3044
  kind: "message",
3420
3045
  agentId: event.agentId,
3421
- ...event.agentName === void 0 ? {} : { agentName: event.agentName },
3046
+ agentName: event.agentName,
3422
3047
  text: child.delta
3423
- };
3048
+ });
3424
3049
  }
3425
3050
  if (child.type === "reasoning_delta") {
3426
- return {
3051
+ return compact({
3427
3052
  kind: "reasoning",
3428
3053
  agentId: event.agentId,
3429
- ...event.agentName === void 0 ? {} : { agentName: event.agentName },
3430
- ...child.id === void 0 ? {} : { reasoningId: child.id },
3054
+ agentName: event.agentName,
3055
+ reasoningId: child.id,
3431
3056
  text: child.delta
3432
- };
3057
+ });
3433
3058
  }
3434
3059
  if (child.type === "tool_call") {
3435
- return {
3060
+ return compact({
3436
3061
  kind: "tool",
3437
3062
  agentId: event.agentId,
3438
- ...event.agentName === void 0 ? {} : { agentName: event.agentName },
3063
+ agentName: event.agentName,
3439
3064
  toolName: child.toolCall.function.name,
3440
- ...child.toolCall.callId === void 0 && child.toolCall.id === void 0 ? {} : { callId: child.toolCall.callId ?? child.toolCall.id },
3441
- args: formatJson2(child.toolCall.function.arguments)
3442
- };
3065
+ callId: child.toolCall.callId ?? child.toolCall.id,
3066
+ args: formatJson(child.toolCall.function.arguments)
3067
+ });
3443
3068
  }
3444
3069
  if (child.type === "tool_result") {
3445
- return {
3070
+ return compact({
3446
3071
  kind: "tool",
3447
3072
  agentId: event.agentId,
3448
- ...event.agentName === void 0 ? {} : { agentName: event.agentName },
3073
+ agentName: event.agentName,
3449
3074
  toolName: child.toolName,
3450
- ...child.toolCallId === void 0 ? {} : { callId: child.toolCallId },
3075
+ callId: child.toolCallId,
3451
3076
  args: child.args,
3452
3077
  result: child.result,
3453
- ...child.structuredResult === void 0 ? {} : { structuredResult: child.structuredResult }
3454
- };
3078
+ structuredResult: child.structuredResult
3079
+ });
3455
3080
  }
3456
3081
  if (child.type === "error") {
3457
- return {
3082
+ return compact({
3458
3083
  kind: "message",
3459
3084
  agentId: event.agentId,
3460
- ...event.agentName === void 0 ? {} : { agentName: event.agentName },
3085
+ agentName: event.agentName,
3461
3086
  text: `Error: ${errorText(child.error)}`
3462
- };
3087
+ });
3463
3088
  }
3464
3089
  return void 0;
3465
3090
  }
@@ -3532,12 +3157,12 @@ function appendTranscriptReasoningText(transcript, delta, reasoningId) {
3532
3157
  last.text = `${last.text}${delta}`;
3533
3158
  return;
3534
3159
  }
3535
- transcript.push({
3160
+ transcript.push(compact({
3536
3161
  entryId: transcript.length,
3537
3162
  kind: "reasoning",
3538
- ...reasoningId === void 0 ? {} : { reasoningId },
3163
+ reasoningId,
3539
3164
  text: delta
3540
- });
3165
+ }));
3541
3166
  }
3542
3167
  function findTranscriptToolEntry(transcript, toolName, callId) {
3543
3168
  for (let index = transcript.length - 1; index >= 0; index -= 1) {
@@ -3574,7 +3199,7 @@ function extractMessageText(message) {
3574
3199
  return [item.text];
3575
3200
  }
3576
3201
  if (item.type === "tool_call") {
3577
- return [`${item.function.name}(${formatJson2(item.function.arguments)})`];
3202
+ return [`${item.function.name}(${formatJson(item.function.arguments)})`];
3578
3203
  }
3579
3204
  if (item.type === "tool_result") {
3580
3205
  return item.content.map(
@@ -3599,25 +3224,19 @@ function optionalTranscriptAttachments(message) {
3599
3224
  }
3600
3225
  if (content.type === "document") {
3601
3226
  return [
3602
- {
3227
+ compact({
3603
3228
  kind: "document",
3604
- ...content.source.filename === void 0 ? {} : { name: content.source.filename },
3605
- ...content.source.mediaType === void 0 ? {} : { mediaType: content.source.mediaType },
3606
- ...content.source.type === "base64" ? { data: content.source.data } : content.source.type === "url" ? { url: content.source.url } : {}
3607
- }
3229
+ name: content.source.filename,
3230
+ mediaType: content.source.mediaType,
3231
+ data: content.source.type === "base64" ? content.source.data : void 0,
3232
+ url: content.source.type === "url" ? content.source.url : void 0
3233
+ })
3608
3234
  ];
3609
3235
  }
3610
3236
  return [];
3611
3237
  });
3612
3238
  return attachments.length === 0 ? {} : { attachments };
3613
3239
  }
3614
- function formatJson2(value) {
3615
- try {
3616
- return JSON.stringify(value, null, 2);
3617
- } catch {
3618
- return String(value);
3619
- }
3620
- }
3621
3240
  async function parseRunRequest(c) {
3622
3241
  let body;
3623
3242
  try {
@@ -3695,7 +3314,7 @@ async function parseRunRequest(c) {
3695
3314
  }
3696
3315
  }
3697
3316
  if ("metadata" in body) {
3698
- if (!isJsonObject2(body.metadata)) {
3317
+ if (!isJsonObject(body.metadata)) {
3699
3318
  return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
3700
3319
  }
3701
3320
  request.metadata = body.metadata;
@@ -3751,7 +3370,7 @@ function registerPipelineRoutes(app, props) {
3751
3370
  const logs = await props.logStore.listPipelineLogs({
3752
3371
  pipelineId,
3753
3372
  limit,
3754
- ...after === void 0 ? {} : { after }
3373
+ ...compact({ after })
3755
3374
  });
3756
3375
  const last = logs.at(-1);
3757
3376
  return c.json({
@@ -3822,7 +3441,7 @@ function registerPipelineRoutes(app, props) {
3822
3441
  }
3823
3442
  return executePipelineRun(c, props, pipeline, {
3824
3443
  input: sourceRun.input,
3825
- ...body.stream === void 0 ? {} : { stream: body.stream },
3444
+ ...compact({ stream: body.stream }),
3826
3445
  metadata: replayMetadata(sourceRun.metadata, body.metadata, sourceRun.runId)
3827
3446
  });
3828
3447
  });
@@ -3838,7 +3457,7 @@ async function executePipelineRun(c, props, pipeline, body) {
3838
3457
  runId,
3839
3458
  stream: body.stream === true,
3840
3459
  input: body.input,
3841
- ...body.metadata === void 0 ? {} : { metadata: body.metadata }
3460
+ ...compact({ metadata: body.metadata })
3842
3461
  })
3843
3462
  );
3844
3463
  await savePipelineRun(props.runStore, {
@@ -3846,7 +3465,7 @@ async function executePipelineRun(c, props, pipeline, body) {
3846
3465
  pipelineId: pipeline.id,
3847
3466
  status: "running",
3848
3467
  input: body.input,
3849
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
3468
+ ...compact({ metadata: body.metadata }),
3850
3469
  startedAt: startedAtIso
3851
3470
  });
3852
3471
  if (body.stream === true) {
@@ -3856,9 +3475,8 @@ async function executePipelineRun(c, props, pipeline, body) {
3856
3475
  input: body.input,
3857
3476
  startedAt,
3858
3477
  startedAtIso,
3859
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
3860
- ...props.logStore === void 0 ? {} : { logStore: props.logStore },
3861
- ...props.runStore === void 0 ? {} : { runStore: props.runStore }
3478
+ ...compact({ metadata: body.metadata }),
3479
+ ...compact({ logStore: props.logStore, runStore: props.runStore })
3862
3480
  });
3863
3481
  }
3864
3482
  try {
@@ -3878,7 +3496,7 @@ async function executePipelineRun(c, props, pipeline, body) {
3878
3496
  status: "success",
3879
3497
  input: body.input,
3880
3498
  output: jsonOutput,
3881
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
3499
+ ...compact({ metadata: body.metadata }),
3882
3500
  startedAt: startedAtIso,
3883
3501
  endedAt: new Date(endedAt).toISOString(),
3884
3502
  durationMs: endedAt - startedAt
@@ -3906,7 +3524,7 @@ async function executePipelineRun(c, props, pipeline, body) {
3906
3524
  status: "error",
3907
3525
  input: body.input,
3908
3526
  error: serializeError(error),
3909
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
3527
+ ...compact({ metadata: body.metadata }),
3910
3528
  startedAt: startedAtIso,
3911
3529
  endedAt: new Date(endedAt).toISOString(),
3912
3530
  durationMs: endedAt - startedAt
@@ -3953,7 +3571,7 @@ async function* pipelineRunEvents(props) {
3953
3571
  status: "success",
3954
3572
  input: props.input,
3955
3573
  output: jsonOutput,
3956
- ...props.metadata === void 0 ? {} : { metadata: props.metadata },
3574
+ ...compact({ metadata: props.metadata }),
3957
3575
  startedAt: props.startedAtIso,
3958
3576
  endedAt: new Date(endedAt).toISOString(),
3959
3577
  durationMs: endedAt - props.startedAt
@@ -3984,7 +3602,7 @@ async function* pipelineRunEvents(props) {
3984
3602
  status: "error",
3985
3603
  input: props.input,
3986
3604
  error: serializeError(error),
3987
- ...props.metadata === void 0 ? {} : { metadata: props.metadata },
3605
+ ...compact({ metadata: props.metadata }),
3988
3606
  startedAt: props.startedAtIso,
3989
3607
  endedAt: new Date(endedAt).toISOString(),
3990
3608
  durationMs: endedAt - props.startedAt
@@ -4023,7 +3641,7 @@ async function parsePipelineRunRequest(c) {
4023
3641
  if (!isObject(body)) {
4024
3642
  return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
4025
3643
  }
4026
- if (!("input" in body) || !isJsonValue3(body.input)) {
3644
+ if (!("input" in body) || !isJsonValue2(body.input)) {
4027
3645
  return { error: errorResponse(c, 400, "bad_request", "input must be JSON-compatible") };
4028
3646
  }
4029
3647
  const request = {
@@ -4036,7 +3654,7 @@ async function parsePipelineRunRequest(c) {
4036
3654
  request.stream = body.stream;
4037
3655
  }
4038
3656
  if ("metadata" in body) {
4039
- if (!isJsonObject2(body.metadata)) {
3657
+ if (!isJsonObject(body.metadata)) {
4040
3658
  return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
4041
3659
  }
4042
3660
  request.metadata = body.metadata;
@@ -4061,7 +3679,7 @@ async function parsePipelineReplayRequest(c) {
4061
3679
  request.stream = body.stream;
4062
3680
  }
4063
3681
  if ("metadata" in body) {
4064
- if (!isJsonObject2(body.metadata)) {
3682
+ if (!isJsonObject(body.metadata)) {
4065
3683
  return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
4066
3684
  }
4067
3685
  request.metadata = body.metadata;
@@ -4095,22 +3713,22 @@ function parsePipelineLogAfter(value) {
4095
3713
  }
4096
3714
  return after;
4097
3715
  }
4098
- function isJsonValue3(value) {
3716
+ function isJsonValue2(value) {
4099
3717
  if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4100
3718
  return Number.isFinite(value) || typeof value !== "number";
4101
3719
  }
4102
3720
  if (Array.isArray(value)) {
4103
- return value.every(isJsonValue3);
3721
+ return value.every(isJsonValue2);
4104
3722
  }
4105
3723
  if (isObject(value)) {
4106
- return Object.values(value).every((item) => item === void 0 || isJsonValue3(item));
3724
+ return Object.values(value).every((item) => item === void 0 || isJsonValue2(item));
4107
3725
  }
4108
3726
  return false;
4109
3727
  }
4110
3728
 
4111
3729
  // src/runtime/questions.ts
4112
- import { createHook as createHook2 } from "@anvia/core/agent";
4113
- import { parseToolArgs as parseToolArgs2 } from "@anvia/core/tool";
3730
+ import { createHook } from "@anvia/core/agent";
3731
+ import { parseToolArgs } from "@anvia/core/tool";
4114
3732
  function registerQuestionRoutes(app, questions) {
4115
3733
  app.get("/questions", (c) => {
4116
3734
  const status = parseQuestionStatus(c.req.query("status"));
@@ -4187,12 +3805,12 @@ async function parseQuestionAnswerRequest(c) {
4187
3805
  if ("custom" in answer && typeof answer.custom !== "boolean") {
4188
3806
  return { error: errorResponse(c, 400, "bad_request", "custom must be a boolean") };
4189
3807
  }
4190
- answers.push({
3808
+ answers.push(compact({
4191
3809
  questionId: answer.questionId.trim(),
4192
3810
  answer: answer.answer.trim(),
4193
- ...typeof answer.choice === "string" ? { choice: answer.choice } : {},
4194
- ...typeof answer.custom === "boolean" ? { custom: answer.custom } : {}
4195
- });
3811
+ choice: typeof answer.choice === "string" ? answer.choice : void 0,
3812
+ custom: typeof answer.custom === "boolean" ? answer.custom : void 0
3813
+ }));
4196
3814
  }
4197
3815
  return { answers };
4198
3816
  }
@@ -4201,22 +3819,22 @@ function createQuestionRuntime() {
4201
3819
  return {
4202
3820
  questions,
4203
3821
  createHook(context) {
4204
- return createHook2({
3822
+ return createHook({
4205
3823
  async onToolCall({ toolName, toolCallId, internalCallId, args, tool: control }) {
4206
3824
  if (toolName !== "ask_question") {
4207
3825
  return control.run();
4208
3826
  }
4209
- const prompts = normalizeQuestionPrompts(parseToolArgs2(args));
3827
+ const prompts = normalizeQuestionPrompts(parseToolArgs(args));
4210
3828
  if ("error" in prompts) {
4211
3829
  return control.skip(prompts.error);
4212
3830
  }
4213
- const answers = await requestQuestion(questions, context, {
3831
+ const answers = await requestQuestion(questions, context, compact({
4214
3832
  toolName,
4215
- ...toolCallId === void 0 ? {} : { toolCallId },
3833
+ toolCallId,
4216
3834
  internalCallId,
4217
3835
  args,
4218
3836
  questions: prompts.questions
4219
- });
3837
+ }));
4220
3838
  return control.skip(JSON.stringify({ answers }));
4221
3839
  }
4222
3840
  });
@@ -4260,18 +3878,20 @@ function createQuestionRuntime() {
4260
3878
  async function requestQuestion(questions, context, request) {
4261
3879
  const id = globalThis.crypto.randomUUID();
4262
3880
  const question = {
4263
- id,
4264
- runId: context.runId,
4265
- agentId: context.agentId,
4266
- ...context.sessionId === void 0 ? {} : { sessionId: context.sessionId },
4267
- toolName: request.toolName,
4268
- ...request.toolCallId === void 0 ? {} : { callId: request.toolCallId },
4269
- internalCallId: request.internalCallId,
4270
- args: request.args,
4271
- questions: request.questions,
4272
- status: "pending",
4273
- requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
4274
- ...context.emit === void 0 ? {} : { emit: context.emit },
3881
+ ...compact({
3882
+ id,
3883
+ runId: context.runId,
3884
+ agentId: context.agentId,
3885
+ sessionId: context.sessionId,
3886
+ toolName: request.toolName,
3887
+ callId: request.toolCallId,
3888
+ internalCallId: request.internalCallId,
3889
+ args: request.args,
3890
+ questions: request.questions,
3891
+ status: "pending",
3892
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
3893
+ emit: context.emit
3894
+ }),
4275
3895
  resolve: () => {
4276
3896
  }
4277
3897
  };
@@ -4382,7 +4002,7 @@ function sessionCreatedLog(session) {
4382
4002
  category: "session",
4383
4003
  event: "session.created",
4384
4004
  message: "Session created",
4385
- metadata: cleanMetadata2({
4005
+ metadata: compact({
4386
4006
  agentId: session.agentId,
4387
4007
  hasTitle: session.title !== void 0,
4388
4008
  titleLength: session.title?.length ?? 0
@@ -4397,7 +4017,7 @@ function runReceivedLog(props) {
4397
4017
  category: "api",
4398
4018
  event: "run.received",
4399
4019
  message: "Run request received",
4400
- metadata: cleanMetadata2({
4020
+ metadata: compact({
4401
4021
  agentId: props.agentId,
4402
4022
  stream: props.stream,
4403
4023
  message: messageSummary(props.message),
@@ -4416,7 +4036,7 @@ function runStartedLog(session, runId) {
4416
4036
  category: "run",
4417
4037
  event: "run.started",
4418
4038
  message: "Run started",
4419
- metadata: cleanMetadata2({
4039
+ metadata: compact({
4420
4040
  agentId: session.agentId,
4421
4041
  existingMessageCount: session.messageCount
4422
4042
  })
@@ -4430,7 +4050,7 @@ function memoryLoadedLog(session, runId) {
4430
4050
  category: "memory",
4431
4051
  event: "memory.loaded",
4432
4052
  message: "Session memory loaded",
4433
- metadata: cleanMetadata2({
4053
+ metadata: compact({
4434
4054
  messageCount: session.messageCount,
4435
4055
  transcriptEntries: session.transcript.length
4436
4056
  })
@@ -4444,7 +4064,7 @@ function runCompletedLog(props) {
4444
4064
  category: "run",
4445
4065
  event: "run.completed",
4446
4066
  message: "Run completed",
4447
- metadata: cleanMetadata2({
4067
+ metadata: compact({
4448
4068
  durationMs: props.durationMs,
4449
4069
  usage: usageSummary(props.usage),
4450
4070
  outputBytes: byteLength3(props.output),
@@ -4460,7 +4080,7 @@ function memorySavedLog(props) {
4460
4080
  category: "memory",
4461
4081
  event: "memory.saved",
4462
4082
  message: "Session memory saved",
4463
- metadata: cleanMetadata2({
4083
+ metadata: compact({
4464
4084
  messageCount: props.messageCount
4465
4085
  })
4466
4086
  };
@@ -4473,7 +4093,7 @@ function runFailedLog(sessionId, runId, error, startedAt) {
4473
4093
  category: "run",
4474
4094
  event: "run.failed",
4475
4095
  message: "Run failed",
4476
- metadata: cleanMetadata2({
4096
+ metadata: compact({
4477
4097
  durationMs: Date.now() - startedAt,
4478
4098
  error: serializeError(error)
4479
4099
  })
@@ -4490,7 +4110,7 @@ function logsFromStreamEvent(props) {
4490
4110
  category: "prompt",
4491
4111
  event: "prompt.prepared",
4492
4112
  message: `Turn ${event.turn} prompt prepared`,
4493
- metadata: cleanMetadata2({
4113
+ metadata: compact({
4494
4114
  turn: event.turn,
4495
4115
  prompt: messageSummary(event.prompt),
4496
4116
  historyCount: event.history.length
@@ -4507,11 +4127,11 @@ function logsFromStreamEvent(props) {
4507
4127
  category: "tool",
4508
4128
  event: "tool.called",
4509
4129
  message: `Tool ${event.toolCall.function.name} called`,
4510
- metadata: cleanMetadata2({
4130
+ metadata: compact({
4511
4131
  turn: event.turn,
4512
4132
  toolName: event.toolCall.function.name,
4513
4133
  callId: event.toolCall.callId ?? event.toolCall.id,
4514
- argumentBytes: byteLength3(formatUnknown2(event.toolCall.function.arguments))
4134
+ argumentBytes: byteLength3(formatUnknown(event.toolCall.function.arguments))
4515
4135
  })
4516
4136
  }
4517
4137
  ];
@@ -4525,7 +4145,7 @@ function logsFromStreamEvent(props) {
4525
4145
  category: "tool",
4526
4146
  event: "tool.completed",
4527
4147
  message: `Tool ${event.toolName} completed`,
4528
- metadata: cleanMetadata2({
4148
+ metadata: compact({
4529
4149
  turn: event.turn,
4530
4150
  toolName: event.toolName,
4531
4151
  callId: event.toolCallId,
@@ -4546,7 +4166,7 @@ function logsFromStreamEvent(props) {
4546
4166
  category: "model",
4547
4167
  event: "model.turn.completed",
4548
4168
  message: `Model turn ${event.turn} completed`,
4549
- metadata: cleanMetadata2({
4169
+ metadata: compact({
4550
4170
  turn: event.turn,
4551
4171
  contentCount: event.response.choice.length,
4552
4172
  usage: usageSummary(event.response.usage)
@@ -4579,7 +4199,7 @@ function logsFromStreamEvent(props) {
4579
4199
  category: "approval",
4580
4200
  event: "approval.requested",
4581
4201
  message: `Approval requested for ${event.approval.toolName}`,
4582
- metadata: cleanMetadata2({
4202
+ metadata: compact({
4583
4203
  approvalId: event.approval.id,
4584
4204
  toolName: event.approval.toolName,
4585
4205
  callId: event.approval.callId,
@@ -4599,7 +4219,7 @@ function logsFromStreamEvent(props) {
4599
4219
  category: "approval",
4600
4220
  event: "approval.resolved",
4601
4221
  message: `Approval ${event.approval.status} for ${event.approval.toolName}`,
4602
- metadata: cleanMetadata2({
4222
+ metadata: compact({
4603
4223
  approvalId: event.approval.id,
4604
4224
  toolName: event.approval.toolName,
4605
4225
  callId: event.approval.callId,
@@ -4609,392 +4229,696 @@ function logsFromStreamEvent(props) {
4609
4229
  }
4610
4230
  ];
4611
4231
  }
4612
- if (event.type === "tool_question_request") {
4613
- return [
4614
- {
4615
- sessionId,
4616
- runId,
4617
- level: "info",
4618
- category: "question",
4619
- event: "question.requested",
4620
- message: `Question requested by ${event.question.toolName}`,
4621
- metadata: cleanMetadata2({
4622
- questionId: event.question.id,
4623
- toolName: event.question.toolName,
4624
- callId: event.question.callId,
4625
- status: event.question.status,
4626
- questionCount: event.question.questions.length,
4627
- argumentBytes: byteLength3(event.question.args)
4628
- })
4629
- }
4630
- ];
4232
+ if (event.type === "tool_question_request") {
4233
+ return [
4234
+ {
4235
+ sessionId,
4236
+ runId,
4237
+ level: "info",
4238
+ category: "question",
4239
+ event: "question.requested",
4240
+ message: `Question requested by ${event.question.toolName}`,
4241
+ metadata: compact({
4242
+ questionId: event.question.id,
4243
+ toolName: event.question.toolName,
4244
+ callId: event.question.callId,
4245
+ status: event.question.status,
4246
+ questionCount: event.question.questions.length,
4247
+ argumentBytes: byteLength3(event.question.args)
4248
+ })
4249
+ }
4250
+ ];
4251
+ }
4252
+ if (event.type === "tool_question_result") {
4253
+ return [
4254
+ {
4255
+ sessionId,
4256
+ runId,
4257
+ level: "info",
4258
+ category: "question",
4259
+ event: "question.answered",
4260
+ message: `Question answered for ${event.question.toolName}`,
4261
+ metadata: compact({
4262
+ questionId: event.question.id,
4263
+ toolName: event.question.toolName,
4264
+ callId: event.question.callId,
4265
+ status: event.question.status,
4266
+ answerCount: event.question.answers?.length ?? 0
4267
+ })
4268
+ }
4269
+ ];
4270
+ }
4271
+ if (event.type === "agent_tool_event") {
4272
+ return childAgentLog(event, sessionId, runId);
4273
+ }
4274
+ return [];
4275
+ }
4276
+ async function* emitLog(store, input) {
4277
+ const log = await appendSessionLog(store, input);
4278
+ if (log !== void 0) {
4279
+ yield { type: "session_log", log };
4280
+ }
4281
+ }
4282
+ function childAgentLog(event, sessionId, runId) {
4283
+ const child = event.event;
4284
+ if (child.type === "tool_call") {
4285
+ return [
4286
+ {
4287
+ sessionId,
4288
+ runId,
4289
+ level: "debug",
4290
+ category: "tool",
4291
+ event: "child_tool.called",
4292
+ message: `Child agent ${event.agentName ?? event.agentId} called ${child.toolCall.function.name}`,
4293
+ metadata: compact({
4294
+ parentToolName: event.toolName,
4295
+ agentId: event.agentId,
4296
+ hasAgentName: event.agentName !== void 0,
4297
+ turn: event.turn,
4298
+ childTurn: child.turn,
4299
+ toolName: child.toolCall.function.name,
4300
+ callId: child.toolCall.callId ?? child.toolCall.id,
4301
+ argumentBytes: byteLength3(formatUnknown(child.toolCall.function.arguments))
4302
+ })
4303
+ }
4304
+ ];
4305
+ }
4306
+ if (child.type === "tool_result") {
4307
+ return [
4308
+ {
4309
+ sessionId,
4310
+ runId,
4311
+ level: "debug",
4312
+ category: "tool",
4313
+ event: "child_tool.completed",
4314
+ message: `Child agent ${event.agentName ?? event.agentId} completed ${child.toolName}`,
4315
+ metadata: compact({
4316
+ parentToolName: event.toolName,
4317
+ agentId: event.agentId,
4318
+ hasAgentName: event.agentName !== void 0,
4319
+ turn: event.turn,
4320
+ childTurn: child.turn,
4321
+ toolName: child.toolName,
4322
+ callId: child.toolCallId,
4323
+ resultBytes: byteLength3(child.result),
4324
+ structuredResultBytes: child.structuredResult === void 0 ? void 0 : byteLength3(JSON.stringify(child.structuredResult))
4325
+ })
4326
+ }
4327
+ ];
4328
+ }
4329
+ if (child.type === "turn_start") {
4330
+ return [
4331
+ {
4332
+ sessionId,
4333
+ runId,
4334
+ level: "debug",
4335
+ category: "run",
4336
+ event: "child_agent.turn_started",
4337
+ message: `Child agent ${event.agentName ?? event.agentId} turn ${child.turn} started`,
4338
+ metadata: compact({
4339
+ parentToolName: event.toolName,
4340
+ agentId: event.agentId,
4341
+ hasAgentName: event.agentName !== void 0,
4342
+ childTurn: child.turn,
4343
+ historyCount: child.history.length
4344
+ })
4345
+ }
4346
+ ];
4347
+ }
4348
+ if (child.type === "final") {
4349
+ return [
4350
+ {
4351
+ sessionId,
4352
+ runId,
4353
+ level: "debug",
4354
+ category: "run",
4355
+ event: "child_agent.completed",
4356
+ message: `Child agent ${event.agentName ?? event.agentId} completed`,
4357
+ metadata: compact({
4358
+ parentToolName: event.toolName,
4359
+ agentId: event.agentId,
4360
+ hasAgentName: event.agentName !== void 0,
4361
+ usage: usageSummary(child.usage),
4362
+ outputBytes: byteLength3(child.output),
4363
+ messageCount: child.messages.length
4364
+ })
4365
+ }
4366
+ ];
4367
+ }
4368
+ if (child.type === "error") {
4369
+ return [
4370
+ {
4371
+ sessionId,
4372
+ runId,
4373
+ level: "error",
4374
+ category: "run",
4375
+ event: "child_agent.failed",
4376
+ message: `Child agent ${event.agentName ?? event.agentId} failed`,
4377
+ metadata: compact({
4378
+ parentToolName: event.toolName,
4379
+ agentId: event.agentId,
4380
+ hasAgentName: event.agentName !== void 0,
4381
+ error: serializeError(child.error)
4382
+ })
4383
+ }
4384
+ ];
4385
+ }
4386
+ return [];
4387
+ }
4388
+ function messageSummary(message) {
4389
+ if (typeof message === "string") {
4390
+ return {
4391
+ role: "user",
4392
+ contentKind: "text",
4393
+ byteLength: byteLength3(message)
4394
+ };
4395
+ }
4396
+ return {
4397
+ role: message.role,
4398
+ contentKind: Array.isArray(message.content) ? "parts" : "text",
4399
+ partCount: Array.isArray(message.content) ? message.content.length : 1,
4400
+ byteLength: byteLength3(formatUnknown(message.content))
4401
+ };
4402
+ }
4403
+ function usageSummary(value) {
4404
+ if (value === void 0 || value === null || typeof value !== "object") {
4405
+ return void 0;
4406
+ }
4407
+ const record = value;
4408
+ return compact({
4409
+ inputTokens: numericValue(record.inputTokens),
4410
+ outputTokens: numericValue(record.outputTokens),
4411
+ totalTokens: numericValue(record.totalTokens),
4412
+ cachedInputTokens: numericValue(record.cachedInputTokens),
4413
+ cacheCreationInputTokens: numericValue(record.cacheCreationInputTokens)
4414
+ });
4415
+ }
4416
+ function numericValue(value) {
4417
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
4418
+ }
4419
+ function byteLength3(value) {
4420
+ return value === void 0 ? 0 : new TextEncoder().encode(value).byteLength;
4421
+ }
4422
+
4423
+ // src/runtime/sessions.ts
4424
+ function registerSessionRoutes(app, props) {
4425
+ app.get("/sessions", async (c) => {
4426
+ const agentId = optionalQueryString(c.req.query("agentId"));
4427
+ if (agentId !== void 0 && !props.agentMap.has(agentId)) {
4428
+ return errorResponse(c, 404, "not_found", "Agent not found");
4429
+ }
4430
+ const limit = parseLimit(c.req.query("limit"));
4431
+ if (limit === void 0) {
4432
+ return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
4433
+ }
4434
+ const sessions = await props.sessionStore.listSessions({
4435
+ ...compact({ agentId }),
4436
+ limit
4437
+ });
4438
+ return c.json({ sessions });
4439
+ });
4440
+ app.post("/sessions", async (c) => {
4441
+ const body = await parseCreateSessionRequest(c);
4442
+ if ("error" in body) {
4443
+ return body.error;
4444
+ }
4445
+ if (!props.agentMap.has(body.agentId)) {
4446
+ return errorResponse(c, 404, "not_found", "Agent not found");
4447
+ }
4448
+ const session = await props.sessionStore.createSession({
4449
+ id: globalThis.crypto.randomUUID(),
4450
+ agentId: body.agentId,
4451
+ ...compact({ title: body.title, metadata: body.metadata })
4452
+ });
4453
+ await appendSessionLog(props.sessionStore, sessionCreatedLog(session));
4454
+ return c.json(session, 201);
4455
+ });
4456
+ app.get("/sessions/:sessionId", async (c) => {
4457
+ const session = await props.sessionStore.getSession(c.req.param("sessionId"));
4458
+ if (session === void 0) {
4459
+ return errorResponse(c, 404, "not_found", "Session not found");
4460
+ }
4461
+ return c.json(session);
4462
+ });
4463
+ app.get("/sessions/:sessionId/logs", async (c) => {
4464
+ const sessionId = c.req.param("sessionId");
4465
+ const session = await props.sessionStore.getSession(sessionId);
4466
+ if (session === void 0) {
4467
+ return errorResponse(c, 404, "not_found", "Session not found");
4468
+ }
4469
+ if (props.sessionStore.listSessionLogs === void 0) {
4470
+ return errorResponse(
4471
+ c,
4472
+ 501,
4473
+ "unsupported_capability",
4474
+ 'Capability "sessions.logs" is not implemented by this runner',
4475
+ { capability: "sessions", operation: "logs" }
4476
+ );
4477
+ }
4478
+ const limit = parseLimit(c.req.query("limit"), 200, 1e3);
4479
+ if (limit === void 0) {
4480
+ return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
4481
+ }
4482
+ const after = parseAfter(c.req.query("after"));
4483
+ if (after === false) {
4484
+ return errorResponse(c, 400, "bad_request", "after must be a non-negative integer");
4485
+ }
4486
+ const logs = await props.sessionStore.listSessionLogs({
4487
+ sessionId,
4488
+ limit,
4489
+ ...compact({ after })
4490
+ });
4491
+ const last = logs.at(-1);
4492
+ return c.json({
4493
+ logs,
4494
+ ...logs.length === limit && last !== void 0 ? { nextCursor: last.sequence } : {}
4495
+ });
4496
+ });
4497
+ app.delete("/sessions/:sessionId", async (c) => {
4498
+ if (props.sessionStore.deleteSession === void 0) {
4499
+ return errorResponse(
4500
+ c,
4501
+ 501,
4502
+ "unsupported_capability",
4503
+ 'Capability "sessions.delete" is not implemented by this runner',
4504
+ { capability: "sessions", operation: "delete" }
4505
+ );
4506
+ }
4507
+ const deleted = await props.sessionStore.deleteSession(c.req.param("sessionId"));
4508
+ if (!deleted) {
4509
+ return errorResponse(c, 404, "not_found", "Session not found");
4510
+ }
4511
+ return c.body(null, 204);
4512
+ });
4513
+ app.get("/sessions/:sessionId/traces", async (c) => {
4514
+ if (props.traceStore === void 0) {
4515
+ return unsupportedCapability(c, "traces");
4516
+ }
4517
+ const sessionId = c.req.param("sessionId");
4518
+ const session = await props.sessionStore.getSession(sessionId);
4519
+ if (session === void 0) {
4520
+ return errorResponse(c, 404, "not_found", "Session not found");
4521
+ }
4522
+ const limit = parseLimit(c.req.query("limit"));
4523
+ if (limit === void 0) {
4524
+ return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
4525
+ }
4526
+ const traces = await props.traceStore.listSessionTraces({ sessionId, limit });
4527
+ return c.json({ traces });
4528
+ });
4529
+ }
4530
+ async function parseCreateSessionRequest(c) {
4531
+ let body;
4532
+ try {
4533
+ body = await c.req.json();
4534
+ } catch {
4535
+ return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
4536
+ }
4537
+ if (!isObject(body)) {
4538
+ return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
4539
+ }
4540
+ if (typeof body.agentId !== "string" || body.agentId.trim().length === 0) {
4541
+ return { error: errorResponse(c, 400, "bad_request", "agentId must be a string") };
4542
+ }
4543
+ const request = {
4544
+ agentId: body.agentId.trim()
4545
+ };
4546
+ if ("title" in body) {
4547
+ if (typeof body.title !== "string") {
4548
+ return { error: errorResponse(c, 400, "bad_request", "title must be a string") };
4549
+ }
4550
+ const title = body.title.trim();
4551
+ if (title.length > 0) {
4552
+ request.title = title;
4553
+ }
4554
+ }
4555
+ if ("metadata" in body) {
4556
+ if (!isJsonObject(body.metadata)) {
4557
+ return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
4558
+ }
4559
+ request.metadata = body.metadata;
4560
+ }
4561
+ return request;
4562
+ }
4563
+
4564
+ // src/storage/memory-store.ts
4565
+ function createInMemoryStudioStore() {
4566
+ return new InMemoryStudioStore();
4567
+ }
4568
+ var InMemoryStudioStore = class {
4569
+ kind = "memory";
4570
+ sessions = /* @__PURE__ */ new Map();
4571
+ traces = /* @__PURE__ */ new Map();
4572
+ pipelineLogs = /* @__PURE__ */ new Map();
4573
+ pipelineRuns = /* @__PURE__ */ new Map();
4574
+ listSessions(options) {
4575
+ 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);
4576
+ }
4577
+ createSession(input) {
4578
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4579
+ const session = {
4580
+ ...compact({
4581
+ id: input.id,
4582
+ agentId: input.agentId,
4583
+ title: input.title,
4584
+ createdAt: now,
4585
+ updatedAt: now,
4586
+ messageCount: 0,
4587
+ metadata: input.metadata
4588
+ }),
4589
+ messages: [],
4590
+ runs: [],
4591
+ logs: []
4592
+ };
4593
+ this.sessions.set(input.id, session);
4594
+ return sessionSummary(session);
4595
+ }
4596
+ getSession(id) {
4597
+ const session = this.sessions.get(id);
4598
+ return session === void 0 ? void 0 : materializeSession(session);
4599
+ }
4600
+ updateSessionMetadata(id, metadata) {
4601
+ const session = this.sessions.get(id);
4602
+ if (session === void 0) {
4603
+ return void 0;
4604
+ }
4605
+ if (metadata === void 0) {
4606
+ delete session.metadata;
4607
+ } else {
4608
+ session.metadata = metadata;
4609
+ }
4610
+ session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4611
+ return materializeSession(session);
4612
+ }
4613
+ load(context) {
4614
+ return Promise.resolve(this.sessions.get(context.sessionId)?.messages ?? []);
4615
+ }
4616
+ append(input) {
4617
+ const session = this.sessions.get(input.context.sessionId);
4618
+ if (session !== void 0) {
4619
+ session.messages.push(...input.messages);
4620
+ session.messageCount = session.messages.length;
4621
+ session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4622
+ }
4623
+ return Promise.resolve();
4624
+ }
4625
+ clear(context) {
4626
+ const session = this.sessions.get(context.sessionId);
4627
+ if (session !== void 0) {
4628
+ session.messages = [];
4629
+ session.runs = [];
4630
+ session.messageCount = 0;
4631
+ session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4632
+ }
4633
+ return Promise.resolve();
4634
+ }
4635
+ async recordError(input) {
4636
+ await this.saveSessionRunTranscript({
4637
+ id: input.context.sessionId,
4638
+ runId: studioRunId(input.context) ?? input.runId,
4639
+ transcript: transcriptFromMessages(input.messages),
4640
+ status: "error",
4641
+ error: serializeJsonError(input.error)
4642
+ });
4643
+ }
4644
+ saveSessionRunTranscript(input) {
4645
+ const session = this.sessions.get(input.id);
4646
+ if (session === void 0) {
4647
+ return void 0;
4648
+ }
4649
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4650
+ const existingIndex = session.runs.findIndex((run2) => run2.runId === input.runId);
4651
+ const run = {
4652
+ ...input,
4653
+ transcript: renumberTranscript(input.transcript),
4654
+ createdAt: existingIndex === -1 ? now : session.runs[existingIndex]?.createdAt ?? now,
4655
+ updatedAt: now
4656
+ };
4657
+ if (existingIndex === -1) {
4658
+ session.runs.push(run);
4659
+ } else {
4660
+ session.runs[existingIndex] = run;
4661
+ }
4662
+ session.updatedAt = now;
4663
+ return materializeSession(session);
4664
+ }
4665
+ appendSessionLog(input) {
4666
+ const session = this.sessions.get(input.sessionId);
4667
+ const logs = session?.logs ?? [];
4668
+ const entry = compact({
4669
+ id: globalThis.crypto.randomUUID(),
4670
+ sessionId: input.sessionId,
4671
+ runId: input.runId,
4672
+ sequence: logs.length,
4673
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4674
+ level: input.level,
4675
+ category: input.category,
4676
+ event: input.event,
4677
+ message: input.message,
4678
+ metadata: input.metadata
4679
+ });
4680
+ if (session !== void 0) {
4681
+ session.logs.push(entry);
4682
+ session.updatedAt = entry.timestamp;
4683
+ }
4684
+ return entry;
4685
+ }
4686
+ listSessionLogs(options) {
4687
+ return (this.sessions.get(options.sessionId)?.logs ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
4631
4688
  }
4632
- if (event.type === "tool_question_result") {
4633
- return [
4634
- {
4635
- sessionId,
4636
- runId,
4637
- level: "info",
4638
- category: "question",
4639
- event: "question.answered",
4640
- message: `Question answered for ${event.question.toolName}`,
4641
- metadata: cleanMetadata2({
4642
- questionId: event.question.id,
4643
- toolName: event.question.toolName,
4644
- callId: event.question.callId,
4645
- status: event.question.status,
4646
- answerCount: event.question.answers?.length ?? 0
4647
- })
4689
+ deleteSession(id) {
4690
+ for (const trace of this.traces.values()) {
4691
+ if (trace.sessionId === id) {
4692
+ this.traces.delete(trace.id);
4648
4693
  }
4649
- ];
4694
+ }
4695
+ return this.sessions.delete(id);
4650
4696
  }
4651
- if (event.type === "agent_tool_event") {
4652
- return childAgentLog(event, sessionId, runId);
4697
+ listTraces(options) {
4698
+ 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);
4653
4699
  }
4654
- return [];
4655
- }
4656
- async function* emitLog(store, input) {
4657
- const log = await appendSessionLog(store, input);
4658
- if (log !== void 0) {
4659
- yield { type: "session_log", log };
4700
+ listSessionTraces(options) {
4701
+ return this.listTraces({ sessionId: options.sessionId, limit: options.limit });
4660
4702
  }
4661
- }
4662
- function childAgentLog(event, sessionId, runId) {
4663
- const child = event.event;
4664
- if (child.type === "tool_call") {
4665
- return [
4666
- {
4667
- sessionId,
4668
- runId,
4669
- level: "debug",
4670
- category: "tool",
4671
- event: "child_tool.called",
4672
- message: `Child agent ${event.agentName ?? event.agentId} called ${child.toolCall.function.name}`,
4673
- metadata: cleanMetadata2({
4674
- parentToolName: event.toolName,
4675
- agentId: event.agentId,
4676
- hasAgentName: event.agentName !== void 0,
4677
- turn: event.turn,
4678
- childTurn: child.turn,
4679
- toolName: child.toolCall.function.name,
4680
- callId: child.toolCall.callId ?? child.toolCall.id,
4681
- argumentBytes: byteLength3(formatUnknown2(child.toolCall.function.arguments))
4682
- })
4683
- }
4684
- ];
4703
+ getTrace(id) {
4704
+ return this.traces.get(id);
4685
4705
  }
4686
- if (child.type === "tool_result") {
4687
- return [
4688
- {
4689
- sessionId,
4690
- runId,
4691
- level: "debug",
4692
- category: "tool",
4693
- event: "child_tool.completed",
4694
- message: `Child agent ${event.agentName ?? event.agentId} completed ${child.toolName}`,
4695
- metadata: cleanMetadata2({
4696
- parentToolName: event.toolName,
4697
- agentId: event.agentId,
4698
- hasAgentName: event.agentName !== void 0,
4699
- turn: event.turn,
4700
- childTurn: child.turn,
4701
- toolName: child.toolName,
4702
- callId: child.toolCallId,
4703
- resultBytes: byteLength3(child.result),
4704
- structuredResultBytes: child.structuredResult === void 0 ? void 0 : byteLength3(JSON.stringify(child.structuredResult))
4705
- })
4706
- }
4707
- ];
4706
+ saveTrace(trace) {
4707
+ this.traces.set(trace.id, trace);
4708
+ return trace;
4708
4709
  }
4709
- if (child.type === "turn_start") {
4710
- return [
4711
- {
4712
- sessionId,
4713
- runId,
4714
- level: "debug",
4715
- category: "run",
4716
- event: "child_agent.turn_started",
4717
- message: `Child agent ${event.agentName ?? event.agentId} turn ${child.turn} started`,
4718
- metadata: cleanMetadata2({
4719
- parentToolName: event.toolName,
4720
- agentId: event.agentId,
4721
- hasAgentName: event.agentName !== void 0,
4722
- childTurn: child.turn,
4723
- historyCount: child.history.length
4724
- })
4725
- }
4726
- ];
4710
+ appendPipelineLog(input) {
4711
+ const logs = this.pipelineLogs.get(input.pipelineId) ?? [];
4712
+ const entry = compact({
4713
+ id: globalThis.crypto.randomUUID(),
4714
+ pipelineId: input.pipelineId,
4715
+ runId: input.runId,
4716
+ sequence: logs.length,
4717
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4718
+ level: input.level,
4719
+ category: input.category,
4720
+ event: input.event,
4721
+ message: input.message,
4722
+ metadata: input.metadata
4723
+ });
4724
+ this.pipelineLogs.set(input.pipelineId, [...logs, entry]);
4725
+ return entry;
4727
4726
  }
4728
- if (child.type === "final") {
4729
- return [
4730
- {
4731
- sessionId,
4732
- runId,
4733
- level: "debug",
4734
- category: "run",
4735
- event: "child_agent.completed",
4736
- message: `Child agent ${event.agentName ?? event.agentId} completed`,
4737
- metadata: cleanMetadata2({
4738
- parentToolName: event.toolName,
4739
- agentId: event.agentId,
4740
- hasAgentName: event.agentName !== void 0,
4741
- usage: usageSummary(child.usage),
4742
- outputBytes: byteLength3(child.output),
4743
- messageCount: child.messages.length
4744
- })
4745
- }
4746
- ];
4727
+ listPipelineLogs(options) {
4728
+ return (this.pipelineLogs.get(options.pipelineId) ?? []).filter((log) => options.after === void 0 || log.sequence > options.after).slice(0, options.limit);
4747
4729
  }
4748
- if (child.type === "error") {
4749
- return [
4750
- {
4751
- sessionId,
4752
- runId,
4753
- level: "error",
4754
- category: "run",
4755
- event: "child_agent.failed",
4756
- message: `Child agent ${event.agentName ?? event.agentId} failed`,
4757
- metadata: cleanMetadata2({
4758
- parentToolName: event.toolName,
4759
- agentId: event.agentId,
4760
- hasAgentName: event.agentName !== void 0,
4761
- error: serializeError(child.error)
4762
- })
4763
- }
4764
- ];
4730
+ savePipelineRun(input) {
4731
+ const record = compact({
4732
+ runId: input.runId,
4733
+ pipelineId: input.pipelineId,
4734
+ status: input.status,
4735
+ input: input.input,
4736
+ output: input.output,
4737
+ error: input.error,
4738
+ metadata: input.metadata,
4739
+ startedAt: input.startedAt,
4740
+ endedAt: input.endedAt,
4741
+ durationMs: input.durationMs
4742
+ });
4743
+ this.pipelineRuns.set(input.runId, record);
4744
+ return record;
4765
4745
  }
4766
- return [];
4767
- }
4768
- function messageSummary(message) {
4769
- if (typeof message === "string") {
4770
- return {
4771
- role: "user",
4772
- contentKind: "text",
4773
- byteLength: byteLength3(message)
4774
- };
4746
+ getPipelineRun(options) {
4747
+ const run = this.pipelineRuns.get(options.runId);
4748
+ return run?.pipelineId === options.pipelineId ? run : void 0;
4749
+ }
4750
+ listPipelineRuns(options) {
4751
+ return [...this.pipelineRuns.values()].filter((run) => run.pipelineId === options.pipelineId).sort((left, right) => Date.parse(right.startedAt) - Date.parse(left.startedAt)).slice(0, options.limit);
4775
4752
  }
4753
+ };
4754
+ function sessionSummary(session) {
4755
+ return compact({
4756
+ id: session.id,
4757
+ agentId: session.agentId,
4758
+ title: session.title,
4759
+ createdAt: session.createdAt,
4760
+ updatedAt: session.updatedAt,
4761
+ messageCount: session.messages.length,
4762
+ metadata: session.metadata
4763
+ });
4764
+ }
4765
+ function materializeSession(session) {
4776
4766
  return {
4777
- role: message.role,
4778
- contentKind: Array.isArray(message.content) ? "parts" : "text",
4779
- partCount: Array.isArray(message.content) ? message.content.length : 1,
4780
- byteLength: byteLength3(formatUnknown2(message.content))
4767
+ ...sessionSummary(session),
4768
+ messages: [...session.messages],
4769
+ transcript: renumberTranscript(session.runs.flatMap((run) => run.transcript))
4781
4770
  };
4782
4771
  }
4783
- function usageSummary(value) {
4784
- if (value === void 0 || value === null || typeof value !== "object") {
4785
- return void 0;
4786
- }
4787
- const record = value;
4788
- return cleanMetadata2({
4789
- inputTokens: numericValue(record.inputTokens),
4790
- outputTokens: numericValue(record.outputTokens),
4791
- totalTokens: numericValue(record.totalTokens),
4792
- cachedInputTokens: numericValue(record.cachedInputTokens),
4793
- cacheCreationInputTokens: numericValue(record.cacheCreationInputTokens)
4772
+ function traceSummary2(trace) {
4773
+ return compact({
4774
+ id: trace.id,
4775
+ sessionId: trace.sessionId,
4776
+ name: trace.name,
4777
+ status: trace.status,
4778
+ startedAt: trace.startedAt,
4779
+ endedAt: trace.endedAt,
4780
+ durationMs: trace.durationMs,
4781
+ output: trace.output,
4782
+ error: trace.error,
4783
+ usage: trace.usage,
4784
+ metadata: trace.metadata,
4785
+ observationCount: trace.observations.length
4794
4786
  });
4795
4787
  }
4796
- function cleanMetadata2(value) {
4797
- const cleaned = {};
4798
- for (const [key, item] of Object.entries(value)) {
4799
- if (item === void 0) {
4800
- continue;
4801
- }
4802
- const jsonValue = cleanJsonValue(item);
4803
- if (jsonValue !== void 0) {
4804
- cleaned[key] = jsonValue;
4805
- }
4806
- }
4807
- return cleaned;
4788
+ function traceAgentId(trace) {
4789
+ const nestedMetadata = trace.metadata?.metadata;
4790
+ return isJsonObject2(nestedMetadata) && typeof nestedMetadata.agentId === "string" ? nestedMetadata.agentId : void 0;
4808
4791
  }
4809
- function cleanJsonValue(value) {
4810
- if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4811
- return value;
4812
- }
4813
- if (Array.isArray(value)) {
4814
- return value.map((item) => cleanJsonValue(item)).filter((item) => item !== void 0);
4815
- }
4816
- if (typeof value === "object" && value !== null) {
4817
- return cleanMetadata2(value);
4818
- }
4819
- return void 0;
4792
+ function studioRunId(context) {
4793
+ const value = context.metadata?.studioRunId;
4794
+ return typeof value === "string" && value.length > 0 ? value : void 0;
4820
4795
  }
4821
- function numericValue(value) {
4822
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
4796
+ function serializeJsonError(error) {
4797
+ if (error instanceof Error) {
4798
+ return {
4799
+ name: error.name,
4800
+ message: error.message
4801
+ };
4802
+ }
4803
+ return isJsonValue3(error) ? error : String(error);
4823
4804
  }
4824
- function byteLength3(value) {
4825
- return value === void 0 ? 0 : new TextEncoder().encode(value).byteLength;
4805
+ function isJsonObject2(value) {
4806
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4826
4807
  }
4827
- function formatUnknown2(value) {
4828
- if (typeof value === "string") {
4829
- return value;
4808
+ function isJsonValue3(value) {
4809
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4810
+ return true;
4830
4811
  }
4831
- try {
4832
- return JSON.stringify(value);
4833
- } catch {
4834
- return String(value);
4812
+ if (Array.isArray(value)) {
4813
+ return value.every(isJsonValue3);
4835
4814
  }
4815
+ return isJsonObject2(value) && Object.values(value).every(isJsonValue3);
4836
4816
  }
4837
4817
 
4838
- // src/runtime/sessions.ts
4839
- function registerSessionRoutes(app, props) {
4840
- app.get("/sessions", async (c) => {
4841
- const agentId = optionalQueryString(c.req.query("agentId"));
4842
- if (agentId !== void 0 && !props.agentMap.has(agentId)) {
4843
- return errorResponse(c, 404, "not_found", "Agent not found");
4844
- }
4845
- const limit = parseLimit(c.req.query("limit"));
4846
- if (limit === void 0) {
4847
- return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
4848
- }
4849
- const sessions = await props.sessionStore.listSessions({
4850
- ...agentId === void 0 ? {} : { agentId },
4851
- limit
4852
- });
4853
- return c.json({ sessions });
4854
- });
4855
- app.post("/sessions", async (c) => {
4856
- const body = await parseCreateSessionRequest(c);
4857
- if ("error" in body) {
4858
- return body.error;
4859
- }
4860
- if (!props.agentMap.has(body.agentId)) {
4861
- return errorResponse(c, 404, "not_found", "Agent not found");
4862
- }
4863
- const session = await props.sessionStore.createSession({
4864
- id: globalThis.crypto.randomUUID(),
4865
- agentId: body.agentId,
4866
- ...body.title === void 0 ? {} : { title: body.title },
4867
- ...body.metadata === void 0 ? {} : { metadata: body.metadata }
4868
- });
4869
- await appendSessionLog(props.sessionStore, sessionCreatedLog(session));
4870
- return c.json(session, 201);
4871
- });
4872
- app.get("/sessions/:sessionId", async (c) => {
4873
- const session = await props.sessionStore.getSession(c.req.param("sessionId"));
4874
- if (session === void 0) {
4875
- return errorResponse(c, 404, "not_found", "Session not found");
4876
- }
4877
- return c.json(session);
4878
- });
4879
- app.get("/sessions/:sessionId/logs", async (c) => {
4880
- const sessionId = c.req.param("sessionId");
4881
- const session = await props.sessionStore.getSession(sessionId);
4882
- if (session === void 0) {
4883
- return errorResponse(c, 404, "not_found", "Session not found");
4884
- }
4885
- if (props.sessionStore.listSessionLogs === void 0) {
4886
- return errorResponse(
4887
- c,
4888
- 501,
4889
- "unsupported_capability",
4890
- 'Capability "sessions.logs" is not implemented by this runner',
4891
- { capability: "sessions", operation: "logs" }
4892
- );
4893
- }
4894
- const limit = parseSessionLogLimit(c.req.query("limit"));
4895
- if (limit === void 0) {
4896
- return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
4897
- }
4898
- const after = parseSessionLogAfter(c.req.query("after"));
4899
- if (after === false) {
4900
- return errorResponse(c, 400, "bad_request", "after must be a non-negative integer");
4901
- }
4902
- const logs = await props.sessionStore.listSessionLogs({
4903
- sessionId,
4904
- limit,
4905
- ...after === void 0 ? {} : { after }
4906
- });
4907
- const last = logs.at(-1);
4908
- return c.json({
4909
- logs,
4910
- ...logs.length === limit && last !== void 0 ? { nextCursor: last.sequence } : {}
4911
- });
4912
- });
4913
- app.delete("/sessions/:sessionId", async (c) => {
4914
- if (props.sessionStore.deleteSession === void 0) {
4915
- return errorResponse(
4916
- c,
4917
- 501,
4918
- "unsupported_capability",
4919
- 'Capability "sessions.delete" is not implemented by this runner',
4920
- { capability: "sessions", operation: "delete" }
4921
- );
4922
- }
4923
- const deleted = await props.sessionStore.deleteSession(c.req.param("sessionId"));
4924
- if (!deleted) {
4925
- return errorResponse(c, 404, "not_found", "Session not found");
4926
- }
4927
- return c.body(null, 204);
4928
- });
4929
- app.get("/sessions/:sessionId/traces", async (c) => {
4930
- if (props.traceStore === void 0) {
4931
- return unsupportedCapability(c, "traces");
4932
- }
4933
- const sessionId = c.req.param("sessionId");
4934
- const session = await props.sessionStore.getSession(sessionId);
4935
- if (session === void 0) {
4936
- return errorResponse(c, 404, "not_found", "Session not found");
4937
- }
4938
- const limit = parseLimit(c.req.query("limit"));
4939
- if (limit === void 0) {
4940
- return errorResponse(c, 400, "bad_request", "limit must be a positive integer");
4941
- }
4942
- const traces = await props.traceStore.listSessionTraces({ sessionId, limit });
4943
- return c.json({ traces });
4818
+ // src/runtime/shared.ts
4819
+ function resolveStores(options) {
4820
+ const defaultStore = defaultStudioStore();
4821
+ const sessions = resolveSessionStore(options, defaultStore);
4822
+ const traces = resolveTraceStore(options, sessions, defaultStore);
4823
+ const pipelineLogs = resolvePipelineLogStore(options, sessions, defaultStore);
4824
+ const pipelineRuns = resolvePipelineRunStore(options, sessions, pipelineLogs, defaultStore);
4825
+ return compact({
4826
+ sessions,
4827
+ traces,
4828
+ pipelineLogs,
4829
+ pipelineRuns
4944
4830
  });
4945
4831
  }
4946
- function parseSessionLogLimit(value) {
4947
- if (value === void 0 || value.trim().length === 0) {
4948
- return 200;
4832
+ function defaultStudioStore() {
4833
+ return createInMemoryStudioStore();
4834
+ }
4835
+ function resolveSessionStore(options, defaultStore) {
4836
+ if (options.stores?.sessions === false) {
4837
+ return void 0;
4949
4838
  }
4950
- const limit = Number(value);
4951
- if (!Number.isInteger(limit) || limit <= 0) {
4839
+ if (options.stores?.sessions !== void 0) {
4840
+ return options.stores.sessions;
4841
+ }
4842
+ return defaultStore;
4843
+ }
4844
+ function resolveTraceStore(options, sessionStore, defaultStore) {
4845
+ if (options.stores?.traces !== void 0) {
4846
+ return options.stores.traces;
4847
+ }
4848
+ if (sessionStore === void 0) {
4952
4849
  return void 0;
4953
4850
  }
4954
- return Math.min(limit, 1e3);
4851
+ if (isTraceStore(sessionStore)) {
4852
+ return sessionStore;
4853
+ }
4854
+ return defaultStore;
4955
4855
  }
4956
- function parseSessionLogAfter(value) {
4957
- if (value === void 0 || value.trim().length === 0) {
4856
+ function resolvePipelineLogStore(options, sessionStore, defaultStore) {
4857
+ if (options.stores?.pipelineLogs === false) {
4958
4858
  return void 0;
4959
4859
  }
4960
- const after = Number(value);
4961
- if (!Number.isInteger(after) || after < 0) {
4962
- return false;
4860
+ if (options.stores?.pipelineLogs !== void 0) {
4861
+ return options.stores.pipelineLogs;
4963
4862
  }
4964
- return after;
4863
+ if (sessionStore !== void 0 && isPipelineLogStore(sessionStore)) {
4864
+ return sessionStore;
4865
+ }
4866
+ return defaultStore;
4965
4867
  }
4966
- async function parseCreateSessionRequest(c) {
4967
- let body;
4968
- try {
4969
- body = await c.req.json();
4970
- } catch {
4971
- return { error: errorResponse(c, 400, "bad_request", "Request body must be JSON") };
4868
+ function resolvePipelineRunStore(options, sessionStore, pipelineLogStore, defaultStore) {
4869
+ if (options.stores?.pipelineRuns === false) {
4870
+ return void 0;
4972
4871
  }
4973
- if (!isObject(body)) {
4974
- return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
4872
+ if (options.stores?.pipelineRuns !== void 0) {
4873
+ return options.stores.pipelineRuns;
4975
4874
  }
4976
- if (typeof body.agentId !== "string" || body.agentId.trim().length === 0) {
4977
- return { error: errorResponse(c, 400, "bad_request", "agentId must be a string") };
4875
+ if (sessionStore !== void 0 && isPipelineRunStore(sessionStore)) {
4876
+ return sessionStore;
4978
4877
  }
4979
- const request = {
4980
- agentId: body.agentId.trim()
4981
- };
4982
- if ("title" in body) {
4983
- if (typeof body.title !== "string") {
4984
- return { error: errorResponse(c, 400, "bad_request", "title must be a string") };
4878
+ if (pipelineLogStore !== void 0 && isPipelineRunStore(pipelineLogStore)) {
4879
+ return pipelineLogStore;
4880
+ }
4881
+ return defaultStore;
4882
+ }
4883
+ function isTraceStore(store) {
4884
+ const candidate = store;
4885
+ return typeof candidate.listSessionTraces === "function" && typeof candidate.getTrace === "function" && typeof candidate.saveTrace === "function";
4886
+ }
4887
+ function isPipelineLogStore(store) {
4888
+ const candidate = store;
4889
+ return typeof candidate.appendPipelineLog === "function" && typeof candidate.listPipelineLogs === "function";
4890
+ }
4891
+ function isPipelineRunStore(store) {
4892
+ const candidate = store;
4893
+ return typeof candidate.savePipelineRun === "function" && typeof candidate.getPipelineRun === "function" && typeof candidate.listPipelineRuns === "function";
4894
+ }
4895
+ function normalizeAgents(agents) {
4896
+ const ids = /* @__PURE__ */ new Set();
4897
+ return agents.map((agent) => {
4898
+ const id = agent.id.trim();
4899
+ if (id.length === 0) {
4900
+ throw new Error("Studio agent id cannot be empty");
4985
4901
  }
4986
- const title = body.title.trim();
4987
- if (title.length > 0) {
4988
- request.title = title;
4902
+ if (ids.has(id)) {
4903
+ throw new Error(`Duplicate runner agent id: ${id}`);
4989
4904
  }
4990
- }
4991
- if ("metadata" in body) {
4992
- if (!isJsonObject2(body.metadata)) {
4993
- return { error: errorResponse(c, 400, "bad_request", "metadata must be an object") };
4905
+ ids.add(id);
4906
+ return { ...agent, id };
4907
+ });
4908
+ }
4909
+ function normalizePipelines(pipelines) {
4910
+ const ids = /* @__PURE__ */ new Set();
4911
+ return pipelines.map((pipeline) => {
4912
+ const id = pipeline.id.trim();
4913
+ if (id.length === 0) {
4914
+ throw new Error("Studio pipeline id cannot be empty");
4994
4915
  }
4995
- request.metadata = body.metadata;
4996
- }
4997
- return request;
4916
+ if (ids.has(id)) {
4917
+ throw new Error(`Duplicate Studio pipeline id: ${id}`);
4918
+ }
4919
+ ids.add(id);
4920
+ return { ...pipeline, id };
4921
+ });
4998
4922
  }
4999
4923
 
5000
4924
  // src/runtime/status.ts
@@ -5003,30 +4927,31 @@ function registerStatusRoutes(app, props) {
5003
4927
  const summary = {
5004
4928
  runner: {
5005
4929
  id: runnerId(props.options),
5006
- ...props.options.name === void 0 ? {} : { name: props.options.name },
5007
- ...props.options.version === void 0 ? {} : { version: props.options.version }
4930
+ ...compact({ name: props.options.name, version: props.options.version })
5008
4931
  },
5009
4932
  storage: {
5010
- ...props.stores.sessions?.kind === void 0 ? {} : { sessions: props.stores.sessions.kind },
5011
- ...props.stores.traces?.kind === void 0 ? {} : { traces: props.stores.traces.kind },
5012
- ...props.stores.pipelineLogs === void 0 ? {} : { pipelineLogs: "available" },
5013
- ...props.stores.pipelineRuns === void 0 ? {} : { pipelineRuns: "available" }
4933
+ ...compact({
4934
+ sessions: props.stores.sessions?.kind,
4935
+ traces: props.stores.traces?.kind,
4936
+ pipelineLogs: props.stores.pipelineLogs !== void 0 ? "available" : void 0,
4937
+ pipelineRuns: props.stores.pipelineRuns !== void 0 ? "available" : void 0
4938
+ })
5014
4939
  },
5015
4940
  counts: {
5016
4941
  agents: props.agents.length,
5017
4942
  pipelines: props.pipelines.length,
5018
- ...props.stores.sessions === void 0 ? {} : { sessions: (await props.stores.sessions.listSessions({ limit: 100 })).length },
5019
- ...props.stores.traces?.listTraces === void 0 ? {} : { traces: (await props.stores.traces.listTraces({ limit: 100 })).length },
5020
- ...props.stores.pipelineRuns === void 0 || props.pipelines.length === 0 ? {} : {
5021
- pipelineRuns: (await Promise.all(
4943
+ ...compact({
4944
+ sessions: props.stores.sessions !== void 0 ? (await props.stores.sessions.listSessions({ limit: 100 })).length : void 0,
4945
+ traces: props.stores.traces?.listTraces !== void 0 ? (await props.stores.traces.listTraces({ limit: 100 })).length : void 0,
4946
+ pipelineRuns: props.stores.pipelineRuns !== void 0 && props.pipelines.length > 0 ? (await Promise.all(
5022
4947
  props.pipelines.map(
5023
4948
  (pipeline) => props.stores.pipelineRuns?.listPipelineRuns({
5024
4949
  pipelineId: pipeline.id,
5025
4950
  limit: 100
5026
4951
  })
5027
4952
  )
5028
- )).reduce((sum, runs) => sum + (runs?.length ?? 0), 0)
5029
- }
4953
+ )).reduce((sum, runs) => sum + (runs?.length ?? 0), 0) : void 0
4954
+ })
5030
4955
  },
5031
4956
  capabilities: capabilityConfig(props.options, props.agents, props.pipelines, props.stores),
5032
4957
  generatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -5110,16 +5035,16 @@ async function parseToolRunRequest(c) {
5110
5035
  if (body === void 0 || body === null) {
5111
5036
  return { args: {} };
5112
5037
  }
5113
- if (!isJsonObject2(body)) {
5038
+ if (!isJsonObject(body)) {
5114
5039
  return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
5115
5040
  }
5116
5041
  const args = Object.hasOwn(body, "args") ? body.args : {};
5117
- if (!isJsonValue2(args)) {
5042
+ if (!isJsonValue(args)) {
5118
5043
  return { error: errorResponse(c, 400, "bad_request", "args must be JSON-compatible") };
5119
5044
  }
5120
5045
  const request = { args };
5121
5046
  if (Object.hasOwn(body, "context")) {
5122
- if (!isJsonObject2(body.context)) {
5047
+ if (!isJsonObject(body.context)) {
5123
5048
  return { error: errorResponse(c, 400, "bad_request", "context must be an object") };
5124
5049
  }
5125
5050
  request.context = body.context;
@@ -5177,9 +5102,7 @@ function registerTraceRoutes(app, traceStore) {
5177
5102
  const sessionId = optionalQueryString(c.req.query("sessionId"));
5178
5103
  const traces = await traceStore.listTraces({
5179
5104
  limit,
5180
- ...agentId === void 0 ? {} : { agentId },
5181
- ...sessionId === void 0 ? {} : { sessionId },
5182
- ...status === void 0 ? {} : { status }
5105
+ ...compact({ agentId, sessionId, status })
5183
5106
  });
5184
5107
  return c.json({ traces });
5185
5108
  });
@@ -5222,7 +5145,7 @@ var Studio = class {
5222
5145
  const port = serveOptions.port ?? Number(process.env.RUNNER_PORT ?? 4021);
5223
5146
  this.server = serve({
5224
5147
  fetch: (request) => this.fetch(request),
5225
- ...serveOptions.hostname === void 0 ? {} : { hostname: serveOptions.hostname },
5148
+ ...compact({ hostname: serveOptions.hostname }),
5226
5149
  port
5227
5150
  });
5228
5151
  const log = serveOptions.log ?? true;
@@ -5262,9 +5185,9 @@ function studioOptionsFromTargets(targets, options) {
5262
5185
  agents: inferStudioAgents(agents, options.quickPrompts ?? {}),
5263
5186
  pipelines: inferStudioPipelines(pipelines),
5264
5187
  evals: options.evals ?? [],
5265
- ...options.models === void 0 ? {} : { models: options.models },
5266
- ...options.stores === void 0 ? {} : { stores: options.stores },
5267
- ...options.ui === void 0 ? {} : { ui: options.ui }
5188
+ ...compact({ models: options.models }),
5189
+ ...compact({ stores: options.stores }),
5190
+ ...compact({ ui: options.ui })
5268
5191
  };
5269
5192
  }
5270
5193
  function inferStudioAgents(agents, quickPrompts) {
@@ -5286,9 +5209,9 @@ function inferStudioPipelines(pipelines) {
5286
5209
  return {
5287
5210
  id,
5288
5211
  pipeline,
5289
- ...pipeline.name === void 0 ? {} : { name: pipeline.name },
5290
- ...pipeline.description === void 0 ? {} : { description: pipeline.description },
5291
- ...pipeline.metadata === void 0 ? {} : { metadata: pipeline.metadata }
5212
+ ...compact({ name: pipeline.name }),
5213
+ ...compact({ description: pipeline.description }),
5214
+ ...compact({ metadata: pipeline.metadata })
5292
5215
  };
5293
5216
  });
5294
5217
  }
@@ -5304,7 +5227,7 @@ function uniqueAgentId(baseId, ids) {
5304
5227
  }
5305
5228
  function agentMetadata(agent) {
5306
5229
  return {
5307
- ...agent.defaultMaxTurns === void 0 ? {} : { defaultMaxTurns: agent.defaultMaxTurns },
5230
+ ...compact({ defaultMaxTurns: agent.defaultMaxTurns }),
5308
5231
  staticContextCount: agent.staticContext.length,
5309
5232
  dynamicContextCount: agent.dynamicContexts.length,
5310
5233
  dynamicToolCount: agent.dynamicTools.length,
@@ -5375,13 +5298,13 @@ function createStudioApp(options) {
5375
5298
  });
5376
5299
  registerKnowledgeRoutes(app, {
5377
5300
  agents,
5378
- ...stores.traces === void 0 ? {} : { traceStore: stores.traces }
5301
+ ...compact({ traceStore: stores.traces })
5379
5302
  });
5380
5303
  registerPipelineRoutes(app, {
5381
5304
  pipelines,
5382
5305
  pipelineMap,
5383
- ...stores.pipelineLogs === void 0 ? {} : { logStore: stores.pipelineLogs },
5384
- ...stores.pipelineRuns === void 0 ? {} : { runStore: stores.pipelineRuns }
5306
+ ...compact({ logStore: stores.pipelineLogs }),
5307
+ ...compact({ runStore: stores.pipelineRuns })
5385
5308
  });
5386
5309
  app.post("/agents/:agentId/runs", async (c) => {
5387
5310
  const agentId = c.req.param("agentId");
@@ -5428,8 +5351,8 @@ function createStudioApp(options) {
5428
5351
  agentId,
5429
5352
  message: body.message,
5430
5353
  stream: body.stream === true,
5431
- ...body.maxTurns === void 0 ? {} : { maxTurns: body.maxTurns },
5432
- ...body.toolConcurrency === void 0 ? {} : { toolConcurrency: body.toolConcurrency },
5354
+ ...compact({ maxTurns: body.maxTurns }),
5355
+ ...compact({ toolConcurrency: body.toolConcurrency }),
5433
5356
  hasTrace: body.trace !== void 0,
5434
5357
  ...body.metadata === void 0 && selectedModel.ref === void 0 ? {} : {
5435
5358
  metadata: {
@@ -5492,23 +5415,22 @@ function createStudioApp(options) {
5492
5415
  }
5493
5416
  if (body.stream === true) {
5494
5417
  const runtimeEvents = new AsyncEventQueue();
5418
+ request.approvals(
5419
+ approvalRuntime.createApprovals({
5420
+ runId,
5421
+ agentId,
5422
+ ...compact({ sessionId: session?.id }),
5423
+ ...compact({ metadata: body.metadata }),
5424
+ emit: (event) => runtimeEvents.push(event)
5425
+ })
5426
+ );
5495
5427
  const effectiveHook = composeHooks(
5496
- composeHooks(
5497
- runAgent.hook,
5498
- approvalRuntime.createHook({
5499
- runId,
5500
- agentId,
5501
- ...session?.id === void 0 ? {} : { sessionId: session.id },
5502
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
5503
- getTool: (toolName) => runAgent.getTool(toolName),
5504
- emit: (event) => runtimeEvents.push(event)
5505
- })
5506
- ),
5428
+ runAgent.hook,
5507
5429
  questionRuntime.createHook({
5508
5430
  runId,
5509
5431
  agentId,
5510
- ...session?.id === void 0 ? {} : { sessionId: session.id },
5511
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
5432
+ ...compact({ sessionId: session?.id }),
5433
+ ...compact({ metadata: body.metadata }),
5512
5434
  emit: (event) => runtimeEvents.push(event)
5513
5435
  })
5514
5436
  );
@@ -5538,21 +5460,20 @@ function createStudioApp(options) {
5538
5460
  await appendSessionLog(sessionStore, memoryLoadedLog(session, runId));
5539
5461
  }
5540
5462
  const effectiveHook = composeHooks(
5541
- composeHooks(
5542
- runAgent.hook,
5543
- approvalRuntime.createHook({
5544
- runId,
5545
- agentId,
5546
- ...session?.id === void 0 ? {} : { sessionId: session.id },
5547
- ...body.metadata === void 0 ? {} : { metadata: body.metadata },
5548
- getTool: (toolName) => runAgent.getTool(toolName)
5549
- })
5550
- ),
5463
+ runAgent.hook,
5551
5464
  questionRuntime.createHook({
5552
5465
  runId,
5553
5466
  agentId,
5554
- ...session?.id === void 0 ? {} : { sessionId: session.id },
5555
- ...body.metadata === void 0 ? {} : { metadata: body.metadata }
5467
+ ...compact({ sessionId: session?.id }),
5468
+ ...compact({ metadata: body.metadata })
5469
+ })
5470
+ );
5471
+ request.approvals(
5472
+ approvalRuntime.createApprovals({
5473
+ runId,
5474
+ agentId,
5475
+ ...compact({ sessionId: session?.id }),
5476
+ ...compact({ metadata: body.metadata })
5556
5477
  })
5557
5478
  );
5558
5479
  if (effectiveHook !== void 0) {
@@ -5625,7 +5546,7 @@ function createStudioApp(options) {
5625
5546
  registerSessionRoutes(app, {
5626
5547
  agentMap,
5627
5548
  sessionStore: stores.sessions,
5628
- ...stores.traces === void 0 ? {} : { traceStore: stores.traces }
5549
+ ...compact({ traceStore: stores.traces })
5629
5550
  });
5630
5551
  }
5631
5552
  if (stores.traces !== void 0) {
@@ -5645,8 +5566,8 @@ function createStudioApp(options) {
5645
5566
  },
5646
5567
  close() {
5647
5568
  },
5648
- ...stores.sessions === void 0 ? {} : { sessionStore: stores.sessions },
5649
- ...stores.traces === void 0 ? {} : { traceStore: stores.traces }
5569
+ ...compact({ sessionStore: stores.sessions }),
5570
+ ...compact({ traceStore: stores.traces })
5650
5571
  };
5651
5572
  }
5652
5573
  function normalizePromptMessage(message) {
@@ -5704,7 +5625,7 @@ function composeHooks(first, second) {
5704
5625
  if (second === void 0) {
5705
5626
  return first;
5706
5627
  }
5707
- return createHook3({
5628
+ return createHook2({
5708
5629
  async onCompletionCall(args) {
5709
5630
  const firstAction = await first.onCompletionCall?.(args);
5710
5631
  return firstAction?.type === "terminate" ? firstAction : await second.onCompletionCall?.(args) ?? void 0;
@@ -5715,12 +5636,9 @@ function composeHooks(first, second) {
5715
5636
  },
5716
5637
  async onToolCall(args) {
5717
5638
  const firstAction = await first.onToolCall?.(args);
5718
- if (firstAction?.type === "skip" || firstAction?.type === "terminate") {
5639
+ if (firstAction?.type === "skip" || firstAction?.type === "terminate" || firstAction?.type === "approval_request") {
5719
5640
  return firstAction;
5720
5641
  }
5721
- if (firstAction?.type === "approval_request") {
5722
- return await approvalRequestHandler(second)?.(args, firstAction) ?? firstAction;
5723
- }
5724
5642
  const secondAction = await second.onToolCall?.(args);
5725
5643
  return secondAction ?? firstAction ?? void 0;
5726
5644
  },
@@ -5730,10 +5648,6 @@ function composeHooks(first, second) {
5730
5648
  }
5731
5649
  });
5732
5650
  }
5733
- function approvalRequestHandler(hook) {
5734
- const candidate = hook;
5735
- return typeof candidate.handleApprovalRequest === "function" ? candidate.handleApprovalRequest : void 0;
5736
- }
5737
5651
 
5738
5652
  // src/storage/sqlite-store.ts
5739
5653
  import { mkdirSync } from "fs";
@@ -5790,11 +5704,11 @@ var SqliteSessionStore = class {
5790
5704
  return {
5791
5705
  id: input.id,
5792
5706
  agentId: input.agentId,
5793
- ...input.title === void 0 ? {} : { title: input.title },
5707
+ ...compact({ title: input.title }),
5794
5708
  createdAt: now,
5795
5709
  updatedAt: now,
5796
5710
  messageCount: 0,
5797
- ...input.metadata === void 0 ? {} : { metadata: input.metadata }
5711
+ ...compact({ metadata: input.metadata })
5798
5712
  };
5799
5713
  }
5800
5714
  getSession(id) {
@@ -5980,14 +5894,14 @@ var SqliteSessionStore = class {
5980
5894
  const entry = {
5981
5895
  id: globalThis.crypto.randomUUID(),
5982
5896
  sessionId: input.sessionId,
5983
- ...input.runId === void 0 ? {} : { runId: input.runId },
5897
+ ...compact({ runId: input.runId }),
5984
5898
  sequence,
5985
5899
  timestamp: now,
5986
5900
  level: input.level,
5987
5901
  category: input.category,
5988
5902
  event: input.event,
5989
5903
  message: input.message,
5990
- ...input.metadata === void 0 ? {} : { metadata: input.metadata }
5904
+ ...compact({ metadata: input.metadata })
5991
5905
  };
5992
5906
  db.prepare(
5993
5907
  `INSERT INTO anvia_studio_session_logs (
@@ -6061,14 +5975,14 @@ var SqliteSessionStore = class {
6061
5975
  const entry = {
6062
5976
  id: globalThis.crypto.randomUUID(),
6063
5977
  pipelineId: input.pipelineId,
6064
- ...input.runId === void 0 ? {} : { runId: input.runId },
5978
+ ...compact({ runId: input.runId }),
6065
5979
  sequence,
6066
5980
  timestamp: now,
6067
5981
  level: input.level,
6068
5982
  category: input.category,
6069
5983
  event: input.event,
6070
5984
  message: input.message,
6071
- ...input.metadata === void 0 ? {} : { metadata: input.metadata }
5985
+ ...compact({ metadata: input.metadata })
6072
5986
  };
6073
5987
  db.prepare(
6074
5988
  `INSERT INTO anvia_studio_pipeline_logs (
@@ -6186,12 +6100,12 @@ var SqliteSessionStore = class {
6186
6100
  pipelineId: input.pipelineId,
6187
6101
  status: input.status,
6188
6102
  input: input.input,
6189
- ...input.output === void 0 ? {} : { output: input.output },
6190
- ...input.error === void 0 ? {} : { error: input.error },
6191
- ...input.metadata === void 0 ? {} : { metadata: input.metadata },
6103
+ ...compact({ output: input.output }),
6104
+ ...compact({ error: input.error }),
6105
+ ...compact({ metadata: input.metadata }),
6192
6106
  startedAt: input.startedAt,
6193
- ...input.endedAt === void 0 ? {} : { endedAt: input.endedAt },
6194
- ...input.durationMs === void 0 ? {} : { durationMs: input.durationMs }
6107
+ ...compact({ endedAt: input.endedAt }),
6108
+ ...compact({ durationMs: input.durationMs })
6195
6109
  };
6196
6110
  }
6197
6111
  getPipelineRun(options) {
@@ -6622,11 +6536,11 @@ function toSessionSummary(row) {
6622
6536
  return {
6623
6537
  id: row.id,
6624
6538
  agentId: row.agent_id,
6625
- ...row.title === null ? {} : { title: row.title },
6539
+ ...compact({ title: row.title ?? void 0 }),
6626
6540
  createdAt: row.created_at,
6627
6541
  updatedAt: row.updated_at,
6628
6542
  messageCount: row.message_count,
6629
- ...metadata === void 0 ? {} : { metadata }
6543
+ ...compact({ metadata })
6630
6544
  };
6631
6545
  }
6632
6546
  function toSessionLog(row) {
@@ -6634,14 +6548,14 @@ function toSessionLog(row) {
6634
6548
  return {
6635
6549
  id: row.id,
6636
6550
  sessionId: row.session_id,
6637
- ...row.run_id === null ? {} : { runId: row.run_id },
6551
+ ...compact({ runId: row.run_id ?? void 0 }),
6638
6552
  sequence: row.sequence,
6639
6553
  timestamp: row.timestamp,
6640
6554
  level: row.level,
6641
6555
  category: row.category,
6642
6556
  event: row.event,
6643
6557
  message: row.message,
6644
- ...metadata === void 0 ? {} : { metadata }
6558
+ ...compact({ metadata })
6645
6559
  };
6646
6560
  }
6647
6561
  function toPipelineLog(row) {
@@ -6649,14 +6563,14 @@ function toPipelineLog(row) {
6649
6563
  return {
6650
6564
  id: row.id,
6651
6565
  pipelineId: row.pipeline_id,
6652
- ...row.run_id === null ? {} : { runId: row.run_id },
6566
+ ...compact({ runId: row.run_id ?? void 0 }),
6653
6567
  sequence: row.sequence,
6654
6568
  timestamp: row.timestamp,
6655
6569
  level: row.level,
6656
6570
  category: row.category,
6657
6571
  event: row.event,
6658
6572
  message: row.message,
6659
- ...metadata === void 0 ? {} : { metadata }
6573
+ ...compact({ metadata })
6660
6574
  };
6661
6575
  }
6662
6576
  function toPipelineRun(row) {
@@ -6668,12 +6582,12 @@ function toPipelineRun(row) {
6668
6582
  pipelineId: row.pipeline_id,
6669
6583
  status: row.status,
6670
6584
  input: JSON.parse(row.input_json),
6671
- ...output === void 0 ? {} : { output },
6672
- ...error === void 0 ? {} : { error },
6673
- ...metadata === void 0 ? {} : { metadata },
6585
+ ...compact({ output }),
6586
+ ...compact({ error }),
6587
+ ...compact({ metadata }),
6674
6588
  startedAt: row.started_at,
6675
- ...row.ended_at === null ? {} : { endedAt: row.ended_at },
6676
- ...row.duration_ms === null ? {} : { durationMs: row.duration_ms }
6589
+ ...compact({ endedAt: row.ended_at ?? void 0 }),
6590
+ ...compact({ durationMs: row.duration_ms ?? void 0 })
6677
6591
  };
6678
6592
  }
6679
6593
  function messageParts(message) {
@@ -6699,7 +6613,7 @@ function messageFromRows(row, partRows) {
6699
6613
  if (row.role === "assistant") {
6700
6614
  return {
6701
6615
  role: "assistant",
6702
- ...row.message_id === null ? {} : { id: row.message_id },
6616
+ ...compact({ id: row.message_id ?? void 0 }),
6703
6617
  content: parts
6704
6618
  };
6705
6619
  }
@@ -6747,8 +6661,8 @@ function toTrace(row) {
6747
6661
  const input = parseJsonValue(row.input_json);
6748
6662
  return {
6749
6663
  ...toTraceSummary(row),
6750
- ...trace === void 0 ? {} : { trace },
6751
- ...input === void 0 ? {} : { input },
6664
+ ...compact({ trace }),
6665
+ ...compact({ input }),
6752
6666
  observations: parseJsonArray(row.observations_json)
6753
6667
  };
6754
6668
  }
@@ -6760,15 +6674,15 @@ function toTraceSummary(row) {
6760
6674
  return {
6761
6675
  id: row.id,
6762
6676
  sessionId: row.session_id,
6763
- ...row.name === null ? {} : { name: row.name },
6677
+ ...compact({ name: row.name ?? void 0 }),
6764
6678
  status: row.status,
6765
6679
  startedAt: row.started_at,
6766
- ...row.ended_at === null ? {} : { endedAt: row.ended_at },
6767
- ...row.duration_ms === null ? {} : { durationMs: row.duration_ms },
6768
- ...row.output === null ? {} : { output: row.output },
6769
- ...error === void 0 ? {} : { error },
6770
- ...usage === void 0 ? {} : { usage },
6771
- ...metadata === void 0 ? {} : { metadata },
6680
+ ...compact({ endedAt: row.ended_at ?? void 0 }),
6681
+ ...compact({ durationMs: row.duration_ms ?? void 0 }),
6682
+ ...compact({ output: row.output ?? void 0 }),
6683
+ ...compact({ error }),
6684
+ ...compact({ usage }),
6685
+ ...compact({ metadata }),
6772
6686
  observationCount: observations.length
6773
6687
  };
6774
6688
  }
@@ -6798,10 +6712,29 @@ function serializeJsonError2(error) {
6798
6712
  }
6799
6713
  return String(error);
6800
6714
  }
6715
+
6716
+ // src/types.ts
6717
+ function traceSummary3(trace) {
6718
+ return compact({
6719
+ id: trace.id,
6720
+ sessionId: trace.sessionId,
6721
+ name: trace.name,
6722
+ status: trace.status,
6723
+ startedAt: trace.startedAt,
6724
+ endedAt: trace.endedAt,
6725
+ durationMs: trace.durationMs,
6726
+ output: trace.output,
6727
+ error: trace.error,
6728
+ usage: trace.usage,
6729
+ metadata: trace.metadata,
6730
+ observationCount: trace.observations.length
6731
+ });
6732
+ }
6801
6733
  export {
6802
6734
  Studio,
6803
6735
  StudioTraceObserver,
6804
6736
  createInMemoryStudioStore,
6805
- createSqliteSessionStore
6737
+ createSqliteSessionStore,
6738
+ traceSummary3 as traceSummary
6806
6739
  };
6807
6740
  //# sourceMappingURL=index.js.map