@anvia/studio 1.0.0-rc.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 (50) hide show
  1. package/README.md +18 -10
  2. package/dist/index.d.ts +30 -55
  3. package/dist/index.js +610 -338
  4. package/dist/index.js.map +1 -1
  5. package/dist/ui/assets/{ArrowClockwise.es-yNj_oSyD.js → ArrowClockwise.es-DMJj7Hv0.js} +2 -2
  6. package/dist/ui/assets/{ArrowClockwise.es-yNj_oSyD.js.map → ArrowClockwise.es-DMJj7Hv0.js.map} +1 -1
  7. package/dist/ui/assets/{agents-page-ucKNS0fS.js → agents-page-CbQpO3Tg.js} +2 -2
  8. package/dist/ui/assets/{agents-page-ucKNS0fS.js.map → agents-page-CbQpO3Tg.js.map} +1 -1
  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-vwFOGhkh.js → knowledge-page-C8zg8uTL.js} +2 -2
  16. package/dist/ui/assets/{knowledge-page-vwFOGhkh.js.map → knowledge-page-C8zg8uTL.js.map} +1 -1
  17. package/dist/ui/assets/{mcps-page-Bsu_-w7A.js → mcps-page-gNYeqSPB.js} +2 -2
  18. package/dist/ui/assets/{mcps-page-Bsu_-w7A.js.map → mcps-page-gNYeqSPB.js.map} +1 -1
  19. package/dist/ui/assets/{memory-page-DJ_nq7Ip.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-5kT5HxmZ.js → renderers-DC_-TD_X.js} +3 -3
  24. package/dist/ui/assets/{renderers-5kT5HxmZ.js.map → renderers-DC_-TD_X.js.map} +1 -1
  25. package/dist/ui/assets/{sandboxes-page-BQuQepXk.js → sandboxes-page-DtPnuza7.js} +2 -2
  26. package/dist/ui/assets/{sandboxes-page-BQuQepXk.js.map → sandboxes-page-DtPnuza7.js.map} +1 -1
  27. package/dist/ui/assets/{sessions-page-BLGrHrQT.js → sessions-page-DBzoP7MV.js} +2 -2
  28. package/dist/ui/assets/{sessions-page-BLGrHrQT.js.map → sessions-page-DBzoP7MV.js.map} +1 -1
  29. package/dist/ui/assets/{status-page-D-BUKV_r.js → status-page-Bf1lq444.js} +2 -2
  30. package/dist/ui/assets/{status-page-D-BUKV_r.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-6-N-OOCI.js.map → tool-runner-BbUlfPEO.js.map} +1 -1
  33. package/dist/ui/assets/{tools-page-BEQJgFX0.js → tools-page-BgUz-79v.js} +2 -2
  34. package/dist/ui/assets/{tools-page-BEQJgFX0.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-Bbf77TZa.js → transcript-item-HFuuqmKM.js} +3 -3
  38. package/dist/ui/assets/{transcript-item-Bbf77TZa.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/chunk-ADH7NNCS-DM6fsnDI.js +0 -2
  42. package/dist/ui/assets/chunk-ADH7NNCS-DM6fsnDI.js.map +0 -1
  43. package/dist/ui/assets/index-DIV9J1_T.js +0 -56
  44. package/dist/ui/assets/index-DIV9J1_T.js.map +0 -1
  45. package/dist/ui/assets/memory-page-DJ_nq7Ip.js.map +0 -1
  46. package/dist/ui/assets/pipelines-page-BsHeSdbO.js +0 -8
  47. package/dist/ui/assets/pipelines-page-BsHeSdbO.js.map +0 -1
  48. package/dist/ui/assets/tool-runner-6-N-OOCI.js +0 -2
  49. package/dist/ui/assets/trace-browser-DdGcJyNX.js +0 -10
  50. package/dist/ui/assets/trace-browser-DdGcJyNX.js.map +0 -1
package/dist/index.js CHANGED
@@ -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,12 +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,
203
209
  runId: this.props.args.runId,
204
210
  sessionId,
205
211
  status,
206
- trace: this.trace,
212
+ trace: { observer: "studio", ...this.trace },
207
213
  startedAt: this.startedAt.toISOString(),
208
214
  endedAt: result.endedAt.toISOString(),
209
215
  durationMs: durationMs(this.startedAt, result.endedAt),
@@ -282,15 +288,14 @@ var ChildAgentToolTraceAccumulator = class {
282
288
  }
283
289
  if (child.type === "tool_call" && isRecord(child.toolCall)) {
284
290
  const toolCall = child.toolCall;
285
- const toolCallFunction = isRecord(toolCall.function) ? toolCall.function : void 0;
286
- const toolName = typeof toolCallFunction?.name === "string" ? toolCallFunction.name : "tool";
287
- 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;
288
293
  const start = {
289
294
  startedAt: /* @__PURE__ */ new Date(),
290
295
  agentId,
291
296
  childTurn,
292
297
  toolName,
293
- input: toJsonValue(toolCallFunction?.arguments ?? {}),
298
+ input: toJsonValue("input" in toolCall ? toolCall.input : {}),
294
299
  completed: false
295
300
  };
296
301
  if (agentName !== void 0) start.agentName = agentName;
@@ -443,14 +448,12 @@ function generationMetadata(args, endArgs) {
443
448
  const request = args.request;
444
449
  const response = endArgs?.response;
445
450
  const rawResponse = isRecord(response?.rawResponse) ? response.rawResponse : void 0;
446
- const effectiveModel = request.model ?? stringValue(rawResponse?.model) ?? args.modelInfo?.defaultModel ?? "default";
451
+ const modelId = args.modelInfo?.modelId ?? stringValue(rawResponse?.model) ?? "unknown";
447
452
  const providerResponse = providerResponseSummary(rawResponse);
448
453
  const usage = response?.usage;
449
454
  return compactJsonObject({
450
455
  provider: args.modelInfo?.provider,
451
- model: effectiveModel,
452
- requestedModel: request.model,
453
- defaultModel: args.modelInfo?.defaultModel,
456
+ modelId,
454
457
  messageId: response?.messageId,
455
458
  usage,
456
459
  toolCount: request.tools.length,
@@ -460,15 +463,13 @@ function generationMetadata(args, endArgs) {
460
463
  temperature: request.temperature,
461
464
  maxTokens: request.maxTokens,
462
465
  toolChoice: request.toolChoice,
463
- additionalParamKeys: isRecord(request.additionalParams) ? Object.keys(request.additionalParams).sort() : void 0,
466
+ providerOptionKeys: isRecord(request.providerOptions) ? Object.keys(request.providerOptions).sort() : void 0,
464
467
  hasOutputSchema: request.outputSchema !== void 0,
465
468
  firstDeltaMs: endArgs?.firstDeltaMs,
466
469
  providerResponse,
467
470
  modelInfo: compactJsonObject({
468
471
  provider: args.modelInfo?.provider,
469
- model: effectiveModel,
470
- requestedModel: request.model,
471
- defaultModel: args.modelInfo?.defaultModel,
472
+ modelId,
472
473
  capabilities: args.modelInfo?.capabilities
473
474
  }),
474
475
  modelCall: compactJsonObject({
@@ -494,7 +495,6 @@ function generationMetadata(args, endArgs) {
494
495
  }
495
496
  function completionRequestSummary(request) {
496
497
  return compactJsonObject({
497
- model: request.model,
498
498
  instructions: request.instructions === void 0 ? void 0 : { present: true },
499
499
  messageCount: request.chatHistory.length,
500
500
  documentCount: request.documents.length,
@@ -504,7 +504,7 @@ function completionRequestSummary(request) {
504
504
  temperature: request.temperature,
505
505
  maxTokens: request.maxTokens,
506
506
  toolChoice: request.toolChoice,
507
- additionalParamKeys: isRecord(request.additionalParams) ? Object.keys(request.additionalParams).sort() : void 0,
507
+ providerOptionKeys: isRecord(request.providerOptions) ? Object.keys(request.providerOptions).sort() : void 0,
508
508
  hasOutputSchema: request.outputSchema !== void 0
509
509
  });
510
510
  }
@@ -541,7 +541,6 @@ function toolMetadata(args, skipped, result) {
541
541
  argumentBytes: byteLength(args.args),
542
542
  resultBytes: result === void 0 ? void 0 : byteLength(result),
543
543
  hasCallSignature: args.toolCall.signature !== void 0,
544
- hasAdditionalParams: args.toolCall.additionalParams !== void 0,
545
544
  toolDescription: args.toolDefinition?.description,
546
545
  parameterKeys: Object.keys(properties).sort(),
547
546
  requiredParameterKeys: required,
@@ -559,8 +558,7 @@ function toolMetadata(args, skipped, result) {
559
558
  mcpServerName: args.toolMetadata?.mcpServerName,
560
559
  argumentBytes: byteLength(args.args),
561
560
  resultBytes: result === void 0 ? void 0 : byteLength(result),
562
- hasCallSignature: args.toolCall.signature !== void 0,
563
- hasAdditionalParams: args.toolCall.additionalParams !== void 0
561
+ hasCallSignature: args.toolCall.signature !== void 0
564
562
  })
565
563
  });
566
564
  }
@@ -577,6 +575,16 @@ function parseOrString(value) {
577
575
  return value;
578
576
  }
579
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
+ }
580
588
  function isRecord(value) {
581
589
  return typeof value === "object" && value !== null && !Array.isArray(value);
582
590
  }
@@ -877,17 +885,18 @@ function escapeHtml(value) {
877
885
  }
878
886
 
879
887
  // src/runtime/agent-context.ts
880
- import { isContextIndex } from "@anvia/core/agent";
888
+ import { isVectorContext } from "@anvia/core/agent";
881
889
  function staticContextDocuments(agent) {
882
- return agent.context.filter((input) => !isContextIndex(input));
890
+ return agent.context.filter((input) => !isVectorContext(input));
883
891
  }
884
- function contextIndexes(agent) {
885
- return agent.context.filter(isContextIndex);
892
+ function vectorContexts(agent) {
893
+ return agent.context.filter(isVectorContext);
886
894
  }
887
895
 
888
896
  // src/runtime/agent-runs.ts
889
- import { Message } from "@anvia/core/completion";
890
- import { withInternalAgentRunOptions } from "@anvia/core/internal/agent";
897
+ import {
898
+ withInternalAgentRunOptions
899
+ } from "@anvia/core/internal/agent";
891
900
 
892
901
  // src/runtime/agent-utils.ts
893
902
  import {
@@ -914,7 +923,8 @@ function serializeError(error) {
914
923
 
915
924
  // src/runtime/type-guards.ts
916
925
  import {
917
- isJsonValue as isCoreJsonValue
926
+ isJsonValue as isCoreJsonValue,
927
+ isMessage
918
928
  } from "@anvia/core/completion";
919
929
  function isObject(value) {
920
930
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -925,26 +935,16 @@ function isJsonObject(value) {
925
935
  function isJsonValue(value) {
926
936
  return isCoreJsonValue(value);
927
937
  }
928
- function isMessageInput(value) {
929
- return typeof value === "string" || isMessage(value);
930
- }
931
- function isMessage(value) {
932
- if (!isObject(value) || typeof value.role !== "string") {
933
- return false;
934
- }
935
- if (value.role === "system") {
936
- return typeof value.content === "string";
937
- }
938
- if (value.role === "user" || value.role === "assistant" || value.role === "tool") {
939
- return Array.isArray(value.content);
940
- }
941
- return false;
942
- }
943
938
  function isAgentTraceOptions(value) {
944
939
  if (!isObject(value)) {
945
940
  return false;
946
941
  }
947
- 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));
948
948
  }
949
949
  function isNonNegativeInteger(value) {
950
950
  return Number.isInteger(value) && typeof value === "number" && value >= 0;
@@ -955,15 +955,9 @@ function isPositiveInteger(value) {
955
955
  function optionalString(value) {
956
956
  return value === void 0 || typeof value === "string";
957
957
  }
958
- function optionalBoolean(value) {
959
- return value === void 0 || typeof value === "boolean";
960
- }
961
958
  function optionalStringArray(value) {
962
959
  return value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
963
960
  }
964
- function optionalObject(value) {
965
- return value === void 0 || isObject(value);
966
- }
967
961
 
968
962
  // src/runtime/http.ts
969
963
  function errorResponse(c, status, code, message, details) {
@@ -1013,8 +1007,8 @@ function createStudioModelRegistry(config) {
1013
1007
  id,
1014
1008
  staticModels
1015
1009
  };
1016
- if (provider.defaultModel !== void 0) {
1017
- runtimeProvider.defaultModel = normalizeModelId(provider.defaultModel);
1010
+ if (provider.defaultModelId !== void 0) {
1011
+ runtimeProvider.defaultModelId = normalizeModelId(provider.defaultModelId);
1018
1012
  }
1019
1013
  providers.set(id, runtimeProvider);
1020
1014
  }
@@ -1023,8 +1017,10 @@ function createStudioModelRegistry(config) {
1023
1017
  agentPolicies: normalizeAgentPolicies(config.agents ?? {}),
1024
1018
  modelCache: /* @__PURE__ */ new Map()
1025
1019
  };
1026
- if (config.default !== void 0) {
1027
- Object.assign(registry, { defaultModel: normalizeModelRef(config.default) });
1020
+ if (config.defaultModelRef !== void 0) {
1021
+ Object.assign(registry, {
1022
+ defaultModelRef: normalizeModelRef(config.defaultModelRef)
1023
+ });
1028
1024
  }
1029
1025
  return registry;
1030
1026
  }
@@ -1041,7 +1037,7 @@ function studioModelsConfig(registry, agents) {
1041
1037
  models
1042
1038
  };
1043
1039
  if (provider.name !== void 0) config2.name = provider.name;
1044
- if (provider.defaultModel !== void 0) config2.defaultModel = provider.defaultModel;
1040
+ if (provider.defaultModelId !== void 0) config2.defaultModelId = provider.defaultModelId;
1045
1041
  if (provider.metadata !== void 0) config2.metadata = provider.metadata;
1046
1042
  return config2;
1047
1043
  });
@@ -1053,7 +1049,7 @@ function studioModelsConfig(registry, agents) {
1053
1049
  providers,
1054
1050
  agents: agentsConfig
1055
1051
  };
1056
- if (registry.defaultModel !== void 0) config.default = registry.defaultModel;
1052
+ if (registry.defaultModelRef !== void 0) config.defaultModelRef = registry.defaultModelRef;
1057
1053
  return config;
1058
1054
  }
1059
1055
  function registerModelRoutes(app, props) {
@@ -1067,8 +1063,8 @@ function registerModelRoutes(app, props) {
1067
1063
  const response = {
1068
1064
  providers
1069
1065
  };
1070
- if (props.registry.defaultModel !== void 0) {
1071
- response.defaultModel = props.registry.defaultModel;
1066
+ if (props.registry.defaultModelRef !== void 0) {
1067
+ response.defaultModelRef = props.registry.defaultModelRef;
1072
1068
  }
1073
1069
  return c.json(response);
1074
1070
  });
@@ -1101,7 +1097,7 @@ function resolveStudioModel(registry, input) {
1101
1097
  if (registry === void 0) {
1102
1098
  return { warnings: [] };
1103
1099
  }
1104
- 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;
1105
1101
  if (selectedRef === void 0) {
1106
1102
  return { warnings: [] };
1107
1103
  }
@@ -1113,7 +1109,7 @@ function resolveStudioModel(registry, input) {
1113
1109
  }
1114
1110
  let model = registry.modelCache.get(selectedRef);
1115
1111
  if (model === void 0) {
1116
- model = provider.createCompletionModel(modelId);
1112
+ model = provider.createCompletionModel({ modelId });
1117
1113
  registry.modelCache.set(selectedRef, model);
1118
1114
  }
1119
1115
  const metadata = provider.staticModels.get(modelId);
@@ -1131,12 +1127,7 @@ function normalizeOptionalModelRef(ref) {
1131
1127
  return ref === void 0 ? void 0 : normalizeModelRef(ref);
1132
1128
  }
1133
1129
  function normalizeModelRef(ref) {
1134
- if (typeof ref === "string") {
1135
- const trimmed = ref.trim();
1136
- const parsed = parseModelRef(trimmed);
1137
- return `${parsed.providerId}:${parsed.modelId}`;
1138
- }
1139
- return `${normalizeProviderId(ref.provider)}:${normalizeModelId(ref.model)}`;
1130
+ return `${normalizeProviderId(ref.providerId)}:${normalizeModelId(ref.modelId)}`;
1140
1131
  }
1141
1132
  function parseModelRef(ref) {
1142
1133
  const index = ref.indexOf(":");
@@ -1179,12 +1170,12 @@ async function agentModelsCatalog(registry, agent) {
1179
1170
  return [];
1180
1171
  }
1181
1172
  });
1182
- const defaultModel = policy?.default ?? registry.defaultModel;
1173
+ const defaultModelRef = policy?.defaultModelRef ?? registry.defaultModelRef;
1183
1174
  const summary = {
1184
1175
  agentId: agent.id,
1185
1176
  models: [...models, ...exactPolicyModels]
1186
1177
  };
1187
- if (defaultModel !== void 0) summary.defaultModel = defaultModel;
1178
+ if (defaultModelRef !== void 0) summary.defaultModelRef = defaultModelRef;
1188
1179
  if (warnings.length > 0) summary.warnings = warnings;
1189
1180
  return summary;
1190
1181
  }
@@ -1222,7 +1213,7 @@ async function providerCatalog(provider) {
1222
1213
  models: [...models.values()].sort((left, right) => left.ref.localeCompare(right.ref))
1223
1214
  };
1224
1215
  if (provider.name !== void 0) catalog.name = provider.name;
1225
- if (provider.defaultModel !== void 0) catalog.defaultModel = provider.defaultModel;
1216
+ if (provider.defaultModelId !== void 0) catalog.defaultModelId = provider.defaultModelId;
1226
1217
  if (provider.metadata !== void 0) catalog.metadata = provider.metadata;
1227
1218
  if (warning !== void 0) catalog.warning = warning;
1228
1219
  return catalog;
@@ -1256,19 +1247,33 @@ function normalizeAgentPolicies(policies) {
1256
1247
  return new Map(
1257
1248
  Object.entries(policies).map(([agentId, policy]) => {
1258
1249
  const normalized = {};
1259
- if (policy.default !== void 0) normalized.default = normalizeModelRef(policy.default);
1250
+ if (policy.defaultModelRef !== void 0) {
1251
+ normalized.defaultModelRef = normalizeModelRef(policy.defaultModelRef);
1252
+ }
1260
1253
  if (policy.allowed !== void 0) {
1261
- normalized.allowed = policy.allowed.map(
1262
- (entry) => typeof entry === "string" && entry.trim().endsWith(":*") ? `${normalizeProviderId(entry.trim().slice(0, -2))}:*` : normalizeModelRef(entry)
1263
- );
1254
+ normalized.allowed = policy.allowed.map((entry) => {
1255
+ if (typeof entry === "string") {
1256
+ return normalizeWildcardModelRef(entry);
1257
+ }
1258
+ return normalizeModelRef(entry);
1259
+ });
1264
1260
  }
1265
1261
  return [agentId.trim(), normalized];
1266
1262
  })
1267
1263
  );
1268
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
+ }
1269
1272
  function publicPolicy(policy) {
1270
1273
  const config = {};
1271
- if (policy.default !== void 0) config.default = policy.default;
1274
+ if (policy.defaultModelRef !== void 0) {
1275
+ config.defaultModelRef = policy.defaultModelRef;
1276
+ }
1272
1277
  if (policy.allowed !== void 0) config.allowed = policy.allowed;
1273
1278
  return config;
1274
1279
  }
@@ -1299,15 +1304,13 @@ function modelWarnings(ref, model, request) {
1299
1304
  function requestModalities(request) {
1300
1305
  const modalities = /* @__PURE__ */ new Set(["text"]);
1301
1306
  for (const message of requestMessages(request)) {
1302
- if (typeof message === "string") {
1303
- continue;
1304
- }
1305
1307
  if (message.role === "user" || message.role === "assistant") {
1308
+ if (typeof message.content === "string") continue;
1306
1309
  for (const content of message.content) {
1307
1310
  if (content.type === "image") {
1308
1311
  modalities.add("image");
1309
1312
  }
1310
- if (content.type === "document") {
1313
+ if (content.type === "file") {
1311
1314
  modalities.add("document");
1312
1315
  }
1313
1316
  }
@@ -1316,7 +1319,7 @@ function requestModalities(request) {
1316
1319
  return modalities;
1317
1320
  }
1318
1321
  function requestMessages(request) {
1319
- return [...request.history ?? [], request.message];
1322
+ return request.messages;
1320
1323
  }
1321
1324
  function normalizeProviderId(id) {
1322
1325
  const trimmed = id.trim();
@@ -1334,7 +1337,7 @@ function normalizeModelId(id) {
1334
1337
  }
1335
1338
 
1336
1339
  // src/runtime/streams.ts
1337
- import { createEventStream } from "@anvia/server";
1340
+ import { createClientStreamResponse, createEventStreamResponse } from "@anvia/server";
1338
1341
  var studioJsonlHeaders = {
1339
1342
  "cache-control": "no-cache, no-transform",
1340
1343
  connection: "keep-alive",
@@ -1343,7 +1346,15 @@ var studioJsonlHeaders = {
1343
1346
  "x-accel-buffering": "no"
1344
1347
  };
1345
1348
  function streamStudioJsonl(events) {
1346
- 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,
1347
1358
  format: "jsonl",
1348
1359
  headers: studioJsonlHeaders
1349
1360
  });
@@ -1362,8 +1373,9 @@ function withStudioStreamErrors(events) {
1362
1373
  const next = await iterator.next();
1363
1374
  if (next.done === true) {
1364
1375
  done = true;
1376
+ return next;
1365
1377
  }
1366
- return next;
1378
+ return { done: false, value: serializeStreamError(next.value) };
1367
1379
  } catch (error) {
1368
1380
  done = true;
1369
1381
  return {
@@ -1381,6 +1393,12 @@ function withStudioStreamErrors(events) {
1381
1393
  }
1382
1394
  };
1383
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
+ }
1384
1402
  function studioStreamError(error) {
1385
1403
  return {
1386
1404
  type: "error",
@@ -1589,6 +1607,15 @@ function isEventType(value) {
1589
1607
  return value === "session_log" || value === "pipeline_log" || value === "trace";
1590
1608
  }
1591
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
+
1592
1619
  // src/runtime/transcript.ts
1593
1620
  function renumberTranscript(entries) {
1594
1621
  return entries.map((entry, entryId) => ({ ...entry, entryId }));
@@ -1602,7 +1629,8 @@ function transcriptFromMessages(messages) {
1602
1629
  if (message.role === "user") {
1603
1630
  const attachments = attachmentsFromMessage(message);
1604
1631
  let textEntryAdded = false;
1605
- 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) {
1606
1634
  if (content.type === "text") {
1607
1635
  const entry = {
1608
1636
  entryId: transcript.length,
@@ -1631,17 +1659,16 @@ function transcriptFromMessages(messages) {
1631
1659
  transcript.push({
1632
1660
  entryId: transcript.length,
1633
1661
  kind: "tool",
1634
- toolName: "tool_result",
1635
- callId: content.callId ?? content.id,
1636
- result: content.content.map(
1637
- (item) => "text" in item ? item.text : `[image:${item.mediaType ?? "image/png"}]`
1638
- ).join("\n"),
1639
- 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 } : {}
1640
1666
  });
1641
1667
  }
1642
1668
  continue;
1643
1669
  }
1644
- 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) {
1645
1672
  if (content.type === "text") {
1646
1673
  appendAssistantTranscriptText(transcript, content.text);
1647
1674
  } else if (content.type === "reasoning") {
@@ -1652,13 +1679,13 @@ function transcriptFromMessages(messages) {
1652
1679
  };
1653
1680
  if (content.id !== void 0) entry.reasoningId = content.id;
1654
1681
  transcript.push(entry);
1655
- } else if (content.type === "tool_call") {
1682
+ } else if (content.type === "tool-call") {
1656
1683
  transcript.push({
1657
1684
  entryId: transcript.length,
1658
1685
  kind: "tool",
1659
- toolName: content.function.name,
1660
- callId: content.callId ?? content.id,
1661
- args: formatJson(content.function.arguments)
1686
+ toolName: content.toolName,
1687
+ callId: content.callId ?? content.toolCallId,
1688
+ args: formatJson(content.input)
1662
1689
  });
1663
1690
  }
1664
1691
  }
@@ -1669,28 +1696,37 @@ function attachmentsFromMessage(message) {
1669
1696
  if (message.role !== "user" && message.role !== "assistant") {
1670
1697
  return [];
1671
1698
  }
1699
+ if (typeof message.content === "string") return [];
1672
1700
  return message.content.flatMap((content) => {
1673
1701
  if (content.type === "image") {
1674
1702
  const attachment = { kind: "image" };
1675
- if (content.source.type === "base64") {
1676
- attachment.data = content.source.data;
1677
- 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;
1678
1706
  } else {
1679
- attachment.url = content.source.url;
1707
+ attachment.url = content.image.url;
1680
1708
  }
1681
1709
  return [attachment];
1682
1710
  }
1683
- if (content.type === "document") {
1711
+ if (content.type === "file") {
1684
1712
  const attachment = { kind: "document" };
1685
- if (content.source.filename !== void 0) attachment.name = content.source.filename;
1686
- if (content.source.mediaType !== void 0) attachment.mediaType = content.source.mediaType;
1687
- if (content.source.type === "base64") attachment.data = content.source.data;
1688
- 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;
1689
1717
  return [attachment];
1690
1718
  }
1691
1719
  return [];
1692
1720
  });
1693
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
+ }
1694
1730
  function appendAssistantTranscriptText(transcript, text) {
1695
1731
  const last = transcript.at(-1);
1696
1732
  if (last?.kind === "message" && last.role === "assistant") {
@@ -1778,8 +1814,97 @@ async function* mergeRunAndApprovalEvents(runEvents, approvalEvents) {
1778
1814
  approvalEvents.close();
1779
1815
  }
1780
1816
  }
1781
- function streamAgentRunEvents(_c, events, options = {}) {
1782
- 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
+ }
1783
1908
  }
1784
1909
  function withAgentRunCancellation(events, onCancel) {
1785
1910
  const iterator = events[Symbol.asyncIterator]();
@@ -1899,10 +2024,10 @@ function createPersistedStreamingSessionTranscript(props) {
1899
2024
  };
1900
2025
  if (event.type === "error") saveInput.error = serializeError(event.error);
1901
2026
  await saveTranscript(saveInput);
1902
- const generatedMessages = event.type === "final" ? event.messages.slice(1) : [];
2027
+ const generatedMessages = event.type === "final" ? event.result.messages.slice(1) : [];
1903
2028
  if (props.persistGeneratedMessages === true && generatedMessages.length > 0) {
1904
2029
  await props.store.append({
1905
- context: { sessionId: props.session.id },
2030
+ scope: { sessionId: props.session.id },
1906
2031
  runId: props.runId,
1907
2032
  turn: 1,
1908
2033
  messages: generatedMessages
@@ -2004,9 +2129,9 @@ function acceptTranscriptStreamEvent(transcript, event) {
2004
2129
  transcript.push({
2005
2130
  entryId: transcript.length,
2006
2131
  kind: "tool",
2007
- toolName: event.toolCall.function.name,
2008
- callId: event.toolCall.callId ?? event.toolCall.id,
2009
- 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)
2010
2135
  });
2011
2136
  }
2012
2137
  if (event.type === "tool_result") {
@@ -2114,8 +2239,8 @@ function acceptTranscriptStreamEvent(transcript, event) {
2114
2239
  matched.question = question;
2115
2240
  }
2116
2241
  }
2117
- if (event.type === "final" && event.trace?.traceId !== void 0) {
2118
- assignTranscriptTraceId(transcript, event.trace.traceId);
2242
+ if (event.type === "final" && event.result.trace?.traceId !== void 0) {
2243
+ assignTranscriptTraceId(transcript, event.result.trace.traceId);
2119
2244
  }
2120
2245
  if (event.type === "error") {
2121
2246
  appendTranscriptAssistantError(transcript, errorText(event.error));
@@ -2187,9 +2312,9 @@ function childAgentTranscriptEvent(event) {
2187
2312
  const entry = {
2188
2313
  kind: "tool",
2189
2314
  agentId: event.agentId,
2190
- toolName: child.toolCall.function.name,
2191
- callId: child.toolCall.callId ?? child.toolCall.id,
2192
- 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)
2193
2318
  };
2194
2319
  if (event.agentName !== void 0) entry.agentName = event.agentName;
2195
2320
  return entry;
@@ -2326,17 +2451,18 @@ function extractMessageText(message) {
2326
2451
  if (message.role === "system") {
2327
2452
  return message.content;
2328
2453
  }
2454
+ if (typeof message.content === "string") {
2455
+ return message.content;
2456
+ }
2329
2457
  return message.content.flatMap((item) => {
2330
2458
  if (item.type === "text" || item.type === "reasoning") {
2331
2459
  return [item.text];
2332
2460
  }
2333
- if (item.type === "tool_call") {
2334
- return [`${item.function.name}(${formatJson(item.function.arguments)})`];
2461
+ if (item.type === "tool-call") {
2462
+ return [`${item.toolName}(${formatJson(item.input)})`];
2335
2463
  }
2336
- if (item.type === "tool_result") {
2337
- return item.content.map(
2338
- (result) => "text" in result ? result.text : `[image:${result.mediaType ?? "image/png"}]`
2339
- );
2464
+ if (item.type === "tool-result") {
2465
+ return [toolResultOutputText(item.output)];
2340
2466
  }
2341
2467
  return [];
2342
2468
  }).join("\n");
@@ -2345,23 +2471,26 @@ function optionalTranscriptAttachments(message) {
2345
2471
  if (typeof message === "string" || message.role !== "user") {
2346
2472
  return {};
2347
2473
  }
2474
+ if (typeof message.content === "string") {
2475
+ return {};
2476
+ }
2348
2477
  const attachments = message.content.flatMap((content) => {
2349
2478
  if (content.type === "image") {
2350
2479
  const attachment = { kind: "image" };
2351
- if (content.source.type === "base64") {
2352
- attachment.data = content.source.data;
2353
- 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;
2354
2483
  } else {
2355
- attachment.url = content.source.url;
2484
+ attachment.url = content.image.url;
2356
2485
  }
2357
2486
  return [attachment];
2358
2487
  }
2359
- if (content.type === "document") {
2488
+ if (content.type === "file") {
2360
2489
  const attachment = { kind: "document" };
2361
- if (content.source.filename !== void 0) attachment.name = content.source.filename;
2362
- if (content.source.mediaType !== void 0) attachment.mediaType = content.source.mediaType;
2363
- if (content.source.type === "base64") attachment.data = content.source.data;
2364
- 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;
2365
2494
  return [attachment];
2366
2495
  }
2367
2496
  return [];
@@ -2378,32 +2507,27 @@ async function parseRunRequest(c) {
2378
2507
  if (!isObject(body)) {
2379
2508
  return { error: errorResponse(c, 400, "bad_request", "Request body must be an object") };
2380
2509
  }
2381
- const request = "message" in body ? parseLegacyRunRequestBody(c, body) : parseUiRunRequestBody(c, body);
2382
- if ("error" in request) {
2383
- return request;
2384
- }
2385
- return parseRunRequestOptions(c, body, request);
2386
- }
2387
- function parseLegacyRunRequestBody(c, body) {
2388
- if (!isMessageInput(body.message)) {
2510
+ if ("message" in body || "history" in body) {
2389
2511
  return {
2390
- 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
+ )
2391
2518
  };
2392
2519
  }
2393
- const request = {
2394
- message: typeof body.message === "string" ? body.message : body.message
2395
- };
2396
- if ("history" in body) {
2397
- if (!Array.isArray(body.history) || !body.history.every(isMessage)) {
2398
- return { error: errorResponse(c, 400, "bad_request", "history must be a Message array") };
2399
- }
2400
- request.history = body.history;
2520
+ const request = parseRunRequestBody(c, body);
2521
+ if ("error" in request) {
2522
+ return request;
2401
2523
  }
2402
- return request;
2524
+ return parseRunRequestOptions(c, body, request);
2403
2525
  }
2404
- function parseUiRunRequestBody(c, body) {
2405
- const messages = body.messages;
2406
- if (!Array.isArray(messages) || !messages.every(isMessage)) {
2526
+ function parseRunRequestBody(c, body) {
2527
+ let messages;
2528
+ try {
2529
+ messages = parseMessages(body.messages);
2530
+ } catch {
2407
2531
  return {
2408
2532
  error: errorResponse(c, 400, "bad_request", "messages must be a non-empty Message array")
2409
2533
  };
@@ -2419,19 +2543,21 @@ function parseUiRunRequestBody(c, body) {
2419
2543
  error: errorResponse(c, 400, "bad_request", "messages must be a non-empty Message array")
2420
2544
  };
2421
2545
  }
2422
- const history = messages.slice(0, -1);
2423
- const request = { message };
2424
- if (history.length > 0) request.history = history;
2425
- 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 };
2426
2552
  }
2427
2553
  function parseRunRequestOptions(c, body, request) {
2428
2554
  if ("sessionId" in body) {
2429
2555
  if (typeof body.sessionId !== "string" || body.sessionId.trim().length === 0) {
2430
2556
  return { error: errorResponse(c, 400, "bad_request", "sessionId must be a string") };
2431
2557
  }
2432
- if (request.history !== void 0) {
2558
+ if (request.messages.length !== 1 || request.messages[0]?.role !== "user") {
2433
2559
  return {
2434
- 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")
2435
2561
  };
2436
2562
  }
2437
2563
  request.sessionId = body.sessionId;
@@ -2459,12 +2585,10 @@ function parseRunRequestOptions(c, body, request) {
2459
2585
  request.toolConcurrency = body.toolConcurrency;
2460
2586
  }
2461
2587
  if ("model" in body) {
2462
- if (typeof body.model === "string") {
2463
- request.model = body.model;
2464
- } 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") {
2465
2589
  request.model = {
2466
- provider: body.model.provider,
2467
- model: body.model.model
2590
+ providerId: body.model.providerId,
2591
+ modelId: body.model.modelId
2468
2592
  };
2469
2593
  } else {
2470
2594
  return {
@@ -2472,7 +2596,7 @@ function parseRunRequestOptions(c, body, request) {
2472
2596
  c,
2473
2597
  400,
2474
2598
  "bad_request",
2475
- "model must be a provider:model string or { provider, model } object"
2599
+ "model must be a { providerId, modelId } object"
2476
2600
  )
2477
2601
  };
2478
2602
  }
@@ -2493,6 +2617,14 @@ function parseRunRequestOptions(c, body, request) {
2493
2617
  }
2494
2618
  return request;
2495
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
+ }
2496
2628
 
2497
2629
  // src/runtime/session-logs.ts
2498
2630
  async function appendSessionLog(store, input) {
@@ -2627,6 +2759,25 @@ function memorySavedLog(props) {
2627
2759
  metadata
2628
2760
  };
2629
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
+ }
2630
2781
  function runFailedLog(sessionId, runId, error, startedAt) {
2631
2782
  return {
2632
2783
  sessionId,
@@ -2643,6 +2794,9 @@ function runFailedLog(sessionId, runId, error, startedAt) {
2643
2794
  }
2644
2795
  function logsFromStreamEvent(props) {
2645
2796
  const { event, sessionId, runId } = props;
2797
+ if (event.type === "memory_compaction") {
2798
+ return [memoryCompactedLog({ sessionId, runId, ...event })];
2799
+ }
2646
2800
  if (event.type === "turn_start") {
2647
2801
  return [
2648
2802
  {
@@ -2668,12 +2822,12 @@ function logsFromStreamEvent(props) {
2668
2822
  level: "info",
2669
2823
  category: "tool",
2670
2824
  event: "tool.called",
2671
- message: `Tool ${event.toolCall.function.name} called`,
2825
+ message: `Tool ${event.toolCall.toolName} called`,
2672
2826
  metadata: {
2673
2827
  turn: event.turn,
2674
- toolName: event.toolCall.function.name,
2675
- callId: event.toolCall.callId ?? event.toolCall.id,
2676
- 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))
2677
2831
  }
2678
2832
  }
2679
2833
  ];
@@ -2722,16 +2876,17 @@ function logsFromStreamEvent(props) {
2722
2876
  ];
2723
2877
  }
2724
2878
  if (event.type === "final") {
2879
+ const result = event.result;
2725
2880
  return [
2726
2881
  runCompletedLog({
2727
2882
  sessionId,
2728
2883
  runId,
2729
2884
  durationMs: Date.now() - props.startedAt,
2730
- usage: event.usage,
2731
- output: event.output,
2732
- messageCount: event.messages.length
2885
+ usage: result.usage,
2886
+ output: result.text,
2887
+ messageCount: result.messages.length
2733
2888
  }),
2734
- memorySavedLog({ sessionId, runId, messageCount: event.messages.length })
2889
+ memorySavedLog({ sessionId, runId, messageCount: result.messages.length })
2735
2890
  ];
2736
2891
  }
2737
2892
  if (event.type === "error") {
@@ -2843,16 +2998,16 @@ function childAgentLog(event, sessionId, runId) {
2843
2998
  level: "debug",
2844
2999
  category: "tool",
2845
3000
  event: "child_tool.called",
2846
- message: `Child agent ${event.agentName ?? event.agentId} called ${child.toolCall.function.name}`,
3001
+ message: `Child agent ${event.agentName ?? event.agentId} called ${child.toolCall.toolName}`,
2847
3002
  metadata: {
2848
3003
  parentToolName: event.toolName,
2849
3004
  agentId: event.agentId,
2850
3005
  hasAgentName: event.agentName !== void 0,
2851
3006
  turn: event.turn,
2852
3007
  childTurn: child.turn,
2853
- toolName: child.toolCall.function.name,
2854
- callId: child.toolCall.callId ?? child.toolCall.id,
2855
- 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))
2856
3011
  }
2857
3012
  }
2858
3013
  ];
@@ -2903,14 +3058,16 @@ function childAgentLog(event, sessionId, runId) {
2903
3058
  ];
2904
3059
  }
2905
3060
  if (child.type === "final") {
3061
+ const result = child.result;
2906
3062
  const metadata = {
2907
3063
  parentToolName: event.toolName,
2908
3064
  agentId: event.agentId,
2909
3065
  hasAgentName: event.agentName !== void 0,
2910
- outputBytes: byteLength2(child.output),
2911
- messageCount: child.messages.length
3066
+ outputBytes: byteLength2(result.text),
3067
+ messageCount: result.messages.length,
3068
+ status: result.status
2912
3069
  };
2913
- const usage = usageSummary(child.usage);
3070
+ const usage = usageSummary(result.usage);
2914
3071
  if (usage !== void 0) metadata.usage = usage;
2915
3072
  return [
2916
3073
  {
@@ -3036,12 +3193,12 @@ async function prepareAgentRun(c, props) {
3036
3193
  store: props.stores.sessions
3037
3194
  });
3038
3195
  const memoryMetadata = runMemoryMetadata(agentId, body, selectedModel, runId);
3039
- const promptMessage = normalizePromptMessage(body.message);
3196
+ const promptMessage = body.messages.at(-1);
3040
3197
  const sessionStore = props.stores.sessions;
3041
3198
  const shouldPersistSessionMessages = session !== void 0 && sessionStore !== void 0 && !usesStoreAsAgentMemory(runAgent, sessionStore);
3042
3199
  if (shouldPersistSessionMessages) {
3043
3200
  await sessionStore.append({
3044
- context: { sessionId: session.id, metadata: memoryMetadata },
3201
+ scope: { sessionId: session.id, metadata: memoryMetadata },
3045
3202
  runId,
3046
3203
  turn: 1,
3047
3204
  messages: [promptMessage]
@@ -3061,7 +3218,9 @@ async function prepareAgentRun(c, props) {
3061
3218
  body,
3062
3219
  memoryMetadata,
3063
3220
  execution,
3064
- options: createRunOptions(body, agentId, session),
3221
+ failureMessages: void 0,
3222
+ memoryCompactionLogged: false,
3223
+ options: createRunOptions(body, agentId, session, c.req.raw.signal),
3065
3224
  runAgent,
3066
3225
  runId,
3067
3226
  runStartedAt,
@@ -3106,7 +3265,7 @@ async function recordRunReceived(props) {
3106
3265
  sessionId: props.session.id,
3107
3266
  runId: props.runId,
3108
3267
  agentId: props.agentId,
3109
- message: props.body.message,
3268
+ message: props.body.messages.at(-1),
3110
3269
  stream: props.body.stream === true,
3111
3270
  hasTrace: props.body.trace !== void 0
3112
3271
  };
@@ -3154,21 +3313,29 @@ function runMemoryMetadata(agentId, body, selectedModel, runId) {
3154
3313
  return metadata;
3155
3314
  }
3156
3315
  function createRunExecution(props) {
3157
- if (props.session !== void 0 && props.runAgent.memory !== void 0) {
3158
- const session = props.runAgent.session(props.session.id, { metadata: props.memoryMetadata });
3316
+ const session = props.session;
3317
+ if (session !== void 0 && props.runAgent.memory !== void 0) {
3159
3318
  return {
3160
- generate: (options) => session.generate(props.body.message, options),
3161
- stream: (options) => session.stream(props.body.message, options)
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
+ })
3162
3329
  };
3163
3330
  }
3164
- const input = props.session !== void 0 ? [...props.session.messages, props.promptMessage] : props.body.history !== void 0 ? [...props.body.history, props.promptMessage] : props.body.message;
3331
+ const transcript = session !== void 0 ? [...session.messages, props.promptMessage] : props.body.messages;
3165
3332
  return {
3166
- generate: (options) => props.runAgent.generate(input, options),
3167
- stream: (options) => props.runAgent.stream(input, options)
3333
+ generate: (options) => props.runAgent.generate({ messages: transcript, ...options }),
3334
+ stream: (options) => props.runAgent.stream({ messages: transcript, ...options })
3168
3335
  };
3169
3336
  }
3170
- function createRunOptions(body, agentId, session) {
3171
- const options = { retries: {} };
3337
+ function createRunOptions(body, agentId, session, abortSignal) {
3338
+ const options = { abortSignal };
3172
3339
  if (body.maxTurns !== void 0) options.maxTurns = body.maxTurns;
3173
3340
  if (body.toolConcurrency !== void 0) options.toolConcurrency = body.toolConcurrency;
3174
3341
  if (body.trace !== void 0) {
@@ -3221,7 +3388,7 @@ function handleStreamingAgentRun(c, run, props) {
3221
3388
  }),
3222
3389
  store: run.sessionStore,
3223
3390
  session: run.session,
3224
- message: run.body.message,
3391
+ message: run.body.messages.at(-1),
3225
3392
  runId: run.runId,
3226
3393
  startedAt: run.runStartedAt,
3227
3394
  persistGeneratedMessages: run.shouldPersistSessionMessages
@@ -3229,6 +3396,7 @@ function handleStreamingAgentRun(c, run, props) {
3229
3396
  stream = persistedRun.events;
3230
3397
  }
3231
3398
  return streamAgentRunEvents(c, stream, {
3399
+ runId: run.runId,
3232
3400
  onCancel: async () => {
3233
3401
  props.approvalRuntime.cancelRun(run.runId);
3234
3402
  props.questionRuntime.cancelRun(run.runId);
@@ -3277,7 +3445,29 @@ async function startBufferedSessionRun(run, props) {
3277
3445
  if (run.session !== void 0) questionContext.sessionId = run.session.id;
3278
3446
  if (run.body.metadata !== void 0) questionContext.metadata = run.body.metadata;
3279
3447
  const effectiveHook = props.questionRuntime.createHook(questionContext);
3280
- return withInternalAgentRunOptions({ ...run.options }, { hook: effectiveHook, runId: run.runId });
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);
3281
3471
  }
3282
3472
  function createApprovalContext(run, emit) {
3283
3473
  const context = {
@@ -3313,7 +3503,7 @@ async function completeBufferedSessionRun(run, response) {
3313
3503
  const generatedMessages = response.messages.slice(1);
3314
3504
  if (generatedMessages.length > 0) {
3315
3505
  await run.sessionStore.append({
3316
- context: { sessionId: run.session.id, metadata: run.memoryMetadata },
3506
+ scope: { sessionId: run.session.id, metadata: run.memoryMetadata },
3317
3507
  runId: run.runId,
3318
3508
  turn: 1,
3319
3509
  messages: generatedMessages
@@ -3326,10 +3516,21 @@ async function completeBufferedSessionRun(run, response) {
3326
3516
  await run.sessionStore.saveSessionRunTranscript({
3327
3517
  id: run.session.id,
3328
3518
  runId: run.runId,
3329
- ...optionalTitle(run.body.message),
3519
+ ...optionalTitle(run.body.messages.at(-1)),
3330
3520
  transcript,
3331
3521
  status: "success"
3332
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
+ }
3333
3534
  await appendSessionLog(
3334
3535
  run.sessionStore,
3335
3536
  runCompletedLog({
@@ -3337,7 +3538,7 @@ async function completeBufferedSessionRun(run, response) {
3337
3538
  runId: run.runId,
3338
3539
  durationMs: durationMs2,
3339
3540
  usage: response.usage,
3340
- output: response.output,
3541
+ output: response.text,
3341
3542
  messageCount: response.messages.length
3342
3543
  })
3343
3544
  );
@@ -3354,17 +3555,14 @@ async function failBufferedSessionRun(run, error) {
3354
3555
  if (run.session === void 0 || run.sessionStore === void 0) {
3355
3556
  return;
3356
3557
  }
3357
- const messages = await run.sessionStore.load({
3358
- sessionId: run.session.id,
3359
- metadata: run.memoryMetadata
3360
- });
3361
3558
  const durationMs2 = Date.now() - run.runStartedAt;
3362
- const transcript = transcriptFromMessages(messages.slice(run.session.messageCount));
3559
+ const messages = run.failureMessages ?? [run.body.messages.at(-1)];
3560
+ const transcript = transcriptFromMessages([...messages]);
3363
3561
  assignTranscriptRunDuration(transcript, durationMs2);
3364
3562
  await run.sessionStore.saveSessionRunTranscript({
3365
3563
  id: run.session.id,
3366
3564
  runId: run.runId,
3367
- ...optionalTitle(run.body.message),
3565
+ ...optionalTitle(run.body.messages.at(-1)),
3368
3566
  transcript,
3369
3567
  status: "error",
3370
3568
  error: serializeError(error)
@@ -3374,9 +3572,6 @@ async function failBufferedSessionRun(run, error) {
3374
3572
  runFailedLog(run.session.id, run.runId, error, run.runStartedAt)
3375
3573
  );
3376
3574
  }
3377
- function normalizePromptMessage(message) {
3378
- return typeof message === "string" ? Message.user(message) : message;
3379
- }
3380
3575
  function usesStoreAsAgentMemory(agent, store) {
3381
3576
  const memoryStore = agent.memory?.store;
3382
3577
  return memoryStore !== void 0 && rawObservedStore(memoryStore) === rawObservedStore(store);
@@ -3763,7 +3958,7 @@ async function agentKnowledgeConfig(agent) {
3763
3958
  async function knowledgeSources(agent) {
3764
3959
  const toolIndexes = getAgentToolState(agent.agent).toolIndexes;
3765
3960
  const staticContext = staticContextDocuments(agent.agent);
3766
- const indexedContext = contextIndexes(agent.agent);
3961
+ const indexedContext = vectorContexts(agent.agent);
3767
3962
  const sources = [
3768
3963
  {
3769
3964
  sourceId: staticSourceId(),
@@ -3775,20 +3970,20 @@ async function knowledgeSources(agent) {
3775
3970
  }
3776
3971
  ];
3777
3972
  const dynamicContextSources = await Promise.all(
3778
- indexedContext.map(async (contextIndex, index) => {
3779
- const inspect = inspectFn(contextIndex.index);
3780
- const count = await inspectableCount(inspect, contextIndex.filter);
3973
+ indexedContext.map(async (vectorContext, index) => {
3974
+ const inspect = inspectFn(vectorContext.store);
3975
+ const count = await inspectableCount(inspect, vectorContext.filter);
3781
3976
  const source = {
3782
3977
  sourceId: dynamicContextSourceId(index),
3783
3978
  kind: "dynamic_context",
3784
3979
  label: `Dynamic context ${index + 1}`,
3785
3980
  count: 1,
3786
3981
  registrationIndex: index,
3787
- topK: contextIndex.topK,
3982
+ topK: vectorContext.topK,
3788
3983
  inspectable: inspect !== void 0
3789
3984
  };
3790
- if (contextIndex.threshold !== void 0) {
3791
- source.threshold = contextIndex.threshold;
3985
+ if (vectorContext.minScore !== void 0) {
3986
+ source.minScore = vectorContext.minScore;
3792
3987
  }
3793
3988
  if (count !== void 0) source.itemCount = count;
3794
3989
  return source;
@@ -3807,8 +4002,8 @@ async function knowledgeSources(agent) {
3807
4002
  topK: toolIndex.topK,
3808
4003
  inspectable: inspect !== void 0
3809
4004
  };
3810
- if (toolIndex.threshold !== void 0) {
3811
- source.threshold = toolIndex.threshold;
4005
+ if (toolIndex.minScore !== void 0) {
4006
+ source.minScore = toolIndex.minScore;
3812
4007
  }
3813
4008
  if (count !== void 0) source.itemCount = count;
3814
4009
  return source;
@@ -3827,20 +4022,20 @@ async function knowledgeItemsPage(agent, sourceId, request) {
3827
4022
  if (sourceId === staticSourceId()) {
3828
4023
  return staticKnowledgeItemsPage(agent, request);
3829
4024
  }
3830
- const dynamicContextIndex = dynamicSourceIndex(sourceId, "dynamic_context");
3831
- if (dynamicContextIndex !== void 0) {
3832
- const contextIndex = contextIndexes(agent.agent)[dynamicContextIndex];
3833
- if (contextIndex === 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) {
3834
4029
  return void 0;
3835
4030
  }
3836
- const inspect = inspectFn(contextIndex.index);
4031
+ const inspect = inspectFn(vectorContext.store);
3837
4032
  if (inspect === void 0) {
3838
4033
  return nonInspectablePage(agent.id, sourceId, "dynamic_context");
3839
4034
  }
3840
4035
  const page = await inspect({
3841
4036
  limit: request.limit,
3842
4037
  cursor: request.cursor,
3843
- filter: contextIndex.filter
4038
+ filter: vectorContext.filter
3844
4039
  });
3845
4040
  const result = {
3846
4041
  agentId: agent.id,
@@ -3881,12 +4076,12 @@ async function knowledgeItemsPage(agent, sourceId, request) {
3881
4076
  }
3882
4077
  return void 0;
3883
4078
  }
3884
- function inspectFn(index) {
3885
- if (!isRecord3(index) || typeof index.inspect !== "function") {
4079
+ function inspectFn(store) {
4080
+ if (!isRecord3(store) || typeof store.inspect !== "function") {
3886
4081
  return void 0;
3887
4082
  }
3888
- const inspect = index.inspect;
3889
- return (request) => inspect.call(index, request);
4083
+ const inspect = store.inspect;
4084
+ return (request) => inspect.call(store, request);
3890
4085
  }
3891
4086
  function staticKnowledgeItemsPage(agent, request) {
3892
4087
  const staticContext = staticContextDocuments(agent.agent);
@@ -4102,7 +4297,7 @@ function isRecord3(value) {
4102
4297
 
4103
4298
  // src/runtime/tool-metadata.ts
4104
4299
  import { getAgentToolState as getAgentToolState2 } from "@anvia/core/internal/agent";
4105
- var MCP_TOOL_METADATA_KEY = /* @__PURE__ */ Symbol.for("anvia.mcp.tool.metadata");
4300
+ import { isMcpTool } from "@anvia/core/mcp";
4106
4301
  function agentToolItems(agent) {
4107
4302
  const state = getAgentToolState2(agent.agent);
4108
4303
  const items = state.staticTools.map((tool) => ({ tool, source: "static" }));
@@ -4135,15 +4330,10 @@ function toolRequiresApproval(tool) {
4135
4330
  return approval !== void 0 && approval !== false;
4136
4331
  }
4137
4332
  function mcpServerName(tool) {
4138
- const metadata = tool[MCP_TOOL_METADATA_KEY];
4139
- if (typeof metadata !== "object" || metadata === null) {
4140
- return void 0;
4141
- }
4142
- const serverName = metadata.serverName;
4143
- return typeof serverName === "string" && serverName.length > 0 ? serverName : void 0;
4333
+ return isMcpTool(tool) ? tool.mcp.serverName : void 0;
4144
4334
  }
4145
- function agentHasMcpTools(agent) {
4146
- return agentToolItems(agent).some(({ tool }) => mcpServerName(tool) !== void 0);
4335
+ function agentHasMcpServers(agent) {
4336
+ return agent.agent.mcpServers.length > 0;
4147
4337
  }
4148
4338
 
4149
4339
  // src/runtime/config.ts
@@ -4165,7 +4355,7 @@ function agentConfig(agent) {
4165
4355
  function agentRuntimeSummary(agent) {
4166
4356
  const tools = agentToolItems(agent);
4167
4357
  const staticContext = staticContextDocuments(agent.agent);
4168
- const indexedContext = contextIndexes(agent.agent);
4358
+ const indexedContext = vectorContexts(agent.agent);
4169
4359
  const name = agent.name ?? agent.agent.name;
4170
4360
  const description = agent.description ?? agent.agent.description;
4171
4361
  const summary = {
@@ -4178,7 +4368,7 @@ function agentRuntimeSummary(agent) {
4178
4368
  mcpToolCount: tools.filter((item) => mcpServerName(item.tool) !== void 0).length,
4179
4369
  staticContextCount: staticContext.length,
4180
4370
  dynamicContextCount: indexedContext.length,
4181
- observerCount: agent.agent.observers.length,
4371
+ observerCount: Object.keys(agent.agent.observability?.observers ?? {}).length,
4182
4372
  hasMemory: agent.agent.memory !== void 0,
4183
4373
  hasLifecycle: agent.agent.lifecycle !== void 0,
4184
4374
  hasOutputSchema: agent.agent.outputSchema !== void 0
@@ -4250,7 +4440,7 @@ function capabilityConfig(_options, agents, pipelines, stores, sandboxCount = 0)
4250
4440
  if (agents.some((agent) => agent.agent.tools.length > 0)) {
4251
4441
  capabilities.tools = { enabled: true };
4252
4442
  }
4253
- if (agents.some(agentHasMcpTools)) {
4443
+ if (agents.some(agentHasMcpServers)) {
4254
4444
  capabilities.mcps = { enabled: true };
4255
4445
  }
4256
4446
  if (sandboxCount > 0) {
@@ -4354,43 +4544,29 @@ function registerMcpRoutes(app, props) {
4354
4544
  });
4355
4545
  }
4356
4546
  async function agentMcpMetadata(agent) {
4357
- const servers = /* @__PURE__ */ new Map();
4358
- const seen = /* @__PURE__ */ new Set();
4359
- for (const { tool, source } of agentToolItems(agent)) {
4360
- const serverName = mcpServerName(tool);
4361
- if (serverName === void 0) {
4362
- continue;
4363
- }
4364
- const definition = await tool.definition("");
4365
- const key = `${serverName}:${source}:${definition.name}`;
4366
- if (seen.has(key)) {
4367
- continue;
4368
- }
4369
- seen.add(key);
4370
- const tools = servers.get(serverName) ?? [];
4371
- tools.push({
4372
- name: definition.name,
4373
- description: definition.description,
4374
- parameters: definition.parameters,
4375
- source,
4376
- approval: approvalMetadata(tool)
4377
- });
4378
- servers.set(serverName, tools);
4379
- }
4380
- return [...servers.entries()].map(([name, tools]) => {
4381
- const sortedTools = tools.sort((left, right) => {
4382
- if (left.source !== right.source) {
4383
- return left.source === "static" ? -1 : 1;
4384
- }
4385
- return left.name.localeCompare(right.name);
4386
- });
4387
- return {
4388
- agentId: agent.id,
4389
- name,
4390
- toolCount: sortedTools.length,
4391
- tools: sortedTools
4392
- };
4393
- }).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)));
4394
4570
  }
4395
4571
 
4396
4572
  // src/runtime/memory.ts
@@ -4612,7 +4788,7 @@ function agentMemorySource(ref, label, agentId, storeKindValue, inspector) {
4612
4788
  ).slice(0, options.limit);
4613
4789
  },
4614
4790
  async getConversation(conversationRef) {
4615
- const conversation = await inspector.getConversation(conversationRef);
4791
+ const conversation = await inspector.getConversation({ ref: conversationRef });
4616
4792
  return conversation === void 0 ? void 0 : inspectorConversationDetail(conversation, summary.agentIds);
4617
4793
  }
4618
4794
  };
@@ -4835,12 +5011,12 @@ function pipelineRunFailedLog(pipelineId, runId, error, startedAt) {
4835
5011
  }
4836
5012
  };
4837
5013
  }
4838
- function pipelineStageLog(pipelineId, runId, event) {
5014
+ function pipelineStageLog(event, studioPipelineId = event.pipelineId) {
4839
5015
  const category = stageCategory(event.node);
4840
5016
  if (event.type === "stage_started") {
4841
5017
  return {
4842
- pipelineId,
4843
- runId,
5018
+ pipelineId: studioPipelineId,
5019
+ runId: event.runId,
4844
5020
  level: "debug",
4845
5021
  category,
4846
5022
  event: `${event.node.kind}.started`,
@@ -4850,8 +5026,8 @@ function pipelineStageLog(pipelineId, runId, event) {
4850
5026
  }
4851
5027
  if (event.type === "stage_completed") {
4852
5028
  return {
4853
- pipelineId,
4854
- runId,
5029
+ pipelineId: studioPipelineId,
5030
+ runId: event.runId,
4855
5031
  level: "debug",
4856
5032
  category,
4857
5033
  event: `${event.node.kind}.completed`,
@@ -4863,8 +5039,8 @@ function pipelineStageLog(pipelineId, runId, event) {
4863
5039
  };
4864
5040
  }
4865
5041
  return {
4866
- pipelineId,
4867
- runId,
5042
+ pipelineId: studioPipelineId,
5043
+ runId: event.runId,
4868
5044
  level: "error",
4869
5045
  category,
4870
5046
  event: `${event.node.kind}.failed`,
@@ -4891,6 +5067,7 @@ function stageCategory(node) {
4891
5067
  function nodeMetadata(node) {
4892
5068
  const metadata = {
4893
5069
  nodeId: node.id,
5070
+ nodePath: [...node.path],
4894
5071
  kind: node.kind,
4895
5072
  label: node.label
4896
5073
  };
@@ -5052,17 +5229,24 @@ async function executePipelineRun(c, props, pipeline, body) {
5052
5229
  if (body.metadata !== void 0) streamOptions.metadata = body.metadata;
5053
5230
  if (props.logStore !== void 0) streamOptions.logStore = props.logStore;
5054
5231
  if (props.runStore !== void 0) streamOptions.runStore = props.runStore;
5232
+ streamOptions.abortSignal = c.req.raw.signal;
5055
5233
  return streamPipelineRun(c, streamOptions);
5056
5234
  }
5057
5235
  try {
5058
5236
  await appendPipelineLog(props.logStore, pipelineRunStartedLog(pipeline, runId));
5059
- 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,
5060
5242
  observer: {
5061
5243
  async onEvent(event) {
5062
- await appendPipelineLog(props.logStore, pipelineStageLog(pipeline.id, runId, event));
5244
+ await appendPipelineLog(props.logStore, pipelineStageLog(event, pipeline.id));
5063
5245
  }
5064
- }
5246
+ },
5247
+ failOnObserverError: true
5065
5248
  });
5249
+ const output = result.output;
5066
5250
  const jsonOutput = toJsonValue(output);
5067
5251
  const endedAt = Date.now();
5068
5252
  const successRecord = {
@@ -5127,19 +5311,24 @@ function streamPipelineRun(_c, props) {
5127
5311
  async function* pipelineRunEvents(props) {
5128
5312
  yield* emitPipelineLog(props.logStore, pipelineRunStartedLog(props.pipeline, props.runId));
5129
5313
  const events = new AsyncEventQueue();
5130
- 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,
5131
5319
  observer: {
5132
5320
  async onEvent(event) {
5133
5321
  const log = await appendPipelineLog(
5134
5322
  props.logStore,
5135
- pipelineStageLog(props.pipeline.id, props.runId, event)
5323
+ pipelineStageLog(event, props.pipeline.id)
5136
5324
  );
5137
5325
  if (log !== void 0) {
5138
5326
  events.push({ type: "pipeline_log", log });
5139
5327
  }
5140
5328
  }
5141
- }
5142
- }).then(async (output) => {
5329
+ },
5330
+ failOnObserverError: true
5331
+ }).then(async ({ output }) => {
5143
5332
  const jsonOutput = toJsonValue(output);
5144
5333
  const endedAt = Date.now();
5145
5334
  const successRecord = {
@@ -6143,6 +6332,16 @@ function createInMemoryStudioStore() {
6143
6332
  }
6144
6333
  var InMemoryStudioStore = class {
6145
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
+ };
6146
6345
  sessions = /* @__PURE__ */ new Map();
6147
6346
  traces = /* @__PURE__ */ new Map();
6148
6347
  pipelineLogs = /* @__PURE__ */ new Map();
@@ -6184,20 +6383,20 @@ var InMemoryStudioStore = class {
6184
6383
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
6185
6384
  return materializeSession(session);
6186
6385
  }
6187
- load(context) {
6188
- return Promise.resolve(this.sessions.get(context.sessionId)?.messages ?? []);
6386
+ load({ scope }) {
6387
+ return Promise.resolve(cloneMessages(this.sessions.get(scope.sessionId)?.messages ?? []));
6189
6388
  }
6190
6389
  append(input) {
6191
- const session = this.sessions.get(input.context.sessionId);
6390
+ const session = this.sessions.get(input.scope.sessionId);
6192
6391
  if (session !== void 0) {
6193
- session.messages.push(...input.messages);
6392
+ session.messages.push(...cloneMessages(input.messages));
6194
6393
  session.messageCount = session.messages.length;
6195
6394
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
6196
6395
  }
6197
6396
  return Promise.resolve();
6198
6397
  }
6199
- clear(context) {
6200
- const session = this.sessions.get(context.sessionId);
6398
+ clear({ scope }) {
6399
+ const session = this.sessions.get(scope.sessionId);
6201
6400
  if (session !== void 0) {
6202
6401
  session.messages = [];
6203
6402
  session.runs = [];
@@ -6208,13 +6407,26 @@ var InMemoryStudioStore = class {
6208
6407
  }
6209
6408
  async recordError(input) {
6210
6409
  await this.saveSessionRunTranscript({
6211
- id: input.context.sessionId,
6212
- runId: studioRunId(input.context) ?? input.runId,
6410
+ id: input.scope.sessionId,
6411
+ runId: studioRunId(input.scope) ?? input.runId,
6213
6412
  transcript: transcriptFromMessages(input.messages),
6214
6413
  status: "error",
6215
6414
  error: serializeJsonError(input.error)
6216
6415
  });
6217
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
+ }
6218
6430
  saveSessionRunTranscript(input) {
6219
6431
  const session = this.sessions.get(input.id);
6220
6432
  if (session === void 0) {
@@ -6340,18 +6552,24 @@ function sessionSummary(session) {
6340
6552
  function materializeSession(session) {
6341
6553
  return {
6342
6554
  ...sessionSummary(session),
6343
- messages: [...session.messages],
6555
+ messages: cloneMessages(session.messages),
6344
6556
  transcript: renumberTranscript(session.runs.flatMap((run) => run.transcript))
6345
6557
  };
6346
6558
  }
6559
+ function cloneMessages(messages) {
6560
+ return structuredClone([...messages]);
6561
+ }
6347
6562
  function traceAgentId(trace) {
6348
6563
  const nestedMetadata = trace.metadata?.metadata;
6349
6564
  return isJsonObject(nestedMetadata) && typeof nestedMetadata.agentId === "string" ? nestedMetadata.agentId : void 0;
6350
6565
  }
6351
- function studioRunId(context) {
6352
- const value = context.metadata?.studioRunId;
6566
+ function studioRunId(scope) {
6567
+ const value = scope.metadata?.studioRunId;
6353
6568
  return typeof value === "string" && value.length > 0 ? value : void 0;
6354
6569
  }
6570
+ function memoryRevision(messages) {
6571
+ return JSON.stringify(messages);
6572
+ }
6355
6573
  function serializeJsonError(error) {
6356
6574
  if (error instanceof Error) {
6357
6575
  return {
@@ -6877,11 +7095,11 @@ function uniqueAgentId(baseId, ids) {
6877
7095
  function agentMetadata(agent) {
6878
7096
  const metadata = {
6879
7097
  staticContextCount: staticContextDocuments(agent).length,
6880
- dynamicContextCount: contextIndexes(agent).length,
7098
+ dynamicContextCount: vectorContexts(agent).length,
6881
7099
  dynamicToolCount: getAgentToolState3(agent).toolIndexes.length,
6882
7100
  hasLifecycle: agent.lifecycle !== void 0,
6883
7101
  hasOutputSchema: agent.outputSchema !== void 0,
6884
- observerCount: agent.observers.length,
7102
+ observerCount: Object.keys(agent.observability?.observers ?? {}).length,
6885
7103
  approvalToolCount: agent.tools.filter(toolRequiresApproval).length
6886
7104
  };
6887
7105
  if (agent.defaultMaxTurns !== void 0) metadata.defaultMaxTurns = agent.defaultMaxTurns;
@@ -7012,30 +7230,37 @@ function createStudioApp(options) {
7012
7230
  return studio;
7013
7231
  }
7014
7232
  function withStudioTraceObserver(studioAgent, traceStore) {
7015
- if (traceStore === void 0 || hasStudioTraceObserver(studioAgent.agent)) {
7016
- 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
+ }
7017
7243
  }
7018
7244
  return {
7019
7245
  ...studioAgent,
7020
7246
  agent: cloneAgent(studioAgent.agent, {
7021
- observers: [
7022
- ...studioAgent.agent.observers,
7023
- { observer: new StudioTraceObserver({ store: traceStore }) }
7024
- ]
7247
+ observability: {
7248
+ observers: {
7249
+ ...existing?.observers ?? {},
7250
+ studio: studioObserver ?? new StudioTraceObserver({ store: traceStore })
7251
+ },
7252
+ primaryTrace: "studio",
7253
+ errorPolicy: existing?.errorPolicy ?? "ignore"
7254
+ }
7025
7255
  })
7026
7256
  };
7027
7257
  }
7028
- function hasStudioTraceObserver(agent) {
7029
- return agent.observers.some(
7030
- (registration) => registration.observer instanceof StudioTraceObserver
7031
- );
7032
- }
7033
7258
 
7034
7259
  // src/storage/sqlite-store.ts
7035
7260
  import { mkdirSync } from "fs";
7036
7261
  import { createRequire } from "module";
7037
7262
  import { dirname, resolve } from "path";
7038
- import { isJsonValue as isJsonValue2 } from "@anvia/core/completion";
7263
+ import { isJsonValue as isJsonValue3 } from "@anvia/core/completion";
7039
7264
  var DatabaseSync;
7040
7265
  function createSqliteSessionStore(options = {}) {
7041
7266
  return new SqliteSessionStore(options.path ?? ":memory:");
@@ -7046,6 +7271,13 @@ var SqliteSessionStore = class {
7046
7271
  }
7047
7272
  path;
7048
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
+ };
7049
7281
  db;
7050
7282
  listSessions(options) {
7051
7283
  const db = this.database();
@@ -7117,8 +7349,8 @@ var SqliteSessionStore = class {
7117
7349
  }
7118
7350
  return this.getSession(id);
7119
7351
  }
7120
- load(context) {
7121
- const session = this.getSession(context.sessionId);
7352
+ load({ scope }) {
7353
+ const session = this.getSession(scope.sessionId);
7122
7354
  return Promise.resolve(session?.messages ?? []);
7123
7355
  }
7124
7356
  append(input) {
@@ -7129,20 +7361,20 @@ var SqliteSessionStore = class {
7129
7361
  `SELECT id, agent_id, title, metadata_json, created_at, updated_at
7130
7362
  FROM anvia_studio_sessions
7131
7363
  WHERE id = $id`
7132
- ).get({ $id: input.context.sessionId });
7364
+ ).get({ $id: input.scope.sessionId });
7133
7365
  if (row === void 0) {
7134
7366
  db.exec("ROLLBACK");
7135
7367
  return Promise.resolve();
7136
7368
  }
7137
7369
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
7138
- const nextIndex = this.nextMessageIndex(input.context.sessionId);
7139
- 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);
7140
7372
  db.prepare(
7141
7373
  `UPDATE anvia_studio_sessions
7142
7374
  SET updated_at = $updatedAt
7143
7375
  WHERE id = $id`
7144
7376
  ).run({
7145
- $id: input.context.sessionId,
7377
+ $id: input.scope.sessionId,
7146
7378
  $updatedAt: updatedAt
7147
7379
  });
7148
7380
  db.exec("COMMIT");
@@ -7154,7 +7386,7 @@ var SqliteSessionStore = class {
7154
7386
  throw error;
7155
7387
  }
7156
7388
  }
7157
- clear(context) {
7389
+ clear({ scope }) {
7158
7390
  const db = this.database();
7159
7391
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
7160
7392
  try {
@@ -7164,14 +7396,14 @@ var SqliteSessionStore = class {
7164
7396
  SET updated_at = $updatedAt
7165
7397
  WHERE id = $id`
7166
7398
  ).run({
7167
- $id: context.sessionId,
7399
+ $id: scope.sessionId,
7168
7400
  $updatedAt: updatedAt
7169
7401
  });
7170
7402
  db.prepare("DELETE FROM anvia_studio_session_messages WHERE session_id = $id").run({
7171
- $id: context.sessionId
7403
+ $id: scope.sessionId
7172
7404
  });
7173
7405
  db.prepare("DELETE FROM anvia_studio_session_runs WHERE session_id = $id").run({
7174
- $id: context.sessionId
7406
+ $id: scope.sessionId
7175
7407
  });
7176
7408
  db.exec("COMMIT");
7177
7409
  return Promise.resolve();
@@ -7183,17 +7415,51 @@ var SqliteSessionStore = class {
7183
7415
  }
7184
7416
  }
7185
7417
  async recordError(input) {
7186
- const runId = studioRunId2(input.context) ?? input.runId;
7187
- 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);
7188
7420
  const transcript = existing === void 0 || parseJsonArray(existing.transcript_json).length === 0 ? transcriptFromMessages(input.messages) : parseJsonArray(existing.transcript_json);
7189
7421
  await this.saveSessionRunTranscript({
7190
- id: input.context.sessionId,
7422
+ id: input.scope.sessionId,
7191
7423
  runId,
7192
7424
  transcript,
7193
7425
  status: "error",
7194
7426
  error: serializeJsonError2(input.error)
7195
7427
  });
7196
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
+ }
7197
7463
  saveSessionRunTranscript(input) {
7198
7464
  const db = this.database();
7199
7465
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -7889,7 +8155,7 @@ var SqliteSessionStore = class {
7889
8155
  );
7890
8156
  messages.forEach((message, messageOffset) => {
7891
8157
  const messageIndex = startIndex + messageOffset;
7892
- if (message.metadata !== void 0 && !isJsonValue2(message.metadata)) {
8158
+ if (message.metadata !== void 0 && !isJsonValue3(message.metadata)) {
7893
8159
  throw new TypeError("Studio message metadata must be a strict JSON value.");
7894
8160
  }
7895
8161
  insertMessage.run({
@@ -7990,6 +8256,9 @@ function messageParts(message) {
7990
8256
  if (message.role === "system") {
7991
8257
  return [{ type: "text", value: { type: "text", text: message.content } }];
7992
8258
  }
8259
+ if (typeof message.content === "string") {
8260
+ return [{ type: "text", value: { type: "text", text: message.content } }];
8261
+ }
7993
8262
  return message.content.map((content) => ({
7994
8263
  type: content.type,
7995
8264
  value: content
@@ -7998,40 +8267,40 @@ function messageParts(message) {
7998
8267
  function messageFromRows(row, partRows) {
7999
8268
  const parts = partRows.map((partRow) => JSON.parse(partRow.part_json));
8000
8269
  const metadata = parseJsonValue(row.metadata_json);
8001
- if (metadata !== void 0 && !isJsonValue2(metadata)) {
8002
- 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.");
8003
8272
  }
8004
8273
  if (row.role === "system") {
8005
8274
  const message = {
8006
8275
  role: "system",
8007
- content: systemContentFromParts(parts)
8276
+ content: systemContentFromParts(parts),
8277
+ ...metadata === void 0 ? {} : { metadata }
8008
8278
  };
8009
- if (metadata !== void 0) message.metadata = metadata;
8010
8279
  return message;
8011
8280
  }
8012
8281
  if (row.role === "user") {
8013
8282
  const message = {
8014
8283
  role: "user",
8015
- content: parts
8284
+ content: parts,
8285
+ ...metadata === void 0 ? {} : { metadata }
8016
8286
  };
8017
- if (metadata !== void 0) message.metadata = metadata;
8018
8287
  return message;
8019
8288
  }
8020
8289
  if (row.role === "assistant") {
8021
8290
  const message = {
8022
8291
  role: "assistant",
8023
- content: parts
8292
+ content: parts,
8293
+ ...row.message_id === null ? {} : { id: row.message_id },
8294
+ ...metadata === void 0 ? {} : { metadata }
8024
8295
  };
8025
- if (row.message_id !== null) message.id = row.message_id;
8026
- if (metadata !== void 0) message.metadata = metadata;
8027
8296
  return message;
8028
8297
  }
8029
8298
  if (row.role === "tool") {
8030
8299
  const message = {
8031
8300
  role: "tool",
8032
- content: parts
8301
+ content: parts,
8302
+ ...metadata === void 0 ? {} : { metadata }
8033
8303
  };
8034
- if (metadata !== void 0) message.metadata = metadata;
8035
8304
  return message;
8036
8305
  }
8037
8306
  throw new Error(`Unsupported stored message role: ${row.role}`);
@@ -8116,10 +8385,13 @@ function parseJsonValue(value) {
8116
8385
  }
8117
8386
  return JSON.parse(value);
8118
8387
  }
8119
- function studioRunId2(context) {
8120
- const value = context.metadata?.studioRunId;
8388
+ function studioRunId2(scope) {
8389
+ const value = scope.metadata?.studioRunId;
8121
8390
  return typeof value === "string" && value.length > 0 ? value : void 0;
8122
8391
  }
8392
+ function memoryRevision2(messages) {
8393
+ return JSON.stringify(messages);
8394
+ }
8123
8395
  function serializeJsonError2(error) {
8124
8396
  if (error instanceof Error) {
8125
8397
  return {