skybridge 0.0.0-dev.94c22d0 → 0.0.0-dev.9520814

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 (330) hide show
  1. package/README.md +9 -7
  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/resolve-skybridge-config.d.ts +5 -0
  14. package/dist/cli/{resolve-views-dir.js → resolve-skybridge-config.js} +4 -3
  15. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  16. package/dist/cli/run-plain.js +2 -1
  17. package/dist/cli/run-plain.js.map +1 -1
  18. package/dist/cli/telemetry.js +2 -0
  19. package/dist/cli/telemetry.js.map +1 -1
  20. package/dist/cli/use-nodemon.d.ts +11 -1
  21. package/dist/cli/use-nodemon.js +31 -9
  22. package/dist/cli/use-nodemon.js.map +1 -1
  23. package/dist/cli/use-typescript-check.js +1 -1
  24. package/dist/cli/use-typescript-check.js.map +1 -1
  25. package/dist/commands/dev.js +6 -6
  26. package/dist/commands/dev.js.map +1 -1
  27. package/dist/commands/start.js +2 -2
  28. package/dist/commands/start.js.map +1 -1
  29. package/dist/context-warnings.d.ts +5 -0
  30. package/dist/context-warnings.js +31 -0
  31. package/dist/context-warnings.js.map +1 -0
  32. package/dist/context-warnings.test.js +28 -0
  33. package/dist/context-warnings.test.js.map +1 -0
  34. package/dist/server/app.d.ts +194 -0
  35. package/dist/server/app.js +266 -0
  36. package/dist/server/app.js.map +1 -0
  37. package/dist/server/app.test.js +97 -0
  38. package/dist/server/app.test.js.map +1 -0
  39. package/dist/server/auth/discovery.d.ts +2 -1
  40. package/dist/server/auth/discovery.js +2 -2
  41. package/dist/server/auth/discovery.js.map +1 -1
  42. package/dist/server/auth/index.d.ts +35 -5
  43. package/dist/server/auth/index.js.map +1 -1
  44. package/dist/server/auth/providers/auth0.d.ts +25 -3
  45. package/dist/server/auth/providers/auth0.js +13 -8
  46. package/dist/server/auth/providers/auth0.js.map +1 -1
  47. package/dist/server/auth/providers/auth0.test.js +5 -3
  48. package/dist/server/auth/providers/auth0.test.js.map +1 -1
  49. package/dist/server/auth/providers/authplane.d.ts +49 -0
  50. package/dist/server/auth/providers/authplane.js +57 -0
  51. package/dist/server/auth/providers/authplane.js.map +1 -0
  52. package/dist/server/auth/providers/authplane.test.js +143 -0
  53. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  54. package/dist/server/auth/providers/clerk.d.ts +40 -3
  55. package/dist/server/auth/providers/clerk.js +4 -1
  56. package/dist/server/auth/providers/clerk.js.map +1 -1
  57. package/dist/server/auth/providers/clerk.test.js +5 -3
  58. package/dist/server/auth/providers/clerk.test.js.map +1 -1
  59. package/dist/server/auth/providers/custom.d.ts +24 -6
  60. package/dist/server/auth/providers/custom.js +33 -11
  61. package/dist/server/auth/providers/custom.js.map +1 -1
  62. package/dist/server/auth/providers/custom.test.js +71 -17
  63. package/dist/server/auth/providers/custom.test.js.map +1 -1
  64. package/dist/server/auth/providers/descope.d.ts +32 -3
  65. package/dist/server/auth/providers/descope.js +13 -2
  66. package/dist/server/auth/providers/descope.js.map +1 -1
  67. package/dist/server/auth/providers/descope.test.js +42 -17
  68. package/dist/server/auth/providers/descope.test.js.map +1 -1
  69. package/dist/server/auth/providers/stytch.d.ts +16 -3
  70. package/dist/server/auth/providers/stytch.js +4 -1
  71. package/dist/server/auth/providers/stytch.js.map +1 -1
  72. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  73. package/dist/server/auth/providers/verify-spy.js +21 -0
  74. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  75. package/dist/server/auth/providers/workos.d.ts +28 -5
  76. package/dist/server/auth/providers/workos.js +6 -2
  77. package/dist/server/auth/providers/workos.js.map +1 -1
  78. package/dist/server/auth/security-schemes.d.ts +23 -0
  79. package/dist/server/auth/security-schemes.js +64 -0
  80. package/dist/server/auth/security-schemes.js.map +1 -0
  81. package/dist/server/auth/security-schemes.test.js +99 -0
  82. package/dist/server/auth/security-schemes.test.js.map +1 -0
  83. package/dist/server/auth/setup.d.ts +3 -1
  84. package/dist/server/auth/setup.js +66 -26
  85. package/dist/server/auth/setup.js.map +1 -1
  86. package/dist/server/auth/setup.test.js +349 -20
  87. package/dist/server/auth/setup.test.js.map +1 -1
  88. package/dist/server/auth/verify.d.ts +42 -6
  89. package/dist/server/auth/verify.js +27 -3
  90. package/dist/server/auth/verify.js.map +1 -1
  91. package/dist/server/auth/verify.test.js +65 -0
  92. package/dist/server/auth/verify.test.js.map +1 -1
  93. package/dist/server/auth-extra.test-d.js +130 -0
  94. package/dist/server/auth-extra.test-d.js.map +1 -0
  95. package/dist/server/auth.d.ts +43 -6
  96. package/dist/server/auth.js +4 -5
  97. package/dist/server/auth.js.map +1 -1
  98. package/dist/server/build-manifest.test.js +7 -6
  99. package/dist/server/build-manifest.test.js.map +1 -1
  100. package/dist/server/content-helpers.d.ts +1 -1
  101. package/dist/server/content-helpers.js.map +1 -1
  102. package/dist/server/express.d.ts +23 -3
  103. package/dist/server/express.js +38 -32
  104. package/dist/server/express.js.map +1 -1
  105. package/dist/server/express.test.js +220 -103
  106. package/dist/server/express.test.js.map +1 -1
  107. package/dist/server/file-ref.d.ts +1 -1
  108. package/dist/server/file-ref.js +1 -1
  109. package/dist/server/file-ref.js.map +1 -1
  110. package/dist/server/host.d.ts +2 -0
  111. package/dist/server/host.js +11 -0
  112. package/dist/server/host.js.map +1 -0
  113. package/dist/server/host.test.d.ts +1 -0
  114. package/dist/server/host.test.js +13 -0
  115. package/dist/server/host.test.js.map +1 -0
  116. package/dist/server/index.d.ts +16 -9
  117. package/dist/server/index.js +9 -3
  118. package/dist/server/index.js.map +1 -1
  119. package/dist/server/mcp-errors.test.d.ts +1 -0
  120. package/dist/server/mcp-errors.test.js +41 -0
  121. package/dist/server/mcp-errors.test.js.map +1 -0
  122. package/dist/server/middleware.d.ts +35 -10
  123. package/dist/server/middleware.js +33 -0
  124. package/dist/server/middleware.js.map +1 -1
  125. package/dist/server/middleware.test-d.js +1 -1
  126. package/dist/server/middleware.test-d.js.map +1 -1
  127. package/dist/server/middleware.test.js +242 -134
  128. package/dist/server/middleware.test.js.map +1 -1
  129. package/dist/server/register-tool.test.d.ts +1 -0
  130. package/dist/server/register-tool.test.js +110 -0
  131. package/dist/server/register-tool.test.js.map +1 -0
  132. package/dist/server/server.d.ts +234 -120
  133. package/dist/server/server.js +262 -273
  134. package/dist/server/server.js.map +1 -1
  135. package/dist/server/skills-integration.test.d.ts +1 -0
  136. package/dist/server/skills-integration.test.js +86 -0
  137. package/dist/server/skills-integration.test.js.map +1 -0
  138. package/dist/server/skills.d.ts +27 -0
  139. package/dist/server/skills.js +188 -0
  140. package/dist/server/skills.js.map +1 -0
  141. package/dist/server/skills.test.d.ts +1 -0
  142. package/dist/server/skills.test.js +243 -0
  143. package/dist/server/skills.test.js.map +1 -0
  144. package/dist/server/templateHelper.d.ts +0 -3
  145. package/dist/server/templateHelper.js.map +1 -1
  146. package/dist/server/templates.generated.js +4 -8
  147. package/dist/server/templates.generated.js.map +1 -1
  148. package/dist/server/tool-extra.test.d.ts +1 -0
  149. package/dist/server/tool-extra.test.js +88 -0
  150. package/dist/server/tool-extra.test.js.map +1 -0
  151. package/dist/server/view-resource-resolution.test.js +18 -13
  152. package/dist/server/view-resource-resolution.test.js.map +1 -1
  153. package/dist/server/viewsDevServer.js +4 -1
  154. package/dist/server/viewsDevServer.js.map +1 -1
  155. package/dist/test/utils.d.ts +9 -11
  156. package/dist/test/utils.js +220 -201
  157. package/dist/test/utils.js.map +1 -1
  158. package/dist/test/view.test.js +44 -40
  159. package/dist/test/view.test.js.map +1 -1
  160. package/dist/views/index.d.ts +10 -0
  161. package/dist/views/index.js +3 -0
  162. package/dist/views/index.js.map +1 -0
  163. package/dist/{web/plugin → views}/scan-views.js +1 -1
  164. package/dist/views/scan-views.js.map +1 -0
  165. package/dist/views/scan-views.test.d.ts +1 -0
  166. package/dist/views/scan-views.test.js.map +1 -0
  167. package/dist/views/validate-view.d.ts +1 -0
  168. package/dist/{web/plugin → views}/validate-view.js +2 -2
  169. package/dist/views/validate-view.js.map +1 -0
  170. package/dist/views/validate-view.test.d.ts +1 -0
  171. package/dist/views/validate-view.test.js.map +1 -0
  172. package/dist/web/bridges/adaptor.d.ts +13 -3
  173. package/dist/web/bridges/adaptor.js +176 -30
  174. package/dist/web/bridges/adaptor.js.map +1 -1
  175. package/dist/web/bridges/adaptor.test.js +68 -12
  176. package/dist/web/bridges/adaptor.test.js.map +1 -1
  177. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +1 -1
  178. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +1 -1
  179. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  180. package/dist/web/bridges/get-adaptor.test.js +2 -2
  181. package/dist/web/bridges/get-adaptor.test.js.map +1 -1
  182. package/dist/web/bridges/mcp-app/bridge.d.ts +1 -1
  183. package/dist/web/bridges/mcp-app/bridge.js +15 -6
  184. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  185. package/dist/web/bridges/mcp-app/bridge.test.js +2 -2
  186. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -1
  187. package/dist/web/bridges/mcp-app/types.d.ts +19 -2
  188. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  189. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +2 -2
  190. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +1 -1
  191. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  192. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -1
  193. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  194. package/dist/web/bridges/mcp-app/view-tools.test.js +1 -1
  195. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -1
  196. package/dist/web/bridges/types.d.ts +76 -15
  197. package/dist/web/bridges/types.js.map +1 -1
  198. package/dist/web/create-store.test.js +2 -2
  199. package/dist/web/create-store.test.js.map +1 -1
  200. package/dist/web/data-llm.js +3 -2
  201. package/dist/web/data-llm.js.map +1 -1
  202. package/dist/web/data-llm.test.js +11 -4
  203. package/dist/web/data-llm.test.js.map +1 -1
  204. package/dist/web/generate-helpers.d.ts +23 -19
  205. package/dist/web/generate-helpers.js +21 -17
  206. package/dist/web/generate-helpers.js.map +1 -1
  207. package/dist/web/generate-helpers.test-d.js +3 -3
  208. package/dist/web/generate-helpers.test-d.js.map +1 -1
  209. package/dist/web/generate-helpers.test.js +2 -2
  210. package/dist/web/generate-helpers.test.js.map +1 -1
  211. package/dist/web/hooks/index.d.ts +6 -1
  212. package/dist/web/hooks/index.js +6 -1
  213. package/dist/web/hooks/index.js.map +1 -1
  214. package/dist/web/hooks/openai-extensions.test.d.ts +1 -0
  215. package/dist/web/hooks/openai-extensions.test.js +107 -0
  216. package/dist/web/hooks/openai-extensions.test.js.map +1 -0
  217. package/dist/web/hooks/test/utils.d.ts +2 -1
  218. package/dist/web/hooks/test/utils.js +1 -1
  219. package/dist/web/hooks/test/utils.js.map +1 -1
  220. package/dist/web/hooks/use-call-tool.d.ts +2 -2
  221. package/dist/web/hooks/use-call-tool.js +15 -10
  222. package/dist/web/hooks/use-call-tool.js.map +1 -1
  223. package/dist/web/hooks/use-call-tool.test.js +15 -4
  224. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  225. package/dist/web/hooks/use-deep-link.d.ts +22 -0
  226. package/dist/web/hooks/use-deep-link.js +34 -0
  227. package/dist/web/hooks/use-deep-link.js.map +1 -0
  228. package/dist/web/hooks/use-display-mode.d.ts +1 -1
  229. package/dist/web/hooks/use-display-mode.js +1 -1
  230. package/dist/web/hooks/use-display-mode.js.map +1 -1
  231. package/dist/web/hooks/use-display-mode.test.js +1 -1
  232. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  233. package/dist/web/hooks/use-download.d.ts +1 -3
  234. package/dist/web/hooks/use-download.js +1 -2
  235. package/dist/web/hooks/use-download.js.map +1 -1
  236. package/dist/web/hooks/use-download.test.js +7 -7
  237. package/dist/web/hooks/use-download.test.js.map +1 -1
  238. package/dist/web/hooks/use-file-resource.d.ts +37 -0
  239. package/dist/web/hooks/use-file-resource.js +101 -0
  240. package/dist/web/hooks/use-file-resource.js.map +1 -0
  241. package/dist/web/hooks/use-file-resource.test.d.ts +1 -0
  242. package/dist/web/hooks/use-file-resource.test.js +65 -0
  243. package/dist/web/hooks/use-file-resource.test.js.map +1 -0
  244. package/dist/web/hooks/use-files.test.js +1 -1
  245. package/dist/web/hooks/use-files.test.js.map +1 -1
  246. package/dist/web/hooks/use-host.d.ts +44 -0
  247. package/dist/web/hooks/use-host.js +45 -0
  248. package/dist/web/hooks/use-host.js.map +1 -0
  249. package/dist/web/hooks/use-host.test.d.ts +1 -0
  250. package/dist/web/hooks/use-host.test.js +59 -0
  251. package/dist/web/hooks/use-host.test.js.map +1 -0
  252. package/dist/web/hooks/use-model-context.d.ts +44 -0
  253. package/dist/web/hooks/use-model-context.js +63 -0
  254. package/dist/web/hooks/use-model-context.js.map +1 -0
  255. package/dist/web/hooks/use-open-external.test.js +2 -2
  256. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  257. package/dist/web/hooks/use-open-file.d.ts +19 -0
  258. package/dist/web/hooks/use-open-file.js +24 -0
  259. package/dist/web/hooks/use-open-file.js.map +1 -0
  260. package/dist/web/hooks/use-register-view-tool.d.ts +2 -3
  261. package/dist/web/hooks/use-register-view-tool.js.map +1 -1
  262. package/dist/web/hooks/use-request-close.test.js +1 -1
  263. package/dist/web/hooks/use-request-close.test.js.map +1 -1
  264. package/dist/web/hooks/use-request-modal.test.js +1 -1
  265. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  266. package/dist/web/hooks/use-request-size.d.ts +1 -1
  267. package/dist/web/hooks/use-request-size.js +1 -1
  268. package/dist/web/hooks/use-request-size.js.map +1 -1
  269. package/dist/web/hooks/use-request-size.test.js +1 -1
  270. package/dist/web/hooks/use-request-size.test.js.map +1 -1
  271. package/dist/web/hooks/use-send-follow-up-message.d.ts +8 -2
  272. package/dist/web/hooks/use-send-follow-up-message.js +6 -0
  273. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  274. package/dist/web/hooks/use-set-open-in-app-url.test.js +2 -8
  275. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  276. package/dist/web/hooks/use-tool-info.d.ts +1 -20
  277. package/dist/web/hooks/use-tool-info.js +0 -1
  278. package/dist/web/hooks/use-tool-info.js.map +1 -1
  279. package/dist/web/hooks/use-tool-info.test-d.js +0 -5
  280. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  281. package/dist/web/hooks/use-tool-info.test.js +2 -7
  282. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  283. package/dist/web/hooks/use-user.d.ts +3 -2
  284. package/dist/web/hooks/use-user.js +4 -3
  285. package/dist/web/hooks/use-user.js.map +1 -1
  286. package/dist/web/hooks/use-user.test.js +5 -3
  287. package/dist/web/hooks/use-user.test.js.map +1 -1
  288. package/dist/web/hooks/use-view-state.js +19 -9
  289. package/dist/web/hooks/use-view-state.js.map +1 -1
  290. package/dist/web/hooks/use-view-state.test.js +33 -2
  291. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  292. package/dist/web/hooks/use-viewport.d.ts +20 -0
  293. package/dist/web/hooks/use-viewport.js +21 -0
  294. package/dist/web/hooks/use-viewport.js.map +1 -0
  295. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  296. package/dist/web/hooks/{use-layout.test.js → use-viewport.test.js} +12 -32
  297. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  298. package/dist/web/mount-view.d.ts +3 -2
  299. package/dist/web/mount-view.js +5 -8
  300. package/dist/web/mount-view.js.map +1 -1
  301. package/package.json +21 -18
  302. package/dist/cli/resolve-views-dir.d.ts +0 -1
  303. package/dist/cli/resolve-views-dir.js.map +0 -1
  304. package/dist/web/hooks/use-layout.d.ts +0 -24
  305. package/dist/web/hooks/use-layout.js +0 -25
  306. package/dist/web/hooks/use-layout.js.map +0 -1
  307. package/dist/web/hooks/use-layout.test.js.map +0 -1
  308. package/dist/web/plugin/data-llm.test.js +0 -81
  309. package/dist/web/plugin/data-llm.test.js.map +0 -1
  310. package/dist/web/plugin/plugin.d.ts +0 -33
  311. package/dist/web/plugin/plugin.js +0 -188
  312. package/dist/web/plugin/plugin.js.map +0 -1
  313. package/dist/web/plugin/scan-views.js.map +0 -1
  314. package/dist/web/plugin/scan-views.test.js.map +0 -1
  315. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  316. package/dist/web/plugin/transform-data-llm.js +0 -96
  317. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  318. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  319. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  320. package/dist/web/plugin/validate-view.d.ts +0 -1
  321. package/dist/web/plugin/validate-view.js.map +0 -1
  322. package/dist/web/plugin/validate-view.test.js.map +0 -1
  323. /package/dist/{web/hooks/use-layout.test.d.ts → context-warnings.test.d.ts} +0 -0
  324. /package/dist/{web/plugin/data-llm.test.d.ts → server/app.test.d.ts} +0 -0
  325. /package/dist/{web/plugin/transform-data-llm.test.d.ts → server/auth/providers/authplane.test.d.ts} +0 -0
  326. /package/dist/{web/plugin/validate-view.test.d.ts → server/auth/security-schemes.test.d.ts} +0 -0
  327. /package/dist/{web/plugin/scan-views.test.d.ts → server/auth-extra.test-d.d.ts} +0 -0
  328. /package/dist/{web/plugin → views}/scan-views.d.ts +0 -0
  329. /package/dist/{web/plugin → views}/scan-views.test.js +0 -0
  330. /package/dist/{web/plugin → views}/validate-view.test.js +0 -0
