skybridge 0.0.0-dev.8e84184 → 0.0.0-dev.8e99eaf

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 (351) hide show
  1. package/README.md +17 -14
  2. package/dist/cli/build-helpers.d.ts +3 -2
  3. package/dist/cli/build-helpers.js +24 -10
  4. package/dist/cli/build-helpers.js.map +1 -1
  5. package/dist/cli/build-helpers.test.js +48 -5
  6. package/dist/cli/build-helpers.test.js.map +1 -1
  7. package/dist/cli/build-steps.js +10 -5
  8. package/dist/cli/build-steps.js.map +1 -1
  9. package/dist/cli/build-steps.test.js +3 -3
  10. package/dist/cli/build-steps.test.js.map +1 -1
  11. package/dist/cli/detect-port.js +0 -1
  12. package/dist/cli/detect-port.js.map +1 -1
  13. package/dist/cli/header.d.ts +1 -1
  14. package/dist/cli/resolve-skybridge-config.d.ts +5 -0
  15. package/dist/cli/{resolve-views-dir.js → resolve-skybridge-config.js} +4 -3
  16. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  17. package/dist/cli/run-plain.d.ts +18 -0
  18. package/dist/cli/run-plain.js +90 -0
  19. package/dist/cli/run-plain.js.map +1 -0
  20. package/dist/cli/telemetry.js +2 -0
  21. package/dist/cli/telemetry.js.map +1 -1
  22. package/dist/cli/use-nodemon.d.ts +25 -1
  23. package/dist/cli/use-nodemon.js +96 -63
  24. package/dist/cli/use-nodemon.js.map +1 -1
  25. package/dist/cli/use-typescript-check.d.ts +8 -2
  26. package/dist/cli/use-typescript-check.js +70 -67
  27. package/dist/cli/use-typescript-check.js.map +1 -1
  28. package/dist/commands/dev.d.ts +1 -0
  29. package/dist/commands/dev.js +38 -6
  30. package/dist/commands/dev.js.map +1 -1
  31. package/dist/commands/start.js +2 -2
  32. package/dist/commands/start.js.map +1 -1
  33. package/dist/context-warnings.d.ts +5 -0
  34. package/dist/context-warnings.js +31 -0
  35. package/dist/context-warnings.js.map +1 -0
  36. package/dist/context-warnings.test.js +28 -0
  37. package/dist/context-warnings.test.js.map +1 -0
  38. package/dist/server/app.d.ts +194 -0
  39. package/dist/server/app.js +266 -0
  40. package/dist/server/app.js.map +1 -0
  41. package/dist/server/app.test.js +97 -0
  42. package/dist/server/app.test.js.map +1 -0
  43. package/dist/server/auth/discovery.d.ts +2 -1
  44. package/dist/server/auth/discovery.js +2 -2
  45. package/dist/server/auth/discovery.js.map +1 -1
  46. package/dist/server/auth/index.d.ts +35 -5
  47. package/dist/server/auth/index.js.map +1 -1
  48. package/dist/server/auth/providers/auth0.d.ts +25 -3
  49. package/dist/server/auth/providers/auth0.js +13 -8
  50. package/dist/server/auth/providers/auth0.js.map +1 -1
  51. package/dist/server/auth/providers/auth0.test.js +5 -3
  52. package/dist/server/auth/providers/auth0.test.js.map +1 -1
  53. package/dist/server/auth/providers/authplane.d.ts +49 -0
  54. package/dist/server/auth/providers/authplane.js +57 -0
  55. package/dist/server/auth/providers/authplane.js.map +1 -0
  56. package/dist/server/auth/providers/authplane.test.js +143 -0
  57. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  58. package/dist/server/auth/providers/clerk.d.ts +40 -3
  59. package/dist/server/auth/providers/clerk.js +4 -1
  60. package/dist/server/auth/providers/clerk.js.map +1 -1
  61. package/dist/server/auth/providers/clerk.test.js +5 -3
  62. package/dist/server/auth/providers/clerk.test.js.map +1 -1
  63. package/dist/server/auth/providers/custom.d.ts +24 -6
  64. package/dist/server/auth/providers/custom.js +33 -11
  65. package/dist/server/auth/providers/custom.js.map +1 -1
  66. package/dist/server/auth/providers/custom.test.js +71 -17
  67. package/dist/server/auth/providers/custom.test.js.map +1 -1
  68. package/dist/server/auth/providers/descope.d.ts +32 -3
  69. package/dist/server/auth/providers/descope.js +13 -2
  70. package/dist/server/auth/providers/descope.js.map +1 -1
  71. package/dist/server/auth/providers/descope.test.js +42 -17
  72. package/dist/server/auth/providers/descope.test.js.map +1 -1
  73. package/dist/server/auth/providers/stytch.d.ts +16 -3
  74. package/dist/server/auth/providers/stytch.js +4 -1
  75. package/dist/server/auth/providers/stytch.js.map +1 -1
  76. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  77. package/dist/server/auth/providers/verify-spy.js +21 -0
  78. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  79. package/dist/server/auth/providers/workos.d.ts +28 -5
  80. package/dist/server/auth/providers/workos.js +6 -2
  81. package/dist/server/auth/providers/workos.js.map +1 -1
  82. package/dist/server/auth/security-schemes.d.ts +23 -0
  83. package/dist/server/auth/security-schemes.js +64 -0
  84. package/dist/server/auth/security-schemes.js.map +1 -0
  85. package/dist/server/auth/security-schemes.test.js +99 -0
  86. package/dist/server/auth/security-schemes.test.js.map +1 -0
  87. package/dist/server/auth/setup.d.ts +3 -1
  88. package/dist/server/auth/setup.js +66 -26
  89. package/dist/server/auth/setup.js.map +1 -1
  90. package/dist/server/auth/setup.test.js +349 -20
  91. package/dist/server/auth/setup.test.js.map +1 -1
  92. package/dist/server/auth/verify.d.ts +42 -6
  93. package/dist/server/auth/verify.js +27 -3
  94. package/dist/server/auth/verify.js.map +1 -1
  95. package/dist/server/auth/verify.test.js +65 -0
  96. package/dist/server/auth/verify.test.js.map +1 -1
  97. package/dist/server/auth-extra.test-d.js +130 -0
  98. package/dist/server/auth-extra.test-d.js.map +1 -0
  99. package/dist/server/auth.d.ts +43 -6
  100. package/dist/server/auth.js +4 -5
  101. package/dist/server/auth.js.map +1 -1
  102. package/dist/server/build-manifest.test.js +7 -6
  103. package/dist/server/build-manifest.test.js.map +1 -1
  104. package/dist/server/content-helpers.d.ts +1 -1
  105. package/dist/server/content-helpers.js.map +1 -1
  106. package/dist/server/events.d.ts +113 -0
  107. package/dist/server/events.js +318 -0
  108. package/dist/server/events.js.map +1 -0
  109. package/dist/server/events.test.d.ts +1 -0
  110. package/dist/server/events.test.js +172 -0
  111. package/dist/server/events.test.js.map +1 -0
  112. package/dist/server/express.d.ts +23 -3
  113. package/dist/server/express.js +43 -32
  114. package/dist/server/express.js.map +1 -1
  115. package/dist/server/express.test.js +221 -103
  116. package/dist/server/express.test.js.map +1 -1
  117. package/dist/server/file-ref.d.ts +1 -1
  118. package/dist/server/file-ref.js +1 -1
  119. package/dist/server/file-ref.js.map +1 -1
  120. package/dist/server/form-input.d.ts +120 -0
  121. package/dist/server/form-input.js +89 -0
  122. package/dist/server/form-input.js.map +1 -0
  123. package/dist/server/host.d.ts +2 -0
  124. package/dist/server/host.js +11 -0
  125. package/dist/server/host.js.map +1 -0
  126. package/dist/server/host.test.d.ts +1 -0
  127. package/dist/server/host.test.js +13 -0
  128. package/dist/server/host.test.js.map +1 -0
  129. package/dist/server/index.d.ts +18 -9
  130. package/dist/server/index.js +11 -3
  131. package/dist/server/index.js.map +1 -1
  132. package/dist/server/mcp-errors.test.d.ts +1 -0
  133. package/dist/server/mcp-errors.test.js +41 -0
  134. package/dist/server/mcp-errors.test.js.map +1 -0
  135. package/dist/server/middleware.d.ts +35 -10
  136. package/dist/server/middleware.js +33 -0
  137. package/dist/server/middleware.js.map +1 -1
  138. package/dist/server/middleware.test-d.js +1 -1
  139. package/dist/server/middleware.test-d.js.map +1 -1
  140. package/dist/server/middleware.test.js +242 -134
  141. package/dist/server/middleware.test.js.map +1 -1
  142. package/dist/server/register-tool.test.d.ts +1 -0
  143. package/dist/server/register-tool.test.js +230 -0
  144. package/dist/server/register-tool.test.js.map +1 -0
  145. package/dist/server/server.d.ts +373 -128
  146. package/dist/server/server.js +441 -274
  147. package/dist/server/server.js.map +1 -1
  148. package/dist/server/skills-integration.test.d.ts +1 -0
  149. package/dist/server/skills-integration.test.js +86 -0
  150. package/dist/server/skills-integration.test.js.map +1 -0
  151. package/dist/server/skills.d.ts +27 -0
  152. package/dist/server/skills.js +188 -0
  153. package/dist/server/skills.js.map +1 -0
  154. package/dist/server/skills.test.d.ts +1 -0
  155. package/dist/server/skills.test.js +243 -0
  156. package/dist/server/skills.test.js.map +1 -0
  157. package/dist/server/templateHelper.d.ts +0 -3
  158. package/dist/server/templateHelper.js.map +1 -1
  159. package/dist/server/templates.generated.js +4 -8
  160. package/dist/server/templates.generated.js.map +1 -1
  161. package/dist/server/tool-extra.test.d.ts +1 -0
  162. package/dist/server/tool-extra.test.js +167 -0
  163. package/dist/server/tool-extra.test.js.map +1 -0
  164. package/dist/server/view-resource-resolution.test.js +18 -13
  165. package/dist/server/view-resource-resolution.test.js.map +1 -1
  166. package/dist/server/viewsDevServer.js +4 -1
  167. package/dist/server/viewsDevServer.js.map +1 -1
  168. package/dist/test/utils.d.ts +9 -11
  169. package/dist/test/utils.js +220 -201
  170. package/dist/test/utils.js.map +1 -1
  171. package/dist/test/view.test.js +44 -40
  172. package/dist/test/view.test.js.map +1 -1
  173. package/dist/views/index.d.ts +10 -0
  174. package/dist/views/index.js +3 -0
  175. package/dist/views/index.js.map +1 -0
  176. package/dist/{web/plugin → views}/scan-views.js +1 -1
  177. package/dist/views/scan-views.js.map +1 -0
  178. package/dist/views/scan-views.test.d.ts +1 -0
  179. package/dist/views/scan-views.test.js.map +1 -0
  180. package/dist/views/validate-view.d.ts +1 -0
  181. package/dist/{web/plugin → views}/validate-view.js +2 -2
  182. package/dist/views/validate-view.js.map +1 -0
  183. package/dist/views/validate-view.test.d.ts +1 -0
  184. package/dist/views/validate-view.test.js.map +1 -0
  185. package/dist/web/bridges/adaptor.d.ts +14 -3
  186. package/dist/web/bridges/adaptor.js +184 -17
  187. package/dist/web/bridges/adaptor.js.map +1 -1
  188. package/dist/web/bridges/adaptor.test.js +95 -11
  189. package/dist/web/bridges/adaptor.test.js.map +1 -1
  190. package/dist/web/bridges/apps-sdk/bridge.js +1 -1
  191. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  192. package/dist/web/bridges/apps-sdk/types.d.ts +2 -3
  193. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  194. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +4 -4
  195. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +4 -4
  196. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  197. package/dist/web/bridges/get-adaptor.test.js +2 -2
  198. package/dist/web/bridges/get-adaptor.test.js.map +1 -1
  199. package/dist/web/bridges/mcp-app/bridge.d.ts +1 -1
  200. package/dist/web/bridges/mcp-app/bridge.js +15 -6
  201. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  202. package/dist/web/bridges/mcp-app/bridge.test.js +2 -2
  203. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -1
  204. package/dist/web/bridges/mcp-app/types.d.ts +19 -2
  205. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  206. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +2 -2
  207. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +1 -1
  208. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  209. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -1
  210. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  211. package/dist/web/bridges/mcp-app/view-tools.test.js +1 -1
  212. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -1
  213. package/dist/web/bridges/types.d.ts +74 -16
  214. package/dist/web/bridges/types.js +1 -1
  215. package/dist/web/bridges/types.js.map +1 -1
  216. package/dist/web/components/modal-provider.d.ts +1 -1
  217. package/dist/web/create-store.test.js +2 -2
  218. package/dist/web/create-store.test.js.map +1 -1
  219. package/dist/web/data-llm.d.ts +1 -1
  220. package/dist/web/data-llm.js +3 -2
  221. package/dist/web/data-llm.js.map +1 -1
  222. package/dist/web/data-llm.test.js +17 -2
  223. package/dist/web/data-llm.test.js.map +1 -1
  224. package/dist/web/generate-helpers.d.ts +23 -19
  225. package/dist/web/generate-helpers.js +21 -17
  226. package/dist/web/generate-helpers.js.map +1 -1
  227. package/dist/web/generate-helpers.test-d.js +3 -3
  228. package/dist/web/generate-helpers.test-d.js.map +1 -1
  229. package/dist/web/generate-helpers.test.js +2 -2
  230. package/dist/web/generate-helpers.test.js.map +1 -1
  231. package/dist/web/hooks/index.d.ts +6 -1
  232. package/dist/web/hooks/index.js +6 -1
  233. package/dist/web/hooks/index.js.map +1 -1
  234. package/dist/web/hooks/openai-extensions.test.d.ts +1 -0
  235. package/dist/web/hooks/openai-extensions.test.js +107 -0
  236. package/dist/web/hooks/openai-extensions.test.js.map +1 -0
  237. package/dist/web/hooks/test/utils.d.ts +2 -1
  238. package/dist/web/hooks/test/utils.js +1 -1
  239. package/dist/web/hooks/test/utils.js.map +1 -1
  240. package/dist/web/hooks/use-call-tool.d.ts +2 -2
  241. package/dist/web/hooks/use-call-tool.js +15 -10
  242. package/dist/web/hooks/use-call-tool.js.map +1 -1
  243. package/dist/web/hooks/use-call-tool.test.js +15 -4
  244. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  245. package/dist/web/hooks/use-deep-link.d.ts +22 -0
  246. package/dist/web/hooks/use-deep-link.js +34 -0
  247. package/dist/web/hooks/use-deep-link.js.map +1 -0
  248. package/dist/web/hooks/use-display-mode.d.ts +1 -1
  249. package/dist/web/hooks/use-display-mode.js +1 -1
  250. package/dist/web/hooks/use-display-mode.js.map +1 -1
  251. package/dist/web/hooks/use-display-mode.test.js +1 -1
  252. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  253. package/dist/web/hooks/use-download.d.ts +1 -3
  254. package/dist/web/hooks/use-download.js +1 -2
  255. package/dist/web/hooks/use-download.js.map +1 -1
  256. package/dist/web/hooks/use-download.test.js +7 -7
  257. package/dist/web/hooks/use-download.test.js.map +1 -1
  258. package/dist/web/hooks/use-file-resource.d.ts +37 -0
  259. package/dist/web/hooks/use-file-resource.js +98 -0
  260. package/dist/web/hooks/use-file-resource.js.map +1 -0
  261. package/dist/web/hooks/use-file-resource.test.d.ts +1 -0
  262. package/dist/web/hooks/use-file-resource.test.js +65 -0
  263. package/dist/web/hooks/use-file-resource.test.js.map +1 -0
  264. package/dist/web/hooks/use-files.test.js +1 -1
  265. package/dist/web/hooks/use-files.test.js.map +1 -1
  266. package/dist/web/hooks/use-host.d.ts +44 -0
  267. package/dist/web/hooks/use-host.js +45 -0
  268. package/dist/web/hooks/use-host.js.map +1 -0
  269. package/dist/web/hooks/use-host.test.d.ts +1 -0
  270. package/dist/web/hooks/use-host.test.js +59 -0
  271. package/dist/web/hooks/use-host.test.js.map +1 -0
  272. package/dist/web/hooks/use-model-context.d.ts +44 -0
  273. package/dist/web/hooks/use-model-context.js +63 -0
  274. package/dist/web/hooks/use-model-context.js.map +1 -0
  275. package/dist/web/hooks/use-open-external.test.js +2 -2
  276. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  277. package/dist/web/hooks/use-open-file.d.ts +20 -0
  278. package/dist/web/hooks/use-open-file.js +25 -0
  279. package/dist/web/hooks/use-open-file.js.map +1 -0
  280. package/dist/web/hooks/use-register-view-tool.d.ts +3 -4
  281. package/dist/web/hooks/use-register-view-tool.js +1 -1
  282. package/dist/web/hooks/use-register-view-tool.js.map +1 -1
  283. package/dist/web/hooks/use-request-close.test.js +1 -1
  284. package/dist/web/hooks/use-request-close.test.js.map +1 -1
  285. package/dist/web/hooks/use-request-modal.test.js +1 -1
  286. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  287. package/dist/web/hooks/use-request-size.d.ts +1 -1
  288. package/dist/web/hooks/use-request-size.js +1 -1
  289. package/dist/web/hooks/use-request-size.js.map +1 -1
  290. package/dist/web/hooks/use-request-size.test.js +1 -1
  291. package/dist/web/hooks/use-request-size.test.js.map +1 -1
  292. package/dist/web/hooks/use-send-follow-up-message.d.ts +8 -2
  293. package/dist/web/hooks/use-send-follow-up-message.js +6 -0
  294. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  295. package/dist/web/hooks/use-set-open-in-app-url.test.js +2 -8
  296. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  297. package/dist/web/hooks/use-tool-info.d.ts +1 -20
  298. package/dist/web/hooks/use-tool-info.js +0 -1
  299. package/dist/web/hooks/use-tool-info.js.map +1 -1
  300. package/dist/web/hooks/use-tool-info.test-d.js +0 -5
  301. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  302. package/dist/web/hooks/use-tool-info.test.js +2 -7
  303. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  304. package/dist/web/hooks/use-user.d.ts +3 -2
  305. package/dist/web/hooks/use-user.js +4 -3
  306. package/dist/web/hooks/use-user.js.map +1 -1
  307. package/dist/web/hooks/use-user.test.js +5 -3
  308. package/dist/web/hooks/use-user.test.js.map +1 -1
  309. package/dist/web/hooks/use-view-state.js +19 -9
  310. package/dist/web/hooks/use-view-state.js.map +1 -1
  311. package/dist/web/hooks/use-view-state.test.js +33 -2
  312. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  313. package/dist/web/hooks/use-viewport.d.ts +20 -0
  314. package/dist/web/hooks/use-viewport.js +21 -0
  315. package/dist/web/hooks/use-viewport.js.map +1 -0
  316. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  317. package/dist/web/hooks/{use-layout.test.js → use-viewport.test.js} +12 -32
  318. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  319. package/dist/web/mount-view.d.ts +3 -2
  320. package/dist/web/mount-view.js +5 -8
  321. package/dist/web/mount-view.js.map +1 -1
  322. package/package.json +34 -29
  323. package/dist/cli/resolve-views-dir.d.ts +0 -1
  324. package/dist/cli/resolve-views-dir.js.map +0 -1
  325. package/dist/web/hooks/use-layout.d.ts +0 -24
  326. package/dist/web/hooks/use-layout.js +0 -25
  327. package/dist/web/hooks/use-layout.js.map +0 -1
  328. package/dist/web/hooks/use-layout.test.js.map +0 -1
  329. package/dist/web/plugin/data-llm.test.js +0 -81
  330. package/dist/web/plugin/data-llm.test.js.map +0 -1
  331. package/dist/web/plugin/plugin.d.ts +0 -33
  332. package/dist/web/plugin/plugin.js +0 -189
  333. package/dist/web/plugin/plugin.js.map +0 -1
  334. package/dist/web/plugin/scan-views.js.map +0 -1
  335. package/dist/web/plugin/scan-views.test.js.map +0 -1
  336. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  337. package/dist/web/plugin/transform-data-llm.js +0 -96
  338. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  339. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  340. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  341. package/dist/web/plugin/validate-view.d.ts +0 -1
  342. package/dist/web/plugin/validate-view.js.map +0 -1
  343. package/dist/web/plugin/validate-view.test.js.map +0 -1
  344. /package/dist/{web/hooks/use-layout.test.d.ts → context-warnings.test.d.ts} +0 -0
  345. /package/dist/{web/plugin/data-llm.test.d.ts → server/app.test.d.ts} +0 -0
  346. /package/dist/{web/plugin/transform-data-llm.test.d.ts → server/auth/providers/authplane.test.d.ts} +0 -0
  347. /package/dist/{web/plugin/validate-view.test.d.ts → server/auth/security-schemes.test.d.ts} +0 -0
  348. /package/dist/{web/plugin/scan-views.test.d.ts → server/auth-extra.test-d.d.ts} +0 -0
  349. /package/dist/{web/plugin → views}/scan-views.d.ts +0 -0
  350. /package/dist/{web/plugin → views}/scan-views.test.js +0 -0
  351. /package/dist/{web/plugin → views}/validate-view.test.js +0 -0
