@runtypelabs/persona 3.20.0 → 3.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3790,6 +3790,28 @@ var SequenceReorderBuffer = class {
3790
3790
  // src/client.ts
3791
3791
  var DEFAULT_ENDPOINT = "https://api.runtype.com/v1/dispatch";
3792
3792
  var DEFAULT_CLIENT_API_BASE = "https://api.runtype.com";
3793
+ function filenameFromMediaType(mediaType) {
3794
+ var _a, _b;
3795
+ const lower = mediaType.toLowerCase();
3796
+ const knownExtensions = {
3797
+ "application/pdf": "pdf",
3798
+ "application/json": "json",
3799
+ "application/zip": "zip",
3800
+ "text/plain": "txt",
3801
+ "text/csv": "csv",
3802
+ "text/markdown": "md"
3803
+ };
3804
+ const ext = knownExtensions[lower];
3805
+ if (ext) return `attachment.${ext}`;
3806
+ const slash = lower.indexOf("/");
3807
+ if (slash > 0) {
3808
+ const subtype = (_b = (_a = lower.slice(slash + 1).split(";")[0]) == null ? void 0 : _a.trim()) != null ? _b : "";
3809
+ if (subtype && subtype !== "octet-stream" && /^[a-z0-9.+-]+$/i.test(subtype)) {
3810
+ return `attachment.${subtype}`;
3811
+ }
3812
+ }
3813
+ return "attachment";
3814
+ }
3793
3815
  var hasValidContent = (message) => {
3794
3816
  if (message.contentParts && message.contentParts.length > 0) {
3795
3817
  return true;
@@ -5742,6 +5764,89 @@ var AgentWidgetClient = class {
5742
5764
  }
5743
5765
  }
5744
5766
  }
5767
+ } else if (payloadType === "agent_media") {
5768
+ const rawMedia = Array.isArray(payload.media) ? payload.media : [];
5769
+ const mediaContentParts = [];
5770
+ for (const part of rawMedia) {
5771
+ if (!part || typeof part !== "object") continue;
5772
+ const rec = part;
5773
+ const partType = typeof rec.type === "string" ? rec.type : void 0;
5774
+ const rawMediaType = typeof rec.mediaType === "string" ? rec.mediaType.toLowerCase() : "";
5775
+ let src = null;
5776
+ let mediaType = "";
5777
+ if (partType === "media") {
5778
+ const data = typeof rec.data === "string" ? rec.data : void 0;
5779
+ if (!data) continue;
5780
+ mediaType = rawMediaType.length > 0 ? rawMediaType : "application/octet-stream";
5781
+ src = `data:${mediaType};base64,${data}`;
5782
+ } else if (partType === "image-url") {
5783
+ const url = typeof rec.url === "string" ? rec.url : void 0;
5784
+ if (!url) continue;
5785
+ mediaType = rawMediaType;
5786
+ src = url;
5787
+ } else if (partType === "file-url") {
5788
+ const url = typeof rec.url === "string" ? rec.url : void 0;
5789
+ if (!url) continue;
5790
+ mediaType = rawMediaType;
5791
+ src = url;
5792
+ } else {
5793
+ continue;
5794
+ }
5795
+ if (!src) continue;
5796
+ if (partType === "image-url" || mediaType.startsWith("image/")) {
5797
+ mediaContentParts.push({
5798
+ type: "image",
5799
+ image: src,
5800
+ ...mediaType ? { mimeType: mediaType } : {}
5801
+ });
5802
+ } else if (mediaType.startsWith("audio/")) {
5803
+ mediaContentParts.push({
5804
+ type: "audio",
5805
+ audio: src,
5806
+ mimeType: mediaType
5807
+ });
5808
+ } else if (mediaType.startsWith("video/")) {
5809
+ mediaContentParts.push({
5810
+ type: "video",
5811
+ video: src,
5812
+ mimeType: mediaType
5813
+ });
5814
+ } else {
5815
+ const resolvedMediaType = mediaType || "application/octet-stream";
5816
+ mediaContentParts.push({
5817
+ type: "file",
5818
+ data: src,
5819
+ mimeType: resolvedMediaType,
5820
+ filename: filenameFromMediaType(resolvedMediaType)
5821
+ });
5822
+ }
5823
+ }
5824
+ if (mediaContentParts.length > 0) {
5825
+ const seq = nextSequence();
5826
+ const toolCallIdRaw = payload.toolCallId;
5827
+ const mediaIdSuffix = typeof toolCallIdRaw === "string" && toolCallIdRaw.length > 0 ? `${toolCallIdRaw}-${seq}` : String(seq);
5828
+ const mediaMessage = {
5829
+ id: `agent-media-${mediaIdSuffix}`,
5830
+ role: "assistant",
5831
+ content: "",
5832
+ contentParts: mediaContentParts,
5833
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
5834
+ streaming: false,
5835
+ sequence: seq,
5836
+ agentMetadata: {
5837
+ executionId: payload.executionId,
5838
+ iteration: payload.iteration
5839
+ }
5840
+ };
5841
+ emitMessage(mediaMessage);
5842
+ const prevAssistant = assistantMessage;
5843
+ if (prevAssistant) {
5844
+ prevAssistant.streaming = false;
5845
+ emitMessage(prevAssistant);
5846
+ }
5847
+ assistantMessage = null;
5848
+ assistantMessageRef.current = null;
5849
+ }
5745
5850
  } else if (payloadType === "agent_iteration_complete") {
5746
5851
  } else if (payloadType === "agent_reflection" || payloadType === "agent_reflect") {
5747
5852
  const reflectionId = `agent-reflection-${payload.executionId}-${payload.iteration}`;
@@ -7766,8 +7871,10 @@ var AgentWidgetSession = class _AgentWidgetSession {
7766
7871
  */
7767
7872
  async connectStream(stream, options) {
7768
7873
  var _a, _b, _c;
7769
- if (this.streaming) return;
7770
- (_a = this.abortController) == null ? void 0 : _a.abort();
7874
+ if (this.streaming && !(options == null ? void 0 : options.allowReentry)) return;
7875
+ if (!(options == null ? void 0 : options.allowReentry)) {
7876
+ (_a = this.abortController) == null ? void 0 : _a.abort();
7877
+ }
7771
7878
  let hasStale = false;
7772
7879
  for (const msg of this.messages) {
7773
7880
  if (msg.streaming) {
@@ -7801,7 +7908,7 @@ var AgentWidgetSession = class _AgentWidgetSession {
7801
7908
  * and pipes the response stream through connectStream().
7802
7909
  */
7803
7910
  async resolveApproval(approval, decision) {
7804
- var _a, _b, _c;
7911
+ var _a, _b, _c, _d;
7805
7912
  const approvalMessageId = `approval-${approval.id}`;
7806
7913
  const updatedApproval = {
7807
7914
  ...approval,
@@ -7818,6 +7925,9 @@ var AgentWidgetSession = class _AgentWidgetSession {
7818
7925
  approval: updatedApproval
7819
7926
  };
7820
7927
  this.upsertMessage(updatedMessage);
7928
+ (_a = this.abortController) == null ? void 0 : _a.abort();
7929
+ this.abortController = new AbortController();
7930
+ this.setStreaming(true);
7821
7931
  const approvalConfig = this.config.approval;
7822
7932
  const onDecision = approvalConfig && typeof approvalConfig === "object" ? approvalConfig.onDecision : void 0;
7823
7933
  try {
@@ -7848,7 +7958,7 @@ var AgentWidgetSession = class _AgentWidgetSession {
7848
7958
  if (!response.ok) {
7849
7959
  const errorData = await response.json().catch(() => null);
7850
7960
  throw new Error(
7851
- (_a = errorData == null ? void 0 : errorData.error) != null ? _a : `Approval request failed: ${response.status}`
7961
+ (_b = errorData == null ? void 0 : errorData.error) != null ? _b : `Approval request failed: ${response.status}`
7852
7962
  );
7853
7963
  }
7854
7964
  stream = response.body;
@@ -7856,23 +7966,35 @@ var AgentWidgetSession = class _AgentWidgetSession {
7856
7966
  stream = response;
7857
7967
  }
7858
7968
  if (stream) {
7859
- await this.connectStream(stream);
7860
- } else if (decision === "denied") {
7861
- this.appendMessage({
7862
- id: `denial-${approval.id}`,
7863
- role: "assistant",
7864
- content: "Tool execution was denied by user.",
7865
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
7866
- streaming: false,
7867
- sequence: this.nextSequence()
7868
- });
7969
+ await this.connectStream(stream, { allowReentry: true });
7970
+ } else {
7971
+ if (decision === "denied") {
7972
+ this.appendMessage({
7973
+ id: `denial-${approval.id}`,
7974
+ role: "assistant",
7975
+ content: "Tool execution was denied by user.",
7976
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
7977
+ streaming: false,
7978
+ sequence: this.nextSequence()
7979
+ });
7980
+ }
7981
+ this.setStreaming(false);
7982
+ this.abortController = null;
7869
7983
  }
7984
+ } else {
7985
+ this.setStreaming(false);
7986
+ this.abortController = null;
7870
7987
  }
7871
7988
  } catch (error) {
7872
- (_c = (_b = this.callbacks).onError) == null ? void 0 : _c.call(
7873
- _b,
7874
- error instanceof Error ? error : new Error(String(error))
7875
- );
7989
+ const isAbortError = error instanceof Error && (error.name === "AbortError" || error.message.includes("aborted") || error.message.includes("abort"));
7990
+ this.setStreaming(false);
7991
+ this.abortController = null;
7992
+ if (!isAbortError) {
7993
+ (_d = (_c = this.callbacks).onError) == null ? void 0 : _d.call(
7994
+ _c,
7995
+ error instanceof Error ? error : new Error(String(error))
7996
+ );
7997
+ }
7876
7998
  }
7877
7999
  }
7878
8000
  /**
@@ -7926,7 +8048,7 @@ var AgentWidgetSession = class _AgentWidgetSession {
7926
8048
  });
7927
8049
  }
7928
8050
  async resolveAskUserQuestion(toolMessage, answer) {
7929
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
8051
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
7930
8052
  const live = this.messages.find((m) => m.id === toolMessage.id);
7931
8053
  if (((_a = live == null ? void 0 : live.agentMetadata) == null ? void 0 : _a.askUserQuestionAnswered) === true) return;
7932
8054
  const executionId = (_b = toolMessage.agentMetadata) == null ? void 0 : _b.executionId;
@@ -7950,8 +8072,11 @@ var AgentWidgetSession = class _AgentWidgetSession {
7950
8072
  }
7951
8073
  }
7952
8074
  this.markAskUserQuestionResolved(toolMessage, structuredAnswers);
8075
+ (_h = this.abortController) == null ? void 0 : _h.abort();
8076
+ this.abortController = new AbortController();
8077
+ this.setStreaming(true);
7953
8078
  const toolCallId = toolMessage.toolCall.id;
7954
- const args = (_h = toolMessage.toolCall) == null ? void 0 : _h.args;
8079
+ const args = (_i = toolMessage.toolCall) == null ? void 0 : _i.args;
7955
8080
  const questions = Array.isArray(args == null ? void 0 : args.questions) ? args.questions : [];
7956
8081
  if (questions.length === 0) {
7957
8082
  const fallback = typeof answer === "string" ? answer : Object.entries(answer).map(
@@ -7997,17 +8122,25 @@ var AgentWidgetSession = class _AgentWidgetSession {
7997
8122
  if (!response.ok) {
7998
8123
  const errorData = await response.json().catch(() => null);
7999
8124
  throw new Error(
8000
- (_i = errorData == null ? void 0 : errorData.error) != null ? _i : `Resume failed: ${response.status}`
8125
+ (_j = errorData == null ? void 0 : errorData.error) != null ? _j : `Resume failed: ${response.status}`
8001
8126
  );
8002
8127
  }
8003
8128
  if (response.body) {
8004
- await this.connectStream(response.body);
8129
+ await this.connectStream(response.body, { allowReentry: true });
8130
+ } else {
8131
+ this.setStreaming(false);
8132
+ this.abortController = null;
8005
8133
  }
8006
8134
  } catch (error) {
8007
- (_k = (_j = this.callbacks).onError) == null ? void 0 : _k.call(
8008
- _j,
8009
- error instanceof Error ? error : new Error(String(error))
8010
- );
8135
+ const isAbortError = error instanceof Error && (error.name === "AbortError" || error.message.includes("aborted") || error.message.includes("abort"));
8136
+ this.setStreaming(false);
8137
+ this.abortController = null;
8138
+ if (!isAbortError) {
8139
+ (_l = (_k = this.callbacks).onError) == null ? void 0 : _l.call(
8140
+ _k,
8141
+ error instanceof Error ? error : new Error(String(error))
8142
+ );
8143
+ }
8011
8144
  }
8012
8145
  }
8013
8146
  cancel() {
@@ -11122,6 +11255,19 @@ var isSafeImageSrc = (src) => {
11122
11255
  if (!src.includes(":")) return true;
11123
11256
  return false;
11124
11257
  };
11258
+ var isSafeMediaSrc = (src) => {
11259
+ const lower = src.toLowerCase();
11260
+ if (lower.startsWith("javascript:")) return false;
11261
+ if (lower.startsWith("data:text/html")) return false;
11262
+ if (lower.startsWith("data:text/javascript")) return false;
11263
+ if (lower.startsWith("data:text/xml")) return false;
11264
+ if (lower.startsWith("data:application/xhtml")) return false;
11265
+ if (lower.startsWith("data:image/svg+xml")) return false;
11266
+ if (/^(?:https?|blob):/i.test(src)) return true;
11267
+ if (lower.startsWith("data:")) return true;
11268
+ if (!src.includes(":")) return true;
11269
+ return false;
11270
+ };
11125
11271
  var MESSAGE_IMAGE_PREVIEW_MAX_WIDTH_PX = 320;
11126
11272
  var MESSAGE_IMAGE_PREVIEW_MAX_HEIGHT_PX = 320;
11127
11273
  var getMessageImageParts = (message) => {
@@ -11132,6 +11278,24 @@ var getMessageImageParts = (message) => {
11132
11278
  (part) => part.type === "image" && typeof part.image === "string" && part.image.trim().length > 0
11133
11279
  );
11134
11280
  };
11281
+ var getMessageAudioParts = (message) => {
11282
+ if (!message.contentParts || message.contentParts.length === 0) return [];
11283
+ return message.contentParts.filter(
11284
+ (part) => part.type === "audio" && typeof part.audio === "string" && part.audio.trim().length > 0
11285
+ );
11286
+ };
11287
+ var getMessageVideoParts = (message) => {
11288
+ if (!message.contentParts || message.contentParts.length === 0) return [];
11289
+ return message.contentParts.filter(
11290
+ (part) => part.type === "video" && typeof part.video === "string" && part.video.trim().length > 0
11291
+ );
11292
+ };
11293
+ var getMessageFileParts = (message) => {
11294
+ if (!message.contentParts || message.contentParts.length === 0) return [];
11295
+ return message.contentParts.filter(
11296
+ (part) => part.type === "file" && typeof part.data === "string" && part.data.trim().length > 0
11297
+ );
11298
+ };
11135
11299
  var createMessageImagePreviews = (imageParts, hasVisibleText, onPreviewFailed) => {
11136
11300
  if (imageParts.length === 0) return null;
11137
11301
  try {
@@ -11200,6 +11364,109 @@ var createMessageImagePreviews = (imageParts, hasVisibleText, onPreviewFailed) =
11200
11364
  return null;
11201
11365
  }
11202
11366
  };
11367
+ var createMessageAudioPreviews = (audioParts) => {
11368
+ if (audioParts.length === 0) return null;
11369
+ try {
11370
+ const container = createElement(
11371
+ "div",
11372
+ "persona-flex persona-flex-col persona-gap-2"
11373
+ );
11374
+ container.setAttribute("data-message-attachments", "audio");
11375
+ let visible = 0;
11376
+ audioParts.forEach((part) => {
11377
+ if (!isSafeMediaSrc(part.audio)) return;
11378
+ const audioElement = createElement("audio");
11379
+ audioElement.controls = true;
11380
+ audioElement.preload = "metadata";
11381
+ audioElement.src = part.audio;
11382
+ audioElement.style.display = "block";
11383
+ audioElement.style.width = "100%";
11384
+ audioElement.style.maxWidth = `${MESSAGE_IMAGE_PREVIEW_MAX_WIDTH_PX}px`;
11385
+ container.appendChild(audioElement);
11386
+ visible += 1;
11387
+ });
11388
+ if (visible === 0) {
11389
+ container.remove();
11390
+ return null;
11391
+ }
11392
+ return container;
11393
+ } catch {
11394
+ return null;
11395
+ }
11396
+ };
11397
+ var createMessageVideoPreviews = (videoParts) => {
11398
+ if (videoParts.length === 0) return null;
11399
+ try {
11400
+ const container = createElement(
11401
+ "div",
11402
+ "persona-flex persona-flex-col persona-gap-2"
11403
+ );
11404
+ container.setAttribute("data-message-attachments", "video");
11405
+ let visible = 0;
11406
+ videoParts.forEach((part) => {
11407
+ if (!isSafeMediaSrc(part.video)) return;
11408
+ const videoElement = createElement("video");
11409
+ videoElement.controls = true;
11410
+ videoElement.preload = "metadata";
11411
+ videoElement.src = part.video;
11412
+ videoElement.style.display = "block";
11413
+ videoElement.style.width = "100%";
11414
+ videoElement.style.maxWidth = `${MESSAGE_IMAGE_PREVIEW_MAX_WIDTH_PX}px`;
11415
+ videoElement.style.maxHeight = `${MESSAGE_IMAGE_PREVIEW_MAX_HEIGHT_PX}px`;
11416
+ videoElement.style.borderRadius = "10px";
11417
+ videoElement.style.backgroundColor = "var(--persona-attachment-image-bg, var(--persona-container, #f3f4f6))";
11418
+ container.appendChild(videoElement);
11419
+ visible += 1;
11420
+ });
11421
+ if (visible === 0) {
11422
+ container.remove();
11423
+ return null;
11424
+ }
11425
+ return container;
11426
+ } catch {
11427
+ return null;
11428
+ }
11429
+ };
11430
+ var createMessageFilePreviews = (fileParts) => {
11431
+ if (fileParts.length === 0) return null;
11432
+ try {
11433
+ const container = createElement(
11434
+ "div",
11435
+ "persona-flex persona-flex-col persona-gap-2"
11436
+ );
11437
+ container.setAttribute("data-message-attachments", "files");
11438
+ let visible = 0;
11439
+ fileParts.forEach((part) => {
11440
+ if (!isSafeMediaSrc(part.data)) return;
11441
+ const link = createElement("a");
11442
+ link.href = part.data;
11443
+ link.download = part.filename;
11444
+ link.target = "_blank";
11445
+ link.rel = "noopener noreferrer";
11446
+ link.textContent = part.filename;
11447
+ link.className = "persona-message-file-attachment";
11448
+ link.style.display = "inline-flex";
11449
+ link.style.alignItems = "center";
11450
+ link.style.gap = "6px";
11451
+ link.style.padding = "6px 10px";
11452
+ link.style.borderRadius = "8px";
11453
+ link.style.fontSize = "0.875rem";
11454
+ link.style.textDecoration = "underline";
11455
+ link.style.backgroundColor = "var(--persona-attachment-file-bg, var(--persona-container, #f3f4f6))";
11456
+ link.style.border = "1px solid var(--persona-attachment-file-border, var(--persona-border, #e5e7eb))";
11457
+ link.style.color = "inherit";
11458
+ container.appendChild(link);
11459
+ visible += 1;
11460
+ });
11461
+ if (visible === 0) {
11462
+ container.remove();
11463
+ return null;
11464
+ }
11465
+ return container;
11466
+ } catch {
11467
+ return null;
11468
+ }
11469
+ };
11203
11470
  var createTypingIndicator = () => {
11204
11471
  const container = document.createElement("div");
11205
11472
  container.className = "persona-flex persona-items-center persona-space-x-1 persona-h-5 persona-mt-2";
@@ -11530,6 +11797,27 @@ var createStandardBubble = (message, transform, layoutConfig, actionsConfig, act
11530
11797
  textContentDiv.style.display = "";
11531
11798
  }
11532
11799
  }
11800
+ const audioParts = getMessageAudioParts(message);
11801
+ if (audioParts.length > 0) {
11802
+ const audioPreviews = createMessageAudioPreviews(audioParts);
11803
+ if (audioPreviews) {
11804
+ bubble.appendChild(audioPreviews);
11805
+ }
11806
+ }
11807
+ const videoParts = getMessageVideoParts(message);
11808
+ if (videoParts.length > 0) {
11809
+ const videoPreviews = createMessageVideoPreviews(videoParts);
11810
+ if (videoPreviews) {
11811
+ bubble.appendChild(videoPreviews);
11812
+ }
11813
+ }
11814
+ const fileParts = getMessageFileParts(message);
11815
+ if (fileParts.length > 0) {
11816
+ const filePreviews = createMessageFilePreviews(fileParts);
11817
+ if (filePreviews) {
11818
+ bubble.appendChild(filePreviews);
11819
+ }
11820
+ }
11533
11821
  bubble.appendChild(contentDiv);
11534
11822
  if (showTimestamp && timestampPosition === "below" && message.createdAt) {
11535
11823
  const timestamp = createTimestamp(message, timestampConfig);
@@ -728,10 +728,28 @@ type FileContentPart = {
728
728
  mimeType: string;
729
729
  filename: string;
730
730
  };
731
+ /**
732
+ * Audio content part for multi-modal messages
733
+ * Supports base64 data URIs or URLs
734
+ */
735
+ type AudioContentPart = {
736
+ type: 'audio';
737
+ audio: string;
738
+ mimeType?: string;
739
+ };
740
+ /**
741
+ * Video content part for multi-modal messages
742
+ * Supports base64 data URIs or URLs
743
+ */
744
+ type VideoContentPart = {
745
+ type: 'video';
746
+ video: string;
747
+ mimeType?: string;
748
+ };
731
749
  /**
732
750
  * Union type for all content part types
733
751
  */
734
- type ContentPart = TextContentPart | ImageContentPart | FileContentPart;
752
+ type ContentPart = TextContentPart | ImageContentPart | FileContentPart | AudioContentPart | VideoContentPart;
735
753
  /**
736
754
  * Message content can be a simple string or an array of content parts
737
755
  */
@@ -728,10 +728,28 @@ type FileContentPart = {
728
728
  mimeType: string;
729
729
  filename: string;
730
730
  };
731
+ /**
732
+ * Audio content part for multi-modal messages
733
+ * Supports base64 data URIs or URLs
734
+ */
735
+ type AudioContentPart = {
736
+ type: 'audio';
737
+ audio: string;
738
+ mimeType?: string;
739
+ };
740
+ /**
741
+ * Video content part for multi-modal messages
742
+ * Supports base64 data URIs or URLs
743
+ */
744
+ type VideoContentPart = {
745
+ type: 'video';
746
+ video: string;
747
+ mimeType?: string;
748
+ };
731
749
  /**
732
750
  * Union type for all content part types
733
751
  */
734
- type ContentPart = TextContentPart | ImageContentPart | FileContentPart;
752
+ type ContentPart = TextContentPart | ImageContentPart | FileContentPart | AudioContentPart | VideoContentPart;
735
753
  /**
736
754
  * Message content can be a simple string or an array of content parts
737
755
  */