@@ -1,22 +1,20 @@
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
8
+ .object({ writable: z.boolean().optional(), etag: z.string().optional() })
9
+ .optional();
10
+ const WriteResultSchema = z.discriminatedUnion("outcome", [
11
+ z.object({ outcome: z.enum(["saved", "conflict"]), etag: z.string() }),
12
+ z.object({ outcome: z.literal("too-large"), maxBytes: z.number() }),
13
+ ]);
4
14
  const STORAGE_PREFIX = "sb:";
5
15
  const MAX_STORAGE_ENTRIES = 200;
6
- const VIEW_STATE_TOKEN_WARNING_THRESHOLD = 4000;
7
- function getApproximateTokenCount(value) {
8
- try {
9
- return Math.max(1, Math.ceil(JSON.stringify(value).length / 4));
10
- }
11
- catch {
12
- return 0;
13
- }
14
- }
15
- function warnOnLargeViewState(value, source) {
16
- const tokenCount = getApproximateTokenCount(value);
17
- if (tokenCount > VIEW_STATE_TOKEN_WARNING_THRESHOLD) {
18
- console.warn(`[skybridge] ${source} is persisting ${tokenCount} tokens in view state; this exceeds the ${VIEW_STATE_TOKEN_WARNING_THRESHOLD}-token warning threshold and may overload model context.`);
19
- }
16
+ function isImage(mimeType) {
17
+ return mimeType?.startsWith("image/") ?? false;
20
18
  }
21
19
  function findStorageKey(viewUUID) {
22
20
  const suffix = `:${viewUUID}`;
@@ -52,11 +50,15 @@ export class HostAdaptor {
52
50
  _viewState = null;
53
51
  viewStateListeners = new Set();
54
52
  _viewUUID = null;
53
+ _modelContext = null;
54
+ resourceListeners = new Map();
55
+ listeningToResources = false;
55
56
  _polyfillDisplay = { mode: "inline" };
56
57
  polyfillDisplayListeners = new Set();
57
58
  polyfillDisplayStore;
58
59
  polyfillViewStateStore;
59
60
  unsubscribeViewUUID = null;
61
+ unsubscribeModelContext = null;
60
62
  constructor() {
61
63
  this.mcp = McpAppBridge.getInstance();
62
64
  let overlayStores = null;
@@ -90,20 +92,29 @@ export class HostAdaptor {
90
92
  viewState: overlayStores?.viewState ?? this.polyfillViewStateStore,
91
93
  };
92
94
  this.subscribeToViewUUID();
95
+ this.unsubscribeModelContext = this.mcp.subscribe("openai/modelContext")(() => {
96
+ if (this.mcp.getSnapshot("openai/modelContext") === null) {
97
+ this._modelContext = null;
98
+ }
99
+ });
93
100
  }
94
101
  /** @internal Release any subscriptions held on the underlying bridges. */
95
102
  cleanup() {
96
103
  this.unsubscribeViewUUID?.();
97
104
  this.unsubscribeViewUUID = null;
105
+ this.unsubscribeModelContext?.();
106
+ this.unsubscribeModelContext = null;
98
107
  }
99
108
  // ---- Adaptor interface ----
100
109
  getHostContextStore = (key) => this.stores[key];
101
- callTool = async (name, args) => {
110
+ callTool = async (name, args, options) => {
111
+ const timeout = options?.timeout;
112
+ if (timeout !== undefined && (!Number.isFinite(timeout) || timeout <= 0)) {
113
+ throw new RangeError("Tool call timeout must be a positive, finite number of milliseconds.");
114
+ }
102
115
  const app = await this.mcp.getApp();
103
- const response = await app.callServerTool({
104
- name,
105
- arguments: args ?? undefined,
106
- });
116
+ const params = { name, arguments: args ?? undefined };
117
+ const response = await app.callServerTool(params, { timeout });
107
118
  return {
108
119
  content: response.content,
109
120
  structuredContent: response.structuredContent ?? {},
@@ -130,7 +141,8 @@ export class HostAdaptor {
130
141
  await app.sendSizeChanged(size);
131
142
  };
132
143
  sendFollowUpMessage = async (prompt, options) => {
133
- if (this.openai) {
144
+ const target = options?.target;
145
+ if (this.openai && typeof prompt === "string" && target !== "new") {
134
146
  await this.openai.sendFollowUpMessage({
135
147
  prompt,
136
148
  scrollToBottom: options?.scrollToBottom,
@@ -138,10 +150,18 @@ export class HostAdaptor {
138
150
  return;
139
151
  }
140
152
  const app = await this.mcp.getApp();
141
- await app.sendMessage({
153
+ if (target === "new" &&
154
+ !app.getHostCapabilities()?.experimental?.["openai/message"]) {
155
+ throw new NotSupportedError("sendFollowUpMessage", "the host does not advertise openai/message, so it can't open a new conversation");
156
+ }
157
+ const result = await app.sendMessage({
142
158
  role: "user",
143
- content: [{ type: "text", text: prompt }],
159
+ content: typeof prompt === "string" ? [{ type: "text", text: prompt }] : prompt,
160
+ ...(target === "new" && { _meta: { "openai/message": { target } } }),
144
161
  });
162
+ if (result?.isError) {
163
+ throw new Error("The host rejected the follow-up message.");
164
+ }
145
165
  };
146
166
  openExternal = (href, options) => {
147
167
  if (this.openai) {
@@ -187,22 +207,142 @@ export class HostAdaptor {
187
207
  });
188
208
  this.persistToLocalStorage(newState);
189
209
  try {
190
- const app = await this.mcp.getApp();
191
- await app.updateModelContext({
192
- structuredContent: newState,
193
- content: [{ type: "text", text: JSON.stringify(newState) }],
194
- });
210
+ await this.sendModelContext();
195
211
  }
196
212
  catch (error) {
197
213
  console.error("Failed to update view state in MCP App.", error);
198
214
  }
199
215
  };
216
+ updateModelContext = async (params) => {
217
+ const app = await this.mcp.getApp();
218
+ const capabilities = app.getHostCapabilities();
219
+ if (!capabilities?.updateModelContext &&
220
+ !capabilities?.experimental?.["openai/modelContext"]) {
221
+ throw new NotSupportedError("updateModelContext", "the host does not advertise updateModelContext");
222
+ }
223
+ const previous = this._modelContext;
224
+ this._modelContext = params;
225
+ const result = await this.sendModelContext().catch((error) => {
226
+ if (this._modelContext === params) {
227
+ this._modelContext = previous;
228
+ }
229
+ throw error;
230
+ });
231
+ const parsed = z
232
+ .object({ updateId: z.string() })
233
+ .safeParse(result._meta?.["openai/modelContext"]);
234
+ return parsed.success ? parsed.data.updateId : undefined;
235
+ };
236
+ async sendModelContext() {
237
+ const viewState = this.openai ? null : this._viewState;
238
+ const extra = this._modelContext;
239
+ const collisions = Object.keys(extra?.structuredContent ?? {}).filter((key) => viewState !== null && key in viewState);
240
+ if (collisions.length > 0) {
241
+ console.warn(`skybridge: view state overrides model context keys ${collisions.join(", ")}.`);
242
+ }
243
+ const structuredContent = { ...extra?.structuredContent, ...viewState };
244
+ const app = await this.mcp.getApp();
245
+ return app.updateModelContext({
246
+ ...(Object.keys(structuredContent).length > 0 && { structuredContent }),
247
+ content: [
248
+ ...(viewState === null
249
+ ? []
250
+ : [
251
+ {
252
+ type: "text",
253
+ text: JSON.stringify(viewState),
254
+ annotations: { audience: ["assistant"] },
255
+ },
256
+ ]),
257
+ ...(extra?.content ?? []),
258
+ ],
259
+ });
260
+ }
261
+ openFile = async (path) => {
262
+ const app = await this.mcp.getApp();
263
+ if (!app.getHostCapabilities()?.experimental?.["openai/files"]) {
264
+ throw new NotSupportedError("openFile", "the host does not advertise openai/files");
265
+ }
266
+ await app.request({ method: "openai/files/open", params: { path } }, ResultSchema);
267
+ };
268
+ readResource = async (uri, representation) => {
269
+ const app = await this.mcp.getApp();
270
+ const { contents } = await app.readServerResource({
271
+ uri,
272
+ ...(representation && {
273
+ _meta: { "openai/resource": { representation } },
274
+ }),
275
+ });
276
+ const item = contents.find((content) => content.uri === uri) ?? contents[0];
277
+ if (!item) {
278
+ throw new Error(`The host returned no contents for ${uri}.`);
279
+ }
280
+ const { data: meta } = ResourceMetaSchema.safeParse(item._meta?.["openai/resource"]);
281
+ return {
282
+ ...("text" in item ? { text: item.text } : { blob: item.blob }),
283
+ mimeType: item.mimeType,
284
+ writable: meta?.writable ?? false,
285
+ etag: meta?.etag,
286
+ };
287
+ };
288
+ watchResource = (uri, onUpdate) => {
289
+ const app = this.mcp
290
+ .getApp()
291
+ .then((app) => app.getHostCapabilities()?.experimental?.["openai/resource"]
292
+ ? app
293
+ : undefined);
294
+ const listeners = this.resourceListeners.get(uri) ?? new Set();
295
+ if (listeners.size === 0) {
296
+ this.resourceListeners.set(uri, listeners);
297
+ app
298
+ .then((app) => {
299
+ if (!app) {
300
+ return;
301
+ }
302
+ if (!this.listeningToResources) {
303
+ app.setNotificationHandler("notifications/resources/updated", (notification) => {
304
+ this.resourceListeners
305
+ .get(notification.params.uri)
306
+ ?.forEach((l) => {
307
+ l();
308
+ });
309
+ });
310
+ this.listeningToResources = true;
311
+ }
312
+ return app.request({ method: "resources/subscribe", params: { uri } }, ResultSchema);
313
+ })
314
+ .catch((error) => {
315
+ console.warn(`Failed to subscribe to ${uri}.`, error);
316
+ });
317
+ }
318
+ listeners.add(onUpdate);
319
+ return () => {
320
+ if (listeners.delete(onUpdate) && listeners.size === 0) {
321
+ this.resourceListeners.delete(uri);
322
+ app
323
+ .then((app) => app?.request({ method: "resources/unsubscribe", params: { uri } }, ResultSchema))
324
+ .catch(() => { });
325
+ }
326
+ };
327
+ };
328
+ writeResource = async (uri, content, ifMatch) => {
329
+ const app = await this.mcp.getApp();
330
+ if (!app.getHostCapabilities()?.experimental?.["openai/resource"]) {
331
+ throw new NotSupportedError("writeResource", "the host does not advertise openai/resource");
332
+ }
333
+ return app.request({
334
+ method: "openai/resources/write",
335
+ params: { uri, ...content, ...(ifMatch && { ifMatch }) },
336
+ }, WriteResultSchema);
337
+ };
200
338
  uploadFile = async (file, options) => {
201
339
  if (!this.openai) {
202
340
  throw new NotSupportedError("uploadFile");
203
341
  }
204
342
  const metadata = await this.openai.uploadFile(file, options);
205
- await this.trackFileIds(metadata.fileId);
343
+ if (isImage(metadata.mimeType ?? file.type)) {
344
+ await this.trackFileIds(metadata.fileId);
345
+ }
206
346
  return metadata;
207
347
  };
208
348
  getFileDownloadUrl = (file) => {
@@ -219,8 +359,14 @@ export class HostAdaptor {
219
359
  throw new Error("selectFiles is not supported by the current host version.");
220
360
  }
221
361
  const files = await this.openai.selectFiles();
222
- if (files.length > 0) {
223
- await this.trackFileIds(...files.map((f) => f.fileId));
362
+ const imageIds = [];
363
+ for (const file of files) {
364
+ if (isImage(file.mimeType)) {
365
+ imageIds.push(file.fileId);
366
+ }
367
+ }
368
+ if (imageIds.length > 0) {
369
+ await this.trackFileIds(...imageIds);
224
370
  }
225
371
  return files;
226
372
  };
@@ -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;\nconst VIEW_STATE_TOKEN_WARNING_THRESHOLD = 4000;\n\nfunction getApproximateTokenCount(value: unknown): number {\n try {\n return Math.max(1, Math.ceil(JSON.stringify(value).length / 4));\n } catch {\n return 0;\n }\n}\n\nfunction warnOnLargeViewState(value: unknown, source: string): void {\n const tokenCount = getApproximateTokenCount(value);\n if (tokenCount > VIEW_STATE_TOKEN_WARNING_THRESHOLD) {\n console.warn(\n `[skybridge] ${source} is persisting ${tokenCount} tokens in view state; this exceeds the ${VIEW_STATE_TOKEN_WARNING_THRESHOLD}-token warning threshold and may overload model context.`,\n );\n }\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\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 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: 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 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 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 * 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\n .object({ writable: z.boolean().optional(), etag: z.string().optional() })\n .optional();\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 listeningToResources = false;\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 app = this.mcp\n .getApp()\n .then((app) =>\n app.getHostCapabilities()?.experimental?.[\"openai/resource\"]\n ? app\n : undefined,\n );\n const listeners = this.resourceListeners.get(uri) ?? new Set<() => void>();\n if (listeners.size === 0) {\n this.resourceListeners.set(uri, listeners);\n app\n .then((app) => {\n if (!app) {\n return;\n }\n if (!this.listeningToResources) {\n app.setNotificationHandler(\n \"notifications/resources/updated\",\n (notification) => {\n this.resourceListeners\n .get(notification.params.uri)\n ?.forEach((l) => {\n l();\n });\n },\n );\n this.listeningToResources = true;\n }\n return 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 app\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.mcp.getApp();\n if (!app.getHostCapabilities()?.experimental?.[\"openai/resource\"]) {\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 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 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 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 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();
@@ -105,17 +139,33 @@ describe("HostAdaptor", () => {
105
139
  });
106
140
  it("uploadFile delegates to window.openai.uploadFile and tracks fileId in widgetState", async () => {
107
141
  const setWidgetState = vi.fn().mockResolvedValue(undefined);
108
- const uploadFile = vi
109
- .fn()
110
- .mockResolvedValue({ fileId: "abc", fileName: "x" });
142
+ const uploadFile = vi.fn().mockResolvedValue({
143
+ fileId: "abc",
144
+ fileName: "x",
145
+ mimeType: "image/png",
146
+ });
111
147
  vi.stubGlobal("openai", { uploadFile, setWidgetState, widgetState: null });
112
148
  const adaptor = new HostAdaptor();
113
- const file = new File([], "x");
149
+ const file = new File([], "x", { type: "image/png" });
114
150
  const r = await adaptor.uploadFile(file, { library: true });
115
151
  expect(uploadFile).toHaveBeenCalledWith(file, { library: true });
116
152
  expect(r.fileId).toBe("abc");
117
153
  expect(setWidgetState).toHaveBeenCalledWith(expect.objectContaining({ imageIds: ["abc"] }));
118
154
  });
155
+ it("uploadFile does not track a non-image fileId in widgetState.imageIds", async () => {
156
+ const setWidgetState = vi.fn().mockResolvedValue(undefined);
157
+ const uploadFile = vi.fn().mockResolvedValue({
158
+ fileId: "sediment://file_txt",
159
+ fileName: "notes.txt",
160
+ mimeType: "text/plain",
161
+ });
162
+ vi.stubGlobal("openai", { uploadFile, setWidgetState, widgetState: null });
163
+ const adaptor = new HostAdaptor();
164
+ await adaptor.uploadFile(new File([], "notes.txt", { type: "text/plain" }));
165
+ for (const call of setWidgetState.mock.calls) {
166
+ expect(call[0].imageIds ?? []).not.toContain("sediment://file_txt");
167
+ }
168
+ });
119
169
  it("setViewState uses window.openai.setWidgetState when present", async () => {
120
170
  const setWidgetState = vi.fn().mockResolvedValue(undefined);
121
171
  vi.stubGlobal("openai", { setWidgetState, widgetState: null });
@@ -123,13 +173,13 @@ describe("HostAdaptor", () => {
123
173
  await adaptor.setViewState({ count: 1 });
124
174
  expect(setWidgetState).toHaveBeenCalledWith(expect.objectContaining({ modelContent: { count: 1 } }));
125
175
  });
126
- it("warns when setViewState persists more than 4K tokens", async () => {
176
+ it("warns when setViewState reaches 20K tokens", async () => {
127
177
  const setWidgetState = vi.fn().mockResolvedValue(undefined);
128
178
  vi.stubGlobal("openai", { setWidgetState, widgetState: null });
129
179
  const adaptor = new HostAdaptor();
130
180
  const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
131
181
  await adaptor.setViewState({
132
- longText: "x".repeat(4096 * 4 + 50),
182
+ longText: "x".repeat(VIEW_STATE_WARNING_TOKENS * 4),
133
183
  });
134
184
  expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("setWidgetState is persisting"));
135
185
  warnSpy.mockRestore();
@@ -147,7 +197,13 @@ describe("HostAdaptor", () => {
147
197
  await adaptor.setViewState({ count: 2 });
148
198
  expect(updateModelContext).toHaveBeenCalledWith({
149
199
  structuredContent: { count: 2 },
150
- content: [{ type: "text", text: JSON.stringify({ count: 2 }) }],
200
+ content: [
201
+ {
202
+ type: "text",
203
+ text: JSON.stringify({ count: 2 }),
204
+ annotations: { audience: ["assistant"] },
205
+ },
206
+ ],
151
207
  });
152
208
  const keys = [];
153
209
  for (let i = 0; i < localStorage.length; i++) {