@@ -1,8 +1,22 @@
1
+ import { ResultSchema } from "@modelcontextprotocol/core";
2
+ import * as z from "zod/v4";
3
+ import { warnOnLargeViewState } from "../../context-warnings.js";
1
4
  import { AppsSdkBridge } from "./apps-sdk/bridge.js";
2
5
  import { McpAppBridge } from "./mcp-app/bridge.js";
3
6
  import { NotSupportedError } from "./types.js";
7
+ const ResourceMetaSchema = z.object({
8
+ writable: z.boolean().optional(),
9
+ etag: z.string().optional(),
10
+ });
11
+ const WriteResultSchema = z.discriminatedUnion("outcome", [
12
+ z.object({ outcome: z.enum(["saved", "conflict"]), etag: z.string() }),
13
+ z.object({ outcome: z.literal("too-large"), maxBytes: z.number() }),
14
+ ]);
4
15
  const STORAGE_PREFIX = "sb:";
5
16
  const MAX_STORAGE_ENTRIES = 200;
17
+ function isImage(mimeType) {
18
+ return mimeType?.startsWith("image/") ?? false;
19
+ }
6
20
  function findStorageKey(viewUUID) {
7
21
  const suffix = `:${viewUUID}`;
8
22
  for (let i = 0; i < localStorage.length; i++) {
@@ -37,11 +51,15 @@ export class HostAdaptor {
37
51
  _viewState = null;
38
52
  viewStateListeners = new Set();
39
53
  _viewUUID = null;
54
+ _modelContext = null;
55
+ resourceListeners = new Map();
56
+ resourceApp;
40
57
  _polyfillDisplay = { mode: "inline" };
41
58
  polyfillDisplayListeners = new Set();
42
59
  polyfillDisplayStore;
43
60
  polyfillViewStateStore;
44
61
  unsubscribeViewUUID = null;
62
+ unsubscribeModelContext = null;
45
63
  constructor() {
46
64
  this.mcp = McpAppBridge.getInstance();
47
65
  let overlayStores = null;
@@ -75,20 +93,29 @@ export class HostAdaptor {
75
93
  viewState: overlayStores?.viewState ?? this.polyfillViewStateStore,
76
94
  };
77
95
  this.subscribeToViewUUID();
96
+ this.unsubscribeModelContext = this.mcp.subscribe("openai/modelContext")(() => {
97
+ if (this.mcp.getSnapshot("openai/modelContext") === null) {
98
+ this._modelContext = null;
99
+ }
100
+ });
78
101
  }
79
102
  /** @internal Release any subscriptions held on the underlying bridges. */
80
103
  cleanup() {
81
104
  this.unsubscribeViewUUID?.();
82
105
  this.unsubscribeViewUUID = null;
106
+ this.unsubscribeModelContext?.();
107
+ this.unsubscribeModelContext = null;
83
108
  }
84
109
  // ---- Adaptor interface ----
85
110
  getHostContextStore = (key) => this.stores[key];
86
- callTool = async (name, args) => {
111
+ callTool = async (name, args, options) => {
112
+ const timeout = options?.timeout;
113
+ if (timeout !== undefined && (!Number.isFinite(timeout) || timeout <= 0)) {
114
+ throw new RangeError("Tool call timeout must be a positive, finite number of milliseconds.");
115
+ }
87
116
  const app = await this.mcp.getApp();
88
- const response = await app.callServerTool({
89
- name,
90
- arguments: args ?? undefined,
91
- });
117
+ const params = { name, arguments: args ?? undefined };
118
+ const response = await app.callServerTool(params, { timeout });
92
119
  return {
93
120
  content: response.content,
94
121
  structuredContent: response.structuredContent ?? {},
@@ -104,6 +131,9 @@ export class HostAdaptor {
104
131
  return app.requestDisplayMode({ mode });
105
132
  };
106
133
  requestClose = async () => {
134
+ if (this.openai) {
135
+ await this.openai.requestClose();
136
+ }
107
137
  const app = await this.mcp.getApp();
108
138
  await app.requestTeardown();
109
139
  };
@@ -112,7 +142,8 @@ export class HostAdaptor {
112
142
  await app.sendSizeChanged(size);
113
143
  };
114
144
  sendFollowUpMessage = async (prompt, options) => {
115
- if (this.openai) {
145
+ const target = options?.target;
146
+ if (this.openai && typeof prompt === "string" && target !== "new") {
116
147
  await this.openai.sendFollowUpMessage({
117
148
  prompt,
118
149
  scrollToBottom: options?.scrollToBottom,
@@ -120,10 +151,18 @@ export class HostAdaptor {
120
151
  return;
121
152
  }
122
153
  const app = await this.mcp.getApp();
123
- await app.sendMessage({
154
+ if (target === "new" &&
155
+ !app.getHostCapabilities()?.experimental?.["openai/message"]) {
156
+ throw new NotSupportedError("sendFollowUpMessage", "the host does not advertise openai/message, so it can't open a new conversation");
157
+ }
158
+ const result = await app.sendMessage({
124
159
  role: "user",
125
- content: [{ type: "text", text: prompt }],
160
+ content: typeof prompt === "string" ? [{ type: "text", text: prompt }] : prompt,
161
+ ...(target === "new" && { _meta: { "openai/message": { target } } }),
126
162
  });
163
+ if (result?.isError) {
164
+ throw new Error("The host rejected the follow-up message.");
165
+ }
127
166
  };
128
167
  openExternal = (href, options) => {
129
168
  if (this.openai) {
@@ -150,6 +189,7 @@ export class HostAdaptor {
150
189
  const modelContent = typeof stateOrUpdater === "function"
151
190
  ? stateOrUpdater(this.openai.widgetState?.modelContent ?? null)
152
191
  : stateOrUpdater;
192
+ warnOnLargeViewState(modelContent, "setWidgetState");
153
193
  await this.openai.setWidgetState({
154
194
  privateContent: {},
155
195
  ...this.openai.widgetState,
@@ -160,6 +200,7 @@ export class HostAdaptor {
160
200
  const newState = typeof stateOrUpdater === "function"
161
201
  ? stateOrUpdater(this._viewState)
162
202
  : stateOrUpdater;
203
+ warnOnLargeViewState(newState, "setViewState");
163
204
  // update local state immediately so successive calls see fresh state
164
205
  this._viewState = newState;
165
206
  this.viewStateListeners.forEach((l) => {
@@ -167,28 +208,148 @@ export class HostAdaptor {
167
208
  });
168
209
  this.persistToLocalStorage(newState);
169
210
  try {
170
- const app = await this.mcp.getApp();
171
- await app.updateModelContext({
172
- structuredContent: newState,
173
- content: [{ type: "text", text: JSON.stringify(newState) }],
174
- });
211
+ await this.sendModelContext();
175
212
  }
176
213
  catch (error) {
177
214
  console.error("Failed to update view state in MCP App.", error);
178
215
  }
179
216
  };
217
+ updateModelContext = async (params) => {
218
+ const app = await this.mcp.getApp();
219
+ const capabilities = app.getHostCapabilities();
220
+ if (!capabilities?.updateModelContext &&
221
+ !capabilities?.experimental?.["openai/modelContext"]) {
222
+ throw new NotSupportedError("updateModelContext", "the host does not advertise updateModelContext");
223
+ }
224
+ const previous = this._modelContext;
225
+ this._modelContext = params;
226
+ const result = await this.sendModelContext().catch((error) => {
227
+ if (this._modelContext === params) {
228
+ this._modelContext = previous;
229
+ }
230
+ throw error;
231
+ });
232
+ const parsed = z
233
+ .object({ updateId: z.string() })
234
+ .safeParse(result._meta?.["openai/modelContext"]);
235
+ return parsed.success ? parsed.data.updateId : undefined;
236
+ };
237
+ async sendModelContext() {
238
+ const viewState = this.openai ? null : this._viewState;
239
+ const extra = this._modelContext;
240
+ const collisions = Object.keys(extra?.structuredContent ?? {}).filter((key) => viewState !== null && key in viewState);
241
+ if (collisions.length > 0) {
242
+ console.warn(`skybridge: view state overrides model context keys ${collisions.join(", ")}.`);
243
+ }
244
+ const structuredContent = { ...extra?.structuredContent, ...viewState };
245
+ const app = await this.mcp.getApp();
246
+ return app.updateModelContext({
247
+ ...(Object.keys(structuredContent).length > 0 && { structuredContent }),
248
+ content: [
249
+ ...(viewState === null
250
+ ? []
251
+ : [
252
+ {
253
+ type: "text",
254
+ text: JSON.stringify(viewState),
255
+ annotations: { audience: ["assistant"] },
256
+ },
257
+ ]),
258
+ ...(extra?.content ?? []),
259
+ ],
260
+ });
261
+ }
262
+ openFile = async (path) => {
263
+ const app = await this.mcp.getApp();
264
+ if (!app.getHostCapabilities()?.experimental?.["openai/files"]) {
265
+ throw new NotSupportedError("openFile", "the host does not advertise openai/files");
266
+ }
267
+ await app.request({ method: "openai/files/open", params: { path } }, ResultSchema);
268
+ };
269
+ readResource = async (uri, representation) => {
270
+ const app = await this.mcp.getApp();
271
+ const { contents } = await app.readServerResource({
272
+ uri,
273
+ ...(representation && {
274
+ _meta: { "openai/resource": { representation } },
275
+ }),
276
+ });
277
+ const item = contents.find((content) => content.uri === uri) ?? contents[0];
278
+ if (!item) {
279
+ throw new Error(`The host returned no contents for ${uri}.`);
280
+ }
281
+ const { data: meta } = ResourceMetaSchema.safeParse(item._meta?.["openai/resource"]);
282
+ return {
283
+ ...("text" in item ? { text: item.text } : { blob: item.blob }),
284
+ mimeType: item.mimeType,
285
+ writable: meta?.writable ?? false,
286
+ etag: meta?.etag,
287
+ };
288
+ };
289
+ watchResource = (uri, onUpdate) => {
290
+ const listeners = this.resourceListeners.get(uri) ?? new Set();
291
+ if (listeners.size === 0) {
292
+ this.resourceListeners.set(uri, listeners);
293
+ this.getResourceApp()
294
+ .then((app) => app?.request({ method: "resources/subscribe", params: { uri } }, ResultSchema))
295
+ .catch((error) => {
296
+ console.warn(`Failed to subscribe to ${uri}.`, error);
297
+ });
298
+ }
299
+ listeners.add(onUpdate);
300
+ return () => {
301
+ if (listeners.delete(onUpdate) && listeners.size === 0) {
302
+ this.resourceListeners.delete(uri);
303
+ this.getResourceApp()
304
+ .then((app) => app?.request({ method: "resources/unsubscribe", params: { uri } }, ResultSchema))
305
+ .catch(() => { });
306
+ }
307
+ };
308
+ };
309
+ writeResource = async (uri, content, ifMatch) => {
310
+ const app = await this.getResourceApp();
311
+ if (!app) {
312
+ throw new NotSupportedError("writeResource", "the host does not advertise openai/resource");
313
+ }
314
+ return app.request({
315
+ method: "openai/resources/write",
316
+ params: { uri, ...content, ...(ifMatch && { ifMatch }) },
317
+ }, WriteResultSchema);
318
+ };
319
+ getResourceApp() {
320
+ this.resourceApp ??= this.mcp.getApp().then((app) => {
321
+ if (!app.getHostCapabilities()?.experimental?.["openai/resource"]) {
322
+ return undefined;
323
+ }
324
+ app.setNotificationHandler("notifications/resources/updated", ({ params }) => {
325
+ this.resourceListeners.get(params.uri)?.forEach((l) => {
326
+ l();
327
+ });
328
+ });
329
+ return app;
330
+ });
331
+ return this.resourceApp;
332
+ }
180
333
  uploadFile = async (file, options) => {
181
334
  if (!this.openai) {
182
335
  throw new NotSupportedError("uploadFile");
183
336
  }
337
+ if (!this.openai.uploadFile) {
338
+ throw new NotSupportedError("uploadFile", "not available on the current host version");
339
+ }
184
340
  const metadata = await this.openai.uploadFile(file, options);
185
- await this.trackFileIds(metadata.fileId);
341
+ if (isImage(metadata.mimeType ?? file.type)) {
342
+ await this.trackFileIds(metadata.fileId);
343
+ }
186
344
  return metadata;
187
345
  };
188
346
  getFileDownloadUrl = (file) => {
189
347
  if (!this.openai) {
190
348
  return Promise.reject(new NotSupportedError("getFileDownloadUrl"));
191
349
  }
350
+ if (!this.openai.getFileDownloadUrl) {
351
+ return Promise.reject(new NotSupportedError("getFileDownloadUrl", "not available on the current host version"));
352
+ }
192
353
  return this.openai.getFileDownloadUrl(file);
193
354
  };
194
355
  selectFiles = async () => {
@@ -196,11 +357,17 @@ export class HostAdaptor {
196
357
  throw new NotSupportedError("selectFiles");
197
358
  }
198
359
  if (!this.openai.selectFiles) {
199
- throw new Error("selectFiles is not supported by the current host version.");
360
+ throw new NotSupportedError("selectFiles", "not available on the current host version");
200
361
  }
201
362
  const files = await this.openai.selectFiles();
202
- if (files.length > 0) {
203
- await this.trackFileIds(...files.map((f) => f.fileId));
363
+ const imageIds = [];
364
+ for (const file of files) {
365
+ if (isImage(file.mimeType)) {
366
+ imageIds.push(file.fileId);
367
+ }
368
+ }
369
+ if (imageIds.length > 0) {
370
+ await this.trackFileIds(...imageIds);
204
371
  }
205
372
  return files;
206
373
  };
@@ -1 +1 @@
1
- {"version":3,"file":"adaptor.js","sourceRoot":"","sources":["../../../src/web/bridges/adaptor.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppsSdkBridge } from \"./apps-sdk/bridge.js\";\nimport type { AppsSdkWidgetState } from \"./apps-sdk/types.js\";\nimport { McpAppBridge } from \"./mcp-app/bridge.js\";\nimport type {\n Adaptor,\n AnyViewToolHandler,\n CallToolResponse,\n DownloadParams,\n DownloadResult,\n FileMetadata,\n HostContext,\n HostContextStore,\n OpenExternalOptions,\n RequestDisplayMode,\n RequestModalOptions,\n RequestSizeOptions,\n SendFollowUpMessageOptions,\n SetViewStateAction,\n UploadFileOptions,\n ViewToolConfig,\n} from \"./types.js\";\nimport { NotSupportedError } from \"./types.js\";\n\nconst STORAGE_PREFIX = \"sb:\";\nconst MAX_STORAGE_ENTRIES = 200;\n\nfunction findStorageKey(viewUUID: string): string | undefined {\n const suffix = `:${viewUUID}`;\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(STORAGE_PREFIX) && key.endsWith(suffix)) {\n return key;\n }\n }\n return undefined;\n}\n\n/**\n * @internal\n * Single composite implementation of {@link Adaptor}. Composes the MCP App\n * bridge (always present) with an optional `window.openai` overlay. Per-method\n * routing rules are encoded inline.\n */\nexport class HostAdaptor implements Adaptor {\n private static instance: HostAdaptor | null = null;\n\n static getInstance(): HostAdaptor {\n if (!HostAdaptor.instance) {\n HostAdaptor.instance = new HostAdaptor();\n }\n return HostAdaptor.instance;\n }\n\n static resetInstance(): void {\n HostAdaptor.instance?.cleanup();\n HostAdaptor.instance = null;\n }\n\n private readonly mcp: McpAppBridge;\n private readonly openai: typeof window.openai | null = null;\n\n private readonly stores: { [K in keyof HostContext]: HostContextStore<K> };\n\n private _viewState: HostContext[\"viewState\"] = null;\n private readonly viewStateListeners = new Set<() => void>();\n private _viewUUID: string | null = null;\n\n private _polyfillDisplay: HostContext[\"display\"] = { mode: \"inline\" };\n private readonly polyfillDisplayListeners = new Set<() => void>();\n\n private readonly polyfillDisplayStore: HostContextStore<\"display\">;\n private readonly polyfillViewStateStore: HostContextStore<\"viewState\">;\n\n private unsubscribeViewUUID: (() => void) | null = null;\n\n constructor() {\n this.mcp = McpAppBridge.getInstance();\n\n let overlayStores: ReturnType<AppsSdkBridge[\"createOverlayStores\"]> | null =\n null;\n if (typeof window !== \"undefined\" && window.openai !== undefined) {\n this.openai = window.openai;\n overlayStores = AppsSdkBridge.getInstance().createOverlayStores();\n }\n\n // Built once so that getHostContextStore returns stable references — required\n // by useSyncExternalStore to avoid resubscribing on every render.\n this.polyfillDisplayStore = {\n subscribe: (onChange: () => void) => {\n this.polyfillDisplayListeners.add(onChange);\n return () => {\n this.polyfillDisplayListeners.delete(onChange);\n };\n },\n getSnapshot: () => this._polyfillDisplay,\n };\n this.polyfillViewStateStore = {\n subscribe: (onChange: () => void) => {\n this.viewStateListeners.add(onChange);\n return () => {\n this.viewStateListeners.delete(onChange);\n };\n },\n getSnapshot: () => this._viewState,\n };\n\n this.stores = {\n ...this.mcp.createContextStores(),\n display: overlayStores?.display ?? this.polyfillDisplayStore,\n viewState: overlayStores?.viewState ?? this.polyfillViewStateStore,\n };\n\n this.subscribeToViewUUID();\n }\n\n /** @internal Release any subscriptions held on the underlying bridges. */\n public cleanup(): void {\n this.unsubscribeViewUUID?.();\n this.unsubscribeViewUUID = null;\n }\n\n // ---- Adaptor interface ----\n\n public getHostContextStore = <K extends keyof HostContext>(\n key: K,\n ): HostContextStore<K> => this.stores[key];\n\n public callTool = async <\n ToolArgs extends Record<string, unknown> | null = null,\n ToolResponse extends CallToolResponse = CallToolResponse,\n >(\n name: string,\n args: ToolArgs,\n ): Promise<ToolResponse> => {\n const app = await this.mcp.getApp();\n const response = await app.callServerTool({\n name,\n arguments: args ?? undefined,\n });\n return {\n content: response.content,\n structuredContent: response.structuredContent ?? {},\n isError: response.isError ?? false,\n meta: response._meta ?? {},\n } as ToolResponse;\n };\n\n public registerViewTool = (\n config: ViewToolConfig,\n handler: AnyViewToolHandler,\n ): (() => void) => {\n return this.mcp.registerViewTool(config, handler);\n };\n\n public requestDisplayMode = async (mode: RequestDisplayMode) => {\n const app = await this.mcp.getApp();\n return app.requestDisplayMode({ mode });\n };\n\n public requestClose = async (): Promise<void> => {\n const app = await this.mcp.getApp();\n await app.requestTeardown();\n };\n\n public requestSize = async (size: RequestSizeOptions): Promise<void> => {\n const app = await this.mcp.getApp();\n await app.sendSizeChanged(size);\n };\n\n public sendFollowUpMessage = async (\n prompt: string,\n options?: SendFollowUpMessageOptions,\n ): Promise<void> => {\n if (this.openai) {\n await this.openai.sendFollowUpMessage({\n prompt,\n scrollToBottom: options?.scrollToBottom,\n });\n return;\n }\n const app = await this.mcp.getApp();\n await app.sendMessage({\n role: \"user\",\n content: [{ type: \"text\", text: prompt }],\n });\n };\n\n public openExternal = (href: string, options?: OpenExternalOptions): void => {\n if (this.openai) {\n this.openai.openExternal({ href, ...options });\n return;\n }\n this.mcp\n .getApp()\n .then((app) => app.openLink({ url: href }))\n .catch((err) => {\n console.error(\"Failed to open external link:\", err);\n });\n };\n\n public download = async (params: DownloadParams): Promise<DownloadResult> => {\n const app = await this.mcp.getApp();\n if (!app.getHostCapabilities()?.downloadFile) {\n console.error(\n \"[skybridge] download: host does not support ui/download-file\",\n );\n return { isError: true };\n }\n return app.downloadFile(params);\n };\n\n public setViewState = async (\n stateOrUpdater: SetViewStateAction,\n ): Promise<void> => {\n if (this.openai) {\n const modelContent =\n typeof stateOrUpdater === \"function\"\n ? stateOrUpdater(this.openai.widgetState?.modelContent ?? null)\n : stateOrUpdater;\n await this.openai.setWidgetState({\n privateContent: {},\n ...this.openai.widgetState,\n modelContent,\n });\n return;\n }\n\n const newState =\n typeof stateOrUpdater === \"function\"\n ? stateOrUpdater(this._viewState)\n : stateOrUpdater;\n\n // update local state immediately so successive calls see fresh state\n this._viewState = newState;\n this.viewStateListeners.forEach((l) => {\n l();\n });\n\n this.persistToLocalStorage(newState);\n\n try {\n const app = await this.mcp.getApp();\n await app.updateModelContext({\n structuredContent: newState,\n content: [{ type: \"text\", text: JSON.stringify(newState) }],\n });\n } catch (error) {\n console.error(\"Failed to update view state in MCP App.\", error);\n }\n };\n\n public uploadFile = async (\n file: File,\n options?: UploadFileOptions,\n ): Promise<FileMetadata> => {\n if (!this.openai) {\n throw new NotSupportedError(\"uploadFile\");\n }\n const metadata = await this.openai.uploadFile(file, options);\n await this.trackFileIds(metadata.fileId);\n return metadata;\n };\n\n public getFileDownloadUrl = (\n file: FileMetadata,\n ): Promise<{ downloadUrl: string }> => {\n if (!this.openai) {\n return Promise.reject(new NotSupportedError(\"getFileDownloadUrl\"));\n }\n return this.openai.getFileDownloadUrl(file);\n };\n\n public selectFiles = async (): Promise<FileMetadata[]> => {\n if (!this.openai) {\n throw new NotSupportedError(\"selectFiles\");\n }\n if (!this.openai.selectFiles) {\n throw new Error(\n \"selectFiles is not supported by the current host version.\",\n );\n }\n const files = await this.openai.selectFiles();\n if (files.length > 0) {\n await this.trackFileIds(...files.map((f) => f.fileId));\n }\n return files;\n };\n\n public openModal = (options: RequestModalOptions): void => {\n if (this.openai) {\n this.openai.requestModal(options);\n return;\n }\n this._polyfillDisplay = { mode: \"modal\", params: options.params };\n this.polyfillDisplayListeners.forEach((l) => {\n l();\n });\n };\n\n public setOpenInAppUrl = (href: string): Promise<void> => {\n if (!this.openai) {\n return Promise.reject(new NotSupportedError(\"setOpenInAppUrl\"));\n }\n const trimmed = href.trim();\n if (!trimmed) {\n return Promise.reject(new Error(\"The href parameter is required.\"));\n }\n return this.openai.setOpenInAppUrl({ href: trimmed });\n };\n\n public closeModal = (): void => {\n if (this.openai) {\n return; // host owns modal lifecycle\n }\n this._polyfillDisplay = { mode: \"inline\" };\n this.polyfillDisplayListeners.forEach((l) => {\n l();\n });\n };\n\n private async trackFileIds(...fileIds: string[]): Promise<void> {\n if (!this.openai) {\n return;\n }\n const current = this.openai.widgetState;\n const state: AppsSdkWidgetState = current\n ? { ...current }\n : { modelContent: {}, privateContent: {} };\n if (!state.imageIds) {\n state.imageIds = [];\n }\n state.imageIds.push(...fileIds);\n await this.openai.setWidgetState(state);\n }\n\n // ---- viewState persistence helpers ----\n\n private subscribeToViewUUID(): void {\n this.unsubscribeViewUUID = this.mcp.subscribe(\"toolResult\")(() => {\n const toolResult = this.mcp.getSnapshot(\"toolResult\");\n const viewUUID = (\n toolResult?._meta as Record<string, unknown> | undefined\n )?.viewUUID as string | undefined;\n if (viewUUID && viewUUID !== this._viewUUID) {\n this._viewUUID = viewUUID;\n this.restoreFromLocalStorage(viewUUID);\n }\n });\n }\n\n private restoreFromLocalStorage(viewUUID: string): void {\n try {\n const existingKey = findStorageKey(viewUUID);\n if (existingKey) {\n const stored = localStorage.getItem(existingKey);\n if (stored !== null) {\n this._viewState = JSON.parse(stored);\n this.viewStateListeners.forEach((l) => {\n l();\n });\n }\n }\n } catch (err) {\n console.error(err);\n }\n }\n\n protected persistToLocalStorage(state: Record<string, unknown> | null): void {\n if (!this._viewUUID || state === null) {\n return;\n }\n try {\n const oldKey = findStorageKey(this._viewUUID);\n if (oldKey) {\n localStorage.removeItem(oldKey);\n }\n const newKey = `${STORAGE_PREFIX}${Date.now()}:${this._viewUUID}`;\n localStorage.setItem(newKey, JSON.stringify(state));\n const keys: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(STORAGE_PREFIX)) {\n keys.push(key);\n }\n }\n if (keys.length <= MAX_STORAGE_ENTRIES) {\n return;\n }\n keys.sort();\n const toRemove = keys.slice(0, keys.length - MAX_STORAGE_ENTRIES);\n for (const key of toRemove) {\n localStorage.removeItem(key);\n }\n } catch (err) {\n console.error(err);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"adaptor.js","sourceRoot":"","sources":["../../../src/web/bridges/adaptor.ts"],"names":[],"mappings":"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","sourcesContent":["import { ResultSchema } from \"@modelcontextprotocol/core\";\nimport type { App } from \"@modelcontextprotocol/ext-apps\";\nimport * as z from \"zod/v4\";\nimport { warnOnLargeViewState } from \"../../context-warnings.js\";\nimport { AppsSdkBridge } from \"./apps-sdk/bridge.js\";\nimport type { AppsSdkWidgetState } from \"./apps-sdk/types.js\";\nimport { McpAppBridge } from \"./mcp-app/bridge.js\";\nimport type {\n Adaptor,\n AnyViewToolHandler,\n CallToolOptions,\n CallToolResponse,\n DownloadParams,\n DownloadResult,\n FileMetadata,\n FileResource,\n FileResourceContent,\n FileResourceWriteResult,\n FollowUpMessage,\n HostContext,\n HostContextStore,\n ModelContextParams,\n OpenExternalOptions,\n RequestDisplayMode,\n RequestModalOptions,\n RequestSizeOptions,\n ResourceRepresentation,\n SendFollowUpMessageOptions,\n SetViewStateAction,\n UploadFileOptions,\n ViewToolConfig,\n} from \"./types.js\";\nimport { NotSupportedError } from \"./types.js\";\n\nconst ResourceMetaSchema = z.object({\n writable: z.boolean().optional(),\n etag: z.string().optional(),\n});\n\nconst WriteResultSchema = z.discriminatedUnion(\"outcome\", [\n z.object({ outcome: z.enum([\"saved\", \"conflict\"]), etag: z.string() }),\n z.object({ outcome: z.literal(\"too-large\"), maxBytes: z.number() }),\n]);\n\nconst STORAGE_PREFIX = \"sb:\";\nconst MAX_STORAGE_ENTRIES = 200;\n\nfunction isImage(mimeType: string | undefined): boolean {\n return mimeType?.startsWith(\"image/\") ?? false;\n}\n\nfunction findStorageKey(viewUUID: string): string | undefined {\n const suffix = `:${viewUUID}`;\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(STORAGE_PREFIX) && key.endsWith(suffix)) {\n return key;\n }\n }\n return undefined;\n}\n\n/**\n * @internal\n * Single composite implementation of {@link Adaptor}. Composes the MCP App\n * bridge (always present) with an optional `window.openai` overlay. Per-method\n * routing rules are encoded inline.\n */\nexport class HostAdaptor implements Adaptor {\n private static instance: HostAdaptor | null = null;\n\n static getInstance(): HostAdaptor {\n if (!HostAdaptor.instance) {\n HostAdaptor.instance = new HostAdaptor();\n }\n return HostAdaptor.instance;\n }\n\n static resetInstance(): void {\n HostAdaptor.instance?.cleanup();\n HostAdaptor.instance = null;\n }\n\n private readonly mcp: McpAppBridge;\n private readonly openai: typeof window.openai | null = null;\n\n private readonly stores: { [K in keyof HostContext]: HostContextStore<K> };\n\n private _viewState: HostContext[\"viewState\"] = null;\n private readonly viewStateListeners = new Set<() => void>();\n private _viewUUID: string | null = null;\n private _modelContext: ModelContextParams | null = null;\n private readonly resourceListeners = new Map<string, Set<() => void>>();\n private resourceApp?: Promise<App | undefined>;\n\n private _polyfillDisplay: HostContext[\"display\"] = { mode: \"inline\" };\n private readonly polyfillDisplayListeners = new Set<() => void>();\n\n private readonly polyfillDisplayStore: HostContextStore<\"display\">;\n private readonly polyfillViewStateStore: HostContextStore<\"viewState\">;\n\n private unsubscribeViewUUID: (() => void) | null = null;\n private unsubscribeModelContext: (() => void) | null = null;\n\n constructor() {\n this.mcp = McpAppBridge.getInstance();\n\n let overlayStores: ReturnType<AppsSdkBridge[\"createOverlayStores\"]> | null =\n null;\n if (typeof window !== \"undefined\" && window.openai !== undefined) {\n this.openai = window.openai;\n overlayStores = AppsSdkBridge.getInstance().createOverlayStores();\n }\n\n // Built once so that getHostContextStore returns stable references — required\n // by useSyncExternalStore to avoid resubscribing on every render.\n this.polyfillDisplayStore = {\n subscribe: (onChange: () => void) => {\n this.polyfillDisplayListeners.add(onChange);\n return () => {\n this.polyfillDisplayListeners.delete(onChange);\n };\n },\n getSnapshot: () => this._polyfillDisplay,\n };\n this.polyfillViewStateStore = {\n subscribe: (onChange: () => void) => {\n this.viewStateListeners.add(onChange);\n return () => {\n this.viewStateListeners.delete(onChange);\n };\n },\n getSnapshot: () => this._viewState,\n };\n\n this.stores = {\n ...this.mcp.createContextStores(),\n display: overlayStores?.display ?? this.polyfillDisplayStore,\n viewState: overlayStores?.viewState ?? this.polyfillViewStateStore,\n };\n\n this.subscribeToViewUUID();\n this.unsubscribeModelContext = this.mcp.subscribe(\"openai/modelContext\")(\n () => {\n if (this.mcp.getSnapshot(\"openai/modelContext\") === null) {\n this._modelContext = null;\n }\n },\n );\n }\n\n /** @internal Release any subscriptions held on the underlying bridges. */\n public cleanup(): void {\n this.unsubscribeViewUUID?.();\n this.unsubscribeViewUUID = null;\n this.unsubscribeModelContext?.();\n this.unsubscribeModelContext = null;\n }\n\n // ---- Adaptor interface ----\n\n public getHostContextStore = <K extends keyof HostContext>(\n key: K,\n ): HostContextStore<K> => this.stores[key];\n\n public callTool = async <\n ToolArgs extends Record<string, unknown> | null = null,\n ToolResponse extends CallToolResponse = CallToolResponse,\n >(\n name: string,\n args: ToolArgs,\n options?: CallToolOptions,\n ): Promise<ToolResponse> => {\n const timeout = options?.timeout;\n if (timeout !== undefined && (!Number.isFinite(timeout) || timeout <= 0)) {\n throw new RangeError(\n \"Tool call timeout must be a positive, finite number of milliseconds.\",\n );\n }\n const app = await this.mcp.getApp();\n const params = { name, arguments: args ?? undefined };\n const response = await app.callServerTool(params, { timeout });\n return {\n content: response.content,\n structuredContent: response.structuredContent ?? {},\n isError: response.isError ?? false,\n meta: response._meta ?? {},\n } as ToolResponse;\n };\n\n public registerViewTool = (\n config: ViewToolConfig,\n handler: AnyViewToolHandler,\n ): (() => void) => {\n return this.mcp.registerViewTool(config, handler);\n };\n\n public requestDisplayMode = async (mode: RequestDisplayMode) => {\n const app = await this.mcp.getApp();\n return app.requestDisplayMode({ mode });\n };\n\n public requestClose = async (): Promise<void> => {\n if (this.openai) {\n await this.openai.requestClose();\n }\n const app = await this.mcp.getApp();\n await app.requestTeardown();\n };\n\n public requestSize = async (size: RequestSizeOptions): Promise<void> => {\n const app = await this.mcp.getApp();\n await app.sendSizeChanged(size);\n };\n\n public sendFollowUpMessage = async (\n prompt: FollowUpMessage,\n options?: SendFollowUpMessageOptions,\n ): Promise<void> => {\n const target = options?.target;\n if (this.openai && typeof prompt === \"string\" && target !== \"new\") {\n await this.openai.sendFollowUpMessage({\n prompt,\n scrollToBottom: options?.scrollToBottom,\n });\n return;\n }\n const app = await this.mcp.getApp();\n if (\n target === \"new\" &&\n !app.getHostCapabilities()?.experimental?.[\"openai/message\"]\n ) {\n throw new NotSupportedError(\n \"sendFollowUpMessage\",\n \"the host does not advertise openai/message, so it can't open a new conversation\",\n );\n }\n const result = await app.sendMessage({\n role: \"user\",\n content:\n typeof prompt === \"string\" ? [{ type: \"text\", text: prompt }] : prompt,\n ...(target === \"new\" && { _meta: { \"openai/message\": { target } } }),\n });\n if (result?.isError) {\n throw new Error(\"The host rejected the follow-up message.\");\n }\n };\n\n public openExternal = (href: string, options?: OpenExternalOptions): void => {\n if (this.openai) {\n this.openai.openExternal({ href, ...options });\n return;\n }\n this.mcp\n .getApp()\n .then((app) => app.openLink({ url: href }))\n .catch((err) => {\n console.error(\"Failed to open external link:\", err);\n });\n };\n\n public download = async (params: DownloadParams): Promise<DownloadResult> => {\n const app = await this.mcp.getApp();\n if (!app.getHostCapabilities()?.downloadFile) {\n console.error(\n \"[skybridge] download: host does not support ui/download-file\",\n );\n return { isError: true };\n }\n return app.downloadFile(params);\n };\n\n public setViewState = async (\n stateOrUpdater: SetViewStateAction,\n ): Promise<void> => {\n if (this.openai) {\n const modelContent =\n typeof stateOrUpdater === \"function\"\n ? stateOrUpdater(this.openai.widgetState?.modelContent ?? null)\n : stateOrUpdater;\n warnOnLargeViewState(modelContent, \"setWidgetState\");\n await this.openai.setWidgetState({\n privateContent: {},\n ...this.openai.widgetState,\n modelContent,\n });\n return;\n }\n\n const newState =\n typeof stateOrUpdater === \"function\"\n ? stateOrUpdater(this._viewState)\n : stateOrUpdater;\n warnOnLargeViewState(newState, \"setViewState\");\n\n // update local state immediately so successive calls see fresh state\n this._viewState = newState;\n this.viewStateListeners.forEach((l) => {\n l();\n });\n\n this.persistToLocalStorage(newState);\n\n try {\n await this.sendModelContext();\n } catch (error) {\n console.error(\"Failed to update view state in MCP App.\", error);\n }\n };\n\n public updateModelContext = async (\n params: ModelContextParams,\n ): Promise<string | undefined> => {\n const app = await this.mcp.getApp();\n const capabilities = app.getHostCapabilities();\n if (\n !capabilities?.updateModelContext &&\n !capabilities?.experimental?.[\"openai/modelContext\"]\n ) {\n throw new NotSupportedError(\n \"updateModelContext\",\n \"the host does not advertise updateModelContext\",\n );\n }\n const previous = this._modelContext;\n this._modelContext = params;\n const result = await this.sendModelContext().catch((error: unknown) => {\n if (this._modelContext === params) {\n this._modelContext = previous;\n }\n throw error;\n });\n const parsed = z\n .object({ updateId: z.string() })\n .safeParse(result._meta?.[\"openai/modelContext\"]);\n return parsed.success ? parsed.data.updateId : undefined;\n };\n\n private async sendModelContext() {\n const viewState = this.openai ? null : this._viewState;\n const extra = this._modelContext;\n const collisions = Object.keys(extra?.structuredContent ?? {}).filter(\n (key) => viewState !== null && key in viewState,\n );\n if (collisions.length > 0) {\n console.warn(\n `skybridge: view state overrides model context keys ${collisions.join(\", \")}.`,\n );\n }\n const structuredContent = { ...extra?.structuredContent, ...viewState };\n const app = await this.mcp.getApp();\n return app.updateModelContext({\n ...(Object.keys(structuredContent).length > 0 && { structuredContent }),\n content: [\n ...(viewState === null\n ? []\n : [\n {\n type: \"text\" as const,\n text: JSON.stringify(viewState),\n annotations: { audience: [\"assistant\" as const] },\n },\n ]),\n ...(extra?.content ?? []),\n ],\n });\n }\n\n public openFile = async (path: string): Promise<void> => {\n const app = await this.mcp.getApp();\n if (!app.getHostCapabilities()?.experimental?.[\"openai/files\"]) {\n throw new NotSupportedError(\n \"openFile\",\n \"the host does not advertise openai/files\",\n );\n }\n await app.request(\n { method: \"openai/files/open\", params: { path } },\n ResultSchema,\n );\n };\n\n public readResource = async (\n uri: string,\n representation?: ResourceRepresentation,\n ): Promise<FileResource> => {\n const app = await this.mcp.getApp();\n const { contents } = await app.readServerResource({\n uri,\n ...(representation && {\n _meta: { \"openai/resource\": { representation } },\n }),\n });\n const item = contents.find((content) => content.uri === uri) ?? contents[0];\n if (!item) {\n throw new Error(`The host returned no contents for ${uri}.`);\n }\n const { data: meta } = ResourceMetaSchema.safeParse(\n item._meta?.[\"openai/resource\"],\n );\n return {\n ...(\"text\" in item ? { text: item.text } : { blob: item.blob }),\n mimeType: item.mimeType,\n writable: meta?.writable ?? false,\n etag: meta?.etag,\n };\n };\n\n public watchResource = (uri: string, onUpdate: () => void): (() => void) => {\n const listeners = this.resourceListeners.get(uri) ?? new Set<() => void>();\n if (listeners.size === 0) {\n this.resourceListeners.set(uri, listeners);\n this.getResourceApp()\n .then((app) =>\n app?.request(\n { method: \"resources/subscribe\", params: { uri } },\n ResultSchema,\n ),\n )\n .catch((error: unknown) => {\n console.warn(`Failed to subscribe to ${uri}.`, error);\n });\n }\n listeners.add(onUpdate);\n return () => {\n if (listeners.delete(onUpdate) && listeners.size === 0) {\n this.resourceListeners.delete(uri);\n this.getResourceApp()\n .then((app) =>\n app?.request(\n { method: \"resources/unsubscribe\", params: { uri } },\n ResultSchema,\n ),\n )\n .catch(() => {});\n }\n };\n };\n\n public writeResource = async (\n uri: string,\n content: FileResourceContent,\n ifMatch?: string,\n ): Promise<FileResourceWriteResult> => {\n const app = await this.getResourceApp();\n if (!app) {\n throw new NotSupportedError(\n \"writeResource\",\n \"the host does not advertise openai/resource\",\n );\n }\n return app.request(\n {\n method: \"openai/resources/write\",\n params: { uri, ...content, ...(ifMatch && { ifMatch }) },\n },\n WriteResultSchema,\n );\n };\n\n private getResourceApp(): Promise<App | undefined> {\n this.resourceApp ??= this.mcp.getApp().then((app) => {\n if (!app.getHostCapabilities()?.experimental?.[\"openai/resource\"]) {\n return undefined;\n }\n app.setNotificationHandler(\n \"notifications/resources/updated\",\n ({ params }) => {\n this.resourceListeners.get(params.uri)?.forEach((l) => {\n l();\n });\n },\n );\n return app;\n });\n return this.resourceApp;\n }\n\n public uploadFile = async (\n file: File,\n options?: UploadFileOptions,\n ): Promise<FileMetadata> => {\n if (!this.openai) {\n throw new NotSupportedError(\"uploadFile\");\n }\n if (!this.openai.uploadFile) {\n throw new NotSupportedError(\n \"uploadFile\",\n \"not available on the current host version\",\n );\n }\n const metadata = await this.openai.uploadFile(file, options);\n if (isImage(metadata.mimeType ?? file.type)) {\n await this.trackFileIds(metadata.fileId);\n }\n return metadata;\n };\n\n public getFileDownloadUrl = (\n file: FileMetadata,\n ): Promise<{ downloadUrl: string }> => {\n if (!this.openai) {\n return Promise.reject(new NotSupportedError(\"getFileDownloadUrl\"));\n }\n if (!this.openai.getFileDownloadUrl) {\n return Promise.reject(\n new NotSupportedError(\n \"getFileDownloadUrl\",\n \"not available on the current host version\",\n ),\n );\n }\n return this.openai.getFileDownloadUrl(file);\n };\n\n public selectFiles = async (): Promise<FileMetadata[]> => {\n if (!this.openai) {\n throw new NotSupportedError(\"selectFiles\");\n }\n if (!this.openai.selectFiles) {\n throw new NotSupportedError(\n \"selectFiles\",\n \"not available on the current host version\",\n );\n }\n const files = await this.openai.selectFiles();\n const imageIds: string[] = [];\n for (const file of files) {\n if (isImage(file.mimeType)) {\n imageIds.push(file.fileId);\n }\n }\n if (imageIds.length > 0) {\n await this.trackFileIds(...imageIds);\n }\n return files;\n };\n\n public openModal = (options: RequestModalOptions): void => {\n if (this.openai) {\n this.openai.requestModal(options);\n return;\n }\n this._polyfillDisplay = { mode: \"modal\", params: options.params };\n this.polyfillDisplayListeners.forEach((l) => {\n l();\n });\n };\n\n public setOpenInAppUrl = (href: string): Promise<void> => {\n if (!this.openai) {\n return Promise.reject(new NotSupportedError(\"setOpenInAppUrl\"));\n }\n const trimmed = href.trim();\n if (!trimmed) {\n return Promise.reject(new Error(\"The href parameter is required.\"));\n }\n return this.openai.setOpenInAppUrl({ href: trimmed });\n };\n\n public closeModal = (): void => {\n if (this.openai) {\n return; // host owns modal lifecycle\n }\n this._polyfillDisplay = { mode: \"inline\" };\n this.polyfillDisplayListeners.forEach((l) => {\n l();\n });\n };\n\n private async trackFileIds(...fileIds: string[]): Promise<void> {\n if (!this.openai) {\n return;\n }\n const current = this.openai.widgetState;\n const state: AppsSdkWidgetState = current\n ? { ...current }\n : { modelContent: {}, privateContent: {} };\n if (!state.imageIds) {\n state.imageIds = [];\n }\n state.imageIds.push(...fileIds);\n await this.openai.setWidgetState(state);\n }\n\n // ---- viewState persistence helpers ----\n\n private subscribeToViewUUID(): void {\n this.unsubscribeViewUUID = this.mcp.subscribe(\"toolResult\")(() => {\n const toolResult = this.mcp.getSnapshot(\"toolResult\");\n const viewUUID = (\n toolResult?._meta as Record<string, unknown> | undefined\n )?.viewUUID as string | undefined;\n if (viewUUID && viewUUID !== this._viewUUID) {\n this._viewUUID = viewUUID;\n this.restoreFromLocalStorage(viewUUID);\n }\n });\n }\n\n private restoreFromLocalStorage(viewUUID: string): void {\n try {\n const existingKey = findStorageKey(viewUUID);\n if (existingKey) {\n const stored = localStorage.getItem(existingKey);\n if (stored !== null) {\n this._viewState = JSON.parse(stored);\n this.viewStateListeners.forEach((l) => {\n l();\n });\n }\n }\n } catch (err) {\n console.error(err);\n }\n }\n\n protected persistToLocalStorage(state: Record<string, unknown> | null): void {\n if (!this._viewUUID || state === null) {\n return;\n }\n try {\n const oldKey = findStorageKey(this._viewUUID);\n if (oldKey) {\n localStorage.removeItem(oldKey);\n }\n const newKey = `${STORAGE_PREFIX}${Date.now()}:${this._viewUUID}`;\n localStorage.setItem(newKey, JSON.stringify(state));\n const keys: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(STORAGE_PREFIX)) {\n keys.push(key);\n }\n }\n if (keys.length <= MAX_STORAGE_ENTRIES) {\n return;\n }\n keys.sort();\n const toRemove = keys.slice(0, keys.length - MAX_STORAGE_ENTRIES);\n for (const key of toRemove) {\n localStorage.removeItem(key);\n }\n } catch (err) {\n console.error(err);\n }\n }\n}\n"]}
@@ -1,13 +1,17 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { VIEW_STATE_WARNING_TOKENS } from "../../context-warnings.js";
2
3
  import { HostAdaptor } from "./adaptor.js";
3
4
  import { AppsSdkBridge } from "./apps-sdk/bridge.js";
4
5
  import { McpAppBridge } from "./mcp-app/bridge.js";
5
6
  import { NotSupportedError } from "./types.js";
7
+ function stubApp(adaptor, app) {
8
+ adaptor.mcp.getApp = () => Promise.resolve(app);
9
+ }
6
10
  describe("HostAdaptor", () => {
7
11
  beforeEach(() => {
8
12
  McpAppBridge.resetInstance();
9
13
  AppsSdkBridge.resetInstance();
10
- vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
14
+ vi.stubGlobal("skybridge", {});
11
15
  vi.stubGlobal("parent", { postMessage: vi.fn() });
12
16
  localStorage.clear();
13
17
  });
@@ -34,7 +38,7 @@ describe("HostAdaptor", () => {
34
38
  expect(fakeApp.callServerTool).toHaveBeenCalledWith({
35
39
  name: "greet",
36
40
  arguments: { name: "alice" },
37
- });
41
+ }, { timeout: undefined });
38
42
  expect(result.structuredContent).toEqual({ ok: true });
39
43
  expect(result.meta).toEqual({ x: 1 });
40
44
  });
@@ -51,7 +55,7 @@ describe("HostAdaptor", () => {
51
55
  expect(r.isError).toBe(true);
52
56
  expect(fakeApp.downloadFile).not.toHaveBeenCalled();
53
57
  });
54
- it("sendFollowUpMessage routes to window.openai only when scrollToBottom is set", async () => {
58
+ it("sendFollowUpMessage uses window.openai for plain text and ui/message for content blocks or a target", async () => {
55
59
  const sendFollowUpMessage = vi.fn().mockResolvedValue(undefined);
56
60
  vi.stubGlobal("openai", { sendFollowUpMessage });
57
61
  let adaptor = new HostAdaptor();
@@ -66,13 +70,43 @@ describe("HostAdaptor", () => {
66
70
  vi.stubGlobal("openai", undefined);
67
71
  adaptor = new HostAdaptor();
68
72
  const sendMessage = vi.fn().mockResolvedValue(undefined);
69
- // biome-ignore lint/suspicious/noExplicitAny: test seam
70
- adaptor.mcp.getApp = vi.fn().mockResolvedValue({ sendMessage });
73
+ const getHostCapabilities = () => ({
74
+ experimental: { "openai/message": {} },
75
+ });
76
+ stubApp(adaptor, { sendMessage });
71
77
  await adaptor.sendFollowUpMessage("hi");
72
78
  expect(sendMessage).toHaveBeenCalledWith({
73
79
  role: "user",
74
80
  content: [{ type: "text", text: "hi" }],
75
81
  });
82
+ McpAppBridge.resetInstance();
83
+ AppsSdkBridge.resetInstance();
84
+ vi.stubGlobal("openai", { sendFollowUpMessage });
85
+ adaptor = new HostAdaptor();
86
+ stubApp(adaptor, { sendMessage, getHostCapabilities });
87
+ const item = {
88
+ type: "text",
89
+ text: "M6 hex bolt",
90
+ _meta: { "openai/title": "Hex bolt" },
91
+ };
92
+ await adaptor.sendFollowUpMessage([item], { target: "new" });
93
+ expect(sendMessage).toHaveBeenLastCalledWith({
94
+ role: "user",
95
+ content: [item],
96
+ _meta: { "openai/message": { target: "new" } },
97
+ });
98
+ expect(sendFollowUpMessage).toHaveBeenCalledTimes(1);
99
+ });
100
+ it("openFile sends openai/files/open only on hosts advertising openai/files", async () => {
101
+ const adaptor = new HostAdaptor();
102
+ const request = vi.fn().mockResolvedValue({});
103
+ let capabilities = {};
104
+ stubApp(adaptor, { request, getHostCapabilities: () => capabilities });
105
+ await expect(adaptor.openFile("/tmp/part.stl")).rejects.toThrow("openai/files");
106
+ expect(request).not.toHaveBeenCalled();
107
+ capabilities = { experimental: { "openai/files": {} } };
108
+ await adaptor.openFile("/tmp/part.stl");
109
+ expect(request).toHaveBeenCalledWith({ method: "openai/files/open", params: { path: "/tmp/part.stl" } }, expect.anything());
76
110
  });
77
111
  it("openExternal routes to window.openai only when redirectUrl: false", async () => {
78
112
  const openExternal = vi.fn();
@@ -103,19 +137,52 @@ describe("HostAdaptor", () => {
103
137
  await expect(adaptor.getFileDownloadUrl({ fileId: "x" })).rejects.toThrow(NotSupportedError);
104
138
  await expect(adaptor.setOpenInAppUrl("https://x")).rejects.toThrow(NotSupportedError);
105
139
  });
140
+ it("file methods throw NotSupportedError when window.openai lacks them", async () => {
141
+ vi.stubGlobal("openai", {});
142
+ const adaptor = new HostAdaptor();
143
+ const uploadError = await adaptor
144
+ .uploadFile(new File([], "x"))
145
+ .catch((e) => e);
146
+ expect(uploadError).toBeInstanceOf(NotSupportedError);
147
+ expect(uploadError.method).toBe("uploadFile");
148
+ const downloadError = await adaptor
149
+ .getFileDownloadUrl({ fileId: "x" })
150
+ .catch((e) => e);
151
+ expect(downloadError).toBeInstanceOf(NotSupportedError);
152
+ expect(downloadError.method).toBe("getFileDownloadUrl");
153
+ const selectError = await adaptor.selectFiles().catch((e) => e);
154
+ expect(selectError).toBeInstanceOf(NotSupportedError);
155
+ expect(selectError.method).toBe("selectFiles");
156
+ });
106
157
  it("uploadFile delegates to window.openai.uploadFile and tracks fileId in widgetState", async () => {
107
158
  const setWidgetState = vi.fn().mockResolvedValue(undefined);
108
- const uploadFile = vi
109
- .fn()
110
- .mockResolvedValue({ fileId: "abc", fileName: "x" });
159
+ const uploadFile = vi.fn().mockResolvedValue({
160
+ fileId: "abc",
161
+ fileName: "x",
162
+ mimeType: "image/png",
163
+ });
111
164
  vi.stubGlobal("openai", { uploadFile, setWidgetState, widgetState: null });
112
165
  const adaptor = new HostAdaptor();
113
- const file = new File([], "x");
166
+ const file = new File([], "x", { type: "image/png" });
114
167
  const r = await adaptor.uploadFile(file, { library: true });
115
168
  expect(uploadFile).toHaveBeenCalledWith(file, { library: true });
116
169
  expect(r.fileId).toBe("abc");
117
170
  expect(setWidgetState).toHaveBeenCalledWith(expect.objectContaining({ imageIds: ["abc"] }));
118
171
  });
172
+ it("uploadFile does not track a non-image fileId in widgetState.imageIds", async () => {
173
+ const setWidgetState = vi.fn().mockResolvedValue(undefined);
174
+ const uploadFile = vi.fn().mockResolvedValue({
175
+ fileId: "sediment://file_txt",
176
+ fileName: "notes.txt",
177
+ mimeType: "text/plain",
178
+ });
179
+ vi.stubGlobal("openai", { uploadFile, setWidgetState, widgetState: null });
180
+ const adaptor = new HostAdaptor();
181
+ await adaptor.uploadFile(new File([], "notes.txt", { type: "text/plain" }));
182
+ for (const call of setWidgetState.mock.calls) {
183
+ expect(call[0].imageIds ?? []).not.toContain("sediment://file_txt");
184
+ }
185
+ });
119
186
  it("setViewState uses window.openai.setWidgetState when present", async () => {
120
187
  const setWidgetState = vi.fn().mockResolvedValue(undefined);
121
188
  vi.stubGlobal("openai", { setWidgetState, widgetState: null });
@@ -123,6 +190,17 @@ describe("HostAdaptor", () => {
123
190
  await adaptor.setViewState({ count: 1 });
124
191
  expect(setWidgetState).toHaveBeenCalledWith(expect.objectContaining({ modelContent: { count: 1 } }));
125
192
  });
193
+ it("warns when setViewState reaches 20K tokens", async () => {
194
+ const setWidgetState = vi.fn().mockResolvedValue(undefined);
195
+ vi.stubGlobal("openai", { setWidgetState, widgetState: null });
196
+ const adaptor = new HostAdaptor();
197
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
198
+ await adaptor.setViewState({
199
+ longText: "x".repeat(VIEW_STATE_WARNING_TOKENS * 4),
200
+ });
201
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("setWidgetState is persisting"));
202
+ warnSpy.mockRestore();
203
+ });
126
204
  it("setViewState falls back to MCP updateModelContext + localStorage when window.openai is absent", async () => {
127
205
  vi.stubGlobal("openai", undefined);
128
206
  const adaptor = new HostAdaptor();
@@ -136,7 +214,13 @@ describe("HostAdaptor", () => {
136
214
  await adaptor.setViewState({ count: 2 });
137
215
  expect(updateModelContext).toHaveBeenCalledWith({
138
216
  structuredContent: { count: 2 },
139
- content: [{ type: "text", text: JSON.stringify({ count: 2 }) }],
217
+ content: [
218
+ {
219
+ type: "text",
220
+ text: JSON.stringify({ count: 2 }),
221
+ annotations: { audience: ["assistant"] },
222
+ },
223
+ ],
140
224
  });
141
225
  const keys = [];
142
226
  for (let i = 0; i < localStorage.length; i++) {
@@ -169,7 +253,7 @@ describe("HostAdaptor", () => {
169
253
  // biome-ignore lint/suspicious/noExplicitAny: test seam
170
254
  expect(adaptor._polyfillDisplay).toEqual({ mode: "inline" });
171
255
  });
172
- it("getHostContextStore: display/viewState route to Apps SDK overlay when present, MCP otherwise", () => {
256
+ it("getHostContextStore: display/viewState route to ChatGPT overlay when present, MCP otherwise", () => {
173
257
  vi.stubGlobal("openai", {
174
258
  view: { mode: "fullscreen" },
175
259
  widgetState: { modelContent: { count: 5 }, privateContent: {} },