@anvia/studio 0.8.1 → 1.0.0-rc.2

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 (51) hide show
  1. package/README.md +31 -19
  2. package/dist/index.d.ts +37 -60
  3. package/dist/index.js +1000 -724
  4. package/dist/index.js.map +1 -1
  5. package/dist/ui/assets/{ArrowClockwise.es-CSN-gjxO.js → ArrowClockwise.es-DMJj7Hv0.js} +2 -2
  6. package/dist/ui/assets/{ArrowClockwise.es-CSN-gjxO.js.map → ArrowClockwise.es-DMJj7Hv0.js.map} +1 -1
  7. package/dist/ui/assets/{agents-page-CkNSbqAj.js → agents-page-CbQpO3Tg.js} +2 -2
  8. package/dist/ui/assets/agents-page-CbQpO3Tg.js.map +1 -0
  9. package/dist/ui/assets/{badge-RJJoRC4P.js → badge-BIWy1K8W.js} +1 -1
  10. package/dist/ui/assets/{badge-RJJoRC4P.js.map → badge-BIWy1K8W.js.map} +1 -1
  11. package/dist/ui/assets/index-DizotQot.js +119 -0
  12. package/dist/ui/assets/index-DizotQot.js.map +1 -0
  13. package/dist/ui/assets/{input-BOUv3rgO.js → input-BTHDDFpv.js} +1 -1
  14. package/dist/ui/assets/{input-BOUv3rgO.js.map → input-BTHDDFpv.js.map} +1 -1
  15. package/dist/ui/assets/{knowledge-page-Cot_uYcE.js → knowledge-page-C8zg8uTL.js} +2 -2
  16. package/dist/ui/assets/{knowledge-page-Cot_uYcE.js.map → knowledge-page-C8zg8uTL.js.map} +1 -1
  17. package/dist/ui/assets/{mcps-page-BSO6ork4.js → mcps-page-gNYeqSPB.js} +2 -2
  18. package/dist/ui/assets/{mcps-page-BSO6ork4.js.map → mcps-page-gNYeqSPB.js.map} +1 -1
  19. package/dist/ui/assets/{memory-page-CG84G--r.js → memory-page-BLrfOqyU.js} +4 -4
  20. package/dist/ui/assets/memory-page-BLrfOqyU.js.map +1 -0
  21. package/dist/ui/assets/pipelines-page-hTEhFZGg.js +8 -0
  22. package/dist/ui/assets/pipelines-page-hTEhFZGg.js.map +1 -0
  23. package/dist/ui/assets/{renderers-B8gvjR2u.js → renderers-DC_-TD_X.js} +3 -3
  24. package/dist/ui/assets/{renderers-B8gvjR2u.js.map → renderers-DC_-TD_X.js.map} +1 -1
  25. package/dist/ui/assets/{sandboxes-page-D910dyFO.js → sandboxes-page-DtPnuza7.js} +2 -2
  26. package/dist/ui/assets/{sandboxes-page-D910dyFO.js.map → sandboxes-page-DtPnuza7.js.map} +1 -1
  27. package/dist/ui/assets/{sessions-page-CSN2vSKZ.js → sessions-page-DBzoP7MV.js} +2 -2
  28. package/dist/ui/assets/{sessions-page-CSN2vSKZ.js.map → sessions-page-DBzoP7MV.js.map} +1 -1
  29. package/dist/ui/assets/{status-page-CgRNt0wi.js → status-page-Bf1lq444.js} +2 -2
  30. package/dist/ui/assets/{status-page-CgRNt0wi.js.map → status-page-Bf1lq444.js.map} +1 -1
  31. package/dist/ui/assets/tool-runner-BbUlfPEO.js +2 -0
  32. package/dist/ui/assets/{tool-runner-BZN-PZJU.js.map → tool-runner-BbUlfPEO.js.map} +1 -1
  33. package/dist/ui/assets/{tools-page-DRv7aklU.js → tools-page-BgUz-79v.js} +2 -2
  34. package/dist/ui/assets/{tools-page-DRv7aklU.js.map → tools-page-BgUz-79v.js.map} +1 -1
  35. package/dist/ui/assets/trace-browser-qfYPcdR2.js +10 -0
  36. package/dist/ui/assets/trace-browser-qfYPcdR2.js.map +1 -0
  37. package/dist/ui/assets/{transcript-item-ZNkQEaCw.js → transcript-item-HFuuqmKM.js} +3 -3
  38. package/dist/ui/assets/{transcript-item-ZNkQEaCw.js.map → transcript-item-HFuuqmKM.js.map} +1 -1
  39. package/dist/ui/index.html +1 -2
  40. package/package.json +12 -11
  41. package/dist/ui/assets/agents-page-CkNSbqAj.js.map +0 -1
  42. package/dist/ui/assets/chunk-ADH7NNCS-DM6fsnDI.js +0 -2
  43. package/dist/ui/assets/chunk-ADH7NNCS-DM6fsnDI.js.map +0 -1
  44. package/dist/ui/assets/index-Bh7RLPBw.js +0 -56
  45. package/dist/ui/assets/index-Bh7RLPBw.js.map +0 -1
  46. package/dist/ui/assets/memory-page-CG84G--r.js.map +0 -1
  47. package/dist/ui/assets/pipelines-page-Hbf5ffUH.js +0 -8
  48. package/dist/ui/assets/pipelines-page-Hbf5ffUH.js.map +0 -1
  49. package/dist/ui/assets/tool-runner-BZN-PZJU.js +0 -2
  50. package/dist/ui/assets/trace-browser-B07coNNE.js +0 -10
  51. package/dist/ui/assets/trace-browser-B07coNNE.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/runtime/studio.ts
2
- import { Agent as Agent2 } from "@anvia/core/internal/agent";
2
+ import { Agent, getAgentToolState as getAgentToolState3 } from "@anvia/core/internal/agent";
3
3
  import { Pipeline } from "@anvia/core/pipeline";
4
4
  import { serve } from "@hono/node-server";
5
5
  import { Hono as HonoApp } from "hono";
