@runtypelabs/persona 4.6.0 → 4.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -783,6 +783,7 @@ type RuntypeExecutionStreamEvent = ({
783
783
  };
784
784
  type: "execution_complete";
785
785
  }) | ({
786
+ blockReason?: string;
786
787
  code?: string;
787
788
  completedAt?: string;
788
789
  error: string | {
@@ -1037,6 +1038,7 @@ type RuntypeExecutionStreamEvent = ({
1037
1038
  startedAt?: string;
1038
1039
  subagent?: {
1039
1040
  agentName?: string;
1041
+ parentToolCallId?: string;
1040
1042
  toolName: string;
1041
1043
  };
1042
1044
  timeout?: number;
@@ -1130,6 +1132,7 @@ type RuntypeFlowSSEEvent = {
1130
1132
  totalTokensUsed?: number;
1131
1133
  type: "flow_complete";
1132
1134
  } | ({
1135
+ blockReason?: string;
1133
1136
  code?: string;
1134
1137
  error: string | {
1135
1138
  code: string;
@@ -1150,6 +1153,7 @@ type RuntypeFlowSSEEvent = {
1150
1153
  type: "flow_error";
1151
1154
  upgradeUrl?: string;
1152
1155
  }) | ({
1156
+ approvalId?: string;
1153
1157
  awaitReason?: string;
1154
1158
  awaitedAt: string;
1155
1159
  crawlId?: string;
@@ -1160,6 +1164,7 @@ type RuntypeFlowSSEEvent = {
1160
1164
  parameters?: Record<string, unknown>;
1161
1165
  seq?: number;
1162
1166
  stepId?: string;
1167
+ timeout?: number;
1163
1168
  toolCallId?: string;
1164
1169
  toolId?: string;
1165
1170
  toolName?: string;
@@ -783,6 +783,7 @@ type RuntypeExecutionStreamEvent = ({
783
783
  };
784
784
  type: "execution_complete";
785
785
  }) | ({
786
+ blockReason?: string;
786
787
  code?: string;
787
788
  completedAt?: string;
788
789
  error: string | {
@@ -1037,6 +1038,7 @@ type RuntypeExecutionStreamEvent = ({
1037
1038
  startedAt?: string;
1038
1039
  subagent?: {
1039
1040
  agentName?: string;
1041
+ parentToolCallId?: string;
1040
1042
  toolName: string;
1041
1043
  };
1042
1044
  timeout?: number;
@@ -1130,6 +1132,7 @@ type RuntypeFlowSSEEvent = {
1130
1132
  totalTokensUsed?: number;
1131
1133
  type: "flow_complete";
1132
1134
  } | ({
1135
+ blockReason?: string;
1133
1136
  code?: string;
1134
1137
  error: string | {
1135
1138
  code: string;
@@ -1150,6 +1153,7 @@ type RuntypeFlowSSEEvent = {
1150
1153
  type: "flow_error";
1151
1154
  upgradeUrl?: string;
1152
1155
  }) | ({
1156
+ approvalId?: string;
1153
1157
  awaitReason?: string;
1154
1158
  awaitedAt: string;
1155
1159
  crawlId?: string;
@@ -1160,6 +1164,7 @@ type RuntypeFlowSSEEvent = {
1160
1164
  parameters?: Record<string, unknown>;
1161
1165
  seq?: number;
1162
1166
  stepId?: string;
1167
+ timeout?: number;
1163
1168
  toolCallId?: string;
1164
1169
  toolId?: string;
1165
1170
  toolName?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runtypelabs/persona",
3
- "version": "4.6.0",
3
+ "version": "4.6.1",
4
4
  "description": "Themeable, pluggable streaming agent widget for websites, in plain JS with support for voice input and reasoning / tool output.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -79,6 +79,7 @@
79
79
  },
80
80
  "devDependencies": {
81
81
  "@size-limit/file": "^12.1.0",
82
+ "acorn": "^8.15.0",
82
83
  "@types/node": "^20.12.7",
83
84
  "@typescript-eslint/eslint-plugin": "^7.0.0",
84
85
  "@typescript-eslint/parser": "^7.0.0",
@@ -120,7 +121,8 @@
120
121
  "access": "public"
121
122
  },
122
123
  "scripts": {
123
- "build": "rimraf dist && pnpm run build:styles && pnpm run build:markdown-parsers && pnpm run build:client && pnpm run build:installer && pnpm run build:launcher && pnpm run build:webmcp-polyfill && pnpm run build:runtype-tts && pnpm run build:theme-ref && pnpm run build:codegen && pnpm run build:theme-editor && pnpm run build:theme-editor-preview && pnpm run build:testing && pnpm run build:smart-dom-reader && pnpm run build:voice-worklet-player && pnpm run build:plugin-kit && pnpm run build:animations",
124
+ "build": "rimraf dist && pnpm run build:styles && pnpm run build:markdown-parsers && pnpm run build:client && pnpm run build:installer && pnpm run build:launcher && pnpm run build:webmcp-polyfill && pnpm run build:runtype-tts && pnpm run build:theme-ref && pnpm run build:codegen && pnpm run build:theme-editor && pnpm run build:theme-editor-preview && pnpm run build:testing && pnpm run build:smart-dom-reader && pnpm run build:voice-worklet-player && pnpm run build:plugin-kit && pnpm run build:animations && pnpm run check:dist-vite8",
125
+ "check:dist-vite8": "node scripts/check-dist-no-in-for-init.mjs",
124
126
  "build:markdown-parsers": "tsup --config tsup.markdown-parsers.config.ts",
125
127
  "build:plugin-kit": "tsup src/plugin-kit.ts --format esm,cjs --minify --dts --out-dir dist --no-splitting",
126
128
  "build:theme-editor": "tsup src/theme-editor.ts --format esm,cjs --minify --dts --out-dir dist --no-splitting",
package/src/client.ts CHANGED
@@ -2562,7 +2562,11 @@ export class AgentWidgetClient {
2562
2562
  const message =
2563
2563
  typeof e === "string" && e !== ""
2564
2564
  ? e
2565
- : e != null && typeof e === "object" && "message" in e
2565
+ : // Reflect.has, not `in`: the `in` operator inside an arrow body can
2566
+ // be minified into a `for(init;;)` head, which Oxc mis-parses and
2567
+ // Rolldown (Vite 8) silently emits as an empty chunk. Same
2568
+ // [[HasProperty]] semantics. Enforced by scripts/check-dist-no-in-for-init.mjs.
2569
+ e != null && typeof e === "object" && Reflect.has(e, "message")
2566
2570
  ? String((e as { message?: unknown }).message ?? "Step failed")
2567
2571
  : "Step failed";
2568
2572
  onEvent({ type: "error", error: new Error(message) });
@@ -3145,7 +3149,8 @@ export class AgentWidgetClient {
3145
3149
  const e = payload.error;
3146
3150
  if (typeof e === "string" && e !== "") {
3147
3151
  resolvedError = new Error(e);
3148
- } else if (e != null && typeof e === "object" && "message" in e) {
3152
+ } else if (e != null && typeof e === "object" && Reflect.has(e, "message")) {
3153
+ // Reflect.has, not `in` — see the note on the equivalent guard above.
3149
3154
  resolvedError = new Error(String((e as { message?: unknown }).message ?? e));
3150
3155
  }
3151
3156
  }
@@ -41,6 +41,7 @@ export type RuntypeExecutionStreamEvent = ({
41
41
  };
42
42
  type: "execution_complete";
43
43
  }) | ({
44
+ blockReason?: string;
44
45
  code?: string;
45
46
  completedAt?: string;
46
47
  error: string | {
@@ -295,6 +296,7 @@ export type RuntypeExecutionStreamEvent = ({
295
296
  startedAt?: string;
296
297
  subagent?: {
297
298
  agentName?: string;
299
+ parentToolCallId?: string;
298
300
  toolName: string;
299
301
  };
300
302
  timeout?: number;
@@ -389,6 +391,7 @@ export type RuntypeFlowSSEEvent = {
389
391
  totalTokensUsed?: number;
390
392
  type: "flow_complete";
391
393
  } | ({
394
+ blockReason?: string;
392
395
  code?: string;
393
396
  error: string | {
394
397
  code: string;
@@ -409,6 +412,7 @@ export type RuntypeFlowSSEEvent = {
409
412
  type: "flow_error";
410
413
  upgradeUrl?: string;
411
414
  }) | ({
415
+ approvalId?: string;
412
416
  awaitReason?: string;
413
417
  awaitedAt: string;
414
418
  crawlId?: string;
@@ -419,6 +423,7 @@ export type RuntypeFlowSSEEvent = {
419
423
  parameters?: Record<string, unknown>;
420
424
  seq?: number;
421
425
  stepId?: string;
426
+ timeout?: number;
422
427
  toolCallId?: string;
423
428
  toolId?: string;
424
429
  toolName?: string;
@@ -673,7 +678,7 @@ export type RuntypeClientInitResponse = {
673
678
  welcomeMessage?: string | null;
674
679
  };
675
680
  expiresAt: string;
676
- flow: {
681
+ flow?: {
677
682
  description?: string | null;
678
683
  id: string;
679
684
  name?: string | null;
@@ -695,6 +700,10 @@ export type RuntypeClientChatRequest = {
695
700
  untrustedContentHint?: boolean;
696
701
  }>;
697
702
  clientToolsFingerprint?: string;
703
+ identityProof?: {
704
+ provider: string;
705
+ token: string;
706
+ };
698
707
  inputs?: Record<string, unknown>;
699
708
  messages: Array<{
700
709
  content: string | (Array<{
@@ -83,4 +83,51 @@ describe("morphMessages", () => {
83
83
  expect(container.querySelector("span")!.textContent).toBe("New text");
84
84
  });
85
85
  });
86
+
87
+ describe("data-tool-elapsed (live duration counter)", () => {
88
+ it("preserves the live span's timer-owned text while the same tool is active", () => {
89
+ // The 100ms global timer wrote "0.3s"; a re-render arrives carrying the
90
+ // render-time value "<0.1s". Morphing it in would make the boundary
91
+ // flicker, so the still-live span (same startedAt) must be left alone.
92
+ const container = makeContainer(
93
+ '<span data-tool-elapsed="1000">0.3s</span>'
94
+ );
95
+ const oldSpan = container.querySelector("span")!;
96
+
97
+ morphMessages(
98
+ container,
99
+ makeNewContent('<span data-tool-elapsed="1000">&lt;0.1s</span>')
100
+ );
101
+
102
+ expect(container.querySelector("span")).toBe(oldSpan);
103
+ expect(container.querySelector("span")!.textContent).toBe("0.3s");
104
+ });
105
+
106
+ it("allows morph to the final static duration once the tool completes", () => {
107
+ const container = makeContainer(
108
+ '<span data-tool-elapsed="1000">0.7s</span>'
109
+ );
110
+
111
+ morphMessages(container, makeNewContent("<span>0.8s</span>"));
112
+
113
+ const span = container.querySelector("span")!;
114
+ expect(span.textContent).toBe("0.8s");
115
+ expect(span.hasAttribute("data-tool-elapsed")).toBe(false);
116
+ });
117
+
118
+ it("allows morph when the slot is reused by a different tool (startedAt changed)", () => {
119
+ const container = makeContainer(
120
+ '<span data-tool-elapsed="1000">0.5s</span>'
121
+ );
122
+
123
+ morphMessages(
124
+ container,
125
+ makeNewContent('<span data-tool-elapsed="2000">&lt;0.1s</span>')
126
+ );
127
+
128
+ const span = container.querySelector("span")!;
129
+ expect(span.getAttribute("data-tool-elapsed")).toBe("2000");
130
+ expect(span.textContent).toBe("<0.1s");
131
+ });
132
+ });
86
133
  });
@@ -37,6 +37,24 @@ export const morphMessages = (
37
37
  if (oldNode.hasAttribute("data-preserve-runtime")) {
38
38
  return false;
39
39
  }
40
+ // The live tool-elapsed span's text is owned by the 100ms global
41
+ // timer in ui.ts (it rewrites `now - startedAt` on a fixed cadence).
42
+ // Re-morphing it to the render-time value fights that timer, so while
43
+ // a tool stays active across frequent re-renders the "<0.1s" boundary
44
+ // flickers. Preserve it while the SAME tool is still live (matching
45
+ // `data-tool-elapsed`, i.e. startedAt); allow the morph once the tool
46
+ // completes (new node drops the marker → final static duration) or the
47
+ // slot is reused by another tool (marker value changed).
48
+ if (oldNode.hasAttribute("data-tool-elapsed")) {
49
+ const sameLiveTool =
50
+ newNode instanceof HTMLElement &&
51
+ newNode.getAttribute("data-tool-elapsed") ===
52
+ oldNode.getAttribute("data-tool-elapsed");
53
+ if (sameLiveTool) {
54
+ return false;
55
+ }
56
+ return;
57
+ }
40
58
  if (oldNode.hasAttribute("data-preserve-animation")) {
41
59
  // Allow morph when the new node drops the attribute (e.g. tool completed)
42
60
  if (newNode instanceof HTMLElement && !newNode.hasAttribute("data-preserve-animation")) {