@assistant-ui/react 0.15.2 → 0.15.3

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 (42) hide show
  1. package/dist/client/ExternalThread.d.ts.map +1 -1
  2. package/dist/client/ExternalThread.js +1 -0
  3. package/dist/client/ExternalThread.js.map +1 -1
  4. package/dist/client/InMemoryThreadList.d.ts.map +1 -1
  5. package/dist/client/InMemoryThreadList.js +199 -176
  6. package/dist/client/InMemoryThreadList.js.map +1 -1
  7. package/dist/client/SingleThreadList.d.ts.map +1 -1
  8. package/dist/client/SingleThreadList.js +56 -48
  9. package/dist/client/SingleThreadList.js.map +1 -1
  10. package/dist/legacy-runtime/cloud/auiV0.d.ts +2 -0
  11. package/dist/legacy-runtime/cloud/auiV0.d.ts.map +1 -1
  12. package/dist/legacy-runtime/cloud/auiV0.js +6 -4
  13. package/dist/legacy-runtime/cloud/auiV0.js.map +1 -1
  14. package/dist/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  15. package/dist/mcp-apps/McpAppRenderer.js +25 -14
  16. package/dist/mcp-apps/McpAppRenderer.js.map +1 -1
  17. package/dist/mcp-apps/McpAppsRemoteHost.d.ts.map +1 -1
  18. package/dist/mcp-apps/McpAppsRemoteHost.js +17 -6
  19. package/dist/mcp-apps/McpAppsRemoteHost.js.map +1 -1
  20. package/dist/primitives/message/MessagePartsGrouped.d.ts +6 -1
  21. package/dist/primitives/message/MessagePartsGrouped.d.ts.map +1 -1
  22. package/dist/primitives/message/MessagePartsGrouped.js.map +1 -1
  23. package/dist/primitives/suggestion/SuggestionTrigger.d.ts +4 -2
  24. package/dist/primitives/suggestion/SuggestionTrigger.d.ts.map +1 -1
  25. package/dist/primitives/suggestion/SuggestionTrigger.js +21 -42
  26. package/dist/primitives/suggestion/SuggestionTrigger.js.map +1 -1
  27. package/dist/primitives/thread/ThreadSuggestion.d.ts +4 -2
  28. package/dist/primitives/thread/ThreadSuggestion.d.ts.map +1 -1
  29. package/dist/primitives/thread/ThreadSuggestion.js.map +1 -1
  30. package/package.json +5 -5
  31. package/src/client/ExternalThread.ts +1 -0
  32. package/src/client/InMemoryThreadList.ts +27 -7
  33. package/src/client/SingleThreadList.ts +10 -2
  34. package/src/legacy-runtime/cloud/auiV0.ts +8 -2
  35. package/src/mcp-apps/McpAppRenderer.test.tsx +262 -3
  36. package/src/mcp-apps/McpAppRenderer.tsx +27 -15
  37. package/src/mcp-apps/McpAppsRemoteHost.ts +18 -9
  38. package/src/primitives/message/MessagePartsGrouped.tsx +6 -1
  39. package/src/primitives/suggestion/SuggestionTrigger.ts +11 -32
  40. package/src/primitives/thread/ThreadSuggestion.ts +2 -1
  41. package/src/tests/RemoteThreadListRuntime.reloadMainThread.test.tsx +115 -0
  42. package/src/tests/threadListItemIsRunning.test.tsx +198 -0
@@ -5,19 +5,21 @@ import { resource } from "@assistant-ui/tap";
5
5
  //#region src/client/SingleThreadList.ts
6
6
  const RESOLVED_PROMISE = Promise.resolve();
7
7
  const THREAD_ID = "default";