@@ -178,7 +178,12 @@ var StudioRunTraceObserver = class {
178
178
  async end(args) {
179
179
  await this.save("success", {
180
180
  endedAt: /* @__PURE__ */ new Date(),
181
- output: args.output,
181
+ output: args.status === "completed" ? traceOutput(args.output) : args.text,
182
+ result: {
183
+ status: args.status,
184
+ text: args.text,
185
+ ...args.status === "completed" ? { output: toJsonValue(args.output) } : { stage: args.stage }
186
+ },
182
187
  usage: args.usage,
183
188
  messages: toJsonValue(args.messages)
184
189
  });
@@ -198,11 +203,13 @@ var StudioRunTraceObserver = class {
198
203
  return;
199
204
  }
200
205
  const metadata = traceMetadata(this.props.args, result.messages);
206
+ if (result.result !== void 0) metadata.result = result.result;
201
207
  const trace = {
202
208
  id: this.props.id,
209
+ runId: this.props.args.runId,
203
210
  sessionId,
204
211
  status,
205
- trace: this.trace,
212
+ trace: { observer: "studio", ...this.trace },
206
213
  startedAt: this.startedAt.toISOString(),
207
214
  endedAt: result.endedAt.toISOString(),
208
215
  durationMs: durationMs(this.startedAt, result.endedAt),
@@ -281,15 +288,14 @@ var ChildAgentToolTraceAccumulator = class {
281
288
  }
282
289
  if (child.type === "tool_call" && isRecord(child.toolCall)) {
283
290
  const toolCall = child.toolCall;
284
- const toolCallFunction = isRecord(toolCall.function) ? toolCall.function : void 0;
285
- const toolName = typeof toolCallFunction?.name === "string" ? toolCallFunction.name : "tool";
286
- const callId = typeof toolCall.callId === "string" ? toolCall.callId : typeof toolCall.id === "string" ? toolCall.id : void 0;
291
+ const toolName = typeof toolCall.toolName === "string" ? toolCall.toolName : "tool";
292
+ const callId = typeof toolCall.toolCallId === "string" ? toolCall.toolCallId : typeof toolCall.callId === "string" ? toolCall.callId : void 0;
287
293
  const start = {
288
294
  startedAt: /* @__PURE__ */ new Date(),
289
295
  agentId,
290
296
  childTurn,
291
297
  toolName,
292
- input: toJsonValue(toolCallFunction?.arguments ?? {}),
298
+ input: toJsonValue("input" in toolCall ? toolCall.input : {}),
293
299
  completed: false
294
300
  };
295
301
  if (agentName !== void 0) start.agentName = agentName;
@@ -427,6 +433,7 @@ function traceObservation(props) {
427
433
  }
428
434
  function traceMetadata(args, messages) {
429
435
  return compactJsonObject({
436
+ runId: args.runId,
430
437
  agentName: args.agentName,
431
438
  agentDescription: args.agentDescription,
432
439
  maxTurns: args.maxTurns,
@@ -441,14 +448,12 @@ function generationMetadata(args, endArgs) {
441
448
  const request = args.request;
442
449
  const response = endArgs?.response;
443
450
  const rawResponse = isRecord(response?.rawResponse) ? response.rawResponse : void 0;
444
- const effectiveModel = request.model ?? stringValue(rawResponse?.model) ?? args.modelInfo?.defaultModel ?? "default";
451
+ const modelId = args.modelInfo?.modelId ?? stringValue(rawResponse?.model) ?? "unknown";
445
452
  const providerResponse = providerResponseSummary(rawResponse);
446
453
  const usage = response?.usage;
447
454
  return compactJsonObject({
448
455
  provider: args.modelInfo?.provider,
449
- model: effectiveModel,
450
- requestedModel: request.model,
451
- defaultModel: args.modelInfo?.defaultModel,
456
+ modelId,
452
457
  messageId: response?.messageId,
453
458
  usage,
454
459
  toolCount: request.tools.length,
@@ -458,15 +463,13 @@ function generationMetadata(args, endArgs) {
458
463
  temperature: request.temperature,
459
464
  maxTokens: request.maxTokens,
460
465
  toolChoice: request.toolChoice,
461
- additionalParamKeys: isRecord(request.additionalParams) ? Object.keys(request.additionalParams).sort() : void 0,
466
+ providerOptionKeys: isRecord(request.providerOptions) ? Object.keys(request.providerOptions).sort() : void 0,
462
467
  hasOutputSchema: request.outputSchema !== void 0,
463
468
  firstDeltaMs: endArgs?.firstDeltaMs,
464
469
  providerResponse,
465
470
  modelInfo: compactJsonObject({
466
471
  provider: args.modelInfo?.provider,
467
- model: effectiveModel,
468
- requestedModel: request.model,
469
- defaultModel: args.modelInfo?.defaultModel,
472
+ modelId,
470
473
  capabilities: args.modelInfo?.capabilities
471
474
  }),
472
475
  modelCall: compactJsonObject({
@@ -492,7 +495,6 @@ function generationMetadata(args, endArgs) {
492
495
  }
493
496
  function completionRequestSummary(request) {
494
497
  return compactJsonObject({
495
- model: request.model,
496
498
  instructions: request.instructions === void 0 ? void 0 : { present: true },
497
499
  messageCount: request.chatHistory.length,
498
500
  documentCount: request.documents.length,
@@ -502,7 +504,7 @@ function completionRequestSummary(request) {
502
504
  temperature: request.temperature,
503
505
  maxTokens: request.maxTokens,
504
506
  toolChoice: request.toolChoice,
505
- additionalParamKeys: isRecord(request.additionalParams) ? Object.keys(request.additionalParams).sort() : void 0,
507
+ providerOptionKeys: isRecord(request.providerOptions) ? Object.keys(request.providerOptions).sort() : void 0,
506
508
  hasOutputSchema: request.outputSchema !== void 0
507
509
  });
508
510
  }
@@ -539,7 +541,6 @@ function toolMetadata(args, skipped, result) {
539
541
  argumentBytes: byteLength(args.args),
540
542
  resultBytes: result === void 0 ? void 0 : byteLength(result),
541
543
  hasCallSignature: args.toolCall.signature !== void 0,
542
- hasAdditionalParams: args.toolCall.additionalParams !== void 0,
543
544
  toolDescription: args.toolDefinition?.description,
544
545
  parameterKeys: Object.keys(properties).sort(),
545
546
  requiredParameterKeys: required,
@@ -557,8 +558,7 @@ function toolMetadata(args, skipped, result) {
557
558
  mcpServerName: args.toolMetadata?.mcpServerName,
558
559
  argumentBytes: byteLength(args.args),
559
560
  resultBytes: result === void 0 ? void 0 : byteLength(result),
560
- hasCallSignature: args.toolCall.signature !== void 0,
561
- hasAdditionalParams: args.toolCall.additionalParams !== void 0
561
+ hasCallSignature: args.toolCall.signature !== void 0
562
562
  })
563
563
  });
564
564
  }
@@ -575,6 +575,16 @@ function parseOrString(value) {
575
575
  return value;
576
576
  }
577
577
  }
578
+ function traceOutput(value) {
579
+ if (typeof value === "string") {
580
+ return value;
581
+ }
582
+ try {
583
+ return JSON.stringify(toJsonValue(value));
584
+ } catch {
585
+ return String(value);
586
+ }
587
+ }
578
588
  function isRecord(value) {
579
589
  return typeof value === "object" && value !== null && !Array.isArray(value);
580
590
  }
@@ -874,70 +884,31 @@ function escapeHtml(value) {
874
884
  return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
875
885
  }
876
886
 
887
+ // src/runtime/agent-context.ts
888
+ import { isVectorContext } from "@anvia/core/agent";
889
+ function staticContextDocuments(agent) {
890
+ return agent.context.filter((input) => !isVectorContext(input));
891
+ }
892
+ function vectorContexts(agent) {
893
+ return agent.context.filter(isVectorContext);
894
+ }
895
+
877
896
  // src/runtime/agent-runs.ts
878
- import { Message } from "@anvia/core/completion";
897
+ import {
898
+ withInternalAgentRunOptions
899
+ } from "@anvia/core/internal/agent";
879
900
 
880
901
  // src/runtime/agent-utils.ts
881
902
  import {
882
- createHook
883
- } from "@anvia/core/hooks";
884
- import { Agent } from "@anvia/core/internal/agent";
903
+ createResolvedAgent,
904
+ getResolvedAgentOptions
905
+ } from "@anvia/core/internal/agent";
885
906
  function cloneAgent(agent, overrides = {}) {
886
- return new Agent({
887
- id: agent.id,
888
- name: agent.name,
889
- description: agent.description,
890
- model: agent.model,
891
- instructions: agent.instructions,
892
- staticContext: agent.staticContext,
893
- temperature: agent.temperature,
894
- maxTokens: agent.maxTokens,
895
- additionalParams: agent.additionalParams,
896
- toolSet: agent.toolSet,
897
- toolChoice: agent.toolChoice,
898
- defaultMaxTurns: agent.defaultMaxTurns,
899
- hook: agent.hook,
900
- outputSchema: agent.outputSchema,
901
- observers: agent.observers,
902
- approvals: agent.approvals,
903
- dynamicContexts: agent.dynamicContexts,
904
- dynamicTools: agent.dynamicTools,
905
- middlewares: agent.middlewares,
906
- memory: agent.memory,
907
- eventStore: agent.eventStore,
907
+ return createResolvedAgent({
908
+ ...getResolvedAgentOptions(agent),
908
909
  ...overrides
909
910
  });
910
911
  }
911
- function composeHooks(first, second) {
912
- if (first === void 0) {
913
- return second;
914
- }
915
- if (second === void 0) {
916
- return first;
917
- }
918
- return createHook({
919
- async onCompletionCall(args) {
920
- const firstAction = await first.onCompletionCall?.(args);
921
- return firstAction?.type === "terminate" ? firstAction : await second.onCompletionCall?.(args) ?? void 0;
922
- },
923
- async onCompletionResponse(args) {
924
- const firstAction = await first.onCompletionResponse?.(args);
925
- return firstAction?.type === "terminate" ? firstAction : await second.onCompletionResponse?.(args) ?? void 0;
926
- },
927
- async onToolCall(args) {
928
- const firstAction = await first.onToolCall?.(args);
929
- if (firstAction?.type === "skip" || firstAction?.type === "terminate" || firstAction?.type === "approval_request") {
930
- return firstAction;
931
- }
932
- const secondAction = await second.onToolCall?.(args);
933
- return secondAction ?? firstAction ?? void 0;
934
- },
935
- async onToolResult(args) {
936
- const firstAction = await first.onToolResult?.(args);
937
- return firstAction?.type === "terminate" ? firstAction : await second.onToolResult?.(args) ?? void 0;
938
- }
939
- });
940
- }
941
912
 
942
913
  // src/runtime/errors.ts
943
914
  function serializeError(error) {
@@ -952,7 +923,8 @@ function serializeError(error) {
952
923
 
953
924
  // src/runtime/type-guards.ts
954
925
  import {
955
- isJsonValue as isCoreJsonValue
926
+ isJsonValue as isCoreJsonValue,
927
+ isMessage
956
928
  } from "@anvia/core/completion";
957
929
  function isObject(value) {
958
930
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -963,26 +935,16 @@ function isJsonObject(value) {
963
935
  function isJsonValue(value) {
964
936
  return isCoreJsonValue(value);
965
937
  }
966
- function isMessageInput(value) {
967
- return typeof value === "string" || isMessage(value);
968
- }
969
- function isMessage(value) {
970
- if (!isObject(value) || typeof value.role !== "string") {
971
- return false;
972
- }
973
- if (value.role === "system") {
974
- return typeof value.content === "string";
975
- }
976
- if (value.role === "user" || value.role === "assistant" || value.role === "tool") {
977
- return Array.isArray(value.content);
978
- }
979
- return false;
980
- }
981
938
  function isAgentTraceOptions(value) {
982
939
  if (!isObject(value)) {
983
940
  return false;
984
941
  }
985
- 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);
942
+ if (!Object.keys(value).every(
943
+ (key) => ["name", "userId", "sessionId", "metadata", "tags", "version", "traceId"].includes(key)
944
+ )) {
945
+ return false;
946
+ }
947
+ return optionalString(value.name) && optionalString(value.userId) && optionalString(value.sessionId) && optionalString(value.version) && optionalString(value.traceId) && optionalStringArray(value.tags) && (value.metadata === void 0 || isJsonObject(value.metadata));
986
948
  }
987
949
  function isNonNegativeInteger(value) {
988
950
  return Number.isInteger(value) && typeof value === "number" && value >= 0;
@@ -993,15 +955,9 @@ function isPositiveInteger(value) {
993
955
  function optionalString(value) {
994
956
  return value === void 0 || typeof value === "string";
995
957
  }
996
- function optionalBoolean(value) {
997
- return value === void 0 || typeof value === "boolean";
998
- }
999
958
  function optionalStringArray(value) {
1000
959
  return value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
1001
960
  }
1002
- function optionalObject(value) {
1003
- return value === void 0 || isObject(value);
1004
- }
1005
961
 
1006
962
  // src/runtime/http.ts
1007
963
  function errorResponse(c, status, code, message, details) {
@@ -1051,8 +1007,8 @@ function createStudioModelRegistry(config) {
1051
1007
  id,
1052
1008
  staticModels
1053
1009
  };
1054
- if (provider.defaultModel !== void 0) {
1055
- runtimeProvider.defaultModel = normalizeModelId(provider.defaultModel);
1010
+ if (provider.defaultModelId !== void 0) {
1011
+ runtimeProvider.defaultModelId = normalizeModelId(provider.defaultModelId);
1056
1012
  }
1057
1013
  providers.set(id, runtimeProvider);
1058
1014
  }
@@ -1061,8 +1017,10 @@ function createStudioModelRegistry(config) {
1061
1017
  agentPolicies: normalizeAgentPolicies(config.agents ?? {}),
1062
1018
  modelCache: /* @__PURE__ */ new Map()
1063
1019
  };
1064
- if (config.default !== void 0) {
1065
- Object.assign(registry, { defaultModel: normalizeModelRef(config.default) });
1020
+ if (config.defaultModelRef !== void 0) {
1021
+ Object.assign(registry, {
1022
+ defaultModelRef: normalizeModelRef(config.defaultModelRef)
1023
+ });
1066
1024
  }
1067
1025
  return registry;
1068
1026
  }
@@ -1079,7 +1037,7 @@ function studioModelsConfig(registry, agents) {
1079
1037
  models
1080
1038
  };
1081
1039
  if (provider.name !== void 0) config2.name = provider.name;
1082
- if (provider.defaultModel !== void 0) config2.defaultModel = provider.defaultModel;
1040
+ if (provider.defaultModelId !== void 0) config2.defaultModelId = provider.defaultModelId;
1083
1041
  if (provider.metadata !== void 0) config2.metadata = provider.metadata;
1084
1042
  return config2;
1085
1043
  });
@@ -1091,7 +1049,7 @@ function studioModelsConfig(registry, agents) {
1091
1049
  providers,
1092
1050
  agents: agentsConfig
1093
1051
  };
1094
- if (registry.defaultModel !== void 0) config.default = registry.defaultModel;
1052
+ if (registry.defaultModelRef !== void 0) config.defaultModelRef = registry.defaultModelRef;
1095
1053
  return config;
1096
1054
  }
1097
1055
  function registerModelRoutes(app, props) {
@@ -1105,8 +1063,8 @@ function registerModelRoutes(app, props) {
1105
1063
  const response = {
1106
1064
  providers
1107
1065
  };
1108
- if (props.registry.defaultModel !== void 0) {
1109
- response.defaultModel = props.registry.defaultModel;
1066
+ if (props.registry.defaultModelRef !== void 0) {
1067
+ response.defaultModelRef = props.registry.defaultModelRef;
1110
1068
  }
1111
1069
  return c.json(response);
1112
1070
  });
@@ -1139,7 +1097,7 @@ function resolveStudioModel(registry, input) {
1139
1097
  if (registry === void 0) {
1140
1098
  return { warnings: [] };
1141
1099
  }
1142
- const selectedRef = normalizeOptionalModelRef(input.request.model) ?? sessionModelRef(input.sessionMetadata) ?? registry.agentPolicies.get(input.agent.id)?.default ?? registry.defaultModel;
1100
+ const selectedRef = normalizeOptionalModelRef(input.request.model) ?? sessionModelRef(input.sessionMetadata) ?? registry.agentPolicies.get(input.agent.id)?.defaultModelRef ?? registry.defaultModelRef;
1143
1101
  if (selectedRef === void 0) {
1144
1102
  return { warnings: [] };
1145
1103
  }
@@ -1151,7 +1109,7 @@ function resolveStudioModel(registry, input) {
1151
1109
  }
1152
1110
  let model = registry.modelCache.get(selectedRef);
1153
1111
  if (model === void 0) {
1154
- model = provider.createCompletionModel(modelId);
1112
+ model = provider.createCompletionModel({ modelId });
1155
1113
  registry.modelCache.set(selectedRef, model);
1156
1114
  }
1157
1115
  const metadata = provider.staticModels.get(modelId);
@@ -1169,12 +1127,7 @@ function normalizeOptionalModelRef(ref) {
1169
1127
  return ref === void 0 ? void 0 : normalizeModelRef(ref);
1170
1128
  }
1171
1129
  function normalizeModelRef(ref) {
1172
- if (typeof ref === "string") {
1173
- const trimmed = ref.trim();
1174
- const parsed = parseModelRef(trimmed);
1175
- return `${parsed.providerId}:${parsed.modelId}`;
1176
- }
1177
- return `${normalizeProviderId(ref.provider)}:${normalizeModelId(ref.model)}`;
1130
+ return `${normalizeProviderId(ref.providerId)}:${normalizeModelId(ref.modelId)}`;
1178
1131
  }
1179
1132
  function parseModelRef(ref) {
1180
1133
  const index = ref.indexOf(":");
@@ -1217,12 +1170,12 @@ async function agentModelsCatalog(registry, agent) {
1217
1170
  return [];
1218
1171
  }
1219
1172
  });
1220
- const defaultModel = policy?.default ?? registry.defaultModel;
1173
+ const defaultModelRef = policy?.defaultModelRef ?? registry.defaultModelRef;
1221
1174
  const summary = {
1222
1175
  agentId: agent.id,
1223
1176
  models: [...models, ...exactPolicyModels]
1224
1177
  };
1225
- if (defaultModel !== void 0) summary.defaultModel = defaultModel;
1178
+ if (defaultModelRef !== void 0) summary.defaultModelRef = defaultModelRef;
1226
1179
  if (warnings.length > 0) summary.warnings = warnings;
1227
1180
  return summary;
1228
1181
  }
@@ -1260,7 +1213,7 @@ async function providerCatalog(provider) {
1260
1213
  models: [...models.values()].sort((left, right) => left.ref.localeCompare(right.ref))
1261
1214
  };
1262
1215
  if (provider.name !== void 0) catalog.name = provider.name;
1263
- if (provider.defaultModel !== void 0) catalog.defaultModel = provider.defaultModel;
1216
+ if (provider.defaultModelId !== void 0) catalog.defaultModelId = provider.defaultModelId;
1264
1217
  if (provider.metadata !== void 0) catalog.metadata = provider.metadata;
1265
1218
  if (warning !== void 0) catalog.warning = warning;
1266
1219
  return catalog;
@@ -1294,19 +1247,33 @@ function normalizeAgentPolicies(policies) {
1294
1247
  return new Map(
1295
1248
  Object.entries(policies).map(([agentId, policy]) => {
1296
1249
  const normalized = {};
1297
- if (policy.default !== void 0) normalized.default = normalizeModelRef(policy.default);
1250
+ if (policy.defaultModelRef !== void 0) {
1251
+ normalized.defaultModelRef = normalizeModelRef(policy.defaultModelRef);
1252
+ }
1298
1253
  if (policy.allowed !== void 0) {
1299
- normalized.allowed = policy.allowed.map(
1300
- (entry) => typeof entry === "string" && entry.trim().endsWith(":*") ? `${normalizeProviderId(entry.trim().slice(0, -2))}:*` : normalizeModelRef(entry)
1301
- );
1254
+ normalized.allowed = policy.allowed.map((entry) => {
1255
+ if (typeof entry === "string") {
1256
+ return normalizeWildcardModelRef(entry);
1257
+ }
1258
+ return normalizeModelRef(entry);
1259
+ });
1302
1260
  }
1303
1261
  return [agentId.trim(), normalized];
1304
1262
  })
1305
1263
  );
1306
1264
  }
1265
+ function normalizeWildcardModelRef(ref) {
1266
+ const normalized = ref.trim();
1267
+ if (!normalized.endsWith(":*")) {
1268
+ throw new ModelSelectionError(`Invalid wildcard model reference: ${ref}`);
1269
+ }
1270
+ return `${normalizeProviderId(normalized.slice(0, -2))}:*`;
1271
+ }
1307
1272
  function publicPolicy(policy) {
1308
1273
  const config = {};
1309
- if (policy.default !== void 0) config.default = policy.default;
1274
+ if (policy.defaultModelRef !== void 0) {
1275
+ config.defaultModelRef = policy.defaultModelRef;
1276
+ }
1310
1277
  if (policy.allowed !== void 0) config.allowed = policy.allowed;
1311
1278
  return config;
1312
1279
  }
@@ -1337,15 +1304,13 @@ function modelWarnings(ref, model, request) {
1337
1304
  function requestModalities(request) {
1338
1305
  const modalities = /* @__PURE__ */ new Set(["text"]);
1339
1306
  for (const message of requestMessages(request)) {
1340
- if (typeof message === "string") {
1341
- continue;
1342
- }
1343
1307
  if (message.role === "user" || message.role === "assistant") {
1308
+ if (typeof message.content === "string") continue;
1344
1309
  for (const content of message.content) {
1345
1310
  if (content.type === "image") {
1346
1311
  modalities.add("image");
1347
1312
  }
1348
- if (content.type === "document") {
1313
+ if (content.type === "file") {
1349
1314
  modalities.add("document");
1350
1315
  }
1351
1316
  }
@@ -1354,7 +1319,7 @@ function requestModalities(request) {
1354
1319
  return modalities;
1355
1320
  }
1356
1321
  function requestMessages(request) {
1357
- return [...request.history ?? [], request.message];
1322
+ return request.messages;
1358
1323
  }
1359
1324
  function normalizeProviderId(id) {
1360
1325
  const trimmed = id.trim();
@@ -1372,7 +1337,7 @@ function normalizeModelId(id) {
1372
1337
  }
1373
1338
 
1374
1339
  // src/runtime/streams.ts
1375
- import { createEventStream } from "@anvia/server";
1340
+ import { createClientStreamResponse, createEventStreamResponse } from "@anvia/server";
1376
1341
  var studioJsonlHeaders = {
1377
1342
  "cache-control": "no-cache, no-transform",
1378
1343
  connection: "keep-alive",
@@ -1381,7 +1346,15 @@ var studioJsonlHeaders = {
1381
1346
  "x-accel-buffering": "no"
1382
1347
  };
1383
1348
  function streamStudioJsonl(events) {
1384
- return createEventStream(withStudioStreamErrors(events), {
1349
+ return createEventStreamResponse({
1350
+ events: withStudioStreamErrors(events),
1351
+ format: "jsonl",
1352
+ headers: studioJsonlHeaders
1353
+ });
1354
+ }
1355
+ function streamStudioClient(options) {
1356
+ return createClientStreamResponse({
1357
+ events: options.events,
1385
1358
  format: "jsonl",
1386
1359
  headers: studioJsonlHeaders
1387
1360
  });
@@ -1400,8 +1373,9 @@ function withStudioStreamErrors(events) {
1400
1373
  const next = await iterator.next();
1401
1374
  if (next.done === true) {
1402
1375
  done = true;
1376
+ return next;
1403
1377
  }
1404
- return next;
1378
+ return { done: false, value: serializeStreamError(next.value) };
1405
1379
  } catch (error) {
1406
1380
  done = true;
1407
1381
  return {
@@ -1419,6 +1393,12 @@ function withStudioStreamErrors(events) {
1419
1393
  }
1420
1394
  };
1421
1395
  }
1396
+ function serializeStreamError(event) {
1397
+ if (typeof event !== "object" || event === null || !("type" in event) || event.type !== "error" || !("error" in event)) {
1398
+ return event;
1399
+ }
1400
+ return { ...event, error: serializeError(event.error) };
1401
+ }
1422
1402
  function studioStreamError(error) {
1423
1403
  return {
1424
1404
  type: "error",
@@ -1435,6 +1415,7 @@ function traceSummary(trace) {
1435
1415
  startedAt: trace.startedAt,
1436
1416
  observationCount: trace.observations.length
1437
1417
  };
1418
+ if (trace.runId !== void 0) summary.runId = trace.runId;
1438
1419
  if (trace.name !== void 0) summary.name = trace.name;
1439
1420
  if (trace.endedAt !== void 0) summary.endedAt = trace.endedAt;
1440
1421
  if (trace.durationMs !== void 0) summary.durationMs = trace.durationMs;
@@ -1626,6 +1607,15 @@ function isEventType(value) {
1626
1607
  return value === "session_log" || value === "pipeline_log" || value === "trace";
1627
1608
  }
1628
1609
 
1610
+ // src/runtime/runs.ts
1611
+ import {
1612
+ customAgentEventsToClientStream
1613
+ } from "@anvia/client";
1614
+ import {
1615
+ isJsonValue as isJsonValue2,
1616
+ parseMessages
1617
+ } from "@anvia/core/completion";
1618
+
1629
1619
  // src/runtime/transcript.ts
1630
1620
  function renumberTranscript(entries) {
1631
1621
  return entries.map((entry, entryId) => ({ ...entry, entryId }));
@@ -1639,7 +1629,8 @@ function transcriptFromMessages(messages) {
1639
1629
  if (message.role === "user") {
1640
1630
  const attachments = attachmentsFromMessage(message);
1641
1631
  let textEntryAdded = false;
1642
- for (const content of message.content) {
1632
+ const contents2 = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
1633
+ for (const content of contents2) {
1643
1634
  if (content.type === "text") {
1644
1635
  const entry = {
1645
1636
  entryId: transcript.length,
@@ -1668,17 +1659,16 @@ function transcriptFromMessages(messages) {
1668
1659
  transcript.push({
1669
1660
  entryId: transcript.length,
1670
1661
  kind: "tool",
1671
- toolName: "tool_result",
1672
- callId: content.callId ?? content.id,
1673
- result: content.content.map(
1674
- (item) => "text" in item ? item.text : `[image:${item.mediaType ?? "image/png"}]`
1675
- ).join("\n"),
1676
- structuredResult: content.content
1662
+ toolName: content.toolName,
1663
+ callId: content.callId ?? content.toolCallId,
1664
+ result: toolResultText(content.output),
1665
+ ...content.output.type === "content" ? { structuredResult: content.output.value } : {}
1677
1666
  });
1678
1667
  }
1679
1668
  continue;
1680
1669
  }
1681
- for (const content of message.content) {
1670
+ const contents = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
1671
+ for (const content of contents) {
1682
1672
  if (content.type === "text") {
1683
1673
  appendAssistantTranscriptText(transcript, content.text);
1684
1674
  } else if (content.type === "reasoning") {
@@ -1689,13 +1679,13 @@ function transcriptFromMessages(messages) {
1689
1679
  };
1690
1680
  if (content.id !== void 0) entry.reasoningId = content.id;
1691
1681
  transcript.push(entry);
1692
- } else if (content.type === "tool_call") {
1682
+ } else if (content.type === "tool-call") {
1693
1683
  transcript.push({
1694
1684
  entryId: transcript.length,
1695
1685
  kind: "tool",
1696
- toolName: content.function.name,
1697
- callId: content.callId ?? content.id,
1698
- args: formatJson(content.function.arguments)
1686
+ toolName: content.toolName,
1687
+ callId: content.callId ?? content.toolCallId,
1688
+ args: formatJson(content.input)
1699
1689
  });
1700
1690
  }
1701
1691
  }
@@ -1706,28 +1696,37 @@ function attachmentsFromMessage(message) {
1706
1696
  if (message.role !== "user" && message.role !== "assistant") {
1707
1697
  return [];
1708
1698
  }
1699
+ if (typeof message.content === "string") return [];
1709
1700
  return message.content.flatMap((content) => {
1710
1701
  if (content.type === "image") {
1711
1702
  const attachment = { kind: "image" };
1712
- if (content.source.type === "base64") {
1713
- attachment.data = content.source.data;
1714
- attachment.mediaType = content.source.mediaType;
1703
+ if (content.image.type === "data") {
1704
+ attachment.data = content.image.data;
1705
+ if (content.mediaType !== void 0) attachment.mediaType = content.mediaType;
1715
1706
  } else {
1716
- attachment.url = content.source.url;
1707
+ attachment.url = content.image.url;
1717
1708
  }
1718
1709
  return [attachment];
1719
1710
  }
1720
- if (content.type === "document") {
1711
+ if (content.type === "file") {
1721
1712
  const attachment = { kind: "document" };
1722
- if (content.source.filename !== void 0) attachment.name = content.source.filename;
1723
- if (content.source.mediaType !== void 0) attachment.mediaType = content.source.mediaType;
1724
- if (content.source.type === "base64") attachment.data = content.source.data;
1725
- if (content.source.type === "url") attachment.url = content.source.url;
1713
+ if (content.filename !== void 0) attachment.name = content.filename;
1714
+ attachment.mediaType = content.mediaType;
1715
+ if (content.data.type === "data") attachment.data = content.data.data;
1716
+ if (content.data.type === "url") attachment.url = content.data.url;
1726
1717
  return [attachment];
1727
1718
  }
1728
1719
  return [];
1729
1720
  });
1730
1721
  }
1722
+ function toolResultText(output) {
1723
+ if (output.type === "text" || output.type === "error-text") return output.value;
1724
+ if (output.type === "json" || output.type === "error-json") return formatJson(output.value);
1725
+ if (output.type === "execution-denied") return output.reason ?? "Execution denied";
1726
+ return output.value.map(
1727
+ (part) => part.type === "text" ? part.text : `[file:${part.mediaType}${part.filename === void 0 ? "" : `:${part.filename}`}]`
1728
+ ).join("\n");
1729
+ }
1731
1730
  function appendAssistantTranscriptText(transcript, text) {
1732
1731
  const last = transcript.at(-1);
1733
1732
  if (last?.kind === "message" && last.role === "assistant") {
@@ -1815,8 +1814,97 @@ async function* mergeRunAndApprovalEvents(runEvents, approvalEvents) {
1815
1814
  approvalEvents.close();
1816
1815
  }
1817
1816
  }
1818
- function streamAgentRunEvents(_c, events, options = {}) {
1819
- return streamStudioJsonl(withAgentRunCancellation(events, options.onCancel));
1817
+ function streamAgentRunEvents(_c, events, options) {
1818
+ return streamStudioClient({
1819
+ events: customAgentEventsToClientStream({
1820
+ events: withAgentRunCancellation(events, options.onCancel),
1821
+ runId: options.runId,
1822
+ mapCustomEvent: studioEventToClientEvent
1823
+ })
1824
+ });
1825
+ }
1826
+ function studioEventToClientEvent(event, context) {
1827
+ if (event.type === "tool_approval_request" || event.type === "tool_approval_result") {
1828
+ return {
1829
+ type: "tool_approval",
1830
+ runId: context.runId,
1831
+ ...context.turn === void 0 ? {} : { turn: context.turn },
1832
+ ...context.scope === void 0 ? {} : { scope: context.scope },
1833
+ approval: {
1834
+ id: event.approval.id,
1835
+ runId: event.approval.runId,
1836
+ agentId: event.approval.agentId,
1837
+ ...event.approval.sessionId === void 0 ? {} : { sessionId: event.approval.sessionId },
1838
+ toolName: event.approval.toolName,
1839
+ ...event.approval.callId === void 0 ? {} : { callId: event.approval.callId },
1840
+ internalCallId: event.approval.internalCallId,
1841
+ input: parseJsonOrString(event.approval.args),
1842
+ status: event.approval.status,
1843
+ requestedAt: event.approval.requestedAt,
1844
+ ...event.approval.resolvedAt === void 0 ? {} : { resolvedAt: event.approval.resolvedAt },
1845
+ ...event.approval.reason === void 0 ? {} : { reason: event.approval.reason }
1846
+ }
1847
+ };
1848
+ }
1849
+ if (event.type === "tool_question_request" || event.type === "tool_question_result") {
1850
+ return {
1851
+ type: "tool_question",
1852
+ runId: context.runId,
1853
+ ...context.turn === void 0 ? {} : { turn: context.turn },
1854
+ ...context.scope === void 0 ? {} : { scope: context.scope },
1855
+ question: {
1856
+ id: event.question.id,
1857
+ runId: event.question.runId,
1858
+ agentId: event.question.agentId,
1859
+ ...event.question.sessionId === void 0 ? {} : { sessionId: event.question.sessionId },
1860
+ toolName: event.question.toolName,
1861
+ ...event.question.callId === void 0 ? {} : { callId: event.question.callId },
1862
+ internalCallId: event.question.internalCallId,
1863
+ input: parseJsonOrString(event.question.args),
1864
+ questions: event.question.questions,
1865
+ status: event.question.status,
1866
+ requestedAt: event.question.requestedAt,
1867
+ ...event.question.answeredAt === void 0 ? {} : { answeredAt: event.question.answeredAt },
1868
+ ...event.question.cancelledAt === void 0 ? {} : { cancelledAt: event.question.cancelledAt },
1869
+ ...event.question.answers === void 0 ? {} : { answers: event.question.answers }
1870
+ }
1871
+ };
1872
+ }
1873
+ if (event.type === "session_log" && isJsonValue2(event.log)) {
1874
+ return {
1875
+ type: "data",
1876
+ runId: context.runId,
1877
+ name: "studio.session_log",
1878
+ data: event.log,
1879
+ transient: true
1880
+ };
1881
+ }
1882
+ if (event.type === "pipeline_log" && isJsonValue2(event.log)) {
1883
+ return {
1884
+ type: "data",
1885
+ runId: context.runId,
1886
+ name: "studio.pipeline_log",
1887
+ data: event.log,
1888
+ transient: true
1889
+ };
1890
+ }
1891
+ if (event.type === "pipeline_final" && isJsonValue2(event.output)) {
1892
+ return {
1893
+ type: "data",
1894
+ runId: context.runId,
1895
+ name: "studio.pipeline_final",
1896
+ data: event.output
1897
+ };
1898
+ }
1899
+ return void 0;
1900
+ }
1901
+ function parseJsonOrString(value) {
1902
+ try {
1903
+ const parsed = JSON.parse(value);
1904
+ return isJsonValue2(parsed) ? parsed : value;
1905
+ } catch {
1906
+ return value;
1907
+ }
1820
1908
  }
1821
1909
  function withAgentRunCancellation(events, onCancel) {
1822
1910
  const iterator = events[Symbol.asyncIterator]();
@@ -1936,10 +2024,10 @@ function createPersistedStreamingSessionTranscript(props) {
1936
2024
  };
1937
2025
  if (event.type === "error") saveInput.error = serializeError(event.error);
1938
2026
  await saveTranscript(saveInput);
1939
- const generatedMessages = event.type === "final" ? event.messages.slice(1) : [];
2027
+ const generatedMessages = event.type === "final" ? event.result.messages.slice(1) : [];
1940
2028
  if (props.persistGeneratedMessages === true && generatedMessages.length > 0) {
1941
2029
  await props.store.append({
1942
- context: { sessionId: props.session.id },
2030
+ scope: { sessionId: props.session.id },
1943
2031
  runId: props.runId,
1944
2032
  turn: 1,
1945
2033
  messages: generatedMessages
@@ -2041,9 +2129,9 @@ function acceptTranscriptStreamEvent(transcript, event) {
2041
2129
  transcript.push({
2042
2130
  entryId: transcript.length,
2043
2131
  kind: "tool",
2044
- toolName: event.toolCall.function.name,
2045
- callId: event.toolCall.callId ?? event.toolCall.id,
2046
- args: formatJson(event.toolCall.function.arguments)
2132
+ toolName: event.toolCall.toolName,
2133
+ callId: event.toolCall.callId ?? event.toolCall.toolCallId,
2134
+ args: formatJson(event.toolCall.input)
2047
2135
  });
2048
2136
  }
2049
2137
  if (event.type === "tool_result") {
@@ -2151,8 +2239,8 @@ function acceptTranscriptStreamEvent(transcript, event) {
2151
2239
  matched.question = question;
2152
2240
  }
2153
2241
  }
2154
- if (event.type === "final" && event.trace?.traceId !== void 0) {
2155
- assignTranscriptTraceId(transcript, event.trace.traceId);
2242
+ if (event.type === "final" && event.result.trace?.traceId !== void 0) {
2243
+ assignTranscriptTraceId(transcript, event.result.trace.traceId);
2156
2244
  }
2157
2245
  if (event.type === "error") {
2158
2246
  appendTranscriptAssistantError(transcript, errorText(event.error));
@@ -2224,9 +2312,9 @@ function childAgentTranscriptEvent(event) {
2224
2312
  const entry = {
2225
2313
  kind: "tool",
2226
2314
  agentId: event.agentId,
2227
- toolName: child.toolCall.function.name,
2228
- callId: child.toolCall.callId ?? child.toolCall.id,
2229
- args: formatJson(child.toolCall.function.arguments)
2315
+ toolName: child.toolCall.toolName,
2316
+ callId: child.toolCall.callId ?? child.toolCall.toolCallId,
2317
+ args: formatJson(child.toolCall.input)
2230
2318
  };
2231
2319
  if (event.agentName !== void 0) entry.agentName = event.agentName;
2232
2320
  return entry;
@@ -2363,17 +2451,18 @@ function extractMessageText(message) {
2363
2451
  if (message.role === "system") {
2364
2452
  return message.content;
2365
2453
  }
2454
+ if (typeof message.content === "string") {
2455
+ return message.content;
2456
+ }
2366
2457
  return message.content.flatMap((item) => {
2367
2458
  if (item.type === "text" || item.type === "reasoning") {
2368
2459
  return [item.text];
2369
2460
  }
2370
- if (item.type === "tool_call") {
2371
- return [`${item.function.name}(${formatJson(item.function.arguments)})`];
2461
+ if (item.type === "tool-call") {
2462
+ return [`${item.toolName}(${formatJson(item.input)})`];
2372
2463
  }
2373
- if (item.type === "tool_result") {
2374
- return item.content.map(
2375
- (result) => "text" in result ? result.text : `[image:${result.mediaType ?? "image/png"}]`
2376
- );
2464
+ if (item.type === "tool-result") {
2465
+ return [toolResultOutputText(item.output)];
2377
2466
  }
2378
2467
  return [];
2379
2468
  }).join("\n");
@@ -2382,23 +2471,26 @@ function optionalTranscriptAttachments(message) {
2382
2471
  if (typeof message === "string" || message.role !== "user") {
2383
2472
  return {};
2384
2473
  }
2474
+ if (typeof message.content === "string") {
2475
+ return {};
2476
+ }
2385
2477
  const attachments = message.content.flatMap((content) => {
2386
2478
  if (content.type === "image") {
2387
2479
  const attachment = { kind: "image" };
2388
- if (content.source.type === "base64") {
2389
- attachment.data = content.source.data;
2390
- attachment.mediaType = content.source.mediaType;
2480
+ if (content.image.type === "data") {
2481
+ attachment.data = content.image.data;
2482
+ if (content.mediaType !== void 0) attachment.mediaType = content.mediaType;
2391
2483
  } else {
2392
- attachment.url = content.source.url;
2484
+ attachment.url = content.image.url;
2393
2485
  }
2394
2486
  return [attachment];
2395
2487
  }
2396
- if (content.type === "document") {
2488
+ if (content.type === "file") {
2397
2489
  const attachment = { kind: "document" };
2398
- if (content.source.filename !== void 0) attachment.name = content.source.filename;
2399
- if (content.source.mediaType !== void 0) attachment.mediaType = content.source.mediaType;
2400
- if (content.source.type === "base64") attachment.data = content.source.data;
2401
- if (content.source.type === "url") attachment.url = content.source.url;
2490
+ if (content.filename !== void 0) attachment.name = content.filename;
2491
+ attachment.mediaType = content.mediaType;
2492
+ if (content.data.type === "data") attachment.data = content.data.data;
2493
+ if (content.data.type === "url") attachment.url = content.data.url;
2402
2494
  return [attachment];
2403
2495
  }
2404
2496
  return [];
@@ -2415,32 +2507,27 @@ async function parseRunRequest(c) {
2415
2507
  if (!isObject(body)) {
2416
2508
  return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
2417
2509
  }
2418
- const request = "message" in body ? parseLegacyRunRequestBody(c, body) : parseUiRunRequestBody(c, body);
2419
- if ("error" in request) {
2420
- return request;
2421
- }
2422
- return parseRunRequestOptions(c, body, request);
2423
- }
2424
- function parseLegacyRunRequestBody(c, body) {
2425
- if (!isMessageInput(body.message)) {
2510
+ if ("message" in body || "history" in body) {
2426
2511
  return {
2427
- error: errorResponse(c, 400, "bad_request", "Request body requires a string or Message")
2512
+ error: errorResponse(
2513
+ c,
2514
+ 400,
2515
+ "bad_request",
2516
+ "Legacy message/history requests are not supported; use messages"
2517
+ )
2428
2518
  };
2429
2519
  }
2430
- const request = {
2431
- message: typeof body.message === "string" ? body.message : body.message
2432
- };
2433
- if ("history" in body) {
2434
- if (!Array.isArray(body.history) || !body.history.every(isMessage)) {
2435
- return { error: errorResponse(c, 400, "bad_request", "history must be a Message array") };
2436
- }
2437
- request.history = body.history;
2520
+ const request = parseRunRequestBody(c, body);
2521
+ if ("error" in request) {
2522
+ return request;
2438
2523
  }
2439
- return request;
2524
+ return parseRunRequestOptions(c, body, request);
2440
2525
  }
2441
- function parseUiRunRequestBody(c, body) {
2442
- const messages = body.messages;
2443
- if (!Array.isArray(messages) || !messages.every(isMessage)) {
2526
+ function parseRunRequestBody(c, body) {
2527
+ let messages;
2528
+ try {
2529
+ messages = parseMessages(body.messages);
2530
+ } catch {
2444
2531
  return {
2445
2532
  error: errorResponse(c, 400, "bad_request", "messages must be a non-empty Message array")
2446
2533
  };
@@ -2456,19 +2543,21 @@ function parseUiRunRequestBody(c, body) {
2456
2543
  error: errorResponse(c, 400, "bad_request", "messages must be a non-empty Message array")
2457
2544
  };
2458
2545
  }
2459
- const history = messages.slice(0, -1);
2460
- const request = { message };
2461
- if (history.length > 0) request.history = history;
2462
- return request;
2546
+ if (message.role !== "user") {
2547
+ return {
2548
+ error: errorResponse(c, 400, "bad_request", "The final message must be user-authored")
2549
+ };
2550
+ }
2551
+ return { messages };
2463
2552
  }
2464
2553
  function parseRunRequestOptions(c, body, request) {
2465
2554
  if ("sessionId" in body) {
2466
2555
  if (typeof body.sessionId !== "string" || body.sessionId.trim().length === 0) {
2467
2556
  return { error: errorResponse(c, 400, "bad_request", "sessionId must be a string") };
2468
2557
  }
2469
- if (request.history !== void 0) {
2558
+ if (request.messages.length !== 1 || request.messages[0]?.role !== "user") {
2470
2559
  return {
2471
- error: errorResponse(c, 400, "bad_request", "sessionId cannot be combined with history")
2560
+ error: errorResponse(c, 400, "bad_request", "sessionId requires exactly one user message")
2472
2561
  };
2473
2562
  }
2474
2563
  request.sessionId = body.sessionId;
@@ -2496,12 +2585,10 @@ function parseRunRequestOptions(c, body, request) {
2496
2585
  request.toolConcurrency = body.toolConcurrency;
2497
2586
  }
2498
2587
  if ("model" in body) {
2499
- if (typeof body.model === "string") {
2500
- request.model = body.model;
2501
- } else if (isObject(body.model) && typeof body.model.provider === "string" && typeof body.model.model === "string") {
2588
+ if (isObject(body.model) && typeof body.model.providerId === "string" && typeof body.model.modelId === "string") {
2502
2589
  request.model = {
2503
- provider: body.model.provider,
2504
- model: body.model.model
2590
+ providerId: body.model.providerId,
2591
+ modelId: body.model.modelId
2505
2592
  };
2506
2593
  } else {
2507
2594
  return {
@@ -2509,7 +2596,7 @@ function parseRunRequestOptions(c, body, request) {
2509
2596
  c,
2510
2597
  400,
2511
2598
  "bad_request",
2512
- "model must be a provider:model string or { provider, model } object"
2599
+ "model must be a { providerId, modelId } object"
2513
2600
  )
2514
2601
  };
2515
2602
  }
@@ -2530,6 +2617,14 @@ function parseRunRequestOptions(c, body, request) {
2530
2617
  }
2531
2618
  return request;
2532
2619
  }
2620
+ function toolResultOutputText(output) {
2621
+ if (output.type === "text" || output.type === "error-text") return output.value;
2622
+ if (output.type === "json" || output.type === "error-json") return formatJson(output.value);
2623
+ if (output.type === "execution-denied") return output.reason ?? "Execution denied";
2624
+ return output.value.map(
2625
+ (part) => part.type === "text" ? part.text : `[file:${part.mediaType}${part.filename === void 0 ? "" : `:${part.filename}`}]`
2626
+ ).join("\n");
2627
+ }
2533
2628
 
2534
2629
  // src/runtime/session-logs.ts
2535
2630
  async function appendSessionLog(store, input) {
@@ -2664,6 +2759,25 @@ function memorySavedLog(props) {
2664
2759
  metadata
2665
2760
  };
2666
2761
  }
2762
+ function memoryCompactedLog(props) {
2763
+ const metadata = {
2764
+ originalMessageCount: props.originalMessageCount,
2765
+ compactedMessageCount: props.compactedMessageCount,
2766
+ retainedMessageCount: props.retainedMessageCount,
2767
+ attempts: props.attempts
2768
+ };
2769
+ const usage = usageSummary(props.usage);
2770
+ if (usage !== void 0) metadata.usage = usage;
2771
+ return {
2772
+ sessionId: props.sessionId,
2773
+ runId: props.runId,
2774
+ level: "info",
2775
+ category: "memory",
2776
+ event: "memory.compacted",
2777
+ message: "Session memory compacted",
2778
+ metadata
2779
+ };
2780
+ }
2667
2781
  function runFailedLog(sessionId, runId, error, startedAt) {
2668
2782
  return {
2669
2783
  sessionId,
@@ -2680,6 +2794,9 @@ function runFailedLog(sessionId, runId, error, startedAt) {
2680
2794
  }
2681
2795
  function logsFromStreamEvent(props) {
2682
2796
  const { event, sessionId, runId } = props;
2797
+ if (event.type === "memory_compaction") {
2798
+ return [memoryCompactedLog({ sessionId, runId, ...event })];
2799
+ }
2683
2800
  if (event.type === "turn_start") {
2684
2801
  return [
2685
2802
  {
@@ -2705,12 +2822,12 @@ function logsFromStreamEvent(props) {
2705
2822
  level: "info",
2706
2823
  category: "tool",
2707
2824
  event: "tool.called",
2708
- message: `Tool ${event.toolCall.function.name} called`,
2825
+ message: `Tool ${event.toolCall.toolName} called`,
2709
2826
  metadata: {
2710
2827
  turn: event.turn,
2711
- toolName: event.toolCall.function.name,
2712
- callId: event.toolCall.callId ?? event.toolCall.id,
2713
- argumentBytes: byteLength2(formatUnknown(event.toolCall.function.arguments))
2828
+ toolName: event.toolCall.toolName,
2829
+ callId: event.toolCall.callId ?? event.toolCall.toolCallId,
2830
+ argumentBytes: byteLength2(formatUnknown(event.toolCall.input))
2714
2831
  }
2715
2832
  }
2716
2833
  ];
@@ -2759,16 +2876,17 @@ function logsFromStreamEvent(props) {
2759
2876
  ];
2760
2877
  }
2761
2878
  if (event.type === "final") {
2879
+ const result = event.result;
2762
2880
  return [
2763
2881
  runCompletedLog({
2764
2882
  sessionId,
2765
2883
  runId,
2766
2884
  durationMs: Date.now() - props.startedAt,
2767
- usage: event.usage,
2768
- output: event.output,
2769
- messageCount: event.messages.length
2885
+ usage: result.usage,
2886
+ output: result.text,
2887
+ messageCount: result.messages.length
2770
2888
  }),
2771
- memorySavedLog({ sessionId, runId, messageCount: event.messages.length })
2889
+ memorySavedLog({ sessionId, runId, messageCount: result.messages.length })
2772
2890
  ];
2773
2891
  }
2774
2892
  if (event.type === "error") {
@@ -2880,16 +2998,16 @@ function childAgentLog(event, sessionId, runId) {
2880
2998
  level: "debug",
2881
2999
  category: "tool",
2882
3000
  event: "child_tool.called",
2883
- message: `Child agent ${event.agentName ?? event.agentId} called ${child.toolCall.function.name}`,
3001
+ message: `Child agent ${event.agentName ?? event.agentId} called ${child.toolCall.toolName}`,
2884
3002
  metadata: {
2885
3003
  parentToolName: event.toolName,
2886
3004
  agentId: event.agentId,
2887
3005
  hasAgentName: event.agentName !== void 0,
2888
3006
  turn: event.turn,
2889
3007
  childTurn: child.turn,
2890
- toolName: child.toolCall.function.name,
2891
- callId: child.toolCall.callId ?? child.toolCall.id,
2892
- argumentBytes: byteLength2(formatUnknown(child.toolCall.function.arguments))
3008
+ toolName: child.toolCall.toolName,
3009
+ callId: child.toolCall.callId ?? child.toolCall.toolCallId,
3010
+ argumentBytes: byteLength2(formatUnknown(child.toolCall.input))
2893
3011
  }
2894
3012
  }
2895
3013
  ];
@@ -2940,14 +3058,16 @@ function childAgentLog(event, sessionId, runId) {
2940
3058
  ];
2941
3059
  }
2942
3060
  if (child.type === "final") {
3061
+ const result = child.result;
2943
3062
  const metadata = {
2944
3063
  parentToolName: event.toolName,
2945
3064
  agentId: event.agentId,
2946
3065
  hasAgentName: event.agentName !== void 0,
2947
- outputBytes: byteLength2(child.output),
2948
- messageCount: child.messages.length
3066
+ outputBytes: byteLength2(result.text),
3067
+ messageCount: result.messages.length,
3068
+ status: result.status
2949
3069
  };
2950
- const usage = usageSummary(child.usage);
3070
+ const usage = usageSummary(result.usage);
2951
3071
  if (usage !== void 0) metadata.usage = usage;
2952
3072
  return [
2953
3073
  {
@@ -3073,18 +3193,18 @@ async function prepareAgentRun(c, props) {
3073
3193
  store: props.stores.sessions
3074
3194
  });
3075
3195
  const memoryMetadata = runMemoryMetadata(agentId, body, selectedModel, runId);
3076
- const promptMessage = normalizePromptMessage(body.message);
3196
+ const promptMessage = body.messages.at(-1);
3077
3197
  const sessionStore = props.stores.sessions;
3078
3198
  const shouldPersistSessionMessages = session !== void 0 && sessionStore !== void 0 && !usesStoreAsAgentMemory(runAgent, sessionStore);
3079
3199
  if (shouldPersistSessionMessages) {
3080
3200
  await sessionStore.append({
3081
- context: { sessionId: session.id, metadata: memoryMetadata },
3201
+ scope: { sessionId: session.id, metadata: memoryMetadata },
3082
3202
  runId,
3083
3203
  turn: 1,
3084
3204
  messages: [promptMessage]
3085
3205
  });
3086
3206
  }
3087
- const request = createRunRequest({
3207
+ const execution = createRunExecution({
3088
3208
  agentId,
3089
3209
  body,
3090
3210
  memoryMetadata,
@@ -3097,7 +3217,10 @@ async function prepareAgentRun(c, props) {
3097
3217
  agent,
3098
3218
  body,
3099
3219
  memoryMetadata,
3100
- request,
3220
+ execution,
3221
+ failureMessages: void 0,
3222
+ memoryCompactionLogged: false,
3223
+ options: createRunOptions(body, agentId, session, c.req.raw.signal),
3101
3224
  runAgent,
3102
3225
  runId,
3103
3226
  runStartedAt,
@@ -3142,7 +3265,7 @@ async function recordRunReceived(props) {
3142
3265
  sessionId: props.session.id,
3143
3266
  runId: props.runId,
3144
3267
  agentId: props.agentId,
3145
- message: props.body.message,
3268
+ message: props.body.messages.at(-1),
3146
3269
  stream: props.body.stream === true,
3147
3270
  hasTrace: props.body.trace !== void 0
3148
3271
  };
@@ -3189,23 +3312,38 @@ function runMemoryMetadata(agentId, body, selectedModel, runId) {
3189
3312
  metadata.studioRunId = runId;
3190
3313
  return metadata;
3191
3314
  }
3192
- function createRunRequest(props) {
3193
- const request = props.session !== void 0 ? props.runAgent.memory === void 0 ? props.runAgent.prompt([...props.session.messages, props.promptMessage]) : props.runAgent.session(props.session.id, { metadata: props.memoryMetadata }).prompt(props.body.message) : props.runAgent.prompt(
3194
- props.body.history !== void 0 ? [...props.body.history, props.promptMessage] : props.body.message
3195
- );
3196
- request.withCompletionRetries();
3197
- if (props.body.maxTurns !== void 0) {
3198
- request.maxTurns(props.body.maxTurns);
3199
- }
3200
- if (props.body.toolConcurrency !== void 0) {
3201
- request.withToolConcurrency(props.body.toolConcurrency);
3315
+ function createRunExecution(props) {
3316
+ const session = props.session;
3317
+ if (session !== void 0 && props.runAgent.memory !== void 0) {
3318
+ return {
3319
+ generate: (options) => props.runAgent.generate({
3320
+ prompt: props.promptMessage,
3321
+ session: { sessionId: session.id, metadata: props.memoryMetadata },
3322
+ ...options
3323
+ }),
3324
+ stream: (options) => props.runAgent.stream({
3325
+ prompt: props.promptMessage,
3326
+ session: { sessionId: session.id, metadata: props.memoryMetadata },
3327
+ ...options
3328
+ })
3329
+ };
3202
3330
  }
3203
- if (props.body.trace !== void 0) {
3204
- request.withTrace(traceForRun(props.body.trace, props.agentId, props.session));
3205
- } else if (props.session !== void 0) {
3206
- request.withTrace(traceForRun(void 0, props.agentId, props.session));
3331
+ const transcript = session !== void 0 ? [...session.messages, props.promptMessage] : props.body.messages;
3332
+ return {
3333
+ generate: (options) => props.runAgent.generate({ messages: transcript, ...options }),
3334
+ stream: (options) => props.runAgent.stream({ messages: transcript, ...options })
3335
+ };
3336
+ }
3337
+ function createRunOptions(body, agentId, session, abortSignal) {
3338
+ const options = { abortSignal };
3339
+ if (body.maxTurns !== void 0) options.maxTurns = body.maxTurns;
3340
+ if (body.toolConcurrency !== void 0) options.toolConcurrency = body.toolConcurrency;
3341
+ if (body.trace !== void 0) {
3342
+ options.trace = traceForRun(body.trace, agentId, session);
3343
+ } else if (session !== void 0) {
3344
+ options.trace = traceForRun(void 0, agentId, session);
3207
3345
  }
3208
- return request;
3346
+ return options;
3209
3347
  }
3210
3348
  function handleStreamingAgentRun(c, run, props) {
3211
3349
  const runtimeEvents = new AsyncEventQueue();
@@ -3216,7 +3354,6 @@ function handleStreamingAgentRun(c, run, props) {
3216
3354
  };
3217
3355
  if (run.session !== void 0) approvalContext.sessionId = run.session.id;
3218
3356
  if (run.body.metadata !== void 0) approvalContext.metadata = run.body.metadata;
3219
- run.request.approvals(props.approvalRuntime.createApprovals(approvalContext));
3220
3357
  const questionContext = {
3221
3358
  runId: run.runId,
3222
3359
  agentId: run.agentId,
@@ -3224,14 +3361,20 @@ function handleStreamingAgentRun(c, run, props) {
3224
3361
  };
3225
3362
  if (run.session !== void 0) questionContext.sessionId = run.session.id;
3226
3363
  if (run.body.metadata !== void 0) questionContext.metadata = run.body.metadata;
3227
- const effectiveHook = composeHooks(
3228
- run.runAgent.hook,
3229
- props.questionRuntime.createHook(questionContext)
3364
+ const effectiveHook = props.questionRuntime.createHook(questionContext);
3365
+ const streamOptions = withInternalAgentRunOptions(
3366
+ { ...run.options },
3367
+ { hook: effectiveHook, runId: run.runId }
3368
+ );
3369
+ const runStream = mergeRunAndApprovalEvents(
3370
+ resumeStreamingApprovals(
3371
+ run.runAgent,
3372
+ run.execution.stream(streamOptions),
3373
+ props.approvalRuntime,
3374
+ approvalContext
3375
+ ),
3376
+ runtimeEvents
3230
3377
  );
3231
- if (effectiveHook !== void 0) {
3232
- run.request.withHook(effectiveHook);
3233
- }
3234
- const runStream = mergeRunAndApprovalEvents(run.request.stream(), runtimeEvents);
3235
3378
  let stream = runStream;
3236
3379
  let persistedRun;
3237
3380
  if (run.session !== void 0 && run.sessionStore !== void 0) {
@@ -3245,7 +3388,7 @@ function handleStreamingAgentRun(c, run, props) {
3245
3388
  }),
3246
3389
  store: run.sessionStore,
3247
3390
  session: run.session,
3248
- message: run.body.message,
3391
+ message: run.body.messages.at(-1),
3249
3392
  runId: run.runId,
3250
3393
  startedAt: run.runStartedAt,
3251
3394
  persistGeneratedMessages: run.shouldPersistSessionMessages
@@ -3253,6 +3396,7 @@ function handleStreamingAgentRun(c, run, props) {
3253
3396
  stream = persistedRun.events;
3254
3397
  }
3255
3398
  return streamAgentRunEvents(c, stream, {
3399
+ runId: run.runId,
3256
3400
  onCancel: async () => {
3257
3401
  props.approvalRuntime.cancelRun(run.runId);
3258
3402
  props.questionRuntime.cancelRun(run.runId);
@@ -3274,8 +3418,14 @@ function handleStreamingAgentRun(c, run, props) {
3274
3418
  }
3275
3419
  async function handleBufferedAgentRun(c, run, props) {
3276
3420
  try {
3277
- await startBufferedSessionRun(run, props);
3278
- const response = await run.request.send();
3421
+ const runtimeOptions = await startBufferedSessionRun(run, props);
3422
+ let result = await run.execution.generate(runtimeOptions);
3423
+ const approvalContext = createApprovalContext(run);
3424
+ while (result.status === "approval_required") {
3425
+ const decision = await props.approvalRuntime.request(approvalContext, result.approval);
3426
+ result = await run.runAgent.resume(result, decision);
3427
+ }
3428
+ const response = result;
3279
3429
  await completeBufferedSessionRun(run, response);
3280
3430
  return c.json(response);
3281
3431
  } catch (error) {
@@ -3294,19 +3444,55 @@ async function startBufferedSessionRun(run, props) {
3294
3444
  };
3295
3445
  if (run.session !== void 0) questionContext.sessionId = run.session.id;
3296
3446
  if (run.body.metadata !== void 0) questionContext.metadata = run.body.metadata;
3297
- const effectiveHook = composeHooks(
3298
- run.runAgent.hook,
3299
- props.questionRuntime.createHook(questionContext)
3300
- );
3301
- const approvalContext = {
3447
+ const effectiveHook = props.questionRuntime.createHook(questionContext);
3448
+ const internalOptions = {
3449
+ hook: effectiveHook,
3450
+ onFailure: ({ messages }) => {
3451
+ run.failureMessages = structuredClone(messages);
3452
+ },
3453
+ runId: run.runId
3454
+ };
3455
+ if (run.session !== void 0 && run.sessionStore !== void 0) {
3456
+ const sessionId = run.session.id;
3457
+ const sessionStore = run.sessionStore;
3458
+ internalOptions.onMemoryCompaction = async (compaction) => {
3459
+ await appendSessionLog(
3460
+ sessionStore,
3461
+ memoryCompactedLog({
3462
+ sessionId,
3463
+ runId: run.runId,
3464
+ ...compaction
3465
+ })
3466
+ );
3467
+ run.memoryCompactionLogged = true;
3468
+ };
3469
+ }
3470
+ return withInternalAgentRunOptions({ ...run.options }, internalOptions);
3471
+ }
3472
+ function createApprovalContext(run, emit) {
3473
+ const context = {
3302
3474
  runId: run.runId,
3303
3475
  agentId: run.agentId
3304
3476
  };
3305
- if (run.session !== void 0) approvalContext.sessionId = run.session.id;
3306
- if (run.body.metadata !== void 0) approvalContext.metadata = run.body.metadata;
3307
- run.request.approvals(props.approvalRuntime.createApprovals(approvalContext));
3308
- if (effectiveHook !== void 0) {
3309
- run.request.withHook(effectiveHook);
3477
+ if (run.session !== void 0) context.sessionId = run.session.id;
3478
+ if (run.body.metadata !== void 0) context.metadata = run.body.metadata;
3479
+ if (emit !== void 0) context.emit = emit;
3480
+ return context;
3481
+ }
3482
+ async function* resumeStreamingApprovals(agent, initialStream, approvalRuntime, context) {
3483
+ let stream = initialStream;
3484
+ while (true) {
3485
+ let pending;
3486
+ for await (const event of stream) {
3487
+ if (event.type === "approval_required") {
3488
+ pending = event;
3489
+ break;
3490
+ }
3491
+ yield event;
3492
+ }
3493
+ if (pending === void 0) return;
3494
+ const decision = await approvalRuntime.request(context, pending.approval);
3495
+ stream = agent.resume(pending, decision);
3310
3496
  }
3311
3497
  }
3312
3498
  async function completeBufferedSessionRun(run, response) {
@@ -3317,7 +3503,7 @@ async function completeBufferedSessionRun(run, response) {
3317
3503
  const generatedMessages = response.messages.slice(1);
3318
3504
  if (generatedMessages.length > 0) {
3319
3505
  await run.sessionStore.append({
3320
- context: { sessionId: run.session.id, metadata: run.memoryMetadata },
3506
+ scope: { sessionId: run.session.id, metadata: run.memoryMetadata },
3321
3507
  runId: run.runId,
3322
3508
  turn: 1,
3323
3509
  messages: generatedMessages
@@ -3330,10 +3516,21 @@ async function completeBufferedSessionRun(run, response) {
3330
3516
  await run.sessionStore.saveSessionRunTranscript({
3331
3517
  id: run.session.id,
3332
3518
  runId: run.runId,
3333
- ...optionalTitle(run.body.message),
3519
+ ...optionalTitle(run.body.messages.at(-1)),
3334
3520
  transcript,
3335
3521
  status: "success"
3336
3522
  });
3523
+ if (response.memoryCompaction !== void 0 && !run.memoryCompactionLogged) {
3524
+ await appendSessionLog(
3525
+ run.sessionStore,
3526
+ memoryCompactedLog({
3527
+ sessionId: run.session.id,
3528
+ runId: run.runId,
3529
+ ...response.memoryCompaction
3530
+ })
3531
+ );
3532
+ run.memoryCompactionLogged = true;
3533
+ }
3337
3534
  await appendSessionLog(
3338
3535
  run.sessionStore,
3339
3536
  runCompletedLog({
@@ -3341,7 +3538,7 @@ async function completeBufferedSessionRun(run, response) {
3341
3538
  runId: run.runId,
3342
3539
  durationMs: durationMs2,
3343
3540
  usage: response.usage,
3344
- output: response.output,
3541
+ output: response.text,
3345
3542
  messageCount: response.messages.length
3346
3543
  })
3347
3544
  );
@@ -3358,17 +3555,14 @@ async function failBufferedSessionRun(run, error) {
3358
3555
  if (run.session === void 0 || run.sessionStore === void 0) {
3359
3556
  return;
3360
3557
  }
3361
- const messages = await run.sessionStore.load({
3362
- sessionId: run.session.id,
3363
- metadata: run.memoryMetadata
3364
- });
3365
3558
  const durationMs2 = Date.now() - run.runStartedAt;
3366
- const transcript = transcriptFromMessages(messages.slice(run.session.messageCount));
3559
+ const messages = run.failureMessages ?? [run.body.messages.at(-1)];
3560
+ const transcript = transcriptFromMessages([...messages]);
3367
3561
  assignTranscriptRunDuration(transcript, durationMs2);
3368
3562
  await run.sessionStore.saveSessionRunTranscript({
3369
3563
  id: run.session.id,
3370
3564
  runId: run.runId,
3371
- ...optionalTitle(run.body.message),
3565
+ ...optionalTitle(run.body.messages.at(-1)),
3372
3566
  transcript,
3373
3567
  status: "error",
3374
3568
  error: serializeError(error)
@@ -3378,14 +3572,14 @@ async function failBufferedSessionRun(run, error) {
3378
3572
  runFailedLog(run.session.id, run.runId, error, run.runStartedAt)
3379
3573
  );
3380
3574
  }
3381
- function normalizePromptMessage(message) {
3382
- return typeof message === "string" ? Message.user(message) : message;
3383
- }
3384
3575
  function usesStoreAsAgentMemory(agent, store) {
3385
3576
  const memoryStore = agent.memory?.store;
3386
3577
  return memoryStore !== void 0 && rawObservedStore(memoryStore) === rawObservedStore(store);
3387
3578
  }
3388
3579
 
3580
+ // src/runtime/approvals.ts
3581
+ import { getAgentApprovalRequestDetails } from "@anvia/core/internal/agent";
3582
+
3389
3583
  // src/runtime/query.ts
3390
3584
  function optionalQueryString(value) {
3391
3585
  const trimmed = value?.trim();
@@ -3491,22 +3685,11 @@ function createApprovalRuntime() {
3491
3685
  const approvals = /* @__PURE__ */ new Map();
3492
3686
  return {
3493
3687
  approvals,
3494
- createApprovals(context) {
3495
- return {
3496
- async handler(request) {
3497
- const approvalRequest = {
3498
- toolName: request.toolName,
3499
- internalCallId: request.internalCallId,
3500
- args: request.rawArgs
3501
- };
3502
- if (request.toolCallId !== void 0) approvalRequest.toolCallId = request.toolCallId;
3503
- if (request.reason !== void 0) approvalRequest.reason = request.reason;
3504
- if (request.rejectMessage !== void 0) {
3505
- approvalRequest.rejectMessage = request.rejectMessage;
3506
- }
3507
- const decision = await requestApproval(approvals, context, approvalRequest);
3508
- return approvalDecision(decision.approved, decision.reason);
3509
- }
3688
+ async request(context, approval) {
3689
+ const decision = await requestApproval(approvals, context, approval);
3690
+ return decision.approved ? { approved: true, ...decision.reason === void 0 ? {} : { reason: decision.reason } } : {
3691
+ approved: false,
3692
+ ...decision.reason === void 0 ? {} : { reason: decision.reason }
3510
3693
  };
3511
3694
  },
3512
3695
  list(options) {
@@ -3567,14 +3750,15 @@ function createApprovalRuntime() {
3567
3750
  };
3568
3751
  }
3569
3752
  async function requestApproval(approvals, context, request) {
3570
- const id = globalThis.crypto.randomUUID();
3753
+ const id = request.id;
3754
+ const details = getAgentApprovalRequestDetails(request);
3571
3755
  const approval = {
3572
3756
  id,
3573
3757
  runId: context.runId,
3574
3758
  agentId: context.agentId,
3575
3759
  toolName: request.toolName,
3576
- internalCallId: request.internalCallId,
3577
- args: request.args,
3760
+ internalCallId: details?.internalCallId ?? request.id,
3761
+ args: details?.rawArgs ?? JSON.stringify(request.input) ?? "null",
3578
3762
  status: "pending",
3579
3763
  requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
3580
3764
  resolve: () => {
@@ -3583,7 +3767,7 @@ async function requestApproval(approvals, context, request) {
3583
3767
  if (context.sessionId !== void 0) approval.sessionId = context.sessionId;
3584
3768
  if (request.toolCallId !== void 0) approval.callId = request.toolCallId;
3585
3769
  if (request.reason !== void 0) approval.reason = request.reason;
3586
- if (request.rejectMessage !== void 0) approval.rejectMessage = request.rejectMessage;
3770
+ if (details?.rejectMessage !== void 0) approval.rejectMessage = details.rejectMessage;
3587
3771
  if (context.emit !== void 0) approval.emit = context.emit;
3588
3772
  const decision = new Promise((resolve2) => {
3589
3773
  approval.resolve = (decision2) => {
@@ -3594,7 +3778,7 @@ async function requestApproval(approvals, context, request) {
3594
3778
  }
3595
3779
  return;
3596
3780
  }
3597
- const reason = decision2.approved ? decision2.reason : decision2.reason ?? request.rejectMessage ?? "Rejected in Anvia Studio.";
3781
+ const reason = decision2.approved ? decision2.reason : decision2.reason ?? details?.rejectMessage ?? "Rejected in Anvia Studio.";
3598
3782
  const resolved = resolveApproval(
3599
3783
  current,
3600
3784
  decision2.approved ? "approved" : "rejected",
@@ -3712,242 +3896,8 @@ function isRecord2(value) {
3712
3896
  return value !== null && typeof value === "object" && !Array.isArray(value);
3713
3897
  }
3714
3898
 
3715
- // src/runtime/tool-metadata.ts
3716
- import { ToolSet } from "@anvia/core/tool";
3717
- var MCP_TOOL_METADATA_KEY = /* @__PURE__ */ Symbol.for("anvia.mcp.tool.metadata");
3718
- function agentToolItems(agent) {
3719
- return [
3720
- ...agent.agent.toolSet.values().map((tool) => ({ tool, source: "static" })),
3721
- ...agent.agent.dynamicTools.flatMap((registration) => {
3722
- const maybeToolSet = registration.index.toolSet;
3723
- if (!(maybeToolSet instanceof ToolSet)) {
3724
- return [];
3725
- }
3726
- return maybeToolSet.values().map((tool) => ({ tool, source: "dynamic" }));
3727
- })
3728
- ];
3729
- }
3730
- function approvalMetadata(tool) {
3731
- const approval = tool.approval;
3732
- if (approval === void 0 || typeof approval !== "object" || approval === null) {
3733
- return { required: false };
3734
- }
3735
- const policy = approval;
3736
- const metadata = { required: true };
3737
- if (typeof policy.reason === "string") metadata.reason = policy.reason;
3738
- if (typeof policy.rejectMessage === "string") metadata.rejectMessage = policy.rejectMessage;
3739
- return metadata;
3740
- }
3741
- function mcpServerName(tool) {
3742
- const metadata = tool[MCP_TOOL_METADATA_KEY];
3743
- if (typeof metadata !== "object" || metadata === null) {
3744
- return void 0;
3745
- }
3746
- const serverName = metadata.serverName;
3747
- return typeof serverName === "string" && serverName.length > 0 ? serverName : void 0;
3748
- }
3749
- function agentHasMcpTools(agent) {
3750
- return agentToolItems(agent).some(({ tool }) => mcpServerName(tool) !== void 0);
3751
- }
3752
-
3753
- // src/runtime/config.ts
3754
- function runnerId(options) {
3755
- return options.id ?? "anvia-studio";
3756
- }
3757
- function agentConfig(agent) {
3758
- const name = agent.name ?? agent.agent.name;
3759
- const description = agent.description ?? agent.agent.description;
3760
- const config = {
3761
- id: agent.id,
3762
- quickPrompts: agent.quickPrompts ?? []
3763
- };
3764
- if (name !== void 0) config.name = name;
3765
- if (description !== void 0) config.description = description;
3766
- if (agent.metadata !== void 0) config.metadata = agent.metadata;
3767
- return config;
3768
- }
3769
- function agentRuntimeSummary(agent) {
3770
- const tools = agentToolItems(agent);
3771
- const name = agent.name ?? agent.agent.name;
3772
- const description = agent.description ?? agent.agent.description;
3773
- const summary = {
3774
- id: agent.id,
3775
- model: toJsonValue2(agent.agent.model),
3776
- toolCount: tools.length,
3777
- staticToolCount: tools.filter((item) => item.source === "static").length,
3778
- dynamicToolCount: tools.filter((item) => item.source === "dynamic").length,
3779
- approvalToolCount: tools.filter((item) => item.tool.approval !== void 0).length,
3780
- mcpToolCount: tools.filter((item) => mcpServerName(item.tool) !== void 0).length,
3781
- staticContextCount: agent.agent.staticContext.length,
3782
- dynamicContextCount: agent.agent.dynamicContexts.length,
3783
- observerCount: agent.agent.observers.length,
3784
- hasMemory: agent.agent.memory !== void 0,
3785
- hasHook: agent.agent.hook !== void 0,
3786
- hasOutputSchema: agent.agent.outputSchema !== void 0
3787
- };
3788
- if (name !== void 0) summary.name = name;
3789
- if (description !== void 0) summary.description = description;
3790
- if (agent.agent.defaultMaxTurns !== void 0) {
3791
- summary.defaultMaxTurns = agent.agent.defaultMaxTurns;
3792
- }
3793
- if (agent.metadata !== void 0) summary.metadata = agent.metadata;
3794
- return summary;
3795
- }
3796
- function pipelineConfig(pipeline) {
3797
- const graph = pipeline.pipeline.graph();
3798
- const stageNodes = graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output");
3799
- const config = {
3800
- id: pipeline.id,
3801
- stageCount: stageNodes.length,
3802
- edgeCount: graph.edges.length,
3803
- hasParallelStages: graph.nodes.some((node) => node.kind === "parallel"),
3804
- agentCount: graph.nodes.filter((node) => node.kind === "agent").length,
3805
- extractorCount: graph.nodes.filter((node) => node.kind === "extractor").length
3806
- };
3807
- if (pipeline.name !== void 0) config.name = pipeline.name;
3808
- if (pipeline.description !== void 0) config.description = pipeline.description;
3809
- if (pipeline.metadata !== void 0) config.metadata = pipeline.metadata;
3810
- return config;
3811
- }
3812
- function buildConfig(options, agents, pipelines, stores, sandboxCount = 0) {
3813
- const models = options.models === void 0 ? void 0 : studioModelsConfig(createStudioModelRegistry(options.models), agents);
3814
- const config = {
3815
- id: runnerId(options),
3816
- agents: agents.map(agentConfig),
3817
- pipelines: pipelines.map(pipelineConfig),
3818
- evals: options.evals.map(evalConfig),
3819
- chat: {
3820
- quickPrompts: Object.fromEntries(agents.map((agent) => [agent.id, agent.quickPrompts ?? []]))
3821
- },
3822
- capabilities: capabilityConfig(options, agents, pipelines, stores, sandboxCount),
3823
- unsupportedCapabilities: unsupportedCapabilities(stores)
3824
- };
3825
- if (options.name !== void 0) config.name = options.name;
3826
- if (options.description !== void 0) config.description = options.description;
3827
- if (options.version !== void 0) config.version = options.version;
3828
- if (models !== void 0) config.models = models;
3829
- return config;
3830
- }
3831
- function capabilityConfig(_options, agents, pipelines, stores, sandboxCount = 0) {
3832
- const capabilities = {
3833
- agents: { enabled: true },
3834
- observability: { enabled: true },
3835
- status: { enabled: true }
3836
- };
3837
- if (stores.sessions !== void 0) {
3838
- capabilities.sessions = { enabled: true };
3839
- }
3840
- if (stores.sessions !== void 0 || agents.some((agent) => agent.agent.memory !== void 0)) {
3841
- capabilities.memory = { enabled: true };
3842
- }
3843
- if (stores.traces !== void 0) {
3844
- capabilities.traces = { enabled: true };
3845
- }
3846
- if (pipelines.length > 0) {
3847
- capabilities.pipelines = { enabled: true };
3848
- }
3849
- if (_options.evals.length > 0) {
3850
- capabilities.evals = { enabled: true };
3851
- }
3852
- if (agents.some(
3853
- (agent) => agent.agent.toolSet.values().length > 0 || agent.agent.dynamicTools.length > 0
3854
- )) {
3855
- capabilities.tools = { enabled: true };
3856
- }
3857
- if (agents.some(agentHasMcpTools)) {
3858
- capabilities.mcps = { enabled: true };
3859
- }
3860
- if (sandboxCount > 0) {
3861
- capabilities.sandboxes = { enabled: true };
3862
- }
3863
- if (agents.some(
3864
- (agent) => agent.agent.hook !== void 0 || agent.agent.toolSet.values().some((tool) => tool.approval)
3865
- )) {
3866
- capabilities.approvals = { enabled: true };
3867
- }
3868
- if (agents.some(
3869
- (agent) => agent.agent.staticContext.length > 0 || agent.agent.dynamicContexts.length > 0 || agent.agent.dynamicTools.length > 0
3870
- )) {
3871
- capabilities.knowledge = { enabled: true };
3872
- }
3873
- return capabilities;
3874
- }
3875
- function unsupportedCapabilities(stores) {
3876
- const capabilities = [];
3877
- if (stores.sessions === void 0) capabilities.push("sessions");
3878
- if (stores.traces === void 0) capabilities.push("traces");
3879
- return capabilities;
3880
- }
3881
- function toJsonValue2(value) {
3882
- return serializeUnknown(value);
3883
- }
3884
-
3885
- // src/runtime/evals.ts
3886
- import { runEvalSuite } from "@anvia/core/evals";
3887
- function registerEvalRoutes(app, props) {
3888
- app.get(
3889
- "/evals",
3890
- (c) => c.json({
3891
- evals: props.evals.map(evalConfig)
3892
- })
3893
- );
3894
- app.get("/evals/:evalId", (c) => {
3895
- const suite = props.evalMap.get(c.req.param("evalId"));
3896
- if (suite === void 0) {
3897
- return errorResponse(c, 404, "not_found", "Eval suite not found");
3898
- }
3899
- return c.json(evalConfig(suite));
3900
- });
3901
- app.post("/evals/:evalId/runs", async (c) => {
3902
- const suite = props.evalMap.get(c.req.param("evalId"));
3903
- if (suite === void 0) {
3904
- return errorResponse(c, 404, "not_found", "Eval suite not found");
3905
- }
3906
- const body = await parseEvalRunRequest(c);
3907
- if ("error" in body) {
3908
- return body.error;
3909
- }
3910
- const runId = globalThis.crypto.randomUUID();
3911
- const startedAt = Date.now();
3912
- const runOptions = { ...suite };
3913
- if (body.concurrency !== void 0) runOptions.concurrency = body.concurrency;
3914
- const result = await runEvalSuite(runOptions);
3915
- const endedAt = Date.now();
3916
- const jsonResult = toJsonValue(result);
3917
- const response = {
3918
- runId,
3919
- suiteId: suite.id ?? suite.name,
3920
- startedAt: new Date(startedAt).toISOString(),
3921
- endedAt: new Date(endedAt).toISOString(),
3922
- durationMs: endedAt - startedAt,
3923
- result: isJsonObject(jsonResult) ? jsonResult : { value: jsonResult }
3924
- };
3925
- return c.json(response);
3926
- });
3927
- }
3928
- async function parseEvalRunRequest(c) {
3929
- let body = {};
3930
- try {
3931
- body = await c.req.json();
3932
- } catch {
3933
- body = {};
3934
- }
3935
- if (!isObject(body)) {
3936
- return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
3937
- }
3938
- const request = {};
3939
- if ("concurrency" in body) {
3940
- if (!isPositiveInteger(body.concurrency)) {
3941
- return {
3942
- error: errorResponse(c, 400, "bad_request", "concurrency must be a positive integer")
3943
- };
3944
- }
3945
- request.concurrency = body.concurrency;
3946
- }
3947
- return request;
3948
- }
3949
-
3950
3899
  // src/runtime/knowledge.ts
3900
+ import { getAgentToolState } from "@anvia/core/internal/agent";
3951
3901
  function registerKnowledgeRoutes(app, props) {
3952
3902
  app.get("/knowledge", async (c) => {
3953
3903
  const limit = parseLimit(c.req.query("limit"));
@@ -3984,12 +3934,17 @@ function registerKnowledgeRoutes(app, props) {
3984
3934
  return c.json(page);
3985
3935
  });
3986
3936
  }
3937
+ function agentHasKnowledge(agent) {
3938
+ const toolIndexes = getAgentToolState(agent.agent).toolIndexes;
3939
+ return agent.agent.context.length > 0 || toolIndexes.length > 0;
3940
+ }
3987
3941
  async function agentKnowledgeConfig(agent) {
3988
3942
  const agentName = agent.name ?? agent.agent.name;
3943
+ const staticContext = staticContextDocuments(agent.agent);
3989
3944
  const config = {
3990
3945
  agentId: agent.id,
3991
3946
  sources: await knowledgeSources(agent),
3992
- staticContext: agent.agent.staticContext.map((document) => {
3947
+ staticContext: staticContext.map((document) => {
3993
3948
  const item = { id: document.id, text: document.text };
3994
3949
  if (document.additionalProps !== void 0) {
3995
3950
  item.additionalProps = jsonObjectFromRecord(document.additionalProps);
@@ -4001,51 +3956,54 @@ async function agentKnowledgeConfig(agent) {
4001
3956
  return config;
4002
3957
  }
4003
3958
  async function knowledgeSources(agent) {
3959
+ const toolIndexes = getAgentToolState(agent.agent).toolIndexes;
3960
+ const staticContext = staticContextDocuments(agent.agent);
3961
+ const indexedContext = vectorContexts(agent.agent);
4004
3962
  const sources = [
4005
3963
  {
4006
3964
  sourceId: staticSourceId(),
4007
3965
  kind: "static_context",
4008
3966
  label: "Static context",
4009
- count: agent.agent.staticContext.length,
3967
+ count: staticContext.length,
4010
3968
  inspectable: true,
4011
- itemCount: agent.agent.staticContext.length
3969
+ itemCount: staticContext.length
4012
3970
  }
4013
3971
  ];
4014
3972
  const dynamicContextSources = await Promise.all(
4015
- agent.agent.dynamicContexts.map(async (registration, index) => {
4016
- const inspect = inspectFn(registration.index);
4017
- const count = await inspectableCount(inspect, registration.options.filter);
3973
+ indexedContext.map(async (vectorContext, index) => {
3974
+ const inspect = inspectFn(vectorContext.store);
3975
+ const count = await inspectableCount(inspect, vectorContext.filter);
4018
3976
  const source = {
4019
3977
  sourceId: dynamicContextSourceId(index),
4020
3978
  kind: "dynamic_context",
4021
3979
  label: `Dynamic context ${index + 1}`,
4022
3980
  count: 1,
4023
3981
  registrationIndex: index,
4024
- topK: registration.options.topK,
3982
+ topK: vectorContext.topK,
4025
3983
  inspectable: inspect !== void 0
4026
3984
  };
4027
- if (registration.options.threshold !== void 0) {
4028
- source.threshold = registration.options.threshold;
3985
+ if (vectorContext.minScore !== void 0) {
3986
+ source.minScore = vectorContext.minScore;
4029
3987
  }
4030
3988
  if (count !== void 0) source.itemCount = count;
4031
3989
  return source;
4032
3990
  })
4033
3991
  );
4034
3992
  const dynamicToolSources = await Promise.all(
4035
- agent.agent.dynamicTools.map(async (registration, index) => {
4036
- const inspect = inspectFn(registration.index);
4037
- const count = await inspectableCount(inspect, registration.options.filter);
3993
+ toolIndexes.map(async (toolIndex, index) => {
3994
+ const inspect = inspectFn(toolIndex);
3995
+ const count = await inspectableCount(inspect, toolIndex.filter);
4038
3996
  const source = {
4039
3997
  sourceId: dynamicToolsSourceId(index),
4040
3998
  kind: "dynamic_tools",
4041
3999
  label: `Dynamic tools ${index + 1}`,
4042
4000
  count: 1,
4043
4001
  registrationIndex: index,
4044
- topK: registration.options.topK,
4002
+ topK: toolIndex.topK,
4045
4003
  inspectable: inspect !== void 0
4046
4004
  };
4047
- if (registration.options.threshold !== void 0) {
4048
- source.threshold = registration.options.threshold;
4005
+ if (toolIndex.minScore !== void 0) {
4006
+ source.minScore = toolIndex.minScore;
4049
4007
  }
4050
4008
  if (count !== void 0) source.itemCount = count;
4051
4009
  return source;
@@ -4064,20 +4022,20 @@ async function knowledgeItemsPage(agent, sourceId, request) {
4064
4022
  if (sourceId === staticSourceId()) {
4065
4023
  return staticKnowledgeItemsPage(agent, request);
4066
4024
  }
4067
- const dynamicContextIndex = dynamicSourceIndex(sourceId, "dynamic_context");
4068
- if (dynamicContextIndex !== void 0) {
4069
- const registration = agent.agent.dynamicContexts[dynamicContextIndex];
4070
- if (registration === void 0) {
4025
+ const vectorContextIndex = dynamicSourceIndex(sourceId, "dynamic_context");
4026
+ if (vectorContextIndex !== void 0) {
4027
+ const vectorContext = vectorContexts(agent.agent)[vectorContextIndex];
4028
+ if (vectorContext === void 0) {
4071
4029
  return void 0;
4072
4030
  }
4073
- const inspect = inspectFn(registration.index);
4031
+ const inspect = inspectFn(vectorContext.store);
4074
4032
  if (inspect === void 0) {
4075
4033
  return nonInspectablePage(agent.id, sourceId, "dynamic_context");
4076
4034
  }
4077
4035
  const page = await inspect({
4078
4036
  limit: request.limit,
4079
4037
  cursor: request.cursor,
4080
- filter: registration.options.filter
4038
+ filter: vectorContext.filter
4081
4039
  });
4082
4040
  const result = {
4083
4041
  agentId: agent.id,
@@ -4092,18 +4050,18 @@ async function knowledgeItemsPage(agent, sourceId, request) {
4092
4050
  }
4093
4051
  const dynamicToolsIndex = dynamicSourceIndex(sourceId, "dynamic_tools");
4094
4052
  if (dynamicToolsIndex !== void 0) {
4095
- const registration = agent.agent.dynamicTools[dynamicToolsIndex];
4096
- if (registration === void 0) {
4053
+ const toolIndex = getAgentToolState(agent.agent).toolIndexes[dynamicToolsIndex];
4054
+ if (toolIndex === void 0) {
4097
4055
  return void 0;
4098
4056
  }
4099
- const inspect = inspectFn(registration.index);
4057
+ const inspect = inspectFn(toolIndex);
4100
4058
  if (inspect === void 0) {
4101
4059
  return nonInspectablePage(agent.id, sourceId, "dynamic_tools");
4102
4060
  }
4103
4061
  const page = await inspect({
4104
4062
  limit: request.limit,
4105
4063
  cursor: request.cursor,
4106
- filter: registration.options.filter
4064
+ filter: toolIndex.filter
4107
4065
  });
4108
4066
  const result = {
4109
4067
  agentId: agent.id,
@@ -4118,16 +4076,17 @@ async function knowledgeItemsPage(agent, sourceId, request) {
4118
4076
  }
4119
4077
  return void 0;
4120
4078
  }
4121
- function inspectFn(index) {
4122
- if (!isRecord3(index) || typeof index.inspect !== "function") {
4079
+ function inspectFn(store) {
4080
+ if (!isRecord3(store) || typeof store.inspect !== "function") {
4123
4081
  return void 0;
4124
4082
  }
4125
- const inspect = index.inspect;
4126
- return (request) => inspect.call(index, request);
4083
+ const inspect = store.inspect;
4084
+ return (request) => inspect.call(store, request);
4127
4085
  }
4128
4086
  function staticKnowledgeItemsPage(agent, request) {
4087
+ const staticContext = staticContextDocuments(agent.agent);
4129
4088
  const start = Math.max(0, Math.trunc(Number(request.cursor ?? "0")));
4130
- const page = agent.agent.staticContext.slice(start, start + request.limit);
4089
+ const page = staticContext.slice(start, start + request.limit);
4131
4090
  const nextOffset = start + page.length;
4132
4091
  const result = {
4133
4092
  agentId: agent.id,
@@ -4145,9 +4104,9 @@ function staticKnowledgeItemsPage(agent, request) {
4145
4104
  }
4146
4105
  return item;
4147
4106
  }),
4148
- totalCount: agent.agent.staticContext.length
4107
+ totalCount: staticContext.length
4149
4108
  };
4150
- if (nextOffset < agent.agent.staticContext.length) result.nextCursor = String(nextOffset);
4109
+ if (nextOffset < staticContext.length) result.nextCursor = String(nextOffset);
4151
4110
  return result;
4152
4111
  }
4153
4112
  function nonInspectablePage(agentId, sourceId, kind) {
@@ -4275,65 +4234,299 @@ function queryFromGenerationInput(value) {
4275
4234
  }
4276
4235
  }
4277
4236
  }
4278
- return void 0;
4237
+ return void 0;
4238
+ }
4239
+ function messageText(value) {
4240
+ if (typeof value === "string") {
4241
+ return value.trim();
4242
+ }
4243
+ if (!isRecord3(value)) {
4244
+ return "";
4245
+ }
4246
+ if (typeof value.text === "string") {
4247
+ return value.text.trim();
4248
+ }
4249
+ if (typeof value.content === "string") {
4250
+ return value.content.trim();
4251
+ }
4252
+ if (Array.isArray(value.content)) {
4253
+ return value.content.map(contentText).filter(Boolean).join("\n").trim();
4254
+ }
4255
+ return "";
4256
+ }
4257
+ function contentText(value) {
4258
+ if (typeof value === "string") {
4259
+ return value.trim();
4260
+ }
4261
+ if (!isRecord3(value)) {
4262
+ return "";
4263
+ }
4264
+ if (typeof value.text === "string") {
4265
+ return value.text.trim();
4266
+ }
4267
+ return "";
4268
+ }
4269
+ function evidenceDocument(value) {
4270
+ if (!isRecord3(value)) {
4271
+ return [];
4272
+ }
4273
+ const id = typeof value.id === "string" ? value.id : void 0;
4274
+ const text = typeof value.text === "string" ? value.text : void 0;
4275
+ const additionalProps = isRecord3(value.additionalProps) ? jsonObjectFromRecord(value.additionalProps) : void 0;
4276
+ if (id === void 0 && text === void 0 && additionalProps === void 0) {
4277
+ return [];
4278
+ }
4279
+ const document = {};
4280
+ if (id !== void 0) document.id = id;
4281
+ if (text !== void 0) document.text = text;
4282
+ if (additionalProps !== void 0) document.additionalProps = additionalProps;
4283
+ return [document];
4284
+ }
4285
+ function evidenceToolName(value) {
4286
+ if (!isRecord3(value) || typeof value.name !== "string") {
4287
+ return [];
4288
+ }
4289
+ return [value.name];
4290
+ }
4291
+ function jsonObjectFromRecord(value) {
4292
+ return compactJsonObject(value);
4293
+ }
4294
+ function isRecord3(value) {
4295
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4296
+ }
4297
+
4298
+ // src/runtime/tool-metadata.ts
4299
+ import { getAgentToolState as getAgentToolState2 } from "@anvia/core/internal/agent";
4300
+ import { isMcpTool } from "@anvia/core/mcp";
4301
+ function agentToolItems(agent) {
4302
+ const state = getAgentToolState2(agent.agent);
4303
+ const items = state.staticTools.map((tool) => ({ tool, source: "static" }));
4304
+ const names = new Set(items.map(({ tool }) => tool.name));
4305
+ for (const index of state.toolIndexes) {
4306
+ for (const tool of index.tools) {
4307
+ if (!names.has(tool.name)) {
4308
+ names.add(tool.name);
4309
+ items.push({ tool, source: "dynamic" });
4310
+ }
4311
+ }
4312
+ }
4313
+ return items;
4314
+ }
4315
+ function approvalMetadata(tool) {
4316
+ const approval = tool.requiresApproval;
4317
+ if (approval === void 0 || approval === false) {
4318
+ return { required: false };
4319
+ }
4320
+ if (typeof approval !== "object" || approval === null) {
4321
+ return { required: true };
4322
+ }
4323
+ const policy = approval;
4324
+ const metadata = { required: true };
4325
+ if (typeof policy.reason === "string") metadata.reason = policy.reason;
4326
+ return metadata;
4327
+ }
4328
+ function toolRequiresApproval(tool) {
4329
+ const approval = tool.requiresApproval;
4330
+ return approval !== void 0 && approval !== false;
4331
+ }
4332
+ function mcpServerName(tool) {
4333
+ return isMcpTool(tool) ? tool.mcp.serverName : void 0;
4334
+ }
4335
+ function agentHasMcpServers(agent) {
4336
+ return agent.agent.mcpServers.length > 0;
4337
+ }
4338
+
4339
+ // src/runtime/config.ts
4340
+ function runnerId(options) {
4341
+ return options.id ?? "anvia-studio";
4342
+ }
4343
+ function agentConfig(agent) {
4344
+ const name = agent.name ?? agent.agent.name;
4345
+ const description = agent.description ?? agent.agent.description;
4346
+ const config = {
4347
+ id: agent.id,
4348
+ quickPrompts: agent.quickPrompts ?? []
4349
+ };
4350
+ if (name !== void 0) config.name = name;
4351
+ if (description !== void 0) config.description = description;
4352
+ if (agent.metadata !== void 0) config.metadata = agent.metadata;
4353
+ return config;
4354
+ }
4355
+ function agentRuntimeSummary(agent) {
4356
+ const tools = agentToolItems(agent);
4357
+ const staticContext = staticContextDocuments(agent.agent);
4358
+ const indexedContext = vectorContexts(agent.agent);
4359
+ const name = agent.name ?? agent.agent.name;
4360
+ const description = agent.description ?? agent.agent.description;
4361
+ const summary = {
4362
+ id: agent.id,
4363
+ model: toJsonValue2(agent.agent.model),
4364
+ toolCount: tools.length,
4365
+ staticToolCount: tools.filter((item) => item.source === "static").length,
4366
+ dynamicToolCount: tools.filter((item) => item.source === "dynamic").length,
4367
+ approvalToolCount: tools.filter((item) => toolRequiresApproval(item.tool)).length,
4368
+ mcpToolCount: tools.filter((item) => mcpServerName(item.tool) !== void 0).length,
4369
+ staticContextCount: staticContext.length,
4370
+ dynamicContextCount: indexedContext.length,
4371
+ observerCount: Object.keys(agent.agent.observability?.observers ?? {}).length,
4372
+ hasMemory: agent.agent.memory !== void 0,
4373
+ hasLifecycle: agent.agent.lifecycle !== void 0,
4374
+ hasOutputSchema: agent.agent.outputSchema !== void 0
4375
+ };
4376
+ if (name !== void 0) summary.name = name;
4377
+ if (description !== void 0) summary.description = description;
4378
+ if (agent.agent.defaultMaxTurns !== void 0) {
4379
+ summary.defaultMaxTurns = agent.agent.defaultMaxTurns;
4380
+ }
4381
+ if (agent.metadata !== void 0) summary.metadata = agent.metadata;
4382
+ return summary;
4279
4383
  }
4280
- function messageText(value) {
4281
- if (typeof value === "string") {
4282
- return value.trim();
4384
+ function pipelineConfig(pipeline) {
4385
+ const graph = pipeline.pipeline.graph();
4386
+ const stageNodes = graph.nodes.filter((node) => node.kind !== "input" && node.kind !== "output");
4387
+ const config = {
4388
+ id: pipeline.id,
4389
+ stageCount: stageNodes.length,
4390
+ edgeCount: graph.edges.length,
4391
+ hasParallelStages: graph.nodes.some((node) => node.kind === "parallel"),
4392
+ agentCount: graph.nodes.filter((node) => node.kind === "agent").length,
4393
+ extractorCount: graph.nodes.filter((node) => node.kind === "extractor").length
4394
+ };
4395
+ if (pipeline.name !== void 0) config.name = pipeline.name;
4396
+ if (pipeline.description !== void 0) config.description = pipeline.description;
4397
+ if (pipeline.metadata !== void 0) config.metadata = pipeline.metadata;
4398
+ return config;
4399
+ }
4400
+ function buildConfig(options, agents, pipelines, stores, sandboxCount = 0) {
4401
+ const models = options.models === void 0 ? void 0 : studioModelsConfig(createStudioModelRegistry(options.models), agents);
4402
+ const config = {
4403
+ id: runnerId(options),
4404
+ agents: agents.map(agentConfig),
4405
+ pipelines: pipelines.map(pipelineConfig),
4406
+ evals: options.evals.map(evalConfig),
4407
+ chat: {
4408
+ quickPrompts: Object.fromEntries(agents.map((agent) => [agent.id, agent.quickPrompts ?? []]))
4409
+ },
4410
+ capabilities: capabilityConfig(options, agents, pipelines, stores, sandboxCount),
4411
+ unsupportedCapabilities: unsupportedCapabilities(stores)
4412
+ };
4413
+ if (options.name !== void 0) config.name = options.name;
4414
+ if (options.description !== void 0) config.description = options.description;
4415
+ if (options.version !== void 0) config.version = options.version;
4416
+ if (models !== void 0) config.models = models;
4417
+ return config;
4418
+ }
4419
+ function capabilityConfig(_options, agents, pipelines, stores, sandboxCount = 0) {
4420
+ const capabilities = {
4421
+ agents: { enabled: true },
4422
+ observability: { enabled: true },
4423
+ status: { enabled: true }
4424
+ };
4425
+ if (stores.sessions !== void 0) {
4426
+ capabilities.sessions = { enabled: true };
4283
4427
  }
4284
- if (!isRecord3(value)) {
4285
- return "";
4428
+ if (stores.sessions !== void 0 || agents.some((agent) => agent.agent.memory !== void 0)) {
4429
+ capabilities.memory = { enabled: true };
4286
4430
  }
4287
- if (typeof value.text === "string") {
4288
- return value.text.trim();
4431
+ if (stores.traces !== void 0) {
4432
+ capabilities.traces = { enabled: true };
4289
4433
  }
4290
- if (typeof value.content === "string") {
4291
- return value.content.trim();
4434
+ if (pipelines.length > 0) {
4435
+ capabilities.pipelines = { enabled: true };
4292
4436
  }
4293
- if (Array.isArray(value.content)) {
4294
- return value.content.map(contentText).filter(Boolean).join("\n").trim();
4437
+ if (_options.evals.length > 0) {
4438
+ capabilities.evals = { enabled: true };
4295
4439
  }
4296
- return "";
4297
- }
4298
- function contentText(value) {
4299
- if (typeof value === "string") {
4300
- return value.trim();
4440
+ if (agents.some((agent) => agent.agent.tools.length > 0)) {
4441
+ capabilities.tools = { enabled: true };
4301
4442
  }
4302
- if (!isRecord3(value)) {
4303
- return "";
4443
+ if (agents.some(agentHasMcpServers)) {
4444
+ capabilities.mcps = { enabled: true };
4304
4445
  }
4305
- if (typeof value.text === "string") {
4306
- return value.text.trim();
4446
+ if (sandboxCount > 0) {
4447
+ capabilities.sandboxes = { enabled: true };
4307
4448
  }
4308
- return "";
4309
- }
4310
- function evidenceDocument(value) {
4311
- if (!isRecord3(value)) {
4312
- return [];
4449
+ if (agents.some((agent) => agent.agent.tools.some(toolRequiresApproval))) {
4450
+ capabilities.approvals = { enabled: true };
4313
4451
  }
4314
- const id = typeof value.id === "string" ? value.id : void 0;
4315
- const text = typeof value.text === "string" ? value.text : void 0;
4316
- const additionalProps = isRecord3(value.additionalProps) ? jsonObjectFromRecord(value.additionalProps) : void 0;
4317
- if (id === void 0 && text === void 0 && additionalProps === void 0) {
4318
- return [];
4452
+ if (agents.some(agentHasKnowledge)) {
4453
+ capabilities.knowledge = { enabled: true };
4319
4454
  }
4320
- const document = {};
4321
- if (id !== void 0) document.id = id;
4322
- if (text !== void 0) document.text = text;
4323
- if (additionalProps !== void 0) document.additionalProps = additionalProps;
4324
- return [document];
4455
+ return capabilities;
4325
4456
  }
4326
- function evidenceToolName(value) {
4327
- if (!isRecord3(value) || typeof value.name !== "string") {
4328
- return [];
4329
- }
4330
- return [value.name];
4457
+ function unsupportedCapabilities(stores) {
4458
+ const capabilities = [];
4459
+ if (stores.sessions === void 0) capabilities.push("sessions");
4460
+ if (stores.traces === void 0) capabilities.push("traces");
4461
+ return capabilities;
4331
4462
  }
4332
- function jsonObjectFromRecord(value) {
4333
- return compactJsonObject(value);
4463
+ function toJsonValue2(value) {
4464
+ return serializeUnknown(value);
4334
4465
  }
4335
- function isRecord3(value) {
4336
- return typeof value === "object" && value !== null && !Array.isArray(value);
4466
+
4467
+ // src/runtime/evals.ts
4468
+ import { runEvalSuite } from "@anvia/core/evals";
4469
+ function registerEvalRoutes(app, props) {
4470
+ app.get(
4471
+ "/evals",
4472
+ (c) => c.json({
4473
+ evals: props.evals.map(evalConfig)
4474
+ })
4475
+ );
4476
+ app.get("/evals/:evalId", (c) => {
4477
+ const suite = props.evalMap.get(c.req.param("evalId"));
4478
+ if (suite === void 0) {
4479
+ return errorResponse(c, 404, "not_found", "Eval suite not found");
4480
+ }
4481
+ return c.json(evalConfig(suite));
4482
+ });
4483
+ app.post("/evals/:evalId/runs", async (c) => {
4484
+ const suite = props.evalMap.get(c.req.param("evalId"));
4485
+ if (suite === void 0) {
4486
+ return errorResponse(c, 404, "not_found", "Eval suite not found");
4487
+ }
4488
+ const body = await parseEvalRunRequest(c);
4489
+ if ("error" in body) {
4490
+ return body.error;
4491
+ }
4492
+ const runId = globalThis.crypto.randomUUID();
4493
+ const startedAt = Date.now();
4494
+ const runOptions = { ...suite };
4495
+ if (body.concurrency !== void 0) runOptions.concurrency = body.concurrency;
4496
+ const result = await runEvalSuite(runOptions);
4497
+ const endedAt = Date.now();
4498
+ const jsonResult = toJsonValue(result);
4499
+ const response = {
4500
+ runId,
4501
+ suiteId: suite.id ?? suite.name,
4502
+ startedAt: new Date(startedAt).toISOString(),
4503
+ endedAt: new Date(endedAt).toISOString(),
4504
+ durationMs: endedAt - startedAt,
4505
+ result: isJsonObject(jsonResult) ? jsonResult : { value: jsonResult }
4506
+ };
4507
+ return c.json(response);
4508
+ });
4509
+ }
4510
+ async function parseEvalRunRequest(c) {
4511
+ let body = {};
4512
+ try {
4513
+ body = await c.req.json();
4514
+ } catch {
4515
+ body = {};
4516
+ }
4517
+ if (!isObject(body)) {
4518
+ return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
4519
+ }
4520
+ const request = {};
4521
+ if ("concurrency" in body) {
4522
+ if (!isPositiveInteger(body.concurrency)) {
4523
+ return {
4524
+ error: errorResponse(c, 400, "bad_request", "concurrency must be a positive integer")
4525
+ };
4526
+ }
4527
+ request.concurrency = body.concurrency;
4528
+ }
4529
+ return request;
4337
4530
  }
4338
4531
 
4339
4532
  // src/runtime/mcps.ts
@@ -4351,43 +4544,29 @@ function registerMcpRoutes(app, props) {
4351
4544
  });
4352
4545
  }
4353
4546
  async function agentMcpMetadata(agent) {
4354
- const servers = /* @__PURE__ */ new Map();
4355
- const seen = /* @__PURE__ */ new Set();
4356
- for (const { tool, source } of agentToolItems(agent)) {
4357
- const serverName = mcpServerName(tool);
4358
- if (serverName === void 0) {
4359
- continue;
4360
- }
4361
- const definition = await tool.definition("");
4362
- const key = `${serverName}:${source}:${definition.name}`;
4363
- if (seen.has(key)) {
4364
- continue;
4365
- }
4366
- seen.add(key);
4367
- const tools = servers.get(serverName) ?? [];
4368
- tools.push({
4369
- name: definition.name,
4370
- description: definition.description,
4371
- parameters: definition.parameters,
4372
- source,
4373
- approval: approvalMetadata(tool)
4374
- });
4375
- servers.set(serverName, tools);
4376
- }
4377
- return [...servers.entries()].map(([name, tools]) => {
4378
- const sortedTools = tools.sort((left, right) => {
4379
- if (left.source !== right.source) {
4380
- return left.source === "static" ? -1 : 1;
4381
- }
4382
- return left.name.localeCompare(right.name);
4383
- });
4384
- return {
4385
- agentId: agent.id,
4386
- name,
4387
- toolCount: sortedTools.length,
4388
- tools: sortedTools
4389
- };
4390
- }).sort((left, right) => left.name.localeCompare(right.name));
4547
+ return Promise.all(
4548
+ agent.agent.mcpServers.map(async (server) => {
4549
+ const tools = await Promise.all(
4550
+ server.tools.map(async (tool) => {
4551
+ const definition = await tool.definition("");
4552
+ return {
4553
+ name: definition.name,
4554
+ description: definition.description,
4555
+ parameters: definition.parameters,
4556
+ source: "static",
4557
+ approval: approvalMetadata(tool)
4558
+ };
4559
+ })
4560
+ );
4561
+ const sortedTools = tools.sort((left, right) => left.name.localeCompare(right.name));
4562
+ return {
4563
+ agentId: agent.id,
4564
+ name: server.name,
4565
+ toolCount: sortedTools.length,
4566
+ tools: sortedTools
4567
+ };
4568
+ })
4569
+ ).then((servers) => servers.sort((left, right) => left.name.localeCompare(right.name)));
4391
4570
  }
4392
4571
 
4393
4572
  // src/runtime/memory.ts
@@ -4609,7 +4788,7 @@ function agentMemorySource(ref, label, agentId, storeKindValue, inspector) {
4609
4788
  ).slice(0, options.limit);
4610
4789
  },
4611
4790
  async getConversation(conversationRef) {
4612
- const conversation = await inspector.getConversation(conversationRef);
4791
+ const conversation = await inspector.getConversation({ ref: conversationRef });
4613
4792
  return conversation === void 0 ? void 0 : inspectorConversationDetail(conversation, summary.agentIds);
4614
4793
  }
4615
4794
  };
@@ -4832,12 +5011,12 @@ function pipelineRunFailedLog(pipelineId, runId, error, startedAt) {
4832
5011
  }
4833
5012
  };
4834
5013
  }
4835
- function pipelineStageLog(pipelineId, runId, event) {
5014
+ function pipelineStageLog(event, studioPipelineId = event.pipelineId) {
4836
5015
  const category = stageCategory(event.node);
4837
5016
  if (event.type === "stage_started") {
4838
5017
  return {
4839
- pipelineId,
4840
- runId,
5018
+ pipelineId: studioPipelineId,
5019
+ runId: event.runId,
4841
5020
  level: "debug",
4842
5021
  category,
4843
5022
  event: `${event.node.kind}.started`,
@@ -4847,8 +5026,8 @@ function pipelineStageLog(pipelineId, runId, event) {
4847
5026
  }
4848
5027
  if (event.type === "stage_completed") {
4849
5028
  return {
4850
- pipelineId,
4851
- runId,
5029
+ pipelineId: studioPipelineId,
5030
+ runId: event.runId,
4852
5031
  level: "debug",
4853
5032
  category,
4854
5033
  event: `${event.node.kind}.completed`,
@@ -4860,8 +5039,8 @@ function pipelineStageLog(pipelineId, runId, event) {
4860
5039
  };
4861
5040
  }
4862
5041
  return {
4863
- pipelineId,
4864
- runId,
5042
+ pipelineId: studioPipelineId,
5043
+ runId: event.runId,
4865
5044
  level: "error",
4866
5045
  category,
4867
5046
  event: `${event.node.kind}.failed`,
@@ -4888,6 +5067,7 @@ function stageCategory(node) {
4888
5067
  function nodeMetadata(node) {
4889
5068
  const metadata = {
4890
5069
  nodeId: node.id,
5070
+ nodePath: [...node.path],
4891
5071
  kind: node.kind,
4892
5072
  label: node.label
4893
5073
  };
@@ -5049,17 +5229,24 @@ async function executePipelineRun(c, props, pipeline, body) {
5049
5229
  if (body.metadata !== void 0) streamOptions.metadata = body.metadata;
5050
5230
  if (props.logStore !== void 0) streamOptions.logStore = props.logStore;
5051
5231
  if (props.runStore !== void 0) streamOptions.runStore = props.runStore;
5232
+ streamOptions.abortSignal = c.req.raw.signal;
5052
5233
  return streamPipelineRun(c, streamOptions);
5053
5234
  }
5054
5235
  try {
5055
5236
  await appendPipelineLog(props.logStore, pipelineRunStartedLog(pipeline, runId));
5056
- const output = await pipeline.pipeline.run(body.input, {
5237
+ const result = await pipeline.pipeline.run({
5238
+ input: body.input,
5239
+ runId,
5240
+ metadata: body.metadata,
5241
+ abortSignal: c.req.raw.signal,
5057
5242
  observer: {
5058
5243
  async onEvent(event) {
5059
- await appendPipelineLog(props.logStore, pipelineStageLog(pipeline.id, runId, event));
5244
+ await appendPipelineLog(props.logStore, pipelineStageLog(event, pipeline.id));
5060
5245
  }
5061
- }
5246
+ },
5247
+ failOnObserverError: true
5062
5248
  });
5249
+ const output = result.output;
5063
5250
  const jsonOutput = toJsonValue(output);
5064
5251
  const endedAt = Date.now();
5065
5252
  const successRecord = {
@@ -5124,19 +5311,24 @@ function streamPipelineRun(_c, props) {
5124
5311
  async function* pipelineRunEvents(props) {
5125
5312
  yield* emitPipelineLog(props.logStore, pipelineRunStartedLog(props.pipeline, props.runId));
5126
5313
  const events = new AsyncEventQueue();
5127
- const run = props.pipeline.pipeline.run(props.input, {
5314
+ const run = props.pipeline.pipeline.run({
5315
+ input: props.input,
5316
+ runId: props.runId,
5317
+ metadata: props.metadata,
5318
+ abortSignal: props.abortSignal,
5128
5319
  observer: {
5129
5320
  async onEvent(event) {
5130
5321
  const log = await appendPipelineLog(
5131
5322
  props.logStore,
5132
- pipelineStageLog(props.pipeline.id, props.runId, event)
5323
+ pipelineStageLog(event, props.pipeline.id)
5133
5324
  );
5134
5325
  if (log !== void 0) {
5135
5326
  events.push({ type: "pipeline_log", log });
5136
5327
  }
5137
5328
  }
5138
- }
5139
- }).then(async (output) => {
5329
+ },
5330
+ failOnObserverError: true
5331
+ }).then(async ({ output }) => {
5140
5332
  const jsonOutput = toJsonValue(output);
5141
5333
  const endedAt = Date.now();
5142
5334
  const successRecord = {
@@ -5290,7 +5482,7 @@ function parsePipelineLogAfter(value) {
5290
5482
  }
5291
5483
 
5292
5484
  // src/runtime/questions.ts
5293
- import { createHook as createHook2 } from "@anvia/core/hooks";
5485
+ import { createHook } from "@anvia/core/internal/agent";
5294
5486
  import { parseToolArgs } from "@anvia/core/tool";
5295
5487
  function registerQuestionRoutes(app, questions) {
5296
5488
  app.get("/questions", (c) => {
@@ -5383,7 +5575,7 @@ function createQuestionRuntime() {
5383
5575
  return {
5384
5576
  questions,
5385
5577
  createHook(context) {
5386
- return createHook2({
5578
+ return createHook({
5387
5579
  async onToolCall({ toolName, toolCallId, internalCallId, args, tool: control }) {
5388
5580
  if (toolName !== "ask_question") {
5389
5581
  return control.run();
@@ -6140,6 +6332,16 @@ function createInMemoryStudioStore() {
6140
6332
  }
6141
6333
  var InMemoryStudioStore = class {
6142
6334
  kind = "memory";
6335
+ compaction = {
6336
+ snapshot: ({ scope }) => {
6337
+ const messages = this.sessions.get(scope.sessionId)?.messages ?? [];
6338
+ return Promise.resolve({
6339
+ revision: memoryRevision(messages),
6340
+ messages: cloneMessages(messages)
6341
+ });
6342
+ },
6343
+ replacePrefix: (options) => this.replaceCompactionPrefix(options)
6344
+ };
6143
6345
  sessions = /* @__PURE__ */ new Map();
6144
6346
  traces = /* @__PURE__ */ new Map();
6145
6347
  pipelineLogs = /* @__PURE__ */ new Map();
@@ -6181,20 +6383,20 @@ var InMemoryStudioStore = class {
6181
6383
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
6182
6384
  return materializeSession(session);
6183
6385
  }
6184
- load(context) {
6185
- return Promise.resolve(this.sessions.get(context.sessionId)?.messages ?? []);
6386
+ load({ scope }) {
6387
+ return Promise.resolve(cloneMessages(this.sessions.get(scope.sessionId)?.messages ?? []));
6186
6388
  }
6187
6389
  append(input) {
6188
- const session = this.sessions.get(input.context.sessionId);
6390
+ const session = this.sessions.get(input.scope.sessionId);
6189
6391
  if (session !== void 0) {
6190
- session.messages.push(...input.messages);
6392
+ session.messages.push(...cloneMessages(input.messages));
6191
6393
  session.messageCount = session.messages.length;
6192
6394
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
6193
6395
  }
6194
6396
  return Promise.resolve();
6195
6397
  }
6196
- clear(context) {
6197
- const session = this.sessions.get(context.sessionId);
6398
+ clear({ scope }) {
6399
+ const session = this.sessions.get(scope.sessionId);
6198
6400
  if (session !== void 0) {
6199
6401
  session.messages = [];
6200
6402
  session.runs = [];
@@ -6205,13 +6407,26 @@ var InMemoryStudioStore = class {
6205
6407
  }
6206
6408
  async recordError(input) {
6207
6409
  await this.saveSessionRunTranscript({
6208
- id: input.context.sessionId,
6209
- runId: studioRunId(input.context) ?? input.runId,
6410
+ id: input.scope.sessionId,
6411
+ runId: studioRunId(input.scope) ?? input.runId,
6210
6412
  transcript: transcriptFromMessages(input.messages),
6211
6413
  status: "error",
6212
6414
  error: serializeJsonError(input.error)
6213
6415
  });
6214
6416
  }
6417
+ replaceCompactionPrefix(input) {
6418
+ if (!Number.isSafeInteger(input.messageCount) || input.messageCount < 1) {
6419
+ throw new RangeError("messageCount must be a positive integer.");
6420
+ }
6421
+ const session = this.sessions.get(input.scope.sessionId);
6422
+ if (session === void 0 || memoryRevision(session.messages) !== input.revision || input.messageCount > session.messages.length) {
6423
+ return Promise.resolve({ status: "conflict" });
6424
+ }
6425
+ session.messages.splice(0, input.messageCount, structuredClone(input.replacement));
6426
+ session.messageCount = session.messages.length;
6427
+ session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
6428
+ return Promise.resolve({ status: "committed" });
6429
+ }
6215
6430
  saveSessionRunTranscript(input) {
6216
6431
  const session = this.sessions.get(input.id);
6217
6432
  if (session === void 0) {
@@ -6337,18 +6552,24 @@ function sessionSummary(session) {
6337
6552
  function materializeSession(session) {
6338
6553
  return {
6339
6554
  ...sessionSummary(session),
6340
- messages: [...session.messages],
6555
+ messages: cloneMessages(session.messages),
6341
6556
  transcript: renumberTranscript(session.runs.flatMap((run) => run.transcript))
6342
6557
  };
6343
6558
  }
6559
+ function cloneMessages(messages) {
6560
+ return structuredClone([...messages]);
6561
+ }
6344
6562
  function traceAgentId(trace) {
6345
6563
  const nestedMetadata = trace.metadata?.metadata;
6346
6564
  return isJsonObject(nestedMetadata) && typeof nestedMetadata.agentId === "string" ? nestedMetadata.agentId : void 0;
6347
6565
  }
6348
- function studioRunId(context) {
6349
- const value = context.metadata?.studioRunId;
6566
+ function studioRunId(scope) {
6567
+ const value = scope.metadata?.studioRunId;
6350
6568
  return typeof value === "string" && value.length > 0 ? value : void 0;
6351
6569
  }
6570
+ function memoryRevision(messages) {
6571
+ return JSON.stringify(messages);
6572
+ }
6352
6573
  function serializeJsonError(error) {
6353
6574
  if (error instanceof Error) {
6354
6575
  return {
@@ -6820,7 +7041,7 @@ function waitForShutdown(signal) {
6820
7041
  });
6821
7042
  }
6822
7043
  function studioOptionsFromTargets(targets, options) {
6823
- const agents = targets.filter((target) => target instanceof Agent2);
7044
+ const agents = targets.filter((target) => target instanceof Agent);
6824
7045
  const pipelines = targets.filter(
6825
7046
  // biome-ignore lint/suspicious/noExplicitAny: Studio accepts heterogeneous user pipelines.
6826
7047
  (target) => target instanceof Pipeline
@@ -6873,13 +7094,13 @@ function uniqueAgentId(baseId, ids) {
6873
7094
  }
6874
7095
  function agentMetadata(agent) {
6875
7096
  const metadata = {
6876
- staticContextCount: agent.staticContext.length,
6877
- dynamicContextCount: agent.dynamicContexts.length,
6878
- dynamicToolCount: agent.dynamicTools.length,
7097
+ staticContextCount: staticContextDocuments(agent).length,
7098
+ dynamicContextCount: vectorContexts(agent).length,
7099
+ dynamicToolCount: getAgentToolState3(agent).toolIndexes.length,
7100
+ hasLifecycle: agent.lifecycle !== void 0,
6879
7101
  hasOutputSchema: agent.outputSchema !== void 0,
6880
- hasHook: agent.hook !== void 0,
6881
- observerCount: agent.observers.length,
6882
- approvalToolCount: agent.toolSet.values().filter((tool) => tool.approval !== void 0).length
7102
+ observerCount: Object.keys(agent.observability?.observers ?? {}).length,
7103
+ approvalToolCount: agent.tools.filter(toolRequiresApproval).length
6883
7104
  };
6884
7105
  if (agent.defaultMaxTurns !== void 0) metadata.defaultMaxTurns = agent.defaultMaxTurns;
6885
7106
  return metadata;
@@ -7009,30 +7230,37 @@ function createStudioApp(options) {
7009
7230
  return studio;
7010
7231
  }
7011
7232
  function withStudioTraceObserver(studioAgent, traceStore) {
7012
- if (traceStore === void 0 || hasStudioTraceObserver(studioAgent.agent)) {
7013
- return studioAgent;
7233
+ if (traceStore === void 0) return studioAgent;
7234
+ const existing = studioAgent.agent.observability;
7235
+ const studioObserver = existing?.observers.studio;
7236
+ if (studioObserver !== void 0 && !(studioObserver instanceof StudioTraceObserver)) {
7237
+ throw new TypeError('Studio reserves the observer name "studio" for local trace persistence.');
7238
+ }
7239
+ for (const [name, observer] of Object.entries(existing?.observers ?? {})) {
7240
+ if (observer instanceof StudioTraceObserver && name !== "studio") {
7241
+ throw new TypeError('StudioTraceObserver must be registered with the name "studio".');
7242
+ }
7014
7243
  }
7015
7244
  return {
7016
7245
  ...studioAgent,
7017
7246
  agent: cloneAgent(studioAgent.agent, {
7018
- observers: [
7019
- ...studioAgent.agent.observers,
7020
- { observer: new StudioTraceObserver({ store: traceStore }) }
7021
- ]
7247
+ observability: {
7248
+ observers: {
7249
+ ...existing?.observers ?? {},
7250
+ studio: studioObserver ?? new StudioTraceObserver({ store: traceStore })
7251
+ },
7252
+ primaryTrace: "studio",
7253
+ errorPolicy: existing?.errorPolicy ?? "ignore"
7254
+ }
7022
7255
  })
7023
7256
  };
7024
7257
  }
7025
- function hasStudioTraceObserver(agent) {
7026
- return agent.observers.some(
7027
- (registration) => registration.observer instanceof StudioTraceObserver
7028
- );
7029
- }
7030
7258
 
7031
7259
  // src/storage/sqlite-store.ts
7032
7260
  import { mkdirSync } from "fs";
7033
7261
  import { createRequire } from "module";
7034
7262
  import { dirname, resolve } from "path";
7035
- import { isJsonValue as isJsonValue2 } from "@anvia/core/completion";
7263
+ import { isJsonValue as isJsonValue3 } from "@anvia/core/completion";
7036
7264
  var DatabaseSync;
7037
7265
  function createSqliteSessionStore(options = {}) {
7038
7266
  return new SqliteSessionStore(options.path ?? ":memory:");
@@ -7043,6 +7271,13 @@ var SqliteSessionStore = class {
7043
7271
  }
7044
7272
  path;
7045
7273
  kind = "sqlite";
7274
+ compaction = {
7275
+ snapshot: ({ scope }) => {
7276
+ const messages = this.listSessionMessages(scope.sessionId);
7277
+ return Promise.resolve({ revision: memoryRevision2(messages), messages });
7278
+ },
7279
+ replacePrefix: (options) => this.replaceCompactionPrefix(options)
7280
+ };
7046
7281
  db;
7047
7282
  listSessions(options) {
7048
7283
  const db = this.database();
@@ -7114,8 +7349,8 @@ var SqliteSessionStore = class {
7114
7349
  }
7115
7350
  return this.getSession(id);
7116
7351
  }
7117
- load(context) {
7118
- const session = this.getSession(context.sessionId);
7352
+ load({ scope }) {
7353
+ const session = this.getSession(scope.sessionId);
7119
7354
  return Promise.resolve(session?.messages ?? []);
7120
7355
  }
7121
7356
  append(input) {
@@ -7126,20 +7361,20 @@ var SqliteSessionStore = class {
7126
7361
  `SELECT id, agent_id, title, metadata_json, created_at, updated_at
7127
7362
  FROM anvia_studio_sessions
7128
7363
  WHERE id = $id`
7129
- ).get({ $id: input.context.sessionId });
7364
+ ).get({ $id: input.scope.sessionId });
7130
7365
  if (row === void 0) {
7131
7366
  db.exec("ROLLBACK");
7132
7367
  return Promise.resolve();
7133
7368
  }
7134
7369
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
7135
- const nextIndex = this.nextMessageIndex(input.context.sessionId);
7136
- this.insertMessages(input.context.sessionId, input.messages, nextIndex, updatedAt);
7370
+ const nextIndex = this.nextMessageIndex(input.scope.sessionId);
7371
+ this.insertMessages(input.scope.sessionId, input.messages, nextIndex, updatedAt);
7137
7372
  db.prepare(
7138
7373
  `UPDATE anvia_studio_sessions
7139
7374
  SET updated_at = $updatedAt
7140
7375
  WHERE id = $id`
7141
7376
  ).run({
7142
- $id: input.context.sessionId,
7377
+ $id: input.scope.sessionId,
7143
7378
  $updatedAt: updatedAt
7144
7379
  });
7145
7380
  db.exec("COMMIT");
@@ -7151,7 +7386,7 @@ var SqliteSessionStore = class {
7151
7386
  throw error;
7152
7387
  }
7153
7388
  }
7154
- clear(context) {
7389
+ clear({ scope }) {
7155
7390
  const db = this.database();
7156
7391
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
7157
7392
  try {
@@ -7161,14 +7396,14 @@ var SqliteSessionStore = class {
7161
7396
  SET updated_at = $updatedAt
7162
7397
  WHERE id = $id`
7163
7398
  ).run({
7164
- $id: context.sessionId,
7399
+ $id: scope.sessionId,
7165
7400
  $updatedAt: updatedAt
7166
7401
  });
7167
7402
  db.prepare("DELETE FROM anvia_studio_session_messages WHERE session_id = $id").run({
7168
- $id: context.sessionId
7403
+ $id: scope.sessionId
7169
7404
  });
7170
7405
  db.prepare("DELETE FROM anvia_studio_session_runs WHERE session_id = $id").run({
7171
- $id: context.sessionId
7406
+ $id: scope.sessionId
7172
7407
  });
7173
7408
  db.exec("COMMIT");
7174
7409
  return Promise.resolve();
@@ -7180,17 +7415,51 @@ var SqliteSessionStore = class {
7180
7415
  }
7181
7416
  }
7182
7417
  async recordError(input) {
7183
- const runId = studioRunId2(input.context) ?? input.runId;
7184
- const existing = this.getSessionRun(input.context.sessionId, runId);
7418
+ const runId = studioRunId2(input.scope) ?? input.runId;
7419
+ const existing = this.getSessionRun(input.scope.sessionId, runId);
7185
7420
  const transcript = existing === void 0 || parseJsonArray(existing.transcript_json).length === 0 ? transcriptFromMessages(input.messages) : parseJsonArray(existing.transcript_json);
7186
7421
  await this.saveSessionRunTranscript({
7187
- id: input.context.sessionId,
7422
+ id: input.scope.sessionId,
7188
7423
  runId,
7189
7424
  transcript,
7190
7425
  status: "error",
7191
7426
  error: serializeJsonError2(input.error)
7192
7427
  });
7193
7428
  }
7429
+ replaceCompactionPrefix(input) {
7430
+ if (!Number.isSafeInteger(input.messageCount) || input.messageCount < 1) {
7431
+ throw new RangeError("messageCount must be a positive integer.");
7432
+ }
7433
+ const db = this.database();
7434
+ try {
7435
+ db.exec("BEGIN IMMEDIATE");
7436
+ const messages = this.listSessionMessages(input.scope.sessionId);
7437
+ if (memoryRevision2(messages) !== input.revision || input.messageCount > messages.length || this.getSessionRow(input.scope.sessionId) === void 0) {
7438
+ db.exec("ROLLBACK");
7439
+ return Promise.resolve({ status: "conflict" });
7440
+ }
7441
+ db.prepare("DELETE FROM anvia_studio_session_messages WHERE session_id = $id").run({
7442
+ $id: input.scope.sessionId
7443
+ });
7444
+ const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
7445
+ this.insertMessages(
7446
+ input.scope.sessionId,
7447
+ [input.replacement, ...messages.slice(input.messageCount)],
7448
+ 0,
7449
+ updatedAt
7450
+ );
7451
+ db.prepare(
7452
+ `UPDATE anvia_studio_sessions
7453
+ SET updated_at = $updatedAt
7454
+ WHERE id = $id`
7455
+ ).run({ $id: input.scope.sessionId, $updatedAt: updatedAt });
7456
+ db.exec("COMMIT");
7457
+ return Promise.resolve({ status: "committed" });
7458
+ } catch (error) {
7459
+ if (db.isTransaction) db.exec("ROLLBACK");
7460
+ throw error;
7461
+ }
7462
+ }
7194
7463
  saveSessionRunTranscript(input) {
7195
7464
  const db = this.database();
7196
7465
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -7886,7 +8155,7 @@ var SqliteSessionStore = class {
7886
8155
  );
7887
8156
  messages.forEach((message, messageOffset) => {
7888
8157
  const messageIndex = startIndex + messageOffset;
7889
- if (message.metadata !== void 0 && !isJsonValue2(message.metadata)) {
8158
+ if (message.metadata !== void 0 && !isJsonValue3(message.metadata)) {
7890
8159
  throw new TypeError("Studio message metadata must be a strict JSON value.");
7891
8160
  }
7892
8161
  insertMessage.run({
@@ -7987,6 +8256,9 @@ function messageParts(message) {
7987
8256
  if (message.role === "system") {
7988
8257
  return [{ type: "text", value: { type: "text", text: message.content } }];
7989
8258
  }
8259
+ if (typeof message.content === "string") {
8260
+ return [{ type: "text", value: { type: "text", text: message.content } }];
8261
+ }
7990
8262
  return message.content.map((content) => ({
7991
8263
  type: content.type,
7992
8264
  value: content
@@ -7995,40 +8267,40 @@ function messageParts(message) {
7995
8267
  function messageFromRows(row, partRows) {
7996
8268
  const parts = partRows.map((partRow) => JSON.parse(partRow.part_json));
7997
8269
  const metadata = parseJsonValue(row.metadata_json);
7998
- if (metadata !== void 0 && !isJsonValue2(metadata)) {
7999
- throw new TypeError("Stored Studio message metadata is not a strict JSON value.");
8270
+ if (metadata !== void 0 && (!isJsonValue3(metadata) || typeof metadata !== "object" || metadata === null || Array.isArray(metadata))) {
8271
+ throw new TypeError("Stored Studio message metadata is not a strict JSON object.");
8000
8272
  }
8001
8273
  if (row.role === "system") {
8002
8274
  const message = {
8003
8275
  role: "system",
8004
- content: systemContentFromParts(parts)
8276
+ content: systemContentFromParts(parts),
8277
+ ...metadata === void 0 ? {} : { metadata }
8005
8278
  };
8006
- if (metadata !== void 0) message.metadata = metadata;
8007
8279
  return message;
8008
8280
  }
8009
8281
  if (row.role === "user") {
8010
8282
  const message = {
8011
8283
  role: "user",
8012
- content: parts
8284
+ content: parts,
8285
+ ...metadata === void 0 ? {} : { metadata }
8013
8286
  };
8014
- if (metadata !== void 0) message.metadata = metadata;
8015
8287
  return message;
8016
8288
  }
8017
8289
  if (row.role === "assistant") {
8018
8290
  const message = {
8019
8291
  role: "assistant",
8020
- content: parts
8292
+ content: parts,
8293
+ ...row.message_id === null ? {} : { id: row.message_id },
8294
+ ...metadata === void 0 ? {} : { metadata }
8021
8295
  };
8022
- if (row.message_id !== null) message.id = row.message_id;
8023
- if (metadata !== void 0) message.metadata = metadata;
8024
8296
  return message;
8025
8297
  }
8026
8298
  if (row.role === "tool") {
8027
8299
  const message = {
8028
8300
  role: "tool",
8029
- content: parts
8301
+ content: parts,
8302
+ ...metadata === void 0 ? {} : { metadata }
8030
8303
  };
8031
- if (metadata !== void 0) message.metadata = metadata;
8032
8304
  return message;
8033
8305
  }
8034
8306
  throw new Error(`Unsupported stored message role: ${row.role}`);
@@ -8100,6 +8372,7 @@ function toTraceSummary(row) {
8100
8372
  if (error !== void 0) summary.error = error;
8101
8373
  if (usage !== void 0) summary.usage = usage;
8102
8374
  if (metadata !== void 0) summary.metadata = metadata;
8375
+ if (typeof metadata?.runId === "string") summary.runId = metadata.runId;
8103
8376
  return summary;
8104
8377
  }
8105
8378
  function parseJsonArray(value) {
@@ -8112,10 +8385,13 @@ function parseJsonValue(value) {
8112
8385
  }
8113
8386
  return JSON.parse(value);
8114
8387
  }
8115
- function studioRunId2(context) {
8116
- const value = context.metadata?.studioRunId;
8388
+ function studioRunId2(scope) {
8389
+ const value = scope.metadata?.studioRunId;
8117
8390
  return typeof value === "string" && value.length > 0 ? value : void 0;
8118
8391
  }
8392
+ function memoryRevision2(messages) {
8393
+ return JSON.stringify(messages);
8394
+ }
8119
8395
  function serializeJsonError2(error) {
8120
8396
  if (error instanceof Error) {
8121
8397
  return {