@runtypelabs/persona 4.21.0 → 4.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{approval-ui-RNNBR5R3.js → approval-ui-K7R5Q5OC.js} +1 -1
- package/dist/approval-ui.cjs +2 -2
- package/dist/approval-ui.d.cts +73 -2
- package/dist/approval-ui.d.ts +73 -2
- package/dist/approval-ui.js +2 -2
- package/dist/artifacts-ui-F4N6VMKF.js +7 -0
- package/dist/artifacts-ui.cjs +1 -1
- package/dist/artifacts-ui.d.cts +73 -2
- package/dist/artifacts-ui.d.ts +73 -2
- package/dist/artifacts-ui.js +1 -1
- package/dist/chunk-NQLDCJAP.js +4 -0
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.js +1 -1
- package/dist/context-mentions.d.cts +73 -2
- package/dist/context-mentions.d.ts +73 -2
- package/dist/event-stream-view-FKWDY3UB.js +1 -0
- package/dist/event-stream-view.cjs +1 -1
- package/dist/event-stream-view.d.cts +73 -2
- package/dist/event-stream-view.d.ts +73 -2
- package/dist/event-stream-view.js +1 -1
- package/dist/forms-ui.d.cts +73 -2
- package/dist/forms-ui.d.ts +73 -2
- package/dist/index.cjs +66 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +136 -5
- package/dist/index.d.ts +136 -5
- package/dist/index.global.js +50 -50
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +67 -67
- package/dist/index.js.map +1 -1
- package/dist/launcher.global.js +2 -2
- package/dist/launcher.global.js.map +1 -1
- package/dist/session-reconnect.d.cts +73 -2
- package/dist/session-reconnect.d.ts +73 -2
- package/dist/smart-dom-reader.d.cts +73 -2
- package/dist/smart-dom-reader.d.ts +73 -2
- package/dist/theme-editor-preview.cjs +65 -65
- package/dist/theme-editor-preview.d.cts +73 -2
- package/dist/theme-editor-preview.d.ts +73 -2
- package/dist/theme-editor-preview.js +49 -49
- package/dist/theme-editor.cjs +4 -4
- package/dist/theme-editor.d.cts +73 -2
- package/dist/theme-editor.d.ts +73 -2
- package/dist/theme-editor.js +2 -2
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.d.cts +65 -1
- package/dist/theme-reference.d.ts +65 -1
- package/dist/theme-reference.js +1 -1
- package/dist/webmcp-polyfill.js +1 -4
- package/dist/webmcp-runtime-JI7T4QYF.js +6 -0
- package/dist/webmcp-runtime.cjs +2 -2
- package/dist/webmcp-runtime.d.cts +34 -2
- package/dist/webmcp-runtime.d.ts +34 -2
- package/dist/webmcp-runtime.js +2 -2
- package/package.json +2 -2
- package/src/client-visitor-history.test.ts +131 -0
- package/src/components/artifact-preview.ts +5 -0
- package/src/components/event-stream-badge-theming.test.ts +159 -0
- package/src/components/event-stream-view.ts +50 -20
- package/src/generated/runtype-openapi-contract.ts +8 -0
- package/src/index-core.ts +2 -0
- package/src/runtime/init.registry.test.ts +56 -0
- package/src/runtime/init.ts +17 -0
- package/src/types/theme.ts +41 -1
- package/src/types.ts +38 -1
- package/src/ui.reasoning-display.test.ts +136 -2
- package/src/ui.ts +69 -21
- package/src/utils/__snapshots__/tokens-parity.test.ts.snap +1740 -0
- package/src/utils/formatting.ts +22 -0
- package/src/utils/theme.ts +16 -0
- package/src/utils/tokens.ts +59 -0
- package/src/webmcp-bridge.test.ts +132 -23
- package/src/webmcp-bridge.ts +26 -2
- package/src/webmcp-runtime-entry.ts +71 -11
- package/dist/artifacts-ui-J6AKUGTS.js +0 -7
- package/dist/chunk-HBE7LFNT.js +0 -4
- package/dist/event-stream-view-73NWKWVQ.js +0 -1
- package/dist/webmcp-runtime-P3CHZRHF.js +0 -6
|
@@ -25,7 +25,8 @@ const injectReasoning = (
|
|
|
25
25
|
controller: ReturnType<typeof createAgentExperience>,
|
|
26
26
|
id: string,
|
|
27
27
|
status: "streaming" | "complete",
|
|
28
|
-
chunks: string[] = ["Weighing the options"]
|
|
28
|
+
chunks: string[] = ["Weighing the options"],
|
|
29
|
+
durationMs?: number
|
|
29
30
|
) => {
|
|
30
31
|
controller.injectTestMessage({
|
|
31
32
|
type: "message",
|
|
@@ -36,7 +37,26 @@ const injectReasoning = (
|
|
|
36
37
|
createdAt: new Date().toISOString(),
|
|
37
38
|
streaming: status !== "complete",
|
|
38
39
|
variant: "reasoning",
|
|
39
|
-
reasoning: { id, status, chunks },
|
|
40
|
+
reasoning: { id, status, chunks, durationMs },
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const injectToolCall = (
|
|
46
|
+
controller: ReturnType<typeof createAgentExperience>,
|
|
47
|
+
id: string,
|
|
48
|
+
status: "pending" | "running" | "complete"
|
|
49
|
+
) => {
|
|
50
|
+
controller.injectTestMessage({
|
|
51
|
+
type: "message",
|
|
52
|
+
message: {
|
|
53
|
+
id,
|
|
54
|
+
role: "assistant",
|
|
55
|
+
content: "",
|
|
56
|
+
createdAt: new Date().toISOString(),
|
|
57
|
+
streaming: status !== "complete",
|
|
58
|
+
variant: "tool",
|
|
59
|
+
toolCall: { id, name: "search", status, chunks: [] },
|
|
40
60
|
},
|
|
41
61
|
});
|
|
42
62
|
};
|
|
@@ -161,4 +181,118 @@ describe("features.reasoningDisplay.completedVisibility", () => {
|
|
|
161
181
|
?.chunks
|
|
162
182
|
).toEqual(["Weighing the options"]);
|
|
163
183
|
});
|
|
184
|
+
|
|
185
|
+
it('"removed-when-short" drops a completed trace with a short reported duration', () => {
|
|
186
|
+
const { mount, controller } = makeController({
|
|
187
|
+
features: { reasoningDisplay: { completedVisibility: "removed-when-short" } },
|
|
188
|
+
});
|
|
189
|
+
injectReasoning(controller, "r1", "complete", ["Weighing the options"], 5_000);
|
|
190
|
+
expect(rowOf(mount, "r1")).toBeNull();
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('"removed-when-short" keeps a completed trace with a long reported duration', () => {
|
|
194
|
+
const { mount, controller } = makeController({
|
|
195
|
+
features: { reasoningDisplay: { completedVisibility: "removed-when-short" } },
|
|
196
|
+
});
|
|
197
|
+
injectReasoning(controller, "r1", "complete", ["Weighing the options"], 20_000);
|
|
198
|
+
expect(rowOf(mount, "r1")).not.toBeNull();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('"removed-when-short" drops a completed trace with no duration and few chars', () => {
|
|
202
|
+
const { mount, controller } = makeController({
|
|
203
|
+
features: { reasoningDisplay: { completedVisibility: "removed-when-short" } },
|
|
204
|
+
});
|
|
205
|
+
injectReasoning(controller, "r1", "complete", ["Short thought"]);
|
|
206
|
+
expect(rowOf(mount, "r1")).toBeNull();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('"removed-when-short" keeps a completed trace with no duration and many chars', () => {
|
|
210
|
+
const { mount, controller } = makeController({
|
|
211
|
+
features: { reasoningDisplay: { completedVisibility: "removed-when-short" } },
|
|
212
|
+
});
|
|
213
|
+
injectReasoning(controller, "r1", "complete", ["x".repeat(1_500)]);
|
|
214
|
+
expect(rowOf(mount, "r1")).not.toBeNull();
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('"removed-when-short" honors custom duration and char thresholds', () => {
|
|
218
|
+
const { mount, controller } = makeController({
|
|
219
|
+
features: {
|
|
220
|
+
reasoningDisplay: {
|
|
221
|
+
completedVisibility: "removed-when-short",
|
|
222
|
+
shortThinkThreshold: { durationMs: 1_000, chars: 50 },
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
// 5s exceeds the custom 1s threshold, so this long-by-default trace is kept.
|
|
227
|
+
injectReasoning(controller, "r1", "complete", ["Weighing the options"], 5_000);
|
|
228
|
+
expect(rowOf(mount, "r1")).not.toBeNull();
|
|
229
|
+
|
|
230
|
+
// 60 chars exceeds the custom 50-char threshold, so this trace is kept too.
|
|
231
|
+
injectReasoning(controller, "r2", "complete", ["y".repeat(60)]);
|
|
232
|
+
expect(rowOf(mount, "r2")).not.toBeNull();
|
|
233
|
+
|
|
234
|
+
// Under both custom thresholds, so this trace is dropped.
|
|
235
|
+
injectReasoning(controller, "r3", "complete", ["z".repeat(10)], 500);
|
|
236
|
+
expect(rowOf(mount, "r3")).toBeNull();
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
describe("features.toolCallDisplay.completedVisibility", () => {
|
|
241
|
+
beforeEach(() => {
|
|
242
|
+
window.localStorage.clear();
|
|
243
|
+
vi.stubGlobal("requestAnimationFrame", (cb: (time: number) => void) => {
|
|
244
|
+
cb(0);
|
|
245
|
+
return 1;
|
|
246
|
+
});
|
|
247
|
+
vi.stubGlobal("cancelAnimationFrame", () => {});
|
|
248
|
+
window.scrollTo = vi.fn();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
afterEach(() => {
|
|
252
|
+
controllers.splice(0).forEach((controller) => controller.destroy());
|
|
253
|
+
mounts.splice(0).forEach((mount) => mount.remove());
|
|
254
|
+
document.body.innerHTML = "";
|
|
255
|
+
vi.restoreAllMocks();
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("keeps a finished tool call row by default", () => {
|
|
259
|
+
const { mount, controller } = makeController();
|
|
260
|
+
injectToolCall(controller, "t1", "complete");
|
|
261
|
+
expect(rowOf(mount, "t1")).not.toBeNull();
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('removes the whole row under "removed", leaving no transcript gap', () => {
|
|
265
|
+
const { mount, controller } = makeController({
|
|
266
|
+
features: { toolCallDisplay: { completedVisibility: "removed" } },
|
|
267
|
+
});
|
|
268
|
+
injectToolCall(controller, "t1", "complete");
|
|
269
|
+
injectText(controller, "a1", "Here is the answer");
|
|
270
|
+
|
|
271
|
+
expect(rowOf(mount, "t1")).toBeNull();
|
|
272
|
+
const rows = mount.querySelectorAll("[data-wrapper-id]");
|
|
273
|
+
expect(Array.from(rows).map((row) => row.getAttribute("data-wrapper-id")))
|
|
274
|
+
.toEqual(["a1"]);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('shows a running tool call under "removed" and drops it once it completes', () => {
|
|
278
|
+
const { mount, controller } = makeController({
|
|
279
|
+
features: { toolCallDisplay: { completedVisibility: "removed" } },
|
|
280
|
+
});
|
|
281
|
+
injectToolCall(controller, "t1", "running");
|
|
282
|
+
expect(rowOf(mount, "t1")).not.toBeNull();
|
|
283
|
+
|
|
284
|
+
injectToolCall(controller, "t1", "complete");
|
|
285
|
+
expect(rowOf(mount, "t1")).toBeNull();
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('keeps the tool call message in the session under "removed"', () => {
|
|
289
|
+
const { controller } = makeController({
|
|
290
|
+
features: { toolCallDisplay: { completedVisibility: "removed" } },
|
|
291
|
+
});
|
|
292
|
+
injectToolCall(controller, "t1", "complete");
|
|
293
|
+
expect(
|
|
294
|
+
controller.getMessages().find((message) => message.id === "t1")?.toolCall
|
|
295
|
+
?.status
|
|
296
|
+
).toEqual("complete");
|
|
297
|
+
});
|
|
164
298
|
});
|
package/src/ui.ts
CHANGED
|
@@ -61,7 +61,8 @@ import {
|
|
|
61
61
|
ComposerQuote,
|
|
62
62
|
ComposerState,
|
|
63
63
|
ComposerStreamingSubmitBehavior,
|
|
64
|
-
ComposerSubmissionSnapshot
|
|
64
|
+
ComposerSubmissionSnapshot,
|
|
65
|
+
AgentWidgetReasoning
|
|
65
66
|
} from "./types";
|
|
66
67
|
import { AttachmentManager, type PendingAttachment } from "./utils/attachment-manager";
|
|
67
68
|
import { createComposerStore } from "./utils/composer-store";
|
|
@@ -282,7 +283,7 @@ import {
|
|
|
282
283
|
latestAgentSuggestions,
|
|
283
284
|
resolveFollowUpsFeature,
|
|
284
285
|
} from "./suggest-replies-tool";
|
|
285
|
-
import { formatElapsedMs } from "./utils/formatting";
|
|
286
|
+
import { formatElapsedMs, isShortReasoning } from "./utils/formatting";
|
|
286
287
|
import { loadApprovalUi, getApprovalUiSync, type ApprovalUiModule } from "./approval-ui-loader";
|
|
287
288
|
import { getWebMcpToolDisplayTitle } from "./webmcp-bridge";
|
|
288
289
|
import type { AgentWidgetPlugin } from "./plugins/types";
|
|
@@ -1054,6 +1055,8 @@ export const createAgentExperience = (
|
|
|
1054
1055
|
messagePersistenceDisabled
|
|
1055
1056
|
? null
|
|
1056
1057
|
: (config.storageAdapter ?? createLocalStorageAdapter());
|
|
1058
|
+
const personaOwnsClientTokenRecovery =
|
|
1059
|
+
Boolean(config.clientToken) && typeof config.reconnectStream !== "function";
|
|
1057
1060
|
let persistentMetadata: Record<string, unknown> = {};
|
|
1058
1061
|
let pendingStoredState: Promise<AgentWidgetStoredState | null> | null = null;
|
|
1059
1062
|
// Resolves once stored state has been applied (or its load failed). Every
|
|
@@ -5313,6 +5316,17 @@ export const createAgentExperience = (
|
|
|
5313
5316
|
? getMessagesForPersistence()
|
|
5314
5317
|
: [];
|
|
5315
5318
|
|
|
5319
|
+
const durableHandle =
|
|
5320
|
+
personaOwnsClientTokenRecovery && session?.getResumableHandle();
|
|
5321
|
+
if (durableHandle) {
|
|
5322
|
+
persistentMetadata = {
|
|
5323
|
+
...persistentMetadata,
|
|
5324
|
+
durableResume: {
|
|
5325
|
+
executionId: durableHandle.executionId,
|
|
5326
|
+
after: durableHandle.lastEventId,
|
|
5327
|
+
},
|
|
5328
|
+
};
|
|
5329
|
+
}
|
|
5316
5330
|
const payload: AgentWidgetStoredState = {
|
|
5317
5331
|
messages,
|
|
5318
5332
|
metadata: persistentMetadata,
|
|
@@ -6284,17 +6298,40 @@ export const createAgentExperience = (
|
|
|
6284
6298
|
/** The live editor, re-grafted into its morphed wrapper after the pass. */
|
|
6285
6299
|
let editHydrate: { messageId: string; element: HTMLElement } | null = null;
|
|
6286
6300
|
|
|
6287
|
-
// `reasoningDisplay.completedVisibility: "removed"
|
|
6288
|
-
//
|
|
6289
|
-
//
|
|
6290
|
-
|
|
6291
|
-
|
|
6301
|
+
// `reasoningDisplay.completedVisibility: "removed"` (or "removed-when-short"
|
|
6302
|
+
// for a short completed trace): no row for the finished trace, so the
|
|
6303
|
+
// transcript gap closes with it. Checked before the row is registered, so
|
|
6304
|
+
// the cached wrapper is pruned too.
|
|
6305
|
+
const reasoningCompletedVisibility =
|
|
6306
|
+
config.features?.reasoningDisplay?.completedVisibility;
|
|
6307
|
+
const dropReasoningRow = (reasoning: AgentWidgetReasoning): boolean => {
|
|
6308
|
+
if (reasoningCompletedVisibility === "removed") return true;
|
|
6309
|
+
if (reasoningCompletedVisibility === "removed-when-short") {
|
|
6310
|
+
return isShortReasoning(
|
|
6311
|
+
reasoning,
|
|
6312
|
+
config.features?.reasoningDisplay?.shortThinkThreshold
|
|
6313
|
+
);
|
|
6314
|
+
}
|
|
6315
|
+
return false;
|
|
6316
|
+
};
|
|
6317
|
+
|
|
6318
|
+
// `toolCallDisplay.completedVisibility: "removed"`: same mechanism as
|
|
6319
|
+
// reasoning removal, no threshold variant.
|
|
6320
|
+
const dropCompletedToolCalls =
|
|
6321
|
+
config.features?.toolCallDisplay?.completedVisibility === "removed";
|
|
6292
6322
|
|
|
6293
6323
|
messages.forEach((message) => {
|
|
6294
6324
|
if (
|
|
6295
|
-
dropCompletedReasoning &&
|
|
6296
6325
|
message.variant === "reasoning" &&
|
|
6297
|
-
message.reasoning?.status === "complete"
|
|
6326
|
+
message.reasoning?.status === "complete" &&
|
|
6327
|
+
dropReasoningRow(message.reasoning)
|
|
6328
|
+
) {
|
|
6329
|
+
return;
|
|
6330
|
+
}
|
|
6331
|
+
if (
|
|
6332
|
+
dropCompletedToolCalls &&
|
|
6333
|
+
message.variant === "tool" &&
|
|
6334
|
+
message.toolCall?.status === "complete"
|
|
6298
6335
|
) {
|
|
6299
6336
|
return;
|
|
6300
6337
|
}
|
|
@@ -6849,6 +6886,12 @@ export const createAgentExperience = (
|
|
|
6849
6886
|
|
|
6850
6887
|
messages.forEach((message) => {
|
|
6851
6888
|
if (message.variant === "tool" && message.toolCall && showToolCalls) {
|
|
6889
|
+
// A tool call hidden by `completedVisibility: "removed"` does not
|
|
6890
|
+
// create a visible break in the transcript, so it should not split
|
|
6891
|
+
// an otherwise contiguous group.
|
|
6892
|
+
if (dropCompletedToolCalls && message.toolCall.status === "complete") {
|
|
6893
|
+
return;
|
|
6894
|
+
}
|
|
6852
6895
|
currentGroup.push(message);
|
|
6853
6896
|
return;
|
|
6854
6897
|
}
|
|
@@ -6858,7 +6901,8 @@ export const createAgentExperience = (
|
|
|
6858
6901
|
if (
|
|
6859
6902
|
message.variant === "reasoning" &&
|
|
6860
6903
|
(!showReasoning ||
|
|
6861
|
-
(
|
|
6904
|
+
(message.reasoning?.status === "complete" &&
|
|
6905
|
+
dropReasoningRow(message.reasoning)))
|
|
6862
6906
|
) {
|
|
6863
6907
|
return;
|
|
6864
6908
|
}
|
|
@@ -8384,8 +8428,6 @@ export const createAgentExperience = (
|
|
|
8384
8428
|
? { executionId: candidate.executionId, after: candidate.after }
|
|
8385
8429
|
: null;
|
|
8386
8430
|
};
|
|
8387
|
-
const personaOwnsClientTokenRecovery =
|
|
8388
|
-
Boolean(config.clientToken) && typeof config.reconnectStream !== "function";
|
|
8389
8431
|
if (config.clientToken) {
|
|
8390
8432
|
config = {
|
|
8391
8433
|
...config,
|
|
@@ -8498,17 +8540,11 @@ export const createAgentExperience = (
|
|
|
8498
8540
|
const hostExecutionState = config.onExecutionState;
|
|
8499
8541
|
const recoveryWindow = mount.ownerDocument.defaultView;
|
|
8500
8542
|
let pageExitInProgress = false;
|
|
8501
|
-
const markPageExit = () =>
|
|
8502
|
-
|
|
8503
|
-
};
|
|
8504
|
-
const markPageActive = () => {
|
|
8505
|
-
pageExitInProgress = false;
|
|
8506
|
-
};
|
|
8507
|
-
recoveryWindow?.addEventListener("beforeunload", markPageExit);
|
|
8543
|
+
const markPageExit = () => (pageExitInProgress = true);
|
|
8544
|
+
const markPageActive = () => (pageExitInProgress = false);
|
|
8508
8545
|
recoveryWindow?.addEventListener("pagehide", markPageExit);
|
|
8509
8546
|
recoveryWindow?.addEventListener("pageshow", markPageActive);
|
|
8510
8547
|
destroyCallbacks.push(() => {
|
|
8511
|
-
recoveryWindow?.removeEventListener("beforeunload", markPageExit);
|
|
8512
8548
|
recoveryWindow?.removeEventListener("pagehide", markPageExit);
|
|
8513
8549
|
recoveryWindow?.removeEventListener("pageshow", markPageActive);
|
|
8514
8550
|
});
|
|
@@ -8638,6 +8674,18 @@ export const createAgentExperience = (
|
|
|
8638
8674
|
let activeStreamingTextCandidate: { index: number; id: string } | null = null;
|
|
8639
8675
|
let pendingStreamingTextMessages: AgentWidgetMessage[] | null = null;
|
|
8640
8676
|
let streamingTextRAF: number | null = null;
|
|
8677
|
+
let pendingDurablePersistenceMessages: AgentWidgetMessage[] | null = null;
|
|
8678
|
+
|
|
8679
|
+
const persistMessages = (messages: AgentWidgetMessage[]) => {
|
|
8680
|
+
if (!personaOwnsClientTokenRecovery) return persistState(messages);
|
|
8681
|
+
pendingDurablePersistenceMessages = messages;
|
|
8682
|
+
queueMicrotask(() => {
|
|
8683
|
+
if (pendingDurablePersistenceMessages === messages) {
|
|
8684
|
+
pendingDurablePersistenceMessages = null;
|
|
8685
|
+
persistState(messages);
|
|
8686
|
+
}
|
|
8687
|
+
});
|
|
8688
|
+
};
|
|
8641
8689
|
|
|
8642
8690
|
const applyMessagesChanged = (messages: AgentWidgetMessage[]) => {
|
|
8643
8691
|
lastAppliedMessages = messages;
|
|
@@ -8698,7 +8746,7 @@ export const createAgentExperience = (
|
|
|
8698
8746
|
}
|
|
8699
8747
|
|
|
8700
8748
|
voiceState.lastUserMessageWasVoice = Boolean(lastUserMessage?.viaVoice);
|
|
8701
|
-
|
|
8749
|
+
persistMessages(messages);
|
|
8702
8750
|
syncComposerBarPeek();
|
|
8703
8751
|
};
|
|
8704
8752
|
|