@runtypelabs/persona 4.16.0 → 4.17.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.
@@ -35,6 +35,7 @@ export type RuntypeExecutionStreamEvent = ({
35
35
  iterations?: number;
36
36
  kind: "agent" | "flow";
37
37
  seq: number;
38
+ stepErrorCount?: number;
38
39
  stopReason?: string;
39
40
  success: boolean;
40
41
  successfulSteps?: number;
@@ -364,10 +365,21 @@ export type RuntypeExecutionStreamEvent = ({
364
365
  mode: "form" | "url";
365
366
  pauseCount?: number;
366
367
  requestedSchema?: Record<string, unknown>;
368
+ requests?: Array<{
369
+ message: string;
370
+ mode: "form" | "url";
371
+ name: string;
372
+ requestedSchema?: Record<string, unknown>;
373
+ url?: string;
374
+ }>;
367
375
  serverName?: string;
368
376
  url?: string;
369
377
  };
370
378
  executionId: string;
379
+ externalAgent?: {
380
+ contextId?: string;
381
+ taskId?: string;
382
+ };
371
383
  origin?: "webmcp" | "sdk";
372
384
  pageOrigin?: string;
373
385
  parameters?: Record<string, unknown>;
@@ -418,23 +430,59 @@ export type RuntypeStopReasonKind = NonNullable<
418
430
 
419
431
  export type RuntypeClientInitRequest = {
420
432
  flowId?: string;
421
- sessionId?: string;
433
+ identityProof?: string;
434
+ token: string;
435
+ visitorHistory?: boolean;
436
+ visitorToken?: string;
437
+ } | {
438
+ flowId?: string;
439
+ identityProof?: string;
440
+ sessionId: string;
441
+ token: string;
442
+ visitorHistory?: boolean;
443
+ visitorToken?: string;
444
+ } | {
445
+ conversationId: string;
446
+ flowId?: string;
447
+ identityProof?: string;
448
+ token: string;
449
+ visitorHistory?: boolean;
450
+ visitorToken: string;
451
+ } | {
452
+ conversationId: string;
453
+ flowId?: string;
454
+ identityProof: string;
422
455
  token: string;
456
+ visitorHistory?: boolean;
457
+ visitorToken?: string;
423
458
  };
424
459
 
425
460
  export type RuntypeClientInitResponse = {
461
+ app?: {
462
+ id: string;
463
+ };
426
464
  config: {
427
- placeholder?: string;
465
+ placeholder: string;
428
466
  theme?: unknown;
429
- welcomeMessage?: string | null;
467
+ welcomeMessage: string | null;
430
468
  };
469
+ conversationId: string;
470
+ conversationRevision: string;
431
471
  expiresAt: string;
432
472
  flow?: {
433
473
  description?: string | null;
434
474
  id: string;
435
- name?: string | null;
475
+ name?: string;
436
476
  };
437
477
  sessionId: string;
478
+ targetId?: string;
479
+ visitor?: {
480
+ endUserId: string | null;
481
+ expiresAt: string;
482
+ id: string;
483
+ identityStatus: "not_provided" | "admitted" | "ignored";
484
+ token?: string;
485
+ };
438
486
  };
439
487
 
440
488
  export type RuntypeClientChatRequest = {
@@ -474,6 +522,7 @@ export type RuntypeClientChatRequest = {
474
522
  text: string;
475
523
  type: "reasoning";
476
524
  }>);
525
+ displayContent?: string;
477
526
  id?: string;
478
527
  role: "user" | "assistant" | "system";
479
528
  }>;
@@ -404,12 +404,46 @@ describe("install.ts: CDN base derivation", () => {
404
404
  expect(cssHref).toBe("https://cdn.jsdelivr.net/npm/@runtypelabs/persona@latest/dist/widget.css");
405
405
  });
406
406
 
407
- it("an explicit `version` opts back into npm-CDN URLs even when the src is derivable", async () => {
407
+ it("an explicit `version` on the first-party CDN stays first-party (versioned path)", async () => {
408
408
  setCurrentScript("https://cdn.runtype.com/persona/latest/install.global.js");
409
+ const { cssHref, scripts } = await installedUrls({ version: "1.2.3" });
410
+ expect(cssHref).toBe("https://cdn.runtype.com/persona/1.2.3/widget.css");
411
+ expect(scripts).toContain("https://cdn.runtype.com/persona/1.2.3/launcher.global.js");
412
+ });
413
+
414
+ it("an explicit `version` on a non-first-party src opts into npm-CDN URLs", async () => {
415
+ setCurrentScript("https://assets.example.com/vendor/persona/install.global.js");
409
416
  const { cssHref } = await installedUrls({ version: "1.2.3" });
410
417
  expect(cssHref).toBe("https://cdn.jsdelivr.net/npm/@runtypelabs/persona@1.2.3/dist/widget.css");
411
418
  });
412
419
 
420
+ it("warns when resolved assets leave the installer's origin (silent-CSP guard)", async () => {
421
+ setCurrentScript("https://cdn.runtype.com/persona/latest/install.global.js");
422
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
423
+ await installedUrls({ cdn: "jsdelivr" });
424
+ expect(warn).toHaveBeenCalledWith(expect.stringContaining("strict CSP may silently block"));
425
+ warn.mockRestore();
426
+ });
427
+
428
+ it("does not warn when assets resolve to the installer's own origin", async () => {
429
+ setCurrentScript("https://cdn.runtype.com/persona/latest/install.global.js");
430
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
431
+ await installedUrls({ version: "1.2.3" });
432
+ expect(warn).not.toHaveBeenCalled();
433
+ warn.mockRestore();
434
+ });
435
+
436
+ it("does not warn for explicit cssUrl + jsUrl overrides on another origin", async () => {
437
+ setCurrentScript("https://cdn.runtype.com/persona/latest/install.global.js");
438
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
439
+ await installedUrls({
440
+ cssUrl: "https://assets.example.com/persona/widget.css",
441
+ jsUrl: "https://assets.example.com/persona/index.global.js",
442
+ });
443
+ expect(warn).not.toHaveBeenCalled();
444
+ warn.mockRestore();
445
+ });
446
+
413
447
  it("an explicit `cdn` opts back into npm-CDN URLs even when the src is derivable", async () => {
414
448
  setCurrentScript("https://cdn.runtype.com/persona/latest/install.global.js");
415
449
  const { cssHref } = await installedUrls({ cdn: "unpkg" });
package/src/install.ts CHANGED
@@ -7,9 +7,12 @@
7
7
  export {};
8
8
 
9
9
  interface SiteAgentInstallConfig {
10
- // Setting `version` or `cdn` explicitly opts into npm-CDN asset URLs
11
- // (jsDelivr/unpkg). When neither is set, assets load from the directory the
12
- // installer script itself was served from — see getCdnBase().
10
+ // Setting `cdn` explicitly opts into npm-CDN asset URLs (jsDelivr/unpkg),
11
+ // and `version` pins the asset version. When neither is set, assets load
12
+ // from the directory the installer script itself was served from. On the
13
+ // first-party CDN (cdn.runtype.com) a `version` stays first-party
14
+ // (…/persona/<version>/); elsewhere it opts into npm-CDN URLs. Prefer
15
+ // pinning via the installer script URL itself — see getCdnBase().
13
16
  version?: string;
14
17
  cdn?: "unpkg" | "jsdelivr";
15
18
  cssUrl?: string;
@@ -239,16 +242,30 @@ declare global {
239
242
 
240
243
  // Default: load assets from wherever the installer was served, so a page
241
244
  // whose CSP allows only its own CDN (e.g. cdn.runtype.com) never has
242
- // sibling requests fan out to a third-party host. An explicit `cdn` or
243
- // `version` keeps the documented npm-CDN behavior.
244
- if (!config.cdn && !config.version) {
245
+ // sibling requests fan out to a third-party host. An explicit `cdn`
246
+ // keeps the documented npm-CDN behavior.
247
+ if (!config.cdn) {
245
248
  const selfBase = getInstallerBase();
246
249
  if (selfBase) {
247
- return {
248
- cssUrl: `${selfBase}/widget.css`,
249
- jsUrl: `${selfBase}/index.global.js`,
250
- launcherUrl: `${selfBase}/launcher.global.js` as string | null,
251
- };
250
+ if (!config.version) {
251
+ return {
252
+ cssUrl: `${selfBase}/widget.css`,
253
+ jsUrl: `${selfBase}/index.global.js`,
254
+ launcherUrl: `${selfBase}/launcher.global.js` as string | null,
255
+ };
256
+ }
257
+ // A `version` on the first-party CDN stays first-party: the bucket
258
+ // mirrors every release at /persona/<version>/, and rerouting to a
259
+ // npm CDN would be blocked by the CSP that allowed the installer.
260
+ const selfOrigin = new URL(selfBase).origin;
261
+ if (selfOrigin === "https://cdn.runtype.com") {
262
+ const base = `${selfOrigin}/persona/${config.version}`;
263
+ return {
264
+ cssUrl: `${base}/widget.css`,
265
+ jsUrl: `${base}/index.global.js`,
266
+ launcherUrl: `${base}/launcher.global.js` as string | null,
267
+ };
268
+ }
252
269
  }
253
270
  }
254
271
 
@@ -268,6 +285,25 @@ declare global {
268
285
 
269
286
  const { cssUrl, jsUrl, launcherUrl } = getCdnBase();
270
287
 
288
+ // Surface silent CSP breakage: when `cdn`/`version` reroutes assets to a
289
+ // different origin than the one that served the installer, a strict CSP
290
+ // (e.g. Runtype-hosted apps) blocks them with no visible error. Explicit
291
+ // cssUrl/jsUrl overrides are a deliberate choice, so they don't warn.
292
+ if (!(config.cssUrl && config.jsUrl)) {
293
+ const selfBase = getInstallerBase();
294
+ try {
295
+ if (selfBase && new URL(selfBase).origin !== new URL(jsUrl, document.baseURI).origin) {
296
+ console.warn(
297
+ `[persona] Widget assets resolve to ${new URL(jsUrl, document.baseURI).origin}, but the installer loaded from ${new URL(selfBase).origin}. ` +
298
+ "A strict CSP may silently block them. To pin a version, put it in the installer script URL " +
299
+ "(e.g. https://cdn.runtype.com/persona/<version>/install.global.js) instead of the `version`/`cdn` config keys.",
300
+ );
301
+ }
302
+ } catch {
303
+ // URL parsing is best-effort; never let diagnostics break installation.
304
+ }
305
+ }
306
+
271
307
  // Check if CSS is already loaded
272
308
  const isCssLoaded = () => {
273
309
  return !!document.head.querySelector('link[data-persona]') ||