@runtypelabs/persona 4.23.1 → 4.23.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 (47) hide show
  1. package/dist/animations/glyph-cycle.d.cts +1 -1
  2. package/dist/animations/glyph-cycle.d.ts +1 -1
  3. package/dist/animations/{types-9Vxm-PPz.d.cts → types-CI7OckWI.d.cts} +23 -2
  4. package/dist/animations/{types-9Vxm-PPz.d.ts → types-CI7OckWI.d.ts} +23 -2
  5. package/dist/animations/wipe.d.cts +1 -1
  6. package/dist/animations/wipe.d.ts +1 -1
  7. package/dist/animations-extra.d.cts +23 -2
  8. package/dist/animations-extra.d.ts +23 -2
  9. package/dist/approval-ui.d.cts +46 -3
  10. package/dist/approval-ui.d.ts +46 -3
  11. package/dist/artifacts-ui.d.cts +46 -3
  12. package/dist/artifacts-ui.d.ts +46 -3
  13. package/dist/codegen.cjs +1 -1
  14. package/dist/codegen.js +1 -1
  15. package/dist/context-mentions.d.cts +46 -3
  16. package/dist/context-mentions.d.ts +46 -3
  17. package/dist/event-stream-view.d.cts +46 -3
  18. package/dist/event-stream-view.d.ts +46 -3
  19. package/dist/forms-ui.d.cts +46 -3
  20. package/dist/forms-ui.d.ts +46 -3
  21. package/dist/history-view.d.cts +23 -2
  22. package/dist/history-view.d.ts +23 -2
  23. package/dist/index.cjs +41 -41
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +67 -12
  26. package/dist/index.d.ts +67 -12
  27. package/dist/index.global.js +26 -26
  28. package/dist/index.global.js.map +1 -1
  29. package/dist/index.js +41 -41
  30. package/dist/index.js.map +1 -1
  31. package/dist/session-reconnect.d.cts +46 -3
  32. package/dist/session-reconnect.d.ts +46 -3
  33. package/dist/smart-dom-reader.d.cts +46 -3
  34. package/dist/smart-dom-reader.d.ts +46 -3
  35. package/dist/theme-editor-preview.cjs +48 -48
  36. package/dist/theme-editor-preview.d.cts +46 -3
  37. package/dist/theme-editor-preview.d.ts +46 -3
  38. package/dist/theme-editor-preview.js +31 -31
  39. package/dist/theme-editor.d.cts +46 -3
  40. package/dist/theme-editor.d.ts +46 -3
  41. package/package.json +1 -1
  42. package/src/client.tool-pair-replay.test.ts +325 -0
  43. package/src/client.ts +32 -31
  44. package/src/generated/runtype-openapi-contract.ts +26 -11
  45. package/src/session.ts +32 -3
  46. package/src/types.ts +43 -1
  47. package/src/utils/tool-pair-replay.ts +100 -0