8
- const useSingleThreadListItem = () => {
9
- const $ = c(2);
8
+ const useSingleThreadListItem = (t0) => {
9
+ const $ = c(3);
10
+ const { isRunning } = t0;
10
11
  const [custom, setCustom] = useState();
11
- let t0;
12
- if ($[0] !== custom) {
13
- t0 = {
12
+ let t1;
13
+ if ($[0] !== custom || $[1] !== isRunning) {
14
+ t1 = {
14
15
  getState: () => ({
15
16
  id: THREAD_ID,
16
17
  remoteId: void 0,
17
18
  externalId: void 0,
18
19
  title: void 0,
19
20
  status: "regular",
20
- custom
21
+ custom,
22
+ isRunning
21
23
  }),
22
24
  switchTo: _temp,
23
25
  rename: _temp2,
@@ -30,9 +32,10 @@ const useSingleThreadListItem = () => {
30
32
  detach: _temp8
31
33
  };
32
34
  $[0] = custom;
33
- $[1] = t0;
34
- } else t0 = $[1];
35
- return t0;
35
+ $[1] = isRunning;
36
+ $[2] = t1;
37
+ } else t1 = $[2];
38
+ return t1;
36
39
  };
37
40
  const SingleThreadListItem = resource(useSingleThreadListItem);
38
41
  /**
@@ -41,34 +44,35 @@ const SingleThreadListItem = resource(useSingleThreadListItem);
41
44
  * Mounts the provided thread resource element.
42
45
  */
43
46
  const useSingleThreadList = (t0) => {
44
- const $ = c(18);
47
+ const $ = c(19);
45
48
  const { thread } = t0;
49
+ const threadClient = useClientResource(thread);
46
50
  let t1;
47
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
48
- t1 = SingleThreadListItem();
49
- $[0] = t1;
50
- } else t1 = $[0];
51
+ if ($[0] !== threadClient.state.isRunning) {
52
+ t1 = SingleThreadListItem({ isRunning: threadClient.state.isRunning });
53
+ $[0] = threadClient.state.isRunning;
54
+ $[1] = t1;
55
+ } else t1 = $[1];
51
56
  const itemClient = useClientResource(t1);
52
- const threadClient = useClientResource(thread);
53
57
  let t2;
54
58
  let t3;
55
- if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
59
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
56
60
  t2 = [THREAD_ID];
57
61
  t3 = [];
58
- $[1] = t2;
59
- $[2] = t3;
62
+ $[2] = t2;
63
+ $[3] = t3;
60
64
  } else {
61
- t2 = $[1];
62
- t3 = $[2];
65
+ t2 = $[2];
66
+ t3 = $[3];
63
67
  }
64
68
  let t4;
65
- if ($[3] !== itemClient.state) {
69
+ if ($[4] !== itemClient.state) {
66
70
  t4 = [itemClient.state];
67
- $[3] = itemClient.state;
68
- $[4] = t4;
69
- } else t4 = $[4];
71
+ $[4] = itemClient.state;
72
+ $[5] = t4;
73
+ } else t4 = $[5];
70
74
  let t5;
71
- if ($[5] !== t4 || $[6] !== threadClient.state) {
75
+ if ($[6] !== t4 || $[7] !== threadClient.state) {
72
76
  t5 = {
73
77
  mainThreadId: THREAD_ID,
74
78
  newThreadId: null,
@@ -80,52 +84,53 @@ const useSingleThreadList = (t0) => {
80
84
  threadItems: t4,
81
85
  main: threadClient.state
82
86
  };
83
- $[5] = t4;
84
- $[6] = threadClient.state;
85
- $[7] = t5;
86
- } else t5 = $[7];
87
+ $[6] = t4;
88
+ $[7] = threadClient.state;
89
+ $[8] = t5;
90
+ } else t5 = $[8];
87
91
  const state = t5;
88
92
  let t6;
89
- if ($[8] !== state) {
93
+ if ($[9] !== state) {
90
94
  t6 = () => state;
91
- $[8] = state;
92
- $[9] = t6;
93
- } else t6 = $[9];
95
+ $[9] = state;
96
+ $[10] = t6;
97
+ } else t6 = $[10];
94
98
  let t7;
95
- if ($[10] !== itemClient.methods) {
99
+ if ($[11] !== itemClient.methods) {
96
100
  t7 = (selector) => {
97
101
  if (selector !== "main" && !(typeof selector === "object" && "id" in selector && selector.id === THREAD_ID) && !(typeof selector === "object" && "index" in selector && selector.index === 0)) throw new Error(`SingleThreadList: unknown item selector ${JSON.stringify(selector)}`);
98
102
  return itemClient.methods;
99
103
  };
100
- $[10] = itemClient.methods;
101
- $[11] = t7;
102
- } else t7 = $[11];
104
+ $[11] = itemClient.methods;
105
+ $[12] = t7;
106
+ } else t7 = $[12];
103
107
  let t8;
104
- if ($[12] !== threadClient.methods) {
108
+ if ($[13] !== threadClient.methods) {
105
109
  t8 = (selector_0) => {
106
110
  if (selector_0 !== "main" && selector_0 !== THREAD_ID) throw new Error(`SingleThreadList: unknown thread selector ${JSON.stringify(selector_0)}`);
107
111
  return threadClient.methods;
108
112
  };
109
- $[12] = threadClient.methods;
110
- $[13] = t8;
111
- } else t8 = $[13];
113
+ $[13] = threadClient.methods;
114
+ $[14] = t8;
115
+ } else t8 = $[14];
112
116
  let t9;
113
- if ($[14] !== t6 || $[15] !== t7 || $[16] !== t8) {
117
+ if ($[15] !== t6 || $[16] !== t7 || $[17] !== t8) {
114
118
  t9 = {
115
119
  getState: t6,
116
120
  switchToThread: _temp9,
117
121
  switchToNewThread: _temp0,
118
122
  getLoadThreadsPromise: _temp1,
119
123
  reload: _temp10,
120
- loadMore: _temp11,
124
+ reloadMainThread: _temp11,
125
+ loadMore: _temp12,
121
126
  item: t7,
122
127
  thread: t8
123
128
  };
124
- $[14] = t6;
125
- $[15] = t7;
126
- $[16] = t8;
127
- $[17] = t9;
128
- } else t9 = $[17];
129
+ $[15] = t6;
130
+ $[16] = t7;
131
+ $[17] = t8;
132
+ $[18] = t9;
133
+ } else t9 = $[18];
129
134
  return t9;
130
135
  };
131
136
  const SingleThreadList = resource(useSingleThreadList);
@@ -157,6 +162,9 @@ function _temp10() {
157
162
  function _temp11() {
158
163
  return RESOLVED_PROMISE;
159
164
  }
165
+ function _temp12() {
166
+ return RESOLVED_PROMISE;
167
+ }
160
168
  //#endregion
161
169
  export { SingleThreadList };
162
170
 
@@ -1 +1 @@
1
- {"version":3,"file":"SingleThreadList.js","names":["useMemo","useState","resource","ClientElement","ClientOutput","useClientResource","RESOLVED_PROMISE","Promise","resolve","THREAD_ID","useSingleThreadListItem","$","_c","custom","setCustom","t0","getState","id","remoteId","undefined","externalId","title","status","switchTo","_temp","rename","_temp2","updateCustom","archive","_temp3","unarchive","_temp4","delete","_temp5","generateTitle","_temp6","initialize","_temp7","detach","_temp8","SingleThreadListItem","SingleThreadListProps","thread","useSingleThreadList","t1","Symbol","for","itemClient","threadClient","t2","t3","t4","state","t5","mainThreadId","newThreadId","isLoading","isLoadingMore","hasMore","threadIds","archivedThreadIds","threadItems","main","t6","t7","methods","selector","index","Error","JSON","stringify","t8","selector_0","t9","switchToThread","_temp9","switchToNewThread","_temp0","getLoadThreadsPromise","_temp1","reload","_temp10","loadMore","_temp11","item","SingleThreadList"],"sources":["../../src/client/SingleThreadList.ts"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport {\n type ClientElement,\n type ClientOutput,\n useClientResource,\n} from \"@assistant-ui/store\";\n\nconst RESOLVED_PROMISE = Promise.resolve();\nconst THREAD_ID = \"default\";\n\nconst useSingleThreadListItem = (): ClientOutput<\"threadListItem\"> => {\n const [custom, setCustom] = useState<Record<string, unknown> | undefined>();\n\n return {\n getState: () => ({\n id: THREAD_ID,\n remoteId: undefined,\n externalId: undefined,\n title: undefined,\n status: \"regular\",\n custom,\n }),\n switchTo: () => {},\n rename: () => {},\n updateCustom: setCustom,\n archive: () => {},\n unarchive: () => {},\n delete: () => {},\n generateTitle: () => {},\n initialize: async () => ({ remoteId: THREAD_ID, externalId: undefined }),\n detach: () => {},\n };\n};\n\nconst SingleThreadListItem = resource(useSingleThreadListItem);\n\ntype SingleThreadListProps = {\n thread: ClientElement<\"thread\">;\n};\n\n/**\n * A minimal threads scope that wraps a single thread.\n * Automatically provided by ExternalThread when no threads scope exists.\n * Mounts the provided thread resource element.\n */\nconst useSingleThreadList = ({\n thread,\n}: SingleThreadListProps): ClientOutput<\"threads\"> => {\n const itemClient = useClientResource(SingleThreadListItem());\n const threadClient = useClientResource(thread);\n\n const state = useMemo(\n () => ({\n mainThreadId: THREAD_ID,\n newThreadId: null,\n isLoading: false,\n isLoadingMore: false,\n hasMore: false,\n threadIds: [THREAD_ID],\n archivedThreadIds: [],\n threadItems: [itemClient.state],\n main: threadClient.state,\n }),\n [itemClient.state, threadClient.state],\n );\n\n return {\n getState: () => state,\n switchToThread: () => {\n throw new Error(\"SingleThreadList does not support switchToThread\");\n },\n switchToNewThread: () => {\n throw new Error(\"SingleThreadList does not support switchToNewThread\");\n },\n getLoadThreadsPromise: () => RESOLVED_PROMISE,\n reload: () => RESOLVED_PROMISE,\n loadMore: () => RESOLVED_PROMISE,\n item: (selector) => {\n if (\n selector !== \"main\" &&\n !(\n typeof selector === \"object\" &&\n \"id\" in selector &&\n selector.id === THREAD_ID\n ) &&\n !(\n typeof selector === \"object\" &&\n \"index\" in selector &&\n selector.index === 0\n )\n ) {\n throw new Error(\n `SingleThreadList: unknown item selector ${JSON.stringify(selector)}`,\n );\n }\n return itemClient.methods;\n },\n thread: (selector) => {\n if (selector !== \"main\" && selector !== THREAD_ID) {\n throw new Error(\n `SingleThreadList: unknown thread selector ${JSON.stringify(selector)}`,\n );\n }\n return threadClient.methods;\n },\n };\n};\n\nexport const SingleThreadList = resource(useSingleThreadList);\n"],"mappings":"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"}
1
+ {"version":3,"file":"SingleThreadList.js","names":["useMemo","useState","resource","ClientElement","ClientOutput","useClientResource","RESOLVED_PROMISE","Promise","resolve","THREAD_ID","useSingleThreadListItem","t0","$","_c","isRunning","custom","setCustom","t1","getState","id","remoteId","undefined","externalId","title","status","switchTo","_temp","rename","_temp2","updateCustom","archive","_temp3","unarchive","_temp4","delete","_temp5","generateTitle","_temp6","initialize","_temp7","detach","_temp8","SingleThreadListItem","SingleThreadListProps","thread","useSingleThreadList","threadClient","state","itemClient","t2","t3","Symbol","for","t4","t5","mainThreadId","newThreadId","isLoading","isLoadingMore","hasMore","threadIds","archivedThreadIds","threadItems","main","t6","t7","methods","selector","index","Error","JSON","stringify","t8","selector_0","t9","switchToThread","_temp9","switchToNewThread","_temp0","getLoadThreadsPromise","_temp1","reload","_temp10","reloadMainThread","_temp11","loadMore","_temp12","item","SingleThreadList"],"sources":["../../src/client/SingleThreadList.ts"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport {\n type ClientElement,\n type ClientOutput,\n useClientResource,\n} from \"@assistant-ui/store\";\n\nconst RESOLVED_PROMISE = Promise.resolve();\nconst THREAD_ID = \"default\";\n\nconst useSingleThreadListItem = ({\n isRunning,\n}: {\n isRunning: boolean;\n}): ClientOutput<\"threadListItem\"> => {\n const [custom, setCustom] = useState<Record<string, unknown> | undefined>();\n\n return {\n getState: () => ({\n id: THREAD_ID,\n remoteId: undefined,\n externalId: undefined,\n title: undefined,\n status: \"regular\",\n custom,\n isRunning,\n }),\n switchTo: () => {},\n rename: () => {},\n updateCustom: setCustom,\n archive: () => {},\n unarchive: () => {},\n delete: () => {},\n generateTitle: () => {},\n initialize: async () => ({ remoteId: THREAD_ID, externalId: undefined }),\n detach: () => {},\n };\n};\n\nconst SingleThreadListItem = resource(useSingleThreadListItem);\n\ntype SingleThreadListProps = {\n thread: ClientElement<\"thread\">;\n};\n\n/**\n * A minimal threads scope that wraps a single thread.\n * Automatically provided by ExternalThread when no threads scope exists.\n * Mounts the provided thread resource element.\n */\nconst useSingleThreadList = ({\n thread,\n}: SingleThreadListProps): ClientOutput<\"threads\"> => {\n const threadClient = useClientResource(thread);\n const itemClient = useClientResource(\n SingleThreadListItem({ isRunning: threadClient.state.isRunning }),\n );\n\n const state = useMemo(\n () => ({\n mainThreadId: THREAD_ID,\n newThreadId: null,\n isLoading: false,\n isLoadingMore: false,\n hasMore: false,\n threadIds: [THREAD_ID],\n archivedThreadIds: [],\n threadItems: [itemClient.state],\n main: threadClient.state,\n }),\n [itemClient.state, threadClient.state],\n );\n\n return {\n getState: () => state,\n switchToThread: () => {\n throw new Error(\"SingleThreadList does not support switchToThread\");\n },\n switchToNewThread: () => {\n throw new Error(\"SingleThreadList does not support switchToNewThread\");\n },\n getLoadThreadsPromise: () => RESOLVED_PROMISE,\n reload: () => RESOLVED_PROMISE,\n reloadMainThread: () => RESOLVED_PROMISE,\n loadMore: () => RESOLVED_PROMISE,\n item: (selector) => {\n if (\n selector !== \"main\" &&\n !(\n typeof selector === \"object\" &&\n \"id\" in selector &&\n selector.id === THREAD_ID\n ) &&\n !(\n typeof selector === \"object\" &&\n \"index\" in selector &&\n selector.index === 0\n )\n ) {\n throw new Error(\n `SingleThreadList: unknown item selector ${JSON.stringify(selector)}`,\n );\n }\n return itemClient.methods;\n },\n thread: (selector) => {\n if (selector !== \"main\" && selector !== THREAD_ID) {\n throw new Error(\n `SingleThreadList: unknown thread selector ${JSON.stringify(selector)}`,\n );\n }\n return threadClient.methods;\n },\n };\n};\n\nexport const SingleThreadList = resource(useSingleThreadList);\n"],"mappings":"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"}
@@ -57,6 +57,7 @@ type AuiV0MessagePart = {
57
57
  readonly data: string;
58
58
  readonly mimeType: string;
59
59
  readonly filename?: string;
60
+ readonly sourceType?: "url" | "id";
60
61
  };
61
62
  type AuiV0AttachmentPart = {
62
63
  readonly type: "text";
@@ -70,6 +71,7 @@ type AuiV0AttachmentPart = {
70
71
  readonly data: string;
71
72
  readonly mimeType: string;
72
73
  readonly filename?: string;
74
+ readonly sourceType?: "url" | "id";
73
75
  } | {
74
76
  readonly type: "audio";
75
77
  readonly audio: {
@@ -1 +1 @@
1
- {"version":3,"file":"auiV0.d.ts","names":[],"sources":["../../../src/legacy-runtime/cloud/auiV0.ts"],"mappings":";;;;;KAgBK;WACM;WACA;WACA;WACA;WACA,mBAAmB;WACnB;WACA;;KAGN;WAEU;WACA;;WAGA;WACA;;WAGA;WACA;WACA;WACA;WACA;WACA,mBAAmB;;WAGnB;WACA;WACA;WACA;WACA;WACA;WACA,mBAAmB;;WAGnB;WACA;WACA;WACA,MAAM;WACN,SAAS;WACT;WACA,WAAW;;WAGX;WACA;WACA;WACA;WACA,SAAS;WACT;WACA,WAAW;;WAGX;WACA;;WAGA;WACA;WACA;WACA;;KAGV;WAEU;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;;WAGA;WACA;aACE;aACA;;;WAIF;WACA;WACA,MAAM;;KAGhB;WACM;WACA,MAAM;WACN;WACA;WACA,QAAQ;WACR,kBAAkB;;KAGxB;WACM;WACA,SAAS;WACT,kBAAkB;WAClB,uBAAuB;WACvB;aACE,iBAAiB;aACjB,+BAA+B;aAC/B,wBAAwB;aACxB;eACE;iBACE;iBACA;;;aAGJ,QAAQ;;;iBAwEL,YAAY,SAAS,gBAAgB;iBA6FrC,YACd,cAAc;EAAiB;IAC9B"}
1
+ {"version":3,"file":"auiV0.d.ts","names":[],"sources":["../../../src/legacy-runtime/cloud/auiV0.ts"],"mappings":";;;;;KAgBK;WACM;WACA;WACA;WACA;WACA,mBAAmB;WACnB;WACA;;KAGN;WAEU;WACA;;WAGA;WACA;;WAGA;WACA;WACA;WACA;WACA;WACA,mBAAmB;;WAGnB;WACA;WACA;WACA;WACA;WACA;WACA,mBAAmB;;WAGnB;WACA;WACA;WACA,MAAM;WACN,SAAS;WACT;WACA,WAAW;;WAGX;WACA;WACA;WACA;WACA,SAAS;WACT;WACA,WAAW;;WAGX;WACA;;WAGA;WACA;WACA;WACA;WACA;;KAGV;WAEU;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;WACA;;WAGA;WACA;aACE;aACA;;;WAIF;WACA;WACA,MAAM;;KAGhB;WACM;WACA,MAAM;WACN;WACA;WACA,QAAQ;WACR,kBAAkB;;KAGxB;WACM;WACA,SAAS;WACT,kBAAkB;WAClB,uBAAuB;WACvB;aACE,iBAAiB;aACjB,+BAA+B;aAC/B,wBAAwB;aACxB;eACE;iBACE;iBACA;;;aAGJ,QAAQ;;;iBA2EL,YAAY,SAAS,gBAAgB;iBA8FrC,YACd,cAAc;EAAiB;IAC9B"}
@@ -17,7 +17,8 @@ const encodeAttachmentPart = (part) => {
17
17
  type: "file",
18
18
  data: part.data,
19
19
  mimeType: part.mimeType,
20
- ...part.filename != null ? { filename: part.filename } : void 0
20
+ ...part.filename != null ? { filename: part.filename } : void 0,
21
+ ...part.sourceType != null ? { sourceType: part.sourceType } : void 0
21
22
  };
22
23
  case "audio": return {
23
24
  type: "audio",
@@ -85,13 +86,13 @@ function auiV0Encode(message) {
85
86
  ...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : void 0
86
87
  };
87
88
  case "tool-call":
88
- if (!isJSONValue(part.result)) console.warn(`tool-call result is not JSON! ${JSON.stringify(part)}`);
89
+ if (part.result !== void 0 && !isJSONValue(part.result)) console.warn(`tool-call result is not JSON! ${JSON.stringify(part)}`);
89
90
  return {
90
91
  type: "tool-call",
91
92
  toolCallId: part.toolCallId,
92
93
  toolName: part.toolName,
93
94
  ...JSON.stringify(part.args) === part.argsText ? { args: part.args } : { argsText: part.argsText },
94
- ...part.result ? { result: part.result } : void 0,
95
+ ...part.result !== void 0 ? { result: part.result } : void 0,
95
96
  ...part.isError ? { isError: true } : void 0,
96
97
  ...part.approval ? { approval: part.approval } : void 0
97
98
  };
@@ -103,7 +104,8 @@ function auiV0Encode(message) {
103
104
  type: "file",
104
105
  data: part.data,
105
106
  mimeType: part.mimeType,
106
- ...part.filename ? { filename: part.filename } : void 0
107
+ ...part.filename ? { filename: part.filename } : void 0,
108
+ ...part.sourceType ? { sourceType: part.sourceType } : void 0
107
109
  };
108
110
  default: throw new Error(`Message part type not supported by aui/v0: ${type}`);
109
111
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auiV0.js","names":["CompleteAttachment","MessageStatus","SourceProviderMetadata","ThreadMessage","ToolApprovalOption","fromThreadMessageLike","CloudMessage","isJSONValue","ReadonlyJSONObject","ReadonlyJSONValue","ExportedMessageRepositoryItem","AuiV0ToolApproval","id","approved","reason","isAutomatic","options","optionId","resolution","AuiV0MessagePart","type","text","sourceType","url","title","providerMetadata","mediaType","filename","toolCallId","toolName","args","result","isError","approval","argsText","image","data","mimeType","AuiV0AttachmentPart","audio","format","name","AuiV0Attachment","contentType","status","content","AuiV0Message","role","attachments","metadata","unstable_state","unstable_annotations","unstable_data","steps","usage","inputTokens","outputTokens","custom","encodeAttachmentPart","part","undefined","console","warn","JSON","stringify","unhandledType","Error","encodeAttachments","message","length","map","auiV0Encode","auiV0Decode","cloudMessage","payload","createdAt","created_at","parentId","parent_id"],"sources":["../../../src/legacy-runtime/cloud/auiV0.ts"],"sourcesContent":["import type {\n CompleteAttachment,\n MessageStatus,\n SourceProviderMetadata,\n ThreadMessage,\n ToolApprovalOption,\n} from \"@assistant-ui/core\";\nimport { fromThreadMessageLike } from \"../runtime-cores/external-store/ThreadMessageLike\";\nimport type { CloudMessage } from \"assistant-cloud\";\nimport { isJSONValue } from \"@assistant-ui/core/internal\";\nimport type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\nimport type { ExportedMessageRepositoryItem } from \"../runtime-cores/utils/MessageRepository\";\n\ntype AuiV0ToolApproval = {\n readonly id: string;\n readonly approved?: boolean;\n readonly reason?: string;\n readonly isAutomatic?: boolean;\n readonly options?: readonly ToolApprovalOption[];\n readonly optionId?: string;\n readonly resolution?: \"cancelled\" | \"expired\";\n};\n\ntype AuiV0MessagePart =\n | {\n readonly type: \"text\";\n readonly text: string;\n }\n | {\n readonly type: \"reasoning\";\n readonly text: string;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"url\";\n readonly id: string;\n readonly url: string;\n readonly title?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"document\";\n readonly id: string;\n readonly title: string;\n readonly mediaType: string;\n readonly filename?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n }\n | {\n readonly type: \"tool-call\";\n readonly toolCallId: string;\n readonly toolName: string;\n readonly args: ReadonlyJSONObject;\n readonly result?: ReadonlyJSONValue;\n readonly isError?: true;\n readonly approval?: AuiV0ToolApproval;\n }\n | {\n readonly type: \"tool-call\";\n readonly toolCallId: string;\n readonly toolName: string;\n readonly argsText: string;\n readonly result?: ReadonlyJSONValue;\n readonly isError?: true;\n readonly approval?: AuiV0ToolApproval;\n }\n | {\n readonly type: \"image\";\n readonly image: string;\n }\n | {\n readonly type: \"file\";\n readonly data: string;\n readonly mimeType: string;\n readonly filename?: string;\n };\n\ntype AuiV0AttachmentPart =\n | {\n readonly type: \"text\";\n readonly text: string;\n }\n | {\n readonly type: \"image\";\n readonly image: string;\n readonly filename?: string;\n }\n | {\n readonly type: \"file\";\n readonly data: string;\n readonly mimeType: string;\n readonly filename?: string;\n }\n | {\n readonly type: \"audio\";\n readonly audio: {\n readonly data: string;\n readonly format: \"mp3\" | \"wav\";\n };\n }\n | {\n readonly type: \"data\";\n readonly name: string;\n readonly data: ReadonlyJSONValue;\n };\n\ntype AuiV0Attachment = {\n readonly id: string;\n readonly type: CompleteAttachment[\"type\"];\n readonly name: string;\n readonly contentType?: string;\n readonly status: CompleteAttachment[\"status\"];\n readonly content: readonly AuiV0AttachmentPart[];\n};\n\ntype AuiV0Message = {\n readonly role: \"assistant\" | \"user\" | \"system\";\n readonly status?: MessageStatus;\n readonly content: readonly AuiV0MessagePart[];\n readonly attachments?: readonly AuiV0Attachment[];\n readonly metadata: {\n readonly unstable_state?: ReadonlyJSONValue;\n readonly unstable_annotations: readonly ReadonlyJSONValue[];\n readonly unstable_data: readonly ReadonlyJSONValue[];\n readonly steps: readonly {\n readonly usage?: {\n readonly inputTokens: number;\n readonly outputTokens: number;\n };\n }[];\n readonly custom: ReadonlyJSONObject;\n };\n};\n\nconst encodeAttachmentPart = (\n part: CompleteAttachment[\"content\"][number],\n): AuiV0AttachmentPart => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\", text: part.text };\n\n case \"image\":\n return {\n type: \"image\",\n image: part.image,\n ...(part.filename != null ? { filename: part.filename } : undefined),\n };\n\n case \"file\":\n return {\n type: \"file\",\n data: part.data,\n mimeType: part.mimeType,\n ...(part.filename != null ? { filename: part.filename } : undefined),\n };\n\n case \"audio\":\n return {\n type: \"audio\",\n audio: { data: part.audio.data, format: part.audio.format },\n };\n\n case \"data\": {\n if (!isJSONValue(part.data)) {\n console.warn(`attachment data is not JSON! ${JSON.stringify(part)}`);\n }\n return {\n type: \"data\",\n name: part.name,\n data: part.data as ReadonlyJSONValue,\n };\n }\n\n default: {\n const unhandledType: never = type;\n throw new Error(\n `Attachment part type not supported by aui/v0: ${unhandledType}`,\n );\n }\n }\n};\n\nconst encodeAttachments = (\n message: ThreadMessage,\n): readonly AuiV0Attachment[] | undefined => {\n if (message.role !== \"user\" || message.attachments.length === 0) {\n return undefined;\n }\n\n return message.attachments.map(\n ({ id, type, name, contentType, status, content }) => ({\n id,\n type,\n name,\n status,\n ...(contentType != null ? { contentType } : undefined),\n content: content.map(encodeAttachmentPart),\n }),\n );\n};\n\nexport function auiV0Encode(message: ThreadMessage): AuiV0Message {\n // info: ID and createdAt are ignored (we use the server value instead)\n const status: MessageStatus | undefined =\n message.status?.type === \"running\"\n ? { type: \"incomplete\", reason: \"cancelled\" }\n : message.status;\n const attachments = encodeAttachments(message);\n\n return {\n role: message.role,\n content: message.content.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\", text: part.text };\n\n case \"reasoning\":\n return { type: \"reasoning\", text: part.text };\n\n case \"source\":\n if (part.sourceType === \"url\") {\n return {\n type: \"source\",\n sourceType: \"url\",\n id: part.id,\n url: part.url,\n ...(part.title != null ? { title: part.title } : undefined),\n ...(part.providerMetadata != null\n ? { providerMetadata: part.providerMetadata }\n : undefined),\n };\n }\n\n return {\n type: \"source\",\n sourceType: \"document\",\n id: part.id,\n title: part.title,\n mediaType: part.mediaType,\n ...(part.filename != null\n ? { filename: part.filename }\n : undefined),\n ...(part.providerMetadata != null\n ? { providerMetadata: part.providerMetadata }\n : undefined),\n };\n\n case \"tool-call\": {\n if (!isJSONValue(part.result)) {\n console.warn(\n `tool-call result is not JSON! ${JSON.stringify(part)}`,\n );\n }\n return {\n type: \"tool-call\",\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n ...(JSON.stringify(part.args) === part.argsText\n ? { args: part.args }\n : { argsText: part.argsText }),\n ...(part.result\n ? { result: part.result as ReadonlyJSONValue }\n : undefined),\n ...(part.isError ? { isError: true } : undefined),\n ...(part.approval ? { approval: part.approval } : undefined),\n };\n }\n\n case \"image\":\n return { type: \"image\", image: part.image };\n\n case \"file\":\n return {\n type: \"file\",\n data: part.data,\n mimeType: part.mimeType,\n ...(part.filename ? { filename: part.filename } : undefined),\n };\n\n default: {\n const unhandledType: \"audio\" | \"data\" | \"generative-ui\" = type;\n throw new Error(\n `Message part type not supported by aui/v0: ${unhandledType}`,\n );\n }\n }\n }),\n metadata: message.metadata as AuiV0Message[\"metadata\"],\n ...(status ? { status } : undefined),\n ...(attachments ? { attachments } : undefined),\n };\n}\n\nexport function auiV0Decode(\n cloudMessage: CloudMessage & { format: \"aui/v0\" },\n): ExportedMessageRepositoryItem {\n const payload = cloudMessage.content as unknown as AuiV0Message;\n const message = fromThreadMessageLike(\n {\n id: cloudMessage.id,\n createdAt: cloudMessage.created_at,\n ...payload,\n },\n cloudMessage.id,\n { type: \"complete\", reason: \"unknown\" },\n );\n\n return {\n parentId: cloudMessage.parent_id,\n message,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"auiV0.js","names":["CompleteAttachment","MessageStatus","SourceProviderMetadata","ThreadMessage","ToolApprovalOption","fromThreadMessageLike","CloudMessage","isJSONValue","ReadonlyJSONObject","ReadonlyJSONValue","ExportedMessageRepositoryItem","AuiV0ToolApproval","id","approved","reason","isAutomatic","options","optionId","resolution","AuiV0MessagePart","type","text","sourceType","url","title","providerMetadata","mediaType","filename","toolCallId","toolName","args","result","isError","approval","argsText","image","data","mimeType","AuiV0AttachmentPart","audio","format","name","AuiV0Attachment","contentType","status","content","AuiV0Message","role","attachments","metadata","unstable_state","unstable_annotations","unstable_data","steps","usage","inputTokens","outputTokens","custom","encodeAttachmentPart","part","undefined","console","warn","JSON","stringify","unhandledType","Error","encodeAttachments","message","length","map","auiV0Encode","auiV0Decode","cloudMessage","payload","createdAt","created_at","parentId","parent_id"],"sources":["../../../src/legacy-runtime/cloud/auiV0.ts"],"sourcesContent":["import type {\n CompleteAttachment,\n MessageStatus,\n SourceProviderMetadata,\n ThreadMessage,\n ToolApprovalOption,\n} from \"@assistant-ui/core\";\nimport { fromThreadMessageLike } from \"../runtime-cores/external-store/ThreadMessageLike\";\nimport type { CloudMessage } from \"assistant-cloud\";\nimport { isJSONValue } from \"@assistant-ui/core/internal\";\nimport type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\nimport type { ExportedMessageRepositoryItem } from \"../runtime-cores/utils/MessageRepository\";\n\ntype AuiV0ToolApproval = {\n readonly id: string;\n readonly approved?: boolean;\n readonly reason?: string;\n readonly isAutomatic?: boolean;\n readonly options?: readonly ToolApprovalOption[];\n readonly optionId?: string;\n readonly resolution?: \"cancelled\" | \"expired\";\n};\n\ntype AuiV0MessagePart =\n | {\n readonly type: \"text\";\n readonly text: string;\n }\n | {\n readonly type: \"reasoning\";\n readonly text: string;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"url\";\n readonly id: string;\n readonly url: string;\n readonly title?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"document\";\n readonly id: string;\n readonly title: string;\n readonly mediaType: string;\n readonly filename?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n }\n | {\n readonly type: \"tool-call\";\n readonly toolCallId: string;\n readonly toolName: string;\n readonly args: ReadonlyJSONObject;\n readonly result?: ReadonlyJSONValue;\n readonly isError?: true;\n readonly approval?: AuiV0ToolApproval;\n }\n | {\n readonly type: \"tool-call\";\n readonly toolCallId: string;\n readonly toolName: string;\n readonly argsText: string;\n readonly result?: ReadonlyJSONValue;\n readonly isError?: true;\n readonly approval?: AuiV0ToolApproval;\n }\n | {\n readonly type: \"image\";\n readonly image: string;\n }\n | {\n readonly type: \"file\";\n readonly data: string;\n readonly mimeType: string;\n readonly filename?: string;\n readonly sourceType?: \"url\" | \"id\";\n };\n\ntype AuiV0AttachmentPart =\n | {\n readonly type: \"text\";\n readonly text: string;\n }\n | {\n readonly type: \"image\";\n readonly image: string;\n readonly filename?: string;\n }\n | {\n readonly type: \"file\";\n readonly data: string;\n readonly mimeType: string;\n readonly filename?: string;\n readonly sourceType?: \"url\" | \"id\";\n }\n | {\n readonly type: \"audio\";\n readonly audio: {\n readonly data: string;\n readonly format: \"mp3\" | \"wav\";\n };\n }\n | {\n readonly type: \"data\";\n readonly name: string;\n readonly data: ReadonlyJSONValue;\n };\n\ntype AuiV0Attachment = {\n readonly id: string;\n readonly type: CompleteAttachment[\"type\"];\n readonly name: string;\n readonly contentType?: string;\n readonly status: CompleteAttachment[\"status\"];\n readonly content: readonly AuiV0AttachmentPart[];\n};\n\ntype AuiV0Message = {\n readonly role: \"assistant\" | \"user\" | \"system\";\n readonly status?: MessageStatus;\n readonly content: readonly AuiV0MessagePart[];\n readonly attachments?: readonly AuiV0Attachment[];\n readonly metadata: {\n readonly unstable_state?: ReadonlyJSONValue;\n readonly unstable_annotations: readonly ReadonlyJSONValue[];\n readonly unstable_data: readonly ReadonlyJSONValue[];\n readonly steps: readonly {\n readonly usage?: {\n readonly inputTokens: number;\n readonly outputTokens: number;\n };\n }[];\n readonly custom: ReadonlyJSONObject;\n };\n};\n\nconst encodeAttachmentPart = (\n part: CompleteAttachment[\"content\"][number],\n): AuiV0AttachmentPart => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\", text: part.text };\n\n case \"image\":\n return {\n type: \"image\",\n image: part.image,\n ...(part.filename != null ? { filename: part.filename } : undefined),\n };\n\n case \"file\":\n return {\n type: \"file\",\n data: part.data,\n mimeType: part.mimeType,\n ...(part.filename != null ? { filename: part.filename } : undefined),\n ...(part.sourceType != null\n ? { sourceType: part.sourceType }\n : undefined),\n };\n\n case \"audio\":\n return {\n type: \"audio\",\n audio: { data: part.audio.data, format: part.audio.format },\n };\n\n case \"data\": {\n if (!isJSONValue(part.data)) {\n console.warn(`attachment data is not JSON! ${JSON.stringify(part)}`);\n }\n return {\n type: \"data\",\n name: part.name,\n data: part.data as ReadonlyJSONValue,\n };\n }\n\n default: {\n const unhandledType: never = type;\n throw new Error(\n `Attachment part type not supported by aui/v0: ${unhandledType}`,\n );\n }\n }\n};\n\nconst encodeAttachments = (\n message: ThreadMessage,\n): readonly AuiV0Attachment[] | undefined => {\n if (message.role !== \"user\" || message.attachments.length === 0) {\n return undefined;\n }\n\n return message.attachments.map(\n ({ id, type, name, contentType, status, content }) => ({\n id,\n type,\n name,\n status,\n ...(contentType != null ? { contentType } : undefined),\n content: content.map(encodeAttachmentPart),\n }),\n );\n};\n\nexport function auiV0Encode(message: ThreadMessage): AuiV0Message {\n // info: ID and createdAt are ignored (we use the server value instead)\n const status: MessageStatus | undefined =\n message.status?.type === \"running\"\n ? { type: \"incomplete\", reason: \"cancelled\" }\n : message.status;\n const attachments = encodeAttachments(message);\n\n return {\n role: message.role,\n content: message.content.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\", text: part.text };\n\n case \"reasoning\":\n return { type: \"reasoning\", text: part.text };\n\n case \"source\":\n if (part.sourceType === \"url\") {\n return {\n type: \"source\",\n sourceType: \"url\",\n id: part.id,\n url: part.url,\n ...(part.title != null ? { title: part.title } : undefined),\n ...(part.providerMetadata != null\n ? { providerMetadata: part.providerMetadata }\n : undefined),\n };\n }\n\n return {\n type: \"source\",\n sourceType: \"document\",\n id: part.id,\n title: part.title,\n mediaType: part.mediaType,\n ...(part.filename != null\n ? { filename: part.filename }\n : undefined),\n ...(part.providerMetadata != null\n ? { providerMetadata: part.providerMetadata }\n : undefined),\n };\n\n case \"tool-call\": {\n if (part.result !== undefined && !isJSONValue(part.result)) {\n console.warn(\n `tool-call result is not JSON! ${JSON.stringify(part)}`,\n );\n }\n return {\n type: \"tool-call\",\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n ...(JSON.stringify(part.args) === part.argsText\n ? { args: part.args }\n : { argsText: part.argsText }),\n ...(part.result !== undefined\n ? { result: part.result as ReadonlyJSONValue }\n : undefined),\n ...(part.isError ? { isError: true } : undefined),\n ...(part.approval ? { approval: part.approval } : undefined),\n };\n }\n\n case \"image\":\n return { type: \"image\", image: part.image };\n\n case \"file\":\n return {\n type: \"file\",\n data: part.data,\n mimeType: part.mimeType,\n ...(part.filename ? { filename: part.filename } : undefined),\n ...(part.sourceType ? { sourceType: part.sourceType } : undefined),\n };\n\n default: {\n const unhandledType: \"audio\" | \"data\" | \"generative-ui\" = type;\n throw new Error(\n `Message part type not supported by aui/v0: ${unhandledType}`,\n );\n }\n }\n }),\n metadata: message.metadata as AuiV0Message[\"metadata\"],\n ...(status ? { status } : undefined),\n ...(attachments ? { attachments } : undefined),\n };\n}\n\nexport function auiV0Decode(\n cloudMessage: CloudMessage & { format: \"aui/v0\" },\n): ExportedMessageRepositoryItem {\n const payload = cloudMessage.content as unknown as AuiV0Message;\n const message = fromThreadMessageLike(\n {\n id: cloudMessage.id,\n createdAt: cloudMessage.created_at,\n ...payload,\n },\n cloudMessage.id,\n { type: \"complete\", reason: \"unknown\" },\n );\n\n return {\n parentId: cloudMessage.parent_id,\n message,\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"McpAppRenderer.d.ts","names":[],"sources":["../../src/mcp-apps/McpAppRenderer.tsx"],"mappings":";;;;;KA8BY;;;;;;EAMV,MAAM,gBAAgB;;EAEtB,UAAU;;;;;EAKV;;EAEA,WAAW;;EAEX,cAAc;;EAEd,WAAW;;EAEX,kBAAkB;;EAElB,gBAAgB,cAAc,OAAO,UAAU;;cAgNpC,4CAAc;WAxBL,QAAA;IAwBmC,SAAA"}
1
+ {"version":3,"file":"McpAppRenderer.d.ts","names":[],"sources":["../../src/mcp-apps/McpAppRenderer.tsx"],"mappings":";;;;;KA+BY;;;;;;EAMV,MAAM,gBAAgB;;EAEtB,UAAU;;;;;EAKV;;EAEA,WAAW;;EAEX,cAAc;;EAEd,WAAW;;EAEX,kBAAkB;;EAElB,gBAAgB,cAAc,OAAO,UAAU;;cA2NpC,4CAAc;WA5BL,QAAA;IA4BmC,SAAA"}
@@ -3,6 +3,7 @@ import { McpAppFrame } from "./app-frame.js";
3
3
  import { getMcpAppFromToolPart } from "./utils.js";
4
4
  import { useAui } from "@assistant-ui/store";
5
5
  import { useEffect, useMemo, useRef, useState } from "@assistant-ui/tap/react-shim";
6
+ import { create } from "zustand";
6
7
  import { Fragment, jsx } from "react/jsx-runtime";
7
8
  import { resource, useResource } from "@assistant-ui/tap";
8
9
  import { isRecord } from "@assistant-ui/core/internal";
@@ -22,7 +23,7 @@ function extractSendMessageText(params) {
22
23
  if (typeof obj["text"] === "string") return obj["text"];
23
24
  if (typeof obj["message"] === "string") return obj["message"];
24
25
  }
25
- function InlineRenderer({ part, internalsRef, optionsRef }) {
26
+ function InlineRenderer({ part, useHostStore, optionsRef }) {
26
27
  const opts = optionsRef.current;
27
28
  const aui = useAui();
28
29
  const app = getMcpAppFromToolPart(part);
@@ -30,26 +31,30 @@ function InlineRenderer({ part, internalsRef, optionsRef }) {
30
31
  if (app != null && (cachedAppRef.current?.resourceUri !== app.resourceUri || cachedAppRef.current?.serverId !== app.serverId)) cachedAppRef.current = app;
31
32
  const appForRender = app ?? cachedAppRef.current;
32
33
  const [loadedResource, setLoadedResource] = useState();
34
+ const host = useHostStore((state) => state.host);
33
35
  const resourceUri = appForRender?.resourceUri;
34
36
  const serverId = appForRender?.serverId;
35
37
  const serverIdRef = useRef(void 0);
36
38
  serverIdRef.current = serverId;
37
39
  useEffect(() => {
38
- if (appForRender == null || resourceUri == null) return;
40
+ if (resourceUri == null) return;
39
41
  let cancelled = false;
42
+ const targetHost = host;
40
43
  const targetUri = resourceUri;
41
44
  const targetServerId = serverId;
42
- internalsRef.current.host.loadResource({
45
+ targetHost.loadResource({
43
46
  uri: targetUri,
44
47
  ...targetServerId ? { serverId: targetServerId } : {}
45
48
  }).then((res) => {
46
49
  if (!cancelled) setLoadedResource({
50
+ host: targetHost,
47
51
  resourceUri: targetUri,
48
52
  ...targetServerId !== void 0 ? { serverId: targetServerId } : {},
49
53
  resource: res
50
54
  });
51
55
  }).catch((error) => {
52
56
  if (!cancelled) setLoadedResource({
57
+ host: targetHost,
53
58
  resourceUri: targetUri,
54
59
  ...targetServerId !== void 0 ? { serverId: targetServerId } : {},
55
60
  error: error instanceof Error ? error : new Error(String(error))
@@ -58,7 +63,11 @@ function InlineRenderer({ part, internalsRef, optionsRef }) {
58
63
  return () => {
59
64
  cancelled = true;
60
65
  };
61
- }, [resourceUri, serverId]);
66
+ }, [
67
+ host,
68
+ resourceUri,
69
+ serverId
70
+ ]);
62
71
  const bridgeHandlers = useMemo(() => ({
63
72
  openLink: defaultOpenLink,
64
73
  sendMessage: (params) => {
@@ -73,23 +82,23 @@ function InlineRenderer({ part, internalsRef, optionsRef }) {
73
82
  }] });
74
83
  return { ok: true };
75
84
  },
76
- callTool: (params_0) => internalsRef.current.host.callTool({
85
+ callTool: (params_0) => useHostStore.getState().host.callTool({
77
86
  ...params_0,
78
87
  ...serverIdRef.current ? { serverId: serverIdRef.current } : {}
79
88
  }),
80
- readResource: (params_1) => internalsRef.current.host.readResource({
89
+ readResource: (params_1) => useHostStore.getState().host.readResource({
81
90
  ...params_1,
82
91
  ...serverIdRef.current ? { serverId: serverIdRef.current } : {}
83
92
  }),
84
93
  listResources: (params_2) => {
85
- if (!serverIdRef.current) return internalsRef.current.host.listResources(params_2);
86
- return internalsRef.current.host.listResources({
94
+ if (!serverIdRef.current) return useHostStore.getState().host.listResources(params_2);
95
+ return useHostStore.getState().host.listResources({
87
96
  ...isRecord(params_2) ? params_2 : {},
88
97
  serverId: serverIdRef.current
89
98
  });
90
99
  }
91
- }), [aui, internalsRef]);
92
- const loadedResourceForApp = loadedResource?.resourceUri === appForRender?.resourceUri && loadedResource?.serverId === appForRender?.serverId ? loadedResource : void 0;
100
+ }), [aui, useHostStore]);
101
+ const loadedResourceForApp = loadedResource?.host === host && loadedResource?.resourceUri === appForRender?.resourceUri && loadedResource?.serverId === appForRender?.serverId ? loadedResource : void 0;
93
102
  const appResource = loadedResourceForApp?.resource;
94
103
  const error_0 = loadedResourceForApp?.error;
95
104
  const fallback = opts.fallback ?? null;
@@ -125,17 +134,19 @@ const useMcpAppRenderer = (options) => {
125
134
  const host = useResource(options.host);
126
135
  const optionsRef = useRef(options);
127
136
  optionsRef.current = options;
128
- const internalsRef = useRef({ host });
129
- internalsRef.current = { host };
137
+ const [useHostStore] = useState(() => create(() => ({ host })));
138
+ useEffect(() => {
139
+ useHostStore.setState({ host });
140
+ }, [host, useHostStore]);
130
141
  return { render: useMemo(() => {
131
142
  const Render = (props) => /* @__PURE__ */ jsx(InlineRenderer, {
132
143
  part: props,
133
- internalsRef,
144
+ useHostStore,
134
145
  optionsRef
135
146
  });
136
147
  Render.displayName = "McpAppRenderer";
137
148
  return Render;
138
- }, []) };
149
+ }, [useHostStore]) };
139
150
  };
140
151
  const McpAppRenderer = resource(useMcpAppRenderer);
141
152
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"McpAppRenderer.js","names":["useEffect","useMemo","useRef","useState","MutableRefObject","ReactNode","McpAppMetadata","ToolCallMessagePartComponent","ToolCallMessagePartProps","useAui","useResource","resource","ResourceElement","McpAppFrame","McpAppBridgeHandlers","McpAppHostContext","McpAppHostInfo","McpAppResource","McpAppSandboxConfig","McpAppsHost","getMcpAppFromToolPart","isRecord","McpAppRendererOptions","host","sandbox","maxHeight","hostInfo","hostContext","fallback","loadingFallback","errorFallback","error","Error","LoadedResourceState","resourceUri","serverId","getInput","part","status","type","argsText","args","undefined","defaultOpenLink","url","window","open","extractSendMessageText","params","obj","Record","InlineRenderer","internalsRef","optionsRef","opts","current","aui","app","cachedAppRef","appForRender","loadedResource","setLoadedResource","serverIdRef","cancelled","targetUri","targetServerId","loadResource","uri","then","res","catch","String","bridgeHandlers","openLink","sendMessage","text","ok","reason","thread","append","content","callTool","readResource","listResources","loadedResourceForApp","appResource","result","useMcpAppRenderer","options","render","Render","props","displayName","McpAppRenderer"],"sources":["../../src/mcp-apps/McpAppRenderer.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n type MutableRefObject,\n type ReactNode,\n} from \"react\";\nimport type { McpAppMetadata } from \"@assistant-ui/core\";\nimport type {\n ToolCallMessagePartComponent,\n ToolCallMessagePartProps,\n} from \"@assistant-ui/core/react\";\nimport { useAui } from \"@assistant-ui/store\";\n\nimport { useResource, resource, type ResourceElement } from \"@assistant-ui/tap\";\nimport { McpAppFrame } from \"./app-frame\";\nimport type {\n McpAppBridgeHandlers,\n McpAppHostContext,\n McpAppHostInfo,\n McpAppResource,\n McpAppSandboxConfig,\n McpAppsHost,\n} from \"./types\";\nimport { getMcpAppFromToolPart } from \"./utils\";\nimport { isRecord } from \"@assistant-ui/core/internal\";\n\nexport type McpAppRendererOptions = {\n /**\n * Provides the data-plane operations the widget can request\n * (`loadResource`, `callTool`, `readResource`, `listResources`). Use\n * `McpAppsRemoteHost({ url })` for the default HTTP-route convention.\n */\n host: ResourceElement<McpAppsHost>;\n /** Sandbox + container styling. Passes through to SafeContentFrame. */\n sandbox?: McpAppSandboxConfig;\n /**\n * Upper bound (in pixels) applied to the widget-driven auto-resize height.\n * Defaults to 800.\n */\n maxHeight?: number;\n /** Identifies the host to the widget in the `ui/initialize` response. */\n hostInfo?: McpAppHostInfo;\n /** Delivered to the widget on initialize and pushed via `notifications/host_context/changed` on change. */\n hostContext?: McpAppHostContext;\n /** Rendered when no MCP app is on the part, or while load is in flight / failed (unless overridden). */\n fallback?: ReactNode;\n /** Rendered while the resource is loading. Defaults to `fallback`. */\n loadingFallback?: ReactNode;\n /** Rendered when the resource load rejects. Defaults to `fallback`. */\n errorFallback?: ReactNode | ((error: Error) => ReactNode);\n};\n\ntype LoadedResourceState = {\n resourceUri: string;\n serverId?: string;\n resource?: McpAppResource;\n error?: Error;\n};\n\nfunction getInput(part: {\n status: { type: string };\n argsText: string;\n args: unknown;\n}): unknown {\n if (\n part.status.type === \"running\" &&\n (part.argsText === \"\" || part.argsText === \"{}\")\n ) {\n return undefined;\n }\n return part.args;\n}\n\nconst defaultOpenLink = ({ url }: { url: string }) => {\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n};\n\nfunction extractSendMessageText(params: unknown): string | undefined {\n if (typeof params === \"string\") return params;\n if (!params || typeof params !== \"object\") return undefined;\n const obj = params as Record<string, unknown>;\n if (typeof obj[\"prompt\"] === \"string\") return obj[\"prompt\"];\n if (typeof obj[\"text\"] === \"string\") return obj[\"text\"];\n if (typeof obj[\"message\"] === \"string\") return obj[\"message\"];\n return undefined;\n}\n\nfunction InlineRenderer({\n part,\n internalsRef,\n optionsRef,\n}: {\n part: ToolCallMessagePartProps;\n internalsRef: MutableRefObject<{ host: McpAppsHost }>;\n optionsRef: MutableRefObject<McpAppRendererOptions>;\n}) {\n const opts = optionsRef.current;\n const aui = useAui();\n const app = getMcpAppFromToolPart(part);\n const cachedAppRef = useRef<McpAppMetadata | undefined>(undefined);\n if (\n app != null &&\n (cachedAppRef.current?.resourceUri !== app.resourceUri ||\n cachedAppRef.current?.serverId !== app.serverId)\n ) {\n cachedAppRef.current = app;\n }\n const appForRender = app ?? cachedAppRef.current;\n\n const [loadedResource, setLoadedResource] = useState<LoadedResourceState>();\n\n const resourceUri = appForRender?.resourceUri;\n const serverId = appForRender?.serverId;\n const serverIdRef = useRef<string | undefined>(undefined);\n serverIdRef.current = serverId;\n useEffect(() => {\n if (appForRender == null || resourceUri == null) return;\n let cancelled = false;\n const targetUri = resourceUri;\n const targetServerId = serverId;\n\n internalsRef.current.host\n .loadResource({\n uri: targetUri,\n ...(targetServerId ? { serverId: targetServerId } : {}),\n })\n .then((res) => {\n if (!cancelled)\n setLoadedResource({\n resourceUri: targetUri,\n ...(targetServerId !== undefined\n ? { serverId: targetServerId }\n : {}),\n resource: res,\n });\n })\n .catch((error: unknown) => {\n if (!cancelled) {\n setLoadedResource({\n resourceUri: targetUri,\n ...(targetServerId !== undefined\n ? { serverId: targetServerId }\n : {}),\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n });\n\n return () => {\n cancelled = true;\n };\n // oxlint-disable-next-line react/exhaustive-deps -- re-fetch only when URI or server identity changes; appForRender identity is unstable and internalsRef is a stable ref\n }, [resourceUri, serverId]);\n\n const bridgeHandlers = useMemo<McpAppBridgeHandlers>(\n () => ({\n openLink: defaultOpenLink,\n sendMessage: (params) => {\n const text = extractSendMessageText(params);\n if (!text) return { ok: false, reason: \"unrecognised params shape\" };\n aui.thread.append({ content: [{ type: \"text\", text }] });\n return { ok: true };\n },\n callTool: (params) =>\n internalsRef.current.host.callTool({\n ...params,\n ...(serverIdRef.current ? { serverId: serverIdRef.current } : {}),\n }),\n readResource: (params) =>\n internalsRef.current.host.readResource({\n ...params,\n ...(serverIdRef.current ? { serverId: serverIdRef.current } : {}),\n }),\n listResources: (params) => {\n if (!serverIdRef.current) {\n return internalsRef.current.host.listResources(params);\n }\n return internalsRef.current.host.listResources({\n ...(isRecord(params) ? params : {}),\n serverId: serverIdRef.current,\n });\n },\n }),\n [aui, internalsRef],\n );\n\n const loadedResourceForApp =\n loadedResource?.resourceUri === appForRender?.resourceUri &&\n loadedResource?.serverId === appForRender?.serverId\n ? loadedResource\n : undefined;\n const appResource = loadedResourceForApp?.resource;\n const error = loadedResourceForApp?.error;\n\n const fallback = opts.fallback ?? null;\n if (appForRender == null) {\n return <>{fallback}</>;\n }\n if (error != null) {\n const errorFallback = opts.errorFallback;\n if (errorFallback === undefined) return <>{fallback}</>;\n if (typeof errorFallback === \"function\") return <>{errorFallback(error)}</>;\n return <>{errorFallback}</>;\n }\n if (appResource == null) {\n return <>{opts.loadingFallback ?? fallback}</>;\n }\n\n return (\n <McpAppFrame\n app={appForRender}\n resource={appResource}\n input={getInput(part)}\n output={part.result}\n sandbox={opts.sandbox}\n handlers={bridgeHandlers}\n hostInfo={opts.hostInfo}\n hostContext={opts.hostContext}\n maxHeight={opts.maxHeight}\n />\n );\n}\n\n/**\n * Creates a tool-call renderer for MCP Apps embedded in assistant messages.\n *\n * Compose this into the `Tools` resource through its `mcpApp` option. When a\n * tool-call part carries `mcp.app` metadata for a `ui://` resource, the\n * renderer loads that resource from the configured host and displays it in a\n * sandboxed frame.\n */\nconst useMcpAppRenderer = (\n options: McpAppRendererOptions,\n): { readonly render: ToolCallMessagePartComponent } => {\n const host = useResource(options.host);\n\n const optionsRef = useRef<McpAppRendererOptions>(options);\n optionsRef.current = options;\n\n const internalsRef = useRef<{ host: McpAppsHost }>({ host });\n internalsRef.current = { host };\n\n const render = useMemo((): ToolCallMessagePartComponent => {\n const Render: ToolCallMessagePartComponent = (props) => (\n <InlineRenderer\n part={props}\n internalsRef={internalsRef}\n optionsRef={optionsRef}\n />\n );\n Render.displayName = \"McpAppRenderer\";\n return Render;\n }, []);\n\n return { render };\n};\n\nexport const McpAppRenderer = resource(useMcpAppRenderer);\n"],"mappings":"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"}
1
+ {"version":3,"file":"McpAppRenderer.js","names":["useEffect","useMemo","useRef","useState","MutableRefObject","ReactNode","McpAppMetadata","ToolCallMessagePartComponent","ToolCallMessagePartProps","useAui","create","StoreApi","UseBoundStore","useResource","resource","ResourceElement","McpAppFrame","McpAppBridgeHandlers","McpAppHostContext","McpAppHostInfo","McpAppResource","McpAppSandboxConfig","McpAppsHost","getMcpAppFromToolPart","isRecord","McpAppRendererOptions","host","sandbox","maxHeight","hostInfo","hostContext","fallback","loadingFallback","errorFallback","error","Error","LoadedResourceState","resourceUri","serverId","UseHostStore","getInput","part","status","type","argsText","args","undefined","defaultOpenLink","url","window","open","extractSendMessageText","params","obj","Record","InlineRenderer","useHostStore","optionsRef","opts","current","aui","app","cachedAppRef","appForRender","loadedResource","setLoadedResource","state","serverIdRef","cancelled","targetHost","targetUri","targetServerId","loadResource","uri","then","res","catch","String","bridgeHandlers","openLink","sendMessage","text","ok","reason","thread","append","content","callTool","getState","readResource","listResources","loadedResourceForApp","appResource","result","useMcpAppRenderer","options","render","setState","Render","props","displayName","McpAppRenderer"],"sources":["../../src/mcp-apps/McpAppRenderer.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n type MutableRefObject,\n type ReactNode,\n} from \"react\";\nimport type { McpAppMetadata } from \"@assistant-ui/core\";\nimport type {\n ToolCallMessagePartComponent,\n ToolCallMessagePartProps,\n} from \"@assistant-ui/core/react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { create, type StoreApi, type UseBoundStore } from \"zustand\";\n\nimport { useResource, resource, type ResourceElement } from \"@assistant-ui/tap\";\nimport { McpAppFrame } from \"./app-frame\";\nimport type {\n McpAppBridgeHandlers,\n McpAppHostContext,\n McpAppHostInfo,\n McpAppResource,\n McpAppSandboxConfig,\n McpAppsHost,\n} from \"./types\";\nimport { getMcpAppFromToolPart } from \"./utils\";\nimport { isRecord } from \"@assistant-ui/core/internal\";\n\nexport type McpAppRendererOptions = {\n /**\n * Provides the data-plane operations the widget can request\n * (`loadResource`, `callTool`, `readResource`, `listResources`). Use\n * `McpAppsRemoteHost({ url })` for the default HTTP-route convention.\n */\n host: ResourceElement<McpAppsHost>;\n /** Sandbox + container styling. Passes through to SafeContentFrame. */\n sandbox?: McpAppSandboxConfig;\n /**\n * Upper bound (in pixels) applied to the widget-driven auto-resize height.\n * Defaults to 800.\n */\n maxHeight?: number;\n /** Identifies the host to the widget in the `ui/initialize` response. */\n hostInfo?: McpAppHostInfo;\n /** Delivered to the widget on initialize and pushed via `notifications/host_context/changed` on change. */\n hostContext?: McpAppHostContext;\n /** Rendered when no MCP app is on the part, or while load is in flight / failed (unless overridden). */\n fallback?: ReactNode;\n /** Rendered while the resource is loading. Defaults to `fallback`. */\n loadingFallback?: ReactNode;\n /** Rendered when the resource load rejects. Defaults to `fallback`. */\n errorFallback?: ReactNode | ((error: Error) => ReactNode);\n};\n\ntype LoadedResourceState = {\n host: McpAppsHost;\n resourceUri: string;\n serverId?: string;\n resource?: McpAppResource;\n error?: Error;\n};\n\ntype UseHostStore = UseBoundStore<StoreApi<{ host: McpAppsHost }>>;\n\nfunction getInput(part: {\n status: { type: string };\n argsText: string;\n args: unknown;\n}): unknown {\n if (\n part.status.type === \"running\" &&\n (part.argsText === \"\" || part.argsText === \"{}\")\n ) {\n return undefined;\n }\n return part.args;\n}\n\nconst defaultOpenLink = ({ url }: { url: string }) => {\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n};\n\nfunction extractSendMessageText(params: unknown): string | undefined {\n if (typeof params === \"string\") return params;\n if (!params || typeof params !== \"object\") return undefined;\n const obj = params as Record<string, unknown>;\n if (typeof obj[\"prompt\"] === \"string\") return obj[\"prompt\"];\n if (typeof obj[\"text\"] === \"string\") return obj[\"text\"];\n if (typeof obj[\"message\"] === \"string\") return obj[\"message\"];\n return undefined;\n}\n\nfunction InlineRenderer({\n part,\n useHostStore,\n optionsRef,\n}: {\n part: ToolCallMessagePartProps;\n useHostStore: UseHostStore;\n optionsRef: MutableRefObject<McpAppRendererOptions>;\n}) {\n const opts = optionsRef.current;\n const aui = useAui();\n const app = getMcpAppFromToolPart(part);\n const cachedAppRef = useRef<McpAppMetadata | undefined>(undefined);\n if (\n app != null &&\n (cachedAppRef.current?.resourceUri !== app.resourceUri ||\n cachedAppRef.current?.serverId !== app.serverId)\n ) {\n cachedAppRef.current = app;\n }\n const appForRender = app ?? cachedAppRef.current;\n\n const [loadedResource, setLoadedResource] = useState<LoadedResourceState>();\n\n const host = useHostStore((state) => state.host);\n const resourceUri = appForRender?.resourceUri;\n const serverId = appForRender?.serverId;\n const serverIdRef = useRef<string | undefined>(undefined);\n serverIdRef.current = serverId;\n useEffect(() => {\n if (resourceUri == null) return;\n let cancelled = false;\n const targetHost = host;\n const targetUri = resourceUri;\n const targetServerId = serverId;\n\n targetHost\n .loadResource({\n uri: targetUri,\n ...(targetServerId ? { serverId: targetServerId } : {}),\n })\n .then((res) => {\n if (!cancelled)\n setLoadedResource({\n host: targetHost,\n resourceUri: targetUri,\n ...(targetServerId !== undefined\n ? { serverId: targetServerId }\n : {}),\n resource: res,\n });\n })\n .catch((error: unknown) => {\n if (!cancelled) {\n setLoadedResource({\n host: targetHost,\n resourceUri: targetUri,\n ...(targetServerId !== undefined\n ? { serverId: targetServerId }\n : {}),\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [host, resourceUri, serverId]);\n\n const bridgeHandlers = useMemo<McpAppBridgeHandlers>(\n () => ({\n openLink: defaultOpenLink,\n sendMessage: (params) => {\n const text = extractSendMessageText(params);\n if (!text) return { ok: false, reason: \"unrecognised params shape\" };\n aui.thread.append({ content: [{ type: \"text\", text }] });\n return { ok: true };\n },\n callTool: (params) =>\n useHostStore.getState().host.callTool({\n ...params,\n ...(serverIdRef.current ? { serverId: serverIdRef.current } : {}),\n }),\n readResource: (params) =>\n useHostStore.getState().host.readResource({\n ...params,\n ...(serverIdRef.current ? { serverId: serverIdRef.current } : {}),\n }),\n listResources: (params) => {\n if (!serverIdRef.current) {\n return useHostStore.getState().host.listResources(params);\n }\n return useHostStore.getState().host.listResources({\n ...(isRecord(params) ? params : {}),\n serverId: serverIdRef.current,\n });\n },\n }),\n [aui, useHostStore],\n );\n\n const loadedResourceForApp =\n loadedResource?.host === host &&\n loadedResource?.resourceUri === appForRender?.resourceUri &&\n loadedResource?.serverId === appForRender?.serverId\n ? loadedResource\n : undefined;\n const appResource = loadedResourceForApp?.resource;\n const error = loadedResourceForApp?.error;\n\n const fallback = opts.fallback ?? null;\n if (appForRender == null) {\n return <>{fallback}</>;\n }\n if (error != null) {\n const errorFallback = opts.errorFallback;\n if (errorFallback === undefined) return <>{fallback}</>;\n if (typeof errorFallback === \"function\") return <>{errorFallback(error)}</>;\n return <>{errorFallback}</>;\n }\n if (appResource == null) {\n return <>{opts.loadingFallback ?? fallback}</>;\n }\n\n return (\n <McpAppFrame\n app={appForRender}\n resource={appResource}\n input={getInput(part)}\n output={part.result}\n sandbox={opts.sandbox}\n handlers={bridgeHandlers}\n hostInfo={opts.hostInfo}\n hostContext={opts.hostContext}\n maxHeight={opts.maxHeight}\n />\n );\n}\n\n/**\n * Creates a tool-call renderer for MCP Apps embedded in assistant messages.\n *\n * Compose this into the `Tools` resource through its `mcpApp` option. When a\n * tool-call part carries `mcp.app` metadata for a `ui://` resource, the\n * renderer loads that resource from the configured host and displays it in a\n * sandboxed frame.\n */\nconst useMcpAppRenderer = (\n options: McpAppRendererOptions,\n): { readonly render: ToolCallMessagePartComponent } => {\n const host = useResource(options.host);\n\n const optionsRef = useRef<McpAppRendererOptions>(options);\n optionsRef.current = options;\n\n const [useHostStore] = useState(() =>\n create<{ host: McpAppsHost }>(() => ({ host })),\n );\n useEffect(() => {\n useHostStore.setState({ host });\n }, [host, useHostStore]);\n\n const render = useMemo((): ToolCallMessagePartComponent => {\n const Render: ToolCallMessagePartComponent = (props) => (\n <InlineRenderer\n part={props}\n useHostStore={useHostStore}\n optionsRef={optionsRef}\n />\n );\n Render.displayName = \"McpAppRenderer\";\n return Render;\n }, [useHostStore]);\n\n return { render };\n};\n\nexport const McpAppRenderer = resource(useMcpAppRenderer);\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"McpAppsRemoteHost.d.ts","names":[],"sources":["../../src/mcp-apps/McpAppsRemoteHost.ts"],"mappings":";;cAoGa,+CAAiB,SAAA,cAAA,SAAA"}
1
+ {"version":3,"file":"McpAppsRemoteHost.d.ts","names":[],"sources":["../../src/mcp-apps/McpAppsRemoteHost.ts"],"mappings":";;cA6Ga,+CAAiB,SAAA,cAAA,SAAA"}
@@ -59,12 +59,23 @@ async function postToHost(options, method, params) {
59
59
  const useMcpAppsRemoteHost = (options) => {
60
60
  const optionsRef = useRef(options);
61
61
  optionsRef.current = options;
62
- return useMemo(() => ({
63
- loadResource: (params) => postToHost(optionsRef.current, "mcp-apps/read-resource", params),
64
- callTool: (params_0) => postToHost(optionsRef.current, "tools/call", params_0),
65
- readResource: (params_1) => postToHost(optionsRef.current, "resources/read", params_1),
66
- listResources: (params_2) => postToHost(optionsRef.current, "resources/list", params_2)
67
- }), []);
62
+ const url = options.url;
63
+ return useMemo(() => {
64
+ const getCurrentOptions = () => {
65
+ const current = optionsRef.current;
66
+ return {
67
+ url,
68
+ ...current.fetch !== void 0 ? { fetch: current.fetch } : {},
69
+ ...current.headers !== void 0 ? { headers: current.headers } : {}
70
+ };
71
+ };
72
+ return {
73
+ loadResource: (params) => postToHost(getCurrentOptions(), "mcp-apps/read-resource", params),
74
+ callTool: (params_0) => postToHost(getCurrentOptions(), "tools/call", params_0),
75
+ readResource: (params_1) => postToHost(getCurrentOptions(), "resources/read", params_1),
76
+ listResources: (params_2) => postToHost(getCurrentOptions(), "resources/list", params_2)
77
+ };
78
+ }, [url]);
68
79
  };
69
80
  const McpAppsRemoteHost = resource(useMcpAppsRemoteHost);
70
81
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"McpAppsRemoteHost.js","names":["useMemo","useRef","resource","McpAppResource","McpAppsHost","McpAppsRemoteHostOptions","truncateBody","body","length","slice","extractErrorBody","trimmed","trim","undefined","parsed","JSON","parse","record","Record","message","error","readErrorBody","res","Response","Promise","text","postToHost","options","method","params","doFetch","fetch","extraHeaders","headers","url","stringify","ok","status","statusText","Error","json","useMcpAppsRemoteHost","optionsRef","current","loadResource","callTool","readResource","listResources","McpAppsRemoteHost"],"sources":["../../src/mcp-apps/McpAppsRemoteHost.ts"],"sourcesContent":["import { useMemo, useRef } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport type {\n McpAppResource,\n McpAppsHost,\n McpAppsRemoteHostOptions,\n} from \"./types\";\n\nconst truncateBody = (body: string) =>\n body.length > 500 ? `${body.slice(0, 500)}...` : body;\n\nconst extractErrorBody = (body: string): string | undefined => {\n const trimmed = body.trim();\n if (!trimmed) return undefined;\n\n try {\n const parsed = JSON.parse(trimmed) as unknown;\n if (parsed && typeof parsed === \"object\") {\n const record = parsed as Record<string, unknown>;\n if (typeof record.message === \"string\") return record.message;\n if (typeof record.error === \"string\") return record.error;\n if (record.error && typeof record.error === \"object\") {\n const error = record.error as Record<string, unknown>;\n if (typeof error.message === \"string\") return error.message;\n }\n }\n } catch {\n return truncateBody(trimmed);\n }\n\n return truncateBody(trimmed);\n};\n\nconst readErrorBody = async (res: Response): Promise<string | undefined> => {\n try {\n return extractErrorBody(await res.text());\n } catch {\n return undefined;\n }\n};\n\nasync function postToHost(\n options: McpAppsRemoteHostOptions,\n method: string,\n params: unknown,\n): Promise<unknown> {\n const doFetch = options.fetch ?? fetch;\n const extraHeaders =\n typeof options.headers === \"function\"\n ? await options.headers()\n : (options.headers ?? {});\n const res = await doFetch(options.url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", ...extraHeaders },\n body: JSON.stringify({ method, params }),\n });\n if (!res.ok) {\n const status = res.statusText\n ? `${res.status} ${res.statusText}`\n : `${res.status}`;\n const body = await readErrorBody(res);\n throw new Error(\n `MCP App host request \"${method}\" to \"${options.url}\" failed with ${status}${body ? `: ${body}` : \"\"}`,\n );\n }\n return res.json();\n}\n\n/**\n * Creates the default HTTP host for MCP App widgets.\n *\n * The host POSTs widget requests to the configured route as `{ method,\n * params }`, using the method names expected by the assistant-ui MCP Apps\n * guide.\n */\nconst useMcpAppsRemoteHost = (\n options: McpAppsRemoteHostOptions,\n): McpAppsHost => {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n return useMemo(\n (): McpAppsHost => ({\n loadResource: (params) =>\n postToHost(\n optionsRef.current,\n \"mcp-apps/read-resource\",\n params,\n ) as Promise<McpAppResource>,\n callTool: (params) =>\n postToHost(optionsRef.current, \"tools/call\", params),\n readResource: (params) =>\n postToHost(optionsRef.current, \"resources/read\", params),\n listResources: (params) =>\n postToHost(optionsRef.current, \"resources/list\", params),\n }),\n [],\n );\n};\n\nexport const McpAppsRemoteHost = resource(useMcpAppsRemoteHost);\n"],"mappings":";;;AAQA,MAAMM,gBAAgBC,SACpBA,KAAKC,SAAS,MAAM,GAAGD,KAAKE,MAAM,GAAG,GAAG,EAAC,OAAQF;AAEnD,MAAMG,oBAAoBH,SAAqC;CAC7D,MAAMI,UAAUJ,KAAKK,KAAK;CAC1B,IAAI,CAACD,SAAS,OAAOE,KAAAA;CAErB,IAAI;EACF,MAAMC,SAASC,KAAKC,MAAML,OAAO;EACjC,IAAIG,UAAU,OAAOA,WAAW,UAAU;GACxC,MAAMG,SAASH;GACf,IAAI,OAAOG,OAAOE,YAAY,UAAU,OAAOF,OAAOE;GACtD,IAAI,OAAOF,OAAOG,UAAU,UAAU,OAAOH,OAAOG;GACpD,IAAIH,OAAOG,SAAS,OAAOH,OAAOG,UAAU,UAAU;IACpD,MAAMA,QAAQH,OAAOG;IACrB,IAAI,OAAOA,MAAMD,YAAY,UAAU,OAAOC,MAAMD;GACtD;EACF;CACF,QAAQ;EACN,OAAOb,aAAaK,OAAO;CAC7B;CAEA,OAAOL,aAAaK,OAAO;AAC7B;AAEA,MAAMU,gBAAgB,OAAOC,QAA+C;CAC1E,IAAI;EACF,OAAOZ,iBAAiB,MAAMY,IAAIG,KAAK,CAAC;CAC1C,QAAQ;EACN;CACF;AACF;AAEA,eAAeC,WACbC,SACAC,QACAC,QACkB;CAClB,MAAMC,UAAUH,QAAQI,SAASA;CACjC,MAAMC,eACJ,OAAOL,QAAQM,YAAY,aACvB,MAAMN,QAAQM,QAAQ,IACrBN,QAAQM,WAAW,CAAC;CAC3B,MAAMX,MAAM,MAAMQ,QAAQH,QAAQO,KAAK;EACrCN,QAAQ;EACRK,SAAS;GAAE,gBAAgB;GAAoB,GAAGD;EAAa;EAC/DzB,MAAMQ,KAAKoB,UAAU;GAAEP;GAAQC;EAAO,CAAC;CACzC,CAAC;CACD,IAAI,CAACP,IAAIc,IAAI;EACX,MAAMC,SAASf,IAAIgB,aACf,GAAGhB,IAAIe,OAAM,GAAIf,IAAIgB,eACrB,GAAGhB,IAAIe;EACX,MAAM9B,OAAO,MAAMc,cAAcC,GAAG;EACpC,MAAM,IAAIiB,MACR,yBAAyBX,OAAM,QAASD,QAAQO,IAAG,gBAAiBG,SAAS9B,OAAO,KAAKA,SAAS,IACpG;CACF;CACA,OAAOe,IAAIkB,KAAK;AAClB;;;;;;;;AASA,MAAMC,wBACJd,YACgB;CAChB,MAAMe,aAAazC,OAAO0B,OAAO;CACjCe,WAAWC,UAAUhB;CAErB,OAAO3B,eACe;EAClB4C,eAAef,WACbH,WACEgB,WAAWC,SACX,0BACAd,MACF;EACFgB,WAAWhB,aACTH,WAAWgB,WAAWC,SAAS,cAAcd,QAAM;EACrDiB,eAAejB,aACbH,WAAWgB,WAAWC,SAAS,kBAAkBd,QAAM;EACzDkB,gBAAgBlB,aACdH,WAAWgB,WAAWC,SAAS,kBAAkBd,QAAM;CAC3D,IACA,CAAA,CACF;AACF;AAEA,MAAamB,oBAAoB9C,SAASuC,oBAAoB"}
1
+ {"version":3,"file":"McpAppsRemoteHost.js","names":["useMemo","useRef","resource","McpAppResource","McpAppsHost","McpAppsRemoteHostOptions","truncateBody","body","length","slice","extractErrorBody","trimmed","trim","undefined","parsed","JSON","parse","record","Record","message","error","readErrorBody","res","Response","Promise","text","postToHost","options","method","params","doFetch","fetch","extraHeaders","headers","url","stringify","ok","status","statusText","Error","json","useMcpAppsRemoteHost","optionsRef","current","getCurrentOptions","loadResource","callTool","readResource","listResources","McpAppsRemoteHost"],"sources":["../../src/mcp-apps/McpAppsRemoteHost.ts"],"sourcesContent":["import { useMemo, useRef } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport type {\n McpAppResource,\n McpAppsHost,\n McpAppsRemoteHostOptions,\n} from \"./types\";\n\nconst truncateBody = (body: string) =>\n body.length > 500 ? `${body.slice(0, 500)}...` : body;\n\nconst extractErrorBody = (body: string): string | undefined => {\n const trimmed = body.trim();\n if (!trimmed) return undefined;\n\n try {\n const parsed = JSON.parse(trimmed) as unknown;\n if (parsed && typeof parsed === \"object\") {\n const record = parsed as Record<string, unknown>;\n if (typeof record.message === \"string\") return record.message;\n if (typeof record.error === \"string\") return record.error;\n if (record.error && typeof record.error === \"object\") {\n const error = record.error as Record<string, unknown>;\n if (typeof error.message === \"string\") return error.message;\n }\n }\n } catch {\n return truncateBody(trimmed);\n }\n\n return truncateBody(trimmed);\n};\n\nconst readErrorBody = async (res: Response): Promise<string | undefined> => {\n try {\n return extractErrorBody(await res.text());\n } catch {\n return undefined;\n }\n};\n\nasync function postToHost(\n options: McpAppsRemoteHostOptions,\n method: string,\n params: unknown,\n): Promise<unknown> {\n const doFetch = options.fetch ?? fetch;\n const extraHeaders =\n typeof options.headers === \"function\"\n ? await options.headers()\n : (options.headers ?? {});\n const res = await doFetch(options.url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", ...extraHeaders },\n body: JSON.stringify({ method, params }),\n });\n if (!res.ok) {\n const status = res.statusText\n ? `${res.status} ${res.statusText}`\n : `${res.status}`;\n const body = await readErrorBody(res);\n throw new Error(\n `MCP App host request \"${method}\" to \"${options.url}\" failed with ${status}${body ? `: ${body}` : \"\"}`,\n );\n }\n return res.json();\n}\n\n/**\n * Creates the default HTTP host for MCP App widgets.\n *\n * The host POSTs widget requests to the configured route as `{ method,\n * params }`, using the method names expected by the assistant-ui MCP Apps\n * guide.\n */\nconst useMcpAppsRemoteHost = (\n options: McpAppsRemoteHostOptions,\n): McpAppsHost => {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const url = options.url;\n\n return useMemo((): McpAppsHost => {\n const getCurrentOptions = (): McpAppsRemoteHostOptions => {\n const current = optionsRef.current;\n return {\n url,\n ...(current.fetch !== undefined ? { fetch: current.fetch } : {}),\n ...(current.headers !== undefined ? { headers: current.headers } : {}),\n };\n };\n return {\n loadResource: (params) =>\n postToHost(\n getCurrentOptions(),\n \"mcp-apps/read-resource\",\n params,\n ) as Promise<McpAppResource>,\n callTool: (params) =>\n postToHost(getCurrentOptions(), \"tools/call\", params),\n readResource: (params) =>\n postToHost(getCurrentOptions(), \"resources/read\", params),\n listResources: (params) =>\n postToHost(getCurrentOptions(), \"resources/list\", params),\n };\n }, [url]);\n};\n\nexport const McpAppsRemoteHost = resource(useMcpAppsRemoteHost);\n"],"mappings":";;;AAQA,MAAMM,gBAAgBC,SACpBA,KAAKC,SAAS,MAAM,GAAGD,KAAKE,MAAM,GAAG,GAAG,EAAC,OAAQF;AAEnD,MAAMG,oBAAoBH,SAAqC;CAC7D,MAAMI,UAAUJ,KAAKK,KAAK;CAC1B,IAAI,CAACD,SAAS,OAAOE,KAAAA;CAErB,IAAI;EACF,MAAMC,SAASC,KAAKC,MAAML,OAAO;EACjC,IAAIG,UAAU,OAAOA,WAAW,UAAU;GACxC,MAAMG,SAASH;GACf,IAAI,OAAOG,OAAOE,YAAY,UAAU,OAAOF,OAAOE;GACtD,IAAI,OAAOF,OAAOG,UAAU,UAAU,OAAOH,OAAOG;GACpD,IAAIH,OAAOG,SAAS,OAAOH,OAAOG,UAAU,UAAU;IACpD,MAAMA,QAAQH,OAAOG;IACrB,IAAI,OAAOA,MAAMD,YAAY,UAAU,OAAOC,MAAMD;GACtD;EACF;CACF,QAAQ;EACN,OAAOb,aAAaK,OAAO;CAC7B;CAEA,OAAOL,aAAaK,OAAO;AAC7B;AAEA,MAAMU,gBAAgB,OAAOC,QAA+C;CAC1E,IAAI;EACF,OAAOZ,iBAAiB,MAAMY,IAAIG,KAAK,CAAC;CAC1C,QAAQ;EACN;CACF;AACF;AAEA,eAAeC,WACbC,SACAC,QACAC,QACkB;CAClB,MAAMC,UAAUH,QAAQI,SAASA;CACjC,MAAMC,eACJ,OAAOL,QAAQM,YAAY,aACvB,MAAMN,QAAQM,QAAQ,IACrBN,QAAQM,WAAW,CAAC;CAC3B,MAAMX,MAAM,MAAMQ,QAAQH,QAAQO,KAAK;EACrCN,QAAQ;EACRK,SAAS;GAAE,gBAAgB;GAAoB,GAAGD;EAAa;EAC/DzB,MAAMQ,KAAKoB,UAAU;GAAEP;GAAQC;EAAO,CAAC;CACzC,CAAC;CACD,IAAI,CAACP,IAAIc,IAAI;EACX,MAAMC,SAASf,IAAIgB,aACf,GAAGhB,IAAIe,OAAM,GAAIf,IAAIgB,eACrB,GAAGhB,IAAIe;EACX,MAAM9B,OAAO,MAAMc,cAAcC,GAAG;EACpC,MAAM,IAAIiB,MACR,yBAAyBX,OAAM,QAASD,QAAQO,IAAG,gBAAiBG,SAAS9B,OAAO,KAAKA,SAAS,IACpG;CACF;CACA,OAAOe,IAAIkB,KAAK;AAClB;;;;;;;;AASA,MAAMC,wBACJd,YACgB;CAChB,MAAMe,aAAazC,OAAO0B,OAAO;CACjCe,WAAWC,UAAUhB;CAErB,MAAMO,MAAMP,QAAQO;CAEpB,OAAOlC,cAA2B;EAChC,MAAM4C,0BAAoD;GACxD,MAAMD,UAAUD,WAAWC;GAC3B,OAAO;IACLT;IACA,GAAIS,QAAQZ,UAAUlB,KAAAA,IAAY,EAAEkB,OAAOY,QAAQZ,MAAM,IAAI,CAAC;IAC9D,GAAIY,QAAQV,YAAYpB,KAAAA,IAAY,EAAEoB,SAASU,QAAQV,QAAQ,IAAI,CAAC;GACtE;EACF;EACA,OAAO;GACLY,eAAehB,WACbH,WACEkB,kBAAkB,GAClB,0BACAf,MACF;GACFiB,WAAWjB,aACTH,WAAWkB,kBAAkB,GAAG,cAAcf,QAAM;GACtDkB,eAAelB,aACbH,WAAWkB,kBAAkB,GAAG,kBAAkBf,QAAM;GAC1DmB,gBAAgBnB,aACdH,WAAWkB,kBAAkB,GAAG,kBAAkBf,QAAM;EAC5D;CACF,GAAG,CAACK,GAAG,CAAC;AACV;AAEA,MAAae,oBAAoB/C,SAASuC,oBAAoB"}