@@ -78,6 +78,7 @@ export type RuntypeExecutionStreamEvent = ({
78
78
  turnIndex?: number;
79
79
  type: "turn_start";
80
80
  }) | ({
81
+ attributes?: Record<string, string | number | boolean>;
81
82
  completedAt?: string;
82
83
  content?: string;
83
84
  cost?: number;
@@ -136,7 +137,8 @@ export type RuntypeExecutionStreamEvent = ({
136
137
  };
137
138
  turnId?: string;
138
139
  type: "model_call_start";
139
- } | {
140
+ } | ({
141
+ attributes?: Record<string, string | number | boolean>;
140
142
  completedAt?: string;
141
143
  cost?: number;
142
144
  durationMs?: number;
@@ -160,10 +162,11 @@ export type RuntypeExecutionStreamEvent = ({
160
162
  cacheWrite?: number;
161
163
  input: number;
162
164
  output: number;
165
+ reasoning?: number;
163
166
  };
164
167
  turnId?: string;
165
168
  type: "model_call_complete";
166
- } | {
169
+ }) | {
167
170
  executionId: string;
168
171
  id: string;
169
172
  index?: number;
@@ -558,38 +561,50 @@ export type RuntypeStopReasonKind = NonNullable<
558
561
  RuntypeTurnCompleteEvent["stopReason"] | RuntypeStepCompleteEvent["stopReason"]
559
562
  >;
560
563
 
561
- export type RuntypeClientInitRequest = {
564
+ export type RuntypeClientInitRequest = ({
562
565
  durableRecovery?: boolean;
563
566
  flowId?: string;
564
- identityProof?: string;
567
+ identityProof?: string | {
568
+ provider: string;
569
+ token: string;
570
+ };
565
571
  token: string;
566
572
  visitorHistory?: boolean;
567
573
  visitorToken?: string;
568
- } | {
574
+ }) | ({
569
575
  durableRecovery?: boolean;
570
576
  flowId?: string;
571
- identityProof?: string;
577
+ identityProof?: string | {
578
+ provider: string;
579
+ token: string;
580
+ };
572
581
  sessionId: string;
573
582
  token: string;
574
583
  visitorHistory?: boolean;
575
584
  visitorToken?: string;
576
- } | {
585
+ }) | ({
577
586
  conversationId: string;
578
587
  durableRecovery?: boolean;
579
588
  flowId?: string;
580
- identityProof?: string;
589
+ identityProof?: string | {
590
+ provider: string;
591
+ token: string;
592
+ };
581
593
  token: string;
582
594
  visitorHistory?: boolean;
583
595
  visitorToken: string;
584
- } | {
596
+ }) | ({
585
597
  conversationId: string;
586
598
  durableRecovery?: boolean;
587
599
  flowId?: string;
588
- identityProof: string;
600
+ identityProof: string | {
601
+ provider: string;
602
+ token: string;
603
+ };
589
604
  token: string;
590
605
  visitorHistory?: boolean;
591
606
  visitorToken?: string;
592
- };
607
+ });
593
608
 
594
609
  export type RuntypeClientInitResponse = {
595
610
  app?: {
package/src/session.ts CHANGED
@@ -3816,16 +3816,34 @@ export class AgentWidgetSession {
3816
3816
  // re-emits don't re-execute the page tool, then complete each bubble.
3817
3817
  // Do this only after /resume HTTP success; if /resume fails, the server
3818
3818
  // may still be paused and the retry path must not show a final result.
3819
+ const batch = ready[0]!.dedupeKey;
3819
3820
  for (const r of ready) {
3820
3821
  this.webMcpResolvedKeys.add(r.dedupeKey);
3822
+ const toolName = r.toolMessage.toolCall?.name;
3823
+ const toolCallId = r.toolMessage.agentMetadata?.webMcpToolCallId;
3821
3824
  this.markWebMcpToolComplete(
3822
3825
  r.toolMessage,
3823
3826
  r.output,
3824
3827
  r.startedAt,
3825
3828
  r.completedAt,
3826
- r.toolMessage.toolCall?.name === SUGGEST_REPLIES_TOOL_NAME
3827
- ? { suggestRepliesResolved: true }
3828
- : undefined,
3829
+ {
3830
+ ...(toolName === SUGGEST_REPLIES_TOOL_NAME
3831
+ ? { suggestRepliesResolved: true }
3832
+ : {}),
3833
+ // Only a provider call id can be replayed: a legacy name-keyed
3834
+ // resume has nothing the model's transcript can reference.
3835
+ ...(toolName && toolCallId
3836
+ ? {
3837
+ clientToolAnswer: {
3838
+ toolCallId,
3839
+ toolName,
3840
+ args: r.toolMessage.toolCall?.args,
3841
+ result: r.output,
3842
+ batch,
3843
+ },
3844
+ }
3845
+ : {}),
3846
+ },
3829
3847
  );
3830
3848
  }
3831
3849
  if (response.body) {
@@ -4928,6 +4946,17 @@ export class AgentWidgetSession {
4928
4946
  awaitingLocalTool: false,
4929
4947
  };
4930
4948
  }
4949
+ // The accepted client-tool answer is what later proxy/agent turns
4950
+ // replay; a post-resume `tool_complete` re-emit carries a fresh
4951
+ // metadata skeleton and must not drop it.
4952
+ const clientToolAnswer = existing.agentMetadata?.clientToolAnswer;
4953
+ if (
4954
+ clientToolAnswer &&
4955
+ merged.agentMetadata &&
4956
+ !merged.agentMetadata.clientToolAnswer
4957
+ ) {
4958
+ merged.agentMetadata = { ...merged.agentMetadata, clientToolAnswer };
4959
+ }
4931
4960
  // Approval equivalent: `approval_complete` carries only the
4932
4961
  // resolution (approvalId, decision, resolvedBy): the runtime does not
4933
4962
  // re-send toolName/description/toolType/reason/parameters, so client.ts
package/src/types.ts CHANGED
@@ -593,10 +593,34 @@ export type AgentWidgetContextMentionTokenRenderContext = {
593
593
  readonly: boolean;
594
594
  };
595
595
 
596
+ /** One earlier client-tool call replayed to the model, in `/v1/dispatch` shape. */
597
+ export type AgentWidgetReplayedToolCall = {
598
+ toolCallId: string;
599
+ /** Model-facing (sanitized) name, e.g. `webmcp_search`. */
600
+ toolName: string;
601
+ args: Record<string, unknown>;
602
+ };
603
+
604
+ /** The browser's answer to an {@link AgentWidgetReplayedToolCall}. */
605
+ export type AgentWidgetReplayedToolResult = {
606
+ toolCallId: string;
607
+ toolName: string;
608
+ result: unknown;
609
+ };
610
+
611
+ /**
612
+ * A message in the proxy/agent request payload. Earlier client-tool calls the
613
+ * browser answered replay as an assistant message carrying `toolCalls`,
614
+ * followed by a `tool` message carrying the matching `toolResults`; both have
615
+ * empty `content`. Client-token mode never sends them: the server replays
616
+ * from its own stored transcript there.
617
+ */
596
618
  export type AgentWidgetRequestPayloadMessage = {
597
- role: AgentWidgetMessageRole;
619
+ role: AgentWidgetMessageRole | "tool";
598
620
  content: MessageContent;
599
621
  createdAt: string;
622
+ toolCalls?: AgentWidgetReplayedToolCall[];
623
+ toolResults?: AgentWidgetReplayedToolResult[];
600
624
  };
601
625
 
602
626
  export type AgentWidgetRequestPayload = {
@@ -1032,6 +1056,24 @@ export type AgentMessageMetadata = {
1032
1056
  * never re-resume the call.
1033
1057
  */
1034
1058
  suggestRepliesResolved?: boolean;
1059
+ /**
1060
+ * The client-tool answer the server accepted through `/resume`, kept so
1061
+ * later proxy/agent turns can replay the call and its result to the model.
1062
+ * `toolName` is the widget's internal name (`webmcp:<name>` or a bare
1063
+ * built-in). Set only after the resume succeeds; preserved across
1064
+ * re-emissions of the tool message.
1065
+ */
1066
+ clientToolAnswer?: {
1067
+ toolCallId: string;
1068
+ toolName: string;
1069
+ args: unknown;
1070
+ result: unknown;
1071
+ /**
1072
+ * Shared by the answers posted in one `/resume`, i.e. one assistant
1073
+ * turn's parallel calls; a chained call gets a new batch.
1074
+ */
1075
+ batch?: string;
1076
+ };
1035
1077
  };
1036
1078
 
1037
1079
  export type AgentWidgetRequestMiddlewareContext = {
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Client-tool pair replay for the proxy and agent payload builders.
3
+ *
4
+ * In proxy and agent mode the widget holds the only copy of a client-tool
5
+ * result, so it owns replaying it. Each call the browser answered through
6
+ * `/resume` is sent to later turns as an assistant `toolCalls` message plus a
7
+ * `tool` message with the matching `toolResults`, with the full result.
8
+ * A pair replays even after the page stops offering its tool: the model
9
+ * already saw that result, and a follow-up about it must not lose it.
10
+ */
11
+
12
+ import type {
13
+ AgentWidgetMessage,
14
+ AgentWidgetReplayedToolCall,
15
+ AgentWidgetReplayedToolResult,
16
+ AgentWidgetRequestPayloadMessage,
17
+ } from "../types";
18
+
19
+ /**
20
+ * The name a tool reaches the model as (`webmcp:get_schema` ->
21
+ * `webmcp_get_schema`).
22
+ */
23
+ export const modelFacingToolName = (name: string): string =>
24
+ name
25
+ .replace(/[^a-zA-Z0-9_]/g, "_")
26
+ .toLowerCase()
27
+ .replace(/_+/g, "_")
28
+ .replace(/^_|_$/g, "");
29
+
30
+ const isRecord = (value: unknown): value is Record<string, unknown> =>
31
+ typeof value === "object" && value !== null && !Array.isArray(value);
32
+
33
+ const replayablePair = (
34
+ message: AgentWidgetMessage,
35
+ ): { call: AgentWidgetReplayedToolCall; result: AgentWidgetReplayedToolResult } | null => {
36
+ if (message.variant !== "tool") return null;
37
+ const answer = message.agentMetadata?.clientToolAnswer;
38
+ if (!answer || !answer.toolCallId || answer.result === undefined) return null;
39
+ const toolName = modelFacingToolName(answer.toolName);
40
+ if (!toolName) return null;
41
+ return {
42
+ call: {
43
+ toolCallId: answer.toolCallId,
44
+ toolName,
45
+ args: isRecord(answer.args) ? answer.args : {},
46
+ },
47
+ result: { toolCallId: answer.toolCallId, toolName, result: answer.result },
48
+ };
49
+ };
50
+
51
+ /**
52
+ * Serialize time-ordered messages, interleaving replayable tool pairs.
53
+ * `toPayload` maps an ordinary message (or returns null to drop it). Answers
54
+ * posted in the same `/resume` batch are one assistant turn's parallel calls,
55
+ * so they group into one call message and one result message; a later batch
56
+ * (a chained call) starts a new pair even with no text between them.
57
+ */
58
+ export const serializeWithToolPairs = (
59
+ messages: readonly AgentWidgetMessage[],
60
+ toPayload: (message: AgentWidgetMessage) => AgentWidgetRequestPayloadMessage | null,
61
+ ): AgentWidgetRequestPayloadMessage[] => {
62
+ const out: AgentWidgetRequestPayloadMessage[] = [];
63
+ let calls: AgentWidgetReplayedToolCall[] = [];
64
+ let results: AgentWidgetReplayedToolResult[] = [];
65
+ let groupCreatedAt = "";
66
+ let groupBatch: string | undefined;
67
+
68
+ const flush = () => {
69
+ if (calls.length === 0) return;
70
+ out.push(
71
+ { role: "assistant", content: "", createdAt: groupCreatedAt, toolCalls: calls },
72
+ { role: "tool", content: "", createdAt: groupCreatedAt, toolResults: results },
73
+ );
74
+ calls = [];
75
+ results = [];
76
+ };
77
+
78
+ for (const message of messages) {
79
+ const pair = replayablePair(message);
80
+ if (pair) {
81
+ const batch = message.agentMetadata?.clientToolAnswer?.batch;
82
+ if (calls.length > 0 && (batch === undefined || batch !== groupBatch)) flush();
83
+ if (calls.length === 0) {
84
+ groupCreatedAt = message.createdAt;
85
+ groupBatch = batch;
86
+ }
87
+ if (!calls.some((call) => call.toolCallId === pair.call.toolCallId)) {
88
+ calls.push(pair.call);
89
+ results.push(pair.result);
90
+ }
91
+ continue;
92
+ }
93
+ const mapped = toPayload(message);
94
+ if (!mapped) continue;
95
+ flush();
96
+ out.push(mapped);
97
+ }
98
+ flush();
99
+ return out;
100
+ };