@theoremjs/studio 0.0.0-stage → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +295 -2
  3. package/agreement.d.ts +14 -0
  4. package/agreement.js +80 -0
  5. package/asks.d.ts +47 -0
  6. package/asks.js +54 -0
  7. package/browser-connection.d.ts +49 -0
  8. package/browser-connection.js +215 -0
  9. package/browser-engine.d.ts +11 -0
  10. package/browser-engine.js +11 -0
  11. package/browser-execution.d.ts +6 -0
  12. package/browser-execution.js +18 -0
  13. package/browser-live.d.ts +4 -0
  14. package/browser-live.js +132 -0
  15. package/browser-transport.d.ts +33 -0
  16. package/browser-transport.js +229 -0
  17. package/browser.d.ts +4 -0
  18. package/browser.js +4 -0
  19. package/canonical.d.ts +10 -0
  20. package/canonical.js +25 -0
  21. package/compile-workspace.d.ts +28 -0
  22. package/compile-workspace.js +295 -0
  23. package/compile.d.ts +65 -0
  24. package/compile.js +1605 -0
  25. package/concierge-demo.d.ts +17 -0
  26. package/concierge-demo.js +1230 -0
  27. package/conversation-key.d.ts +5 -0
  28. package/conversation-key.js +10 -0
  29. package/decision-example-images.d.ts +30 -0
  30. package/decision-example-images.js +30 -0
  31. package/deno.json +3 -0
  32. package/draft.d.ts +407 -0
  33. package/draft.js +505 -0
  34. package/editors.d.ts +29 -0
  35. package/editors.js +51 -0
  36. package/example-embedding-files.d.ts +11 -0
  37. package/example-embedding-files.js +20 -0
  38. package/example.d.ts +36 -0
  39. package/example.js +357 -0
  40. package/guardrail-probe.d.ts +100 -0
  41. package/guardrail-probe.js +722 -0
  42. package/held-credentials.d.ts +28 -0
  43. package/held-credentials.js +87 -0
  44. package/installed.mjs +40 -0
  45. package/lent-keys.d.ts +122 -0
  46. package/lent-keys.js +47 -0
  47. package/line-diff.d.ts +15 -0
  48. package/line-diff.js +41 -0
  49. package/live-connection.d.ts +22 -0
  50. package/live-connection.js +27 -0
  51. package/live-session-bridge.d.ts +15 -0
  52. package/live-session-bridge.js +202 -0
  53. package/map-line.d.ts +19 -0
  54. package/map-line.js +42 -0
  55. package/map.d.ts +154 -0
  56. package/map.js +525 -0
  57. package/media-accept.d.ts +19 -0
  58. package/media-accept.js +65 -0
  59. package/mod.d.ts +39 -0
  60. package/mod.js +33 -0
  61. package/origins.d.ts +52 -0
  62. package/origins.js +165 -0
  63. package/package.json +85 -4
  64. package/page/assets/Banner-BISz3nXA.js +2 -0
  65. package/page/assets/BottomSheet-BwfBDtje.js +1 -0
  66. package/page/assets/Card-Lp-0P5eL.js +1 -0
  67. package/page/assets/CardWall-CBRLdDZW.js +1 -0
  68. package/page/assets/Center-nHS1JSux.js +1 -0
  69. package/page/assets/CheckboxInput-Cj5pk-KI.js +2 -0
  70. package/page/assets/CodeBlock-C7XJ4ioE.js +51 -0
  71. package/page/assets/CollapsibleGroup-N7_SOjbm.js +2 -0
  72. package/page/assets/ContextMenu-CBu9H-9H.js +2 -0
  73. package/page/assets/DateInput-BGrQ5tPC.js +1 -0
  74. package/page/assets/Dialog-DELWQo-v.js +1 -0
  75. package/page/assets/EmptyState-C8W4JKBZ.js +1 -0
  76. package/page/assets/HoverCard-D1Y1ltWQ.js +1 -0
  77. package/page/assets/Icon-JrysT8aU.js +3 -0
  78. package/page/assets/IconAlertTriangle-BqAEqqdU.js +1 -0
  79. package/page/assets/IconButton-DlOGzJIX.js +1 -0
  80. package/page/assets/IconEye-BB5aY-wQ.js +1 -0
  81. package/page/assets/IconFileText-6zOFKKrF.js +1 -0
  82. package/page/assets/IconSearch-BTx66a40.js +1 -0
  83. package/page/assets/IconShield-DDOh7Gr5.js +1 -0
  84. package/page/assets/ItemSwipeLayer-Ckn4X6h9.js +1 -0
  85. package/page/assets/PaneState-BvA2tLQg.js +1 -0
  86. package/page/assets/PaneState-eUzUkNE8.css +1 -0
  87. package/page/assets/ScrollableArea-Ckugdj1N.js +1 -0
  88. package/page/assets/Section-DJ97F7QE.js +1 -0
  89. package/page/assets/SegmentedControlItem-h-aaXzyS.js +1 -0
  90. package/page/assets/SidePanel-BL32abk8.js +1 -0
  91. package/page/assets/StackItem-CQviqAfM.js +1 -0
  92. package/page/assets/Text-bum6zWWx.js +2 -0
  93. package/page/assets/TimestampHoverCard-DQIG0RZF.js +1 -0
  94. package/page/assets/ToolResultCharts-CgshSv9Q.js +1 -0
  95. package/page/assets/Tooltip-BH9xiRMl.js +1 -0
  96. package/page/assets/TraceInspector-_yZiz05W.js +1 -0
  97. package/page/assets/TraceOverview-BPO-HIYK.js +57 -0
  98. package/page/assets/VStack-CkVMcNiK.js +1 -0
  99. package/page/assets/_virtual_studio-type-sources-ByxqQaOG.js +12936 -0
  100. package/page/assets/arrive-DvbqpeRS.js +1 -0
  101. package/page/assets/browser-engine-CYq9DQAM.js +9 -0
  102. package/page/assets/browser-transport-D-2jDYe7.js +47 -0
  103. package/page/assets/codicon-DF1abBS2.ttf +0 -0
  104. package/page/assets/compile-egress-BSxOdX4K.js +23 -0
  105. package/page/assets/container.stylex-BmOi-8DQ.js +1 -0
  106. package/page/assets/createReactComponent-CZwsv6DD.js +1 -0
  107. package/page/assets/decision-example-images-CZGr7YIT.js +1 -0
  108. package/page/assets/devWarning-DxuplmRl.js +1 -0
  109. package/page/assets/editor-DjpsE8to.css +1 -0
  110. package/page/assets/editor.api-Cd3ViPQa.js +908 -0
  111. package/page/assets/editor.worker-6GY8RhDc.js +1 -0
  112. package/page/assets/editor.worker-BmdWdrHZ.js +33 -0
  113. package/page/assets/editors-BJX_S59A.js +1 -0
  114. package/page/assets/egress-automata-B5ZGE1mT.js +1 -0
  115. package/page/assets/embedding-space-view-CfQBPDxD.js +140 -0
  116. package/page/assets/encode-files-Bc3HJyAh.js +1 -0
  117. package/page/assets/export-agent-C3yyzXH8.js +43 -0
  118. package/page/assets/figtree-latin-400-normal-BD4aNku5.woff +0 -0
  119. package/page/assets/figtree-latin-400-normal-g7Dtegnw.woff2 +0 -0
  120. package/page/assets/figtree-latin-500-normal-BWnGEVsr.woff2 +0 -0
  121. package/page/assets/figtree-latin-500-normal-B_yy1phn.woff +0 -0
  122. package/page/assets/figtree-latin-600-normal-BM_oTo4n.woff +0 -0
  123. package/page/assets/figtree-latin-600-normal-Cv_xCTDl.woff2 +0 -0
  124. package/page/assets/figtree-latin-700-normal-BCCt2T1q.woff +0 -0
  125. package/page/assets/figtree-latin-700-normal-th6qEP7c.woff2 +0 -0
  126. package/page/assets/focusOutline.stylex-BT0kfa4t.js +1 -0
  127. package/page/assets/focusableSelector-DXZeMU85.js +1 -0
  128. package/page/assets/groupStyles-C7Ter7zC.js +1 -0
  129. package/page/assets/guardrail-tester-Gut5xK4a.js +9 -0
  130. package/page/assets/host-patterns-C9RMP16Q.js +1 -0
  131. package/page/assets/index-CvvmFKgS.js +105 -0
  132. package/page/assets/index-DOaHlqBo.css +1 -0
  133. package/page/assets/isRtlElement-BG33-k_H.js +1 -0
  134. package/page/assets/labels-provider-4TIWDvsE.js +3 -0
  135. package/page/assets/lent-keys-C32ems-I.js +1 -0
  136. package/page/assets/live-ingress-lDUGPwth.js +1 -0
  137. package/page/assets/live-messages-CnkL4GWi.js +1 -0
  138. package/page/assets/mergeProps-ptS-gIMz.js +1 -0
  139. package/page/assets/padding.stylex-B76907Zf.js +1 -0
  140. package/page/assets/preload-helper-DpV6A1kQ.js +1 -0
  141. package/page/assets/reader-BOCCYaRp.js +7 -0
  142. package/page/assets/register-CDgivxvX.js +2 -0
  143. package/page/assets/rolldown-runtime-hePW80VL.js +1 -0
  144. package/page/assets/schemas-BQ9Jydzb.js +56 -0
  145. package/page/assets/shaped-data-BcarWqd5.js +16 -0
  146. package/page/assets/sharedResizeObserver-4U9Xq5Oq.js +1 -0
  147. package/page/assets/stub-DhdcU_Ew.js +471 -0
  148. package/page/assets/studio-code-pane-C_SAbcOa.js +8 -0
  149. package/page/assets/studio-console-DZwlEsvr.js +3 -0
  150. package/page/assets/studio-decision-B0FnCAXA.js +1 -0
  151. package/page/assets/studio-embedding-CmA51HVo.js +2 -0
  152. package/page/assets/studio-host-console-By7hqu2l.js +2 -0
  153. package/page/assets/studio-live-BrcVQcyV.js +1 -0
  154. package/page/assets/studio-map-B_xSia-z.js +1 -0
  155. package/page/assets/studio-map-Bb06Tw1F.css +1 -0
  156. package/page/assets/studio-monaco-CbKf90i6.css +1 -0
  157. package/page/assets/studio-monaco-xfyfezQS.js +34 -0
  158. package/page/assets/studio-ts.worker-B-EXG4Sv.js +67741 -0
  159. package/page/assets/studio-ts.worker-BXtW3z-O.js +1 -0
  160. package/page/assets/studio-type-checker-BOvxudki.js +23 -0
  161. package/page/assets/themeProps-3IqahpCr.js +1 -0
  162. package/page/assets/tokens.stylex-DkHf0P9C.js +1 -0
  163. package/page/assets/tool-schema-idaOe2nI.js +18 -0
  164. package/page/assets/trace-patterns-DnYJa0nI.js +1 -0
  165. package/page/assets/trace-record-C3zNksA_.js +1 -0
  166. package/page/assets/trace-schema-9CdEyG6Q.js +1 -0
  167. package/page/assets/tree-DqyAMsbI.js +3 -0
  168. package/page/assets/turn-client-Du3Um3Mg.js +2 -0
  169. package/page/assets/types-BhfXQCLx.js +1 -0
  170. package/page/assets/typescript-20GgZ8PJ.js +1 -0
  171. package/page/assets/use-one-call-Hcs8YBp1.js +1 -0
  172. package/page/assets/useAdaptivePresentation-BzmPCddb.js +1 -0
  173. package/page/assets/useClipboard-BgGRxRMJ.js +1 -0
  174. package/page/assets/useContainerReveal-BFy8N_QU.js +1 -0
  175. package/page/assets/useDevWarning-Z9SoixOP.js +1 -0
  176. package/page/assets/useLayerDismissal-B_G7IWpC.js +1 -0
  177. package/page/assets/useMediaQuery-BCT0NUeZ.js +1 -0
  178. package/page/assets/useScrollLock-Dyf6PHJt.js +1 -0
  179. package/page/assets/useScrollableArea-0NzdiBCq.js +1 -0
  180. package/page/assets/useTooltip-CJM_xhLB.js +1 -0
  181. package/page/assets/workspace-DZALqEDX.js +1 -0
  182. package/page/assets/zip-DTcEfps6.js +1 -0
  183. package/page/index.html +90 -0
  184. package/page.mjs +49 -0
  185. package/people.d.ts +87 -0
  186. package/people.js +110 -0
  187. package/policy.d.ts +43 -0
  188. package/policy.js +102 -0
  189. package/ports.d.mts +32 -0
  190. package/ports.mjs +85 -0
  191. package/probe-battery.d.ts +13 -0
  192. package/probe-battery.js +404 -0
  193. package/providers.d.ts +149 -0
  194. package/providers.js +306 -0
  195. package/read-source.d.ts +48 -0
  196. package/read-source.js +1301 -0
  197. package/read-steps.d.ts +23 -0
  198. package/read-steps.js +2 -0
  199. package/reader.d.ts +11 -0
  200. package/reader.js +11 -0
  201. package/registrations.d.ts +83 -0
  202. package/registrations.js +1 -0
  203. package/requirements.d.ts +22 -0
  204. package/requirements.js +38 -0
  205. package/run-payload-core.d.ts +28 -0
  206. package/run-payload-core.js +123 -0
  207. package/run-payload.d.ts +32 -0
  208. package/run-payload.js +26 -0
  209. package/runtime-scope.d.ts +84 -0
  210. package/runtime-scope.js +308 -0
  211. package/runtime.d.ts +84 -0
  212. package/runtime.js +387 -0
  213. package/section-notes.d.ts +33 -0
  214. package/section-notes.js +38 -0
  215. package/serve-page.mjs +96 -0
  216. package/server/draft-decide.d.ts +72 -0
  217. package/server/draft-decide.js +111 -0
  218. package/server/draft-embedding.d.ts +3 -0
  219. package/server/draft-embedding.js +35 -0
  220. package/server/draft-handler.d.ts +82 -0
  221. package/server/draft-handler.js +213 -0
  222. package/server/draft-probe.d.ts +14 -0
  223. package/server/draft-probe.js +61 -0
  224. package/server/draft-replies.d.ts +22 -0
  225. package/server/draft-replies.js +46 -0
  226. package/server/edited-session.d.ts +28 -0
  227. package/server/edited-session.js +83 -0
  228. package/server/edits.d.ts +38 -0
  229. package/server/edits.js +195 -0
  230. package/server/handler.d.ts +133 -0
  231. package/server/handler.js +598 -0
  232. package/server/lent-draft.d.ts +19 -0
  233. package/server/lent-draft.js +23 -0
  234. package/server/live.d.ts +15 -0
  235. package/server/live.js +96 -0
  236. package/server/open-editor.d.ts +63 -0
  237. package/server/open-editor.js +115 -0
  238. package/server/origins.d.ts +18 -0
  239. package/server/origins.js +330 -0
  240. package/server/project-source.d.ts +208 -0
  241. package/server/project-source.js +1042 -0
  242. package/server/project.d.ts +22 -0
  243. package/server/project.js +56 -0
  244. package/server/run-traces.d.ts +20 -0
  245. package/server/run-traces.js +96 -0
  246. package/server/save-new.d.ts +29 -0
  247. package/server/save-new.js +514 -0
  248. package/server/save-plan.d.ts +46 -0
  249. package/server/save-plan.js +1134 -0
  250. package/server/save-remove.d.ts +21 -0
  251. package/server/save-remove.js +528 -0
  252. package/server/save-session.d.ts +96 -0
  253. package/server/save-session.js +418 -0
  254. package/server/save-wire.d.ts +235 -0
  255. package/server/save-wire.js +8 -0
  256. package/server/save.d.ts +52 -0
  257. package/server/save.js +209 -0
  258. package/server/serve.d.ts +23 -0
  259. package/server/serve.js +413 -0
  260. package/server/test-connection.d.ts +17 -0
  261. package/server/test-connection.js +362 -0
  262. package/server/test-key.d.ts +2 -0
  263. package/server/test-key.js +83 -0
  264. package/server/watch.d.ts +28 -0
  265. package/server/watch.js +93 -0
  266. package/server/zod-edit.d.ts +74 -0
  267. package/server/zod-edit.js +558 -0
  268. package/server.d.ts +8 -0
  269. package/server.js +8 -0
  270. package/setups.mjs +170 -0
  271. package/shared-carry.d.ts +114 -0
  272. package/shared-carry.js +523 -0
  273. package/shared-settings.d.ts +34 -0
  274. package/shared-settings.js +70 -0
  275. package/source.d.ts +75 -0
  276. package/source.js +414 -0
  277. package/start.mjs +169 -0
  278. package/stream-lines.d.ts +9 -0
  279. package/stream-lines.js +27 -0
  280. package/stub.d.ts +6 -0
  281. package/stub.js +33 -0
  282. package/surface.d.ts +53 -0
  283. package/surface.js +631 -0
  284. package/system-markup.d.ts +20 -0
  285. package/system-markup.js +51 -0
  286. package/tool-schema.d.ts +23 -0
  287. package/tool-schema.js +69 -0
  288. package/tools.d.ts +16 -0
  289. package/tools.js +91 -0
  290. package/traces.d.ts +24 -0
  291. package/traces.js +29 -0
  292. package/transport.d.ts +57 -0
  293. package/transport.js +187 -0
  294. package/tree.d.ts +32 -0
  295. package/tree.js +83 -0
  296. package/types.d.ts +62 -0
  297. package/types.js +6 -0
  298. package/ui/acting-as-button.d.ts +2 -0
  299. package/ui/acting-as-button.js +16 -0
  300. package/ui/add-provider.d.ts +13 -0
  301. package/ui/add-provider.js +20 -0
  302. package/ui/boot-mark.css +53 -0
  303. package/ui/boot-mark.d.ts +19 -0
  304. package/ui/boot-mark.js +128 -0
  305. package/ui/boot-paint.d.ts +8 -0
  306. package/ui/boot-paint.js +8 -0
  307. package/ui/brand-icons.d.ts +57 -0
  308. package/ui/brand-icons.js +148 -0
  309. package/ui/built/theme.css +830 -0
  310. package/ui/built/theme.css.d.ts +9 -0
  311. package/ui/built/theorem-studio.d.ts +13 -0
  312. package/ui/built/theorem-studio.js +705 -0
  313. package/ui/built/theorem-studio.variants.d.ts +28 -0
  314. package/ui/code/monaco-contributions.d.ts +45 -0
  315. package/ui/code/studio-code.d.ts +7 -0
  316. package/ui/code/studio-code.js +253 -0
  317. package/ui/code/studio-monaco.d.ts +44 -0
  318. package/ui/code/studio-monaco.js +48 -0
  319. package/ui/code/studio-ts.worker.d.ts +1 -0
  320. package/ui/code/studio-ts.worker.js +16 -0
  321. package/ui/code/studio-type-checker.d.ts +12 -0
  322. package/ui/code/studio-type-checker.js +308 -0
  323. package/ui/code/studio-type-sources.d.ts +26 -0
  324. package/ui/confirm-write.d.ts +12 -0
  325. package/ui/confirm-write.js +45 -0
  326. package/ui/diff-block.d.ts +21 -0
  327. package/ui/diff-block.js +17 -0
  328. package/ui/figtree.css +59 -0
  329. package/ui/file-place.d.ts +4 -0
  330. package/ui/file-place.js +26 -0
  331. package/ui/guardrail-tester.d.ts +18 -0
  332. package/ui/guardrail-tester.js +248 -0
  333. package/ui/inspector-context.d.ts +119 -0
  334. package/ui/inspector-context.js +84 -0
  335. package/ui/inspector.d.ts +247 -0
  336. package/ui/inspector.js +284 -0
  337. package/ui/lib/acting-as.d.ts +25 -0
  338. package/ui/lib/acting-as.js +90 -0
  339. package/ui/lib/boot-sequence.d.ts +32 -0
  340. package/ui/lib/boot-sequence.js +57 -0
  341. package/ui/lib/export-agent.d.ts +11 -0
  342. package/ui/lib/export-agent.js +335 -0
  343. package/ui/lib/facet-icons.d.ts +20 -0
  344. package/ui/lib/facet-icons.js +21 -0
  345. package/ui/lib/panel-motion.d.ts +8 -0
  346. package/ui/lib/panel-motion.js +74 -0
  347. package/ui/lib/project-address.d.ts +14 -0
  348. package/ui/lib/project-address.js +24 -0
  349. package/ui/lib/project-starting.d.ts +13 -0
  350. package/ui/lib/project-starting.js +30 -0
  351. package/ui/lib/project-traces.d.ts +17 -0
  352. package/ui/lib/project-traces.js +54 -0
  353. package/ui/lib/read-map.d.ts +30 -0
  354. package/ui/lib/read-map.js +173 -0
  355. package/ui/lib/read-progress.d.ts +14 -0
  356. package/ui/lib/read-progress.js +12 -0
  357. package/ui/lib/refusal-lines.d.ts +3 -0
  358. package/ui/lib/refusal-lines.js +8 -0
  359. package/ui/lib/studio-activity.d.ts +5 -0
  360. package/ui/lib/studio-activity.js +17 -0
  361. package/ui/lib/studio-console.d.ts +27 -0
  362. package/ui/lib/studio-console.js +9 -0
  363. package/ui/lib/studio-conversation.d.ts +20 -0
  364. package/ui/lib/studio-conversation.js +130 -0
  365. package/ui/lib/studio-examples.d.ts +31 -0
  366. package/ui/lib/studio-examples.js +25 -0
  367. package/ui/lib/studio-labels.d.ts +6 -0
  368. package/ui/lib/studio-labels.js +13 -0
  369. package/ui/lib/studio-map-kept.d.ts +17 -0
  370. package/ui/lib/studio-map-kept.js +48 -0
  371. package/ui/lib/studio-open.d.ts +22 -0
  372. package/ui/lib/studio-open.js +54 -0
  373. package/ui/lib/studio-page.d.ts +33 -0
  374. package/ui/lib/studio-page.js +121 -0
  375. package/ui/lib/studio-prefs.d.ts +26 -0
  376. package/ui/lib/studio-prefs.js +87 -0
  377. package/ui/lib/studio-project.d.ts +106 -0
  378. package/ui/lib/studio-project.js +177 -0
  379. package/ui/lib/studio-restore.d.ts +49 -0
  380. package/ui/lib/studio-restore.js +251 -0
  381. package/ui/lib/studio-run-open.d.ts +15 -0
  382. package/ui/lib/studio-run-open.js +16 -0
  383. package/ui/lib/studio-session.d.ts +34 -0
  384. package/ui/lib/studio-session.js +17 -0
  385. package/ui/lib/studio-settings.d.ts +15 -0
  386. package/ui/lib/studio-settings.js +48 -0
  387. package/ui/lib/studio-store.d.ts +64 -0
  388. package/ui/lib/studio-store.js +391 -0
  389. package/ui/lib/studio-watch.d.ts +12 -0
  390. package/ui/lib/studio-watch.js +27 -0
  391. package/ui/lib/tab-fills.d.ts +6 -0
  392. package/ui/lib/tab-fills.js +14 -0
  393. package/ui/lib/tool-credentials.d.ts +3 -0
  394. package/ui/lib/tool-credentials.js +23 -0
  395. package/ui/lib/tool-probe.d.ts +19 -0
  396. package/ui/lib/tool-probe.js +104 -0
  397. package/ui/lib/type-icons.d.ts +35 -0
  398. package/ui/lib/type-icons.js +38 -0
  399. package/ui/lib/when-idle.d.ts +5 -0
  400. package/ui/lib/when-idle.js +14 -0
  401. package/ui/lib/zip.d.ts +5 -0
  402. package/ui/lib/zip.js +8 -0
  403. package/ui/map-token.css +11 -0
  404. package/ui/map-token.d.ts +17 -0
  405. package/ui/map-token.js +29 -0
  406. package/ui/mcp-icon.d.ts +6 -0
  407. package/ui/mcp-icon.js +8 -0
  408. package/ui/motion.css +113 -0
  409. package/ui/pan.d.ts +32 -0
  410. package/ui/pan.js +90 -0
  411. package/ui/profile-editor.d.ts +33 -0
  412. package/ui/profile-editor.js +2638 -0
  413. package/ui/provider-editor.d.ts +15 -0
  414. package/ui/provider-editor.js +92 -0
  415. package/ui/read-map.css +48 -0
  416. package/ui/read-map.d.ts +7 -0
  417. package/ui/read-map.js +163 -0
  418. package/ui/refusal-detail.d.ts +4 -0
  419. package/ui/refusal-detail.js +21 -0
  420. package/ui/shared-change.d.ts +9 -0
  421. package/ui/shared-change.js +28 -0
  422. package/ui/shell-motion.css +121 -0
  423. package/ui/shell-motion.d.ts +73 -0
  424. package/ui/shell-motion.js +194 -0
  425. package/ui/studio-code-pane.d.ts +19 -0
  426. package/ui/studio-code-pane.js +44 -0
  427. package/ui/studio-compare.d.ts +80 -0
  428. package/ui/studio-compare.js +326 -0
  429. package/ui/studio-conflicts.d.ts +17 -0
  430. package/ui/studio-conflicts.js +87 -0
  431. package/ui/studio-connection.d.ts +64 -0
  432. package/ui/studio-connection.js +286 -0
  433. package/ui/studio-decision.d.ts +6 -0
  434. package/ui/studio-decision.js +49 -0
  435. package/ui/studio-embedding.d.ts +6 -0
  436. package/ui/studio-embedding.js +30 -0
  437. package/ui/studio-host-console.d.ts +6 -0
  438. package/ui/studio-host-console.js +17 -0
  439. package/ui/studio-host.d.ts +73 -0
  440. package/ui/studio-host.js +12 -0
  441. package/ui/studio-live.d.ts +17 -0
  442. package/ui/studio-live.js +26 -0
  443. package/ui/studio-map.css +273 -0
  444. package/ui/studio-map.d.ts +17 -0
  445. package/ui/studio-map.js +397 -0
  446. package/ui/studio-nav.d.ts +24 -0
  447. package/ui/studio-nav.js +17 -0
  448. package/ui/studio-no-project.d.ts +5 -0
  449. package/ui/studio-no-project.js +9 -0
  450. package/ui/studio-run.css +76 -0
  451. package/ui/studio-run.d.ts +14 -0
  452. package/ui/studio-run.js +119 -0
  453. package/ui/studio-runner.d.ts +45 -0
  454. package/ui/studio-runner.js +187 -0
  455. package/ui/studio-save.d.ts +49 -0
  456. package/ui/studio-save.js +307 -0
  457. package/ui/studio-screen.d.ts +61 -0
  458. package/ui/studio-screen.js +2078 -0
  459. package/ui/studio-settings.d.ts +31 -0
  460. package/ui/studio-settings.js +288 -0
  461. package/ui/studio-shell.css +27 -0
  462. package/ui/studio-shell.d.ts +43 -0
  463. package/ui/studio-shell.js +87 -0
  464. package/ui/studio-theme.d.ts +7 -0
  465. package/ui/studio-theme.js +94 -0
  466. package/ui/studio.css +427 -0
  467. package/ui/theorem-mark.css +84 -0
  468. package/ui/theorem-mark.d.ts +22 -0
  469. package/ui/theorem-mark.js +21 -0
  470. package/vite.d.mts +30 -0
  471. package/vite.mjs +277 -0
  472. package/workspace.d.ts +230 -0
  473. package/workspace.js +1054 -0
@@ -0,0 +1,28 @@
1
+ /**
2
+ * A tool's credentials stay with the project. The page gets the tool's URLs and headers with
3
+ * their credentials masked, and a mask it sends back is filled in from what the project holds:
4
+ * the tool it registered for a run, the file's own text for a Save.
5
+ *
6
+ * @module
7
+ */
8
+ /** A tool as the page gets it: the credentials in its URLs and headers masked. */
9
+ export declare function withoutCredentials<T extends object>(tool: T): T;
10
+ /**
11
+ * What a provider connects with, as the page gets it: its addresses with any credential masked.
12
+ * Only what is text is told; a provider defined with nothing has nothing to tell.
13
+ */
14
+ export declare function shownConnection(connection: unknown): Record<string, string> | undefined;
15
+ /**
16
+ * Why a provider cannot run or be saved, when what it connects with shows a mask. A provider's
17
+ * credential is its key slot's, so a mask here stands for nothing the project holds.
18
+ */
19
+ export declare function unheldConnection(id: string, connection: Record<string, string> | undefined): string | undefined;
20
+ /** One setting of a tool the page sent, each mask in it filled in from `held`, the project's own. */
21
+ export declare function heldSetting(key: string, shown: unknown, held: unknown): unknown;
22
+ /**
23
+ * The credentials `tool` shows masked that nothing holds a value for: every mask, or with
24
+ * `opened`, the tool as the page got it, the masks that were not there.
25
+ */
26
+ export declare function unheld(tool: object, opened?: object): string[];
27
+ /** Why a tool cannot run or be saved, when it shows a credential nothing holds a value for. */
28
+ export declare function unheldProblem(name: string, tool: object, opened?: object): string | undefined;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * A tool's credentials stay with the project. The page gets the tool's URLs and headers with
3
+ * their credentials masked, and a mask it sends back is filled in from what the project holds:
4
+ * the tool it registered for a run, the file's own text for a Save.
5
+ *
6
+ * @module
7
+ */
8
+ import { MASK, maskHeaders, maskUrl, unmaskHeaders, unmaskUrl } from '@theoremjs/agents/surface';
9
+ const URLS = ['endpoint', 'serverUrl'];
10
+ /** What a held URL is told as in a refusal: a mask in a URL has no name of its own to give. */
11
+ const URL_LABELS = {
12
+ endpoint: 'its endpoint URL',
13
+ serverUrl: 'its server URL',
14
+ };
15
+ const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
16
+ /** A tool as the page gets it: the credentials in its URLs and headers masked. */
17
+ export function withoutCredentials(tool) {
18
+ const shown = { ...tool };
19
+ for (const key of URLS) {
20
+ const url = shown[key];
21
+ if (typeof url === 'string')
22
+ shown[key] = maskUrl(url);
23
+ }
24
+ if (isRecord(shown.headers))
25
+ shown.headers = maskHeaders(shown.headers);
26
+ return shown;
27
+ }
28
+ /**
29
+ * What a provider connects with, as the page gets it: its addresses with any credential masked.
30
+ * Only what is text is told; a provider defined with nothing has nothing to tell.
31
+ */
32
+ export function shownConnection(connection) {
33
+ if (!isRecord(connection))
34
+ return undefined;
35
+ const shown = Object.entries(connection).flatMap(([key, value]) => typeof value === 'string' ? [[key, maskUrl(value)]] : []);
36
+ return shown.length > 0 ? Object.fromEntries(shown) : undefined;
37
+ }
38
+ /**
39
+ * Why a provider cannot run or be saved, when what it connects with shows a mask. A provider's
40
+ * credential is its key slot's, so a mask here stands for nothing the project holds.
41
+ */
42
+ export function unheldConnection(id, connection) {
43
+ const names = Object.entries(connection ?? {}).flatMap(([name, value]) => value.includes(MASK) ? [name] : []);
44
+ return names.length
45
+ ? `${id}: the studio has no value for ${names.join(', ')}. A provider's key comes from its key slot. Write the address without one.` // labels-exempt: builder diagnostic
46
+ : undefined;
47
+ }
48
+ /** One setting of a tool the page sent, each mask in it filled in from `held`, the project's own. */
49
+ export function heldSetting(key, shown, held) {
50
+ if (URLS.includes(key) && typeof shown === 'string') {
51
+ return typeof held === 'string' ? unmaskUrl(shown, held) : shown;
52
+ }
53
+ if (key === 'headers' && isRecord(shown)) {
54
+ return unmaskHeaders(shown, isRecord(held) ? held : undefined);
55
+ }
56
+ return shown;
57
+ }
58
+ /**
59
+ * The credentials `tool` shows masked that nothing holds a value for: every mask, or with
60
+ * `opened`, the tool as the page got it, the masks that were not there.
61
+ */
62
+ export function unheld(tool, opened) {
63
+ const [shown, before] = [tool, (opened ?? {})];
64
+ const names = [];
65
+ for (const key of URLS) {
66
+ const [url, was] = [shown[key], before[key]];
67
+ if (typeof url !== 'string')
68
+ continue;
69
+ // A mask the opened URL had is one the project holds; any text stands in for its value here.
70
+ const filled = unmaskUrl(url, typeof was === 'string' ? was.replaceAll(MASK, 'held') : '');
71
+ if (filled.includes(MASK))
72
+ names.push(URL_LABELS[key] ?? key);
73
+ }
74
+ const was = isRecord(before.headers) ? before.headers : {};
75
+ for (const [name, value] of Object.entries(isRecord(shown.headers) ? shown.headers : {})) {
76
+ if (value === MASK && was[name] !== MASK)
77
+ names.push(name);
78
+ }
79
+ return names;
80
+ }
81
+ /** Why a tool cannot run or be saved, when it shows a credential nothing holds a value for. */
82
+ export function unheldProblem(name, tool, opened) {
83
+ const names = unheld(tool, opened);
84
+ return names.length
85
+ ? `${name}: the studio has no value for ${names.join(', ')}. It fills in only what the project's file holds. Write the value there, or put it under Auth.` // labels-exempt: builder diagnostic
86
+ : undefined;
87
+ }
package/installed.mjs ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Stops with the install line when a package the studio runs on is missing. The studio is opt-in:
3
+ * nothing installs it with the kernel, so its commands check for it and never install it themselves.
4
+ * The packages resolve from here as the studio's own code finds them: beside it in the repo, or
5
+ * in the project's install when the studio is installed from the registry.
6
+ */
7
+ import { existsSync } from 'node:fs';
8
+ import { createRequire } from 'node:module';
9
+ import path from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { BUILT_PAGE } from './page.mjs';
12
+
13
+ const here = path.dirname(fileURLToPath(import.meta.url));
14
+ const require = createRequire(import.meta.url);
15
+
16
+ /** Whether this is the installed package, with its page built. The repo's page is built as it is served. */
17
+ export const builtPage = existsSync(path.join(here, BUILT_PAGE, 'index.html'));
18
+ /** What the project's server runs on, and in the repo what Vite builds the page from. */
19
+ const NEEDED = [
20
+ 'zod',
21
+ '@theoremjs/agents',
22
+ '@theoremjs/react',
23
+ ...(builtPage ? [] : ['react', 'react-dom', '@astryxdesign/core', 'vite']),
24
+ ];
25
+
26
+ /** Whether `name` is installed where Node would look for it from here; its exports need not list its manifest. */
27
+ const installed = (name) =>
28
+ (require.resolve.paths(name) ?? []).some((dir) =>
29
+ existsSync(path.join(dir, name, 'package.json')),
30
+ );
31
+ const missing = NEEDED.filter((name) => !installed(name));
32
+ if (missing.length) {
33
+ const line = here.split(path.sep).includes('node_modules')
34
+ ? `npm install ${missing.join(' ')}`
35
+ : `npm install --prefix ${here}`;
36
+ console.error(
37
+ `The studio is missing ${missing.join(', ')}. Install it once, then run this again:\n\n ${line}\n`,
38
+ );
39
+ process.exit(1);
40
+ }
package/lent-keys.d.ts ADDED
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Keys a page lends to whoever opens its studio. The studio runs agents on them for anyone, so it
3
+ * holds those runs to what the page says its keys allow. A studio given none has no such runs:
4
+ * it runs on the builder's own keys, their own machine, or their project.
5
+ *
6
+ * @module
7
+ */
8
+ import type { TaintGate } from '@theoremjs/agents/guardrails';
9
+ import type { DecisionQuestion } from '@theoremjs/agents/kernel';
10
+ import type { ModelBindingDraft, StudioProfileType } from './draft.ts';
11
+ import type { ModelRoute } from './providers.ts';
12
+ /** An agent type that runs on a model. */
13
+ export type ModelProfileType = Exclude<StudioProfileType, 'host'>;
14
+ /** Where a new model of `type` starts: its provider and API model. */
15
+ export type ModelStart = (type: ModelProfileType) => Pick<ModelBindingDraft, 'protocol' | 'provider' | 'apiId'>;
16
+ /** What switching an agent's type reads from lent keys: each type's models, and where a new one starts. */
17
+ export type ModelPicks = Pick<LentKeys, 'models' | 'start'>;
18
+ /** A model the lent keys offer, as a picker lists it. */
19
+ export interface LentModel {
20
+ id: string;
21
+ label: string;
22
+ }
23
+ /** A binding as these checks read it: its route and its built-ins. */
24
+ export type LentBinding = ModelRoute & Pick<ModelBindingDraft, 'builtInTools'>;
25
+ /** What is wrong with a binding, on the field that holds it. */
26
+ export interface ModelBindingViolation {
27
+ field: 'provider' | 'apiId' | 'builtInTools';
28
+ message: string;
29
+ }
30
+ /** The most a decision sent on the lent keys may hold. */
31
+ export interface LentDecisionLimits {
32
+ questions: number;
33
+ /** Options or levels in one question. */
34
+ criteria: number;
35
+ instructionsChars: number;
36
+ criterionChars: number;
37
+ /** Question ids, option labels, model ids, and the handle. */
38
+ nameChars: number;
39
+ /** The profile id, the contract, and the API model. */
40
+ idChars: number;
41
+ stateBytes: number;
42
+ /** Images one decision may carry; 0 takes none, and a box question then has nothing to read. */
43
+ images: number;
44
+ /** The most one image may weigh, in bytes, before it is encoded. */
45
+ imageBytes: number;
46
+ timeoutMs: number;
47
+ }
48
+ /** What runs on lent keys keep to, whatever a profile says. The editor notes each where it is set. */
49
+ export interface LentHolds {
50
+ /** Runs reach public hosts only: a profile's network rules give way to the kernel's default. */
51
+ publicHostsOnly: boolean;
52
+ /** The calls a turn refuses once it has read a remote result. A profile that refuses more keeps its own. */
53
+ afterRemoteRead: TaintGate;
54
+ }
55
+ /** A page's lent keys, and what runs on them. */
56
+ export interface LentKeys {
57
+ /** The models a binding of `type` may pick on a provider from `definition`, in order. */
58
+ models(type: ModelProfileType, definition: string | undefined): readonly LentModel[];
59
+ /** Whether the keys run agents of `type` on a provider from `definition`. */
60
+ runs(type: ModelProfileType, definition: string | undefined): boolean;
61
+ /** The binding a new model of `type` starts on. */
62
+ start: ModelStart;
63
+ /** Why `binding` can't run on the keys; `null` when it can. */
64
+ violation(binding: LentBinding): ModelBindingViolation | null;
65
+ /** The built-ins `apiId` may use on the keys. */
66
+ builtins(apiId: string): readonly string[];
67
+ /** The most a decision may hold. */
68
+ decision: LentDecisionLimits;
69
+ /** Why `question` can't be asked of `binding`'s model; `null` when it can. */
70
+ questionViolation(binding: ModelRoute, question: DecisionQuestion): string | null;
71
+ /** Why `state` can't be decided on by `binding`'s model; `null` when it can. */
72
+ stateViolation(binding: ModelRoute, state: unknown): string | null;
73
+ /** The most input tokens a Live session holds on the keys. Compression starts below it. */
74
+ liveInputTokens: number;
75
+ /** What runs on the keys keep to, whatever a profile says. */
76
+ holds: LentHolds;
77
+ }
78
+ /**
79
+ * What a studio runs on: a page's lent keys, the builder's own keys, or their own machine. Runs
80
+ * on lent keys always carry the keys they are held to.
81
+ */
82
+ export type StudioRunsOn = {
83
+ mode: 'demo';
84
+ keys: LentKeys;
85
+ } | {
86
+ mode: 'byok';
87
+ } | {
88
+ mode: 'local';
89
+ };
90
+ /**
91
+ * The compression sizes a Live session runs with on lent keys: those the profile sets, and for a
92
+ * blank one Gemini's rule (start at 80% of the window, keep half the start), applied to what a
93
+ * session holds on the keys. Gemini would apply it to the model's whole window, past what the keys
94
+ * hold, so the session would be cut before compression started.
95
+ */
96
+ export declare function lentCompression(keys: Pick<LentKeys, 'liveInputTokens'>, set: {
97
+ triggerTokens?: number;
98
+ targetTokens?: number;
99
+ }): {
100
+ triggerTokens: number;
101
+ targetTokens: number;
102
+ };
103
+ /** The builder's own keys. */
104
+ export declare const ON_OWN_KEYS: StudioRunsOn;
105
+ /** Where a run's tools may reach, from what the studio runs it on. */
106
+ export type RuntimeNetwork = 'public' | 'asWritten' | 'none';
107
+ /** The parts of a runtime that decide its network. */
108
+ export type NetworkRuntime = StudioRunsOn & {
109
+ remoteTools?: boolean;
110
+ providers?: {
111
+ local?: unknown;
112
+ };
113
+ };
114
+ /**
115
+ * Lent keys that hold runs to public hosts drop the draft's network rules. A local model with
116
+ * remote tools off reaches no host. Otherwise the rules run as written.
117
+ */
118
+ export declare function runtimeNetwork(runtime: NetworkRuntime): RuntimeNetwork;
119
+ /** What the studio does with the Network section on `runtime`; nothing when it runs as written. */
120
+ export declare function studioNetworkNote(runtime: NetworkRuntime): string | undefined;
121
+ /** What lent keys refuse after a remote read; nothing when the profile's own setting runs. */
122
+ export declare function studioTaintNote(on: StudioRunsOn): string | undefined;
package/lent-keys.js ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Keys a page lends to whoever opens its studio. The studio runs agents on them for anyone, so it
3
+ * holds those runs to what the page says its keys allow. A studio given none has no such runs:
4
+ * it runs on the builder's own keys, their own machine, or their project.
5
+ *
6
+ * @module
7
+ */
8
+ /**
9
+ * The compression sizes a Live session runs with on lent keys: those the profile sets, and for a
10
+ * blank one Gemini's rule (start at 80% of the window, keep half the start), applied to what a
11
+ * session holds on the keys. Gemini would apply it to the model's whole window, past what the keys
12
+ * hold, so the session would be cut before compression started.
13
+ */
14
+ export function lentCompression(keys, set) {
15
+ const triggerTokens = set.triggerTokens ?? Math.round(keys.liveInputTokens * 0.8);
16
+ return { triggerTokens, targetTokens: set.targetTokens ?? Math.round(triggerTokens / 2) };
17
+ }
18
+ /** The builder's own keys. */
19
+ export const ON_OWN_KEYS = { mode: 'byok' };
20
+ /**
21
+ * Lent keys that hold runs to public hosts drop the draft's network rules. A local model with
22
+ * remote tools off reaches no host. Otherwise the rules run as written.
23
+ */
24
+ export function runtimeNetwork(runtime) {
25
+ if (runtime.mode === 'demo')
26
+ return runtime.keys.holds.publicHostsOnly ? 'public' : 'asWritten';
27
+ return (runtime.mode === 'local' || runtime.providers?.local) && !runtime.remoteTools
28
+ ? 'none'
29
+ : 'asWritten';
30
+ }
31
+ const NETWORK_NOTES = {
32
+ public: "This page's keys reach public hosts only.",
33
+ asWritten: undefined,
34
+ none: 'Remote tools off: no host reached.',
35
+ };
36
+ /** What the studio does with the Network section on `runtime`; nothing when it runs as written. */
37
+ export function studioNetworkNote(runtime) {
38
+ return NETWORK_NOTES[runtimeNetwork(runtime)];
39
+ }
40
+ /** What lent keys refuse after a remote read; nothing when the profile's own setting runs. */
41
+ export function studioTaintNote(on) {
42
+ const gate = on.mode === 'demo' ? on.keys.holds.afterRemoteRead : 'off';
43
+ if (gate === 'off')
44
+ return undefined;
45
+ const refused = gate === 'write' ? 'writes' : 'destructive calls';
46
+ return `This page's keys refuse ${refused} after a remote read. Stricter settings hold.`;
47
+ }
package/line-diff.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Two texts as the lines one takes out and the other puts in, with the lines they share between.
3
+ *
4
+ * @module
5
+ */
6
+ /** One line of a diff: shared, taken out, or put in. */
7
+ export interface DiffLine {
8
+ sign: ' ' | '-' | '+';
9
+ text: string;
10
+ }
11
+ /**
12
+ * `was` and `now` line by line. A line both hold in the same order is shared; the rest are taken
13
+ * out of `was` or put in by `now`, the taken-out lines first where they meet.
14
+ */
15
+ export declare function lineDiff(was: string, now: string): DiffLine[];
package/line-diff.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Two texts as the lines one takes out and the other puts in, with the lines they share between.
3
+ *
4
+ * @module
5
+ */
6
+ /**
7
+ * `was` and `now` line by line. A line both hold in the same order is shared; the rest are taken
8
+ * out of `was` or put in by `now`, the taken-out lines first where they meet.
9
+ */
10
+ export function lineDiff(was, now) {
11
+ const [a, b] = [was.split('\n'), now.split('\n')];
12
+ // The longest run of lines both hold, from each place to the end, row after row.
13
+ const width = b.length + 1;
14
+ const held = new Array((a.length + 1) * width).fill(0);
15
+ const run = (i, j) => held[i * width + j] ?? 0;
16
+ for (let i = a.length - 1; i >= 0; i -= 1) {
17
+ for (let j = b.length - 1; j >= 0; j -= 1) {
18
+ held[i * width + j] =
19
+ a[i] === b[j] ? run(i + 1, j + 1) + 1 : Math.max(run(i + 1, j), run(i, j + 1));
20
+ }
21
+ }
22
+ const lines = [];
23
+ let [i, j] = [0, 0];
24
+ while (i < a.length || j < b.length) {
25
+ const [out, put] = [a[i], b[j]];
26
+ if (out !== undefined && out === put) {
27
+ lines.push({ sign: ' ', text: out });
28
+ i += 1;
29
+ j += 1;
30
+ }
31
+ else if (out !== undefined && (put === undefined || run(i + 1, j) >= run(i, j + 1))) {
32
+ lines.push({ sign: '-', text: out });
33
+ i += 1;
34
+ }
35
+ else {
36
+ lines.push({ sign: '+', text: put ?? '' });
37
+ j += 1;
38
+ }
39
+ }
40
+ return lines;
41
+ }
@@ -0,0 +1,22 @@
1
+ import type { ProfileDefinition } from '@theoremjs/agents';
2
+ import type { PageTools } from '@theoremjs/react/client';
3
+ import type { ToolRegistration } from './registrations.ts';
4
+ import type { StudioRunPayload } from './run-payload.ts';
5
+ /** The first message on a studio live call: the draft the relay runs, on a scope of its own. */
6
+ export type StudioLiveDraftMessage = {
7
+ type: 'draft';
8
+ profile: ProfileDefinition;
9
+ customTools: ToolRegistration[];
10
+ };
11
+ /**
12
+ * A live call that carries its draft, so no other call can reach or replace it.
13
+ * The react client's `LiveConnection` accepts it as is.
14
+ */
15
+ export declare function studioLiveConnection(payload: StudioRunPayload): {
16
+ openMessage: StudioLiveDraftMessage;
17
+ };
18
+ /**
19
+ * The studio's page: for each tool the page answers (`answeredBy: 'page'`), a function that
20
+ * answers with the tool's stub. A host's page does the real thing here.
21
+ */
22
+ export declare function studioPageTools(payload: Pick<StudioRunPayload, 'customTools'>): PageTools;
@@ -0,0 +1,27 @@
1
+ import { stubOutputFromSchema } from "./stub.js";
2
+ /**
3
+ * A live call that carries its draft, so no other call can reach or replace it.
4
+ * The react client's `LiveConnection` accepts it as is.
5
+ */
6
+ export function studioLiveConnection(payload) {
7
+ const openMessage = {
8
+ type: 'draft',
9
+ profile: payload.profile,
10
+ customTools: payload.customTools,
11
+ };
12
+ return { openMessage };
13
+ }
14
+ /**
15
+ * The studio's page: for each tool the page answers (`answeredBy: 'page'`), a function that
16
+ * answers with the tool's stub. A host's page does the real thing here.
17
+ */
18
+ export function studioPageTools(payload) {
19
+ const pageTools = {};
20
+ for (const tool of payload.customTools) {
21
+ if (tool.type !== 'function' || tool.answeredBy !== 'page')
22
+ continue;
23
+ const output = tool.stubResponse ?? stubOutputFromSchema(tool.outputSchema);
24
+ pageTools[tool.name] = () => ({ output });
25
+ }
26
+ return pageTools;
27
+ }
@@ -0,0 +1,15 @@
1
+ import type { LabelOverrides, LiveSession, TurnEvent } from '@theoremjs/agents';
2
+ import { type ClientTurnOptions } from '@theoremjs/agents/host';
3
+ import { type PageToolResult } from '@theoremjs/react/server';
4
+ import type { StudioTraceRoute } from './traces.ts';
5
+ export type StudioLiveSocket = Pick<WebSocket, 'send' | 'close' | 'addEventListener'>;
6
+ export type StudioLiveBridgeOptions = {
7
+ pageResult?: (result: PageToolResult) => Promise<boolean | undefined>;
8
+ /** Save trusted checkpoint ownership before the bridge exposes the event. */
9
+ beforeEvent?: (event: TurnEvent) => void | Promise<void>;
10
+ /** How long the browser has to run a call the model made before the bridge settles it as unanswered. */
11
+ clientCallTimeoutMs?: number;
12
+ /** Who reads the bridge's events and failures (`forClient`). Default: a visitor. */
13
+ clientEvents?: ClientTurnOptions;
14
+ };
15
+ export declare function attachStudioLiveSession(socket: StudioLiveSocket, session: LiveSession, profileId: string, sessionId: string, traces: StudioTraceRoute, labels?: LabelOverrides, options?: StudioLiveBridgeOptions): Promise<void>;
@@ -0,0 +1,202 @@
1
+ import { clientError, forClient, forClientEvents, } from '@theoremjs/agents/host';
2
+ import { bytesToBase64 } from '@theoremjs/agents/kernel';
3
+ import { issuedOperationId as requiredOperationId } from '@theoremjs/react/client';
4
+ import { parseLiveClientMessage } from '@theoremjs/react/server';
5
+ function errorBody(err, reads) {
6
+ return clientError(err, reads.labels, reads.clientEvents);
7
+ }
8
+ function errorEnvelope(err, reads) {
9
+ return JSON.stringify({ type: 'error', ...errorBody(err, reads) });
10
+ }
11
+ function callWatch(session, timeoutMs) {
12
+ const timers = new Map();
13
+ const stop = (callId, operationId) => {
14
+ const watched = timers.get(callId);
15
+ if (watched?.operationId !== operationId)
16
+ return;
17
+ clearTimeout(watched.timer);
18
+ timers.delete(callId);
19
+ };
20
+ return {
21
+ start(callId, operationId) {
22
+ const previous = timers.get(callId);
23
+ if (previous)
24
+ clearTimeout(previous.timer);
25
+ timers.set(callId, {
26
+ operationId,
27
+ timer: setTimeout(() => {
28
+ timers.delete(callId);
29
+ // The kernel never times out an ungated held call; a refusal here means it already settled.
30
+ session.executeTool({ callId, operationId, page: { timedOut: true } }).catch(() => { });
31
+ }, timeoutMs),
32
+ });
33
+ },
34
+ stop,
35
+ stopAll() {
36
+ for (const watched of timers.values())
37
+ clearTimeout(watched.timer);
38
+ timers.clear();
39
+ },
40
+ };
41
+ }
42
+ function pipeBrowserToSession(serverWs, session, watch, reads, pageResult) {
43
+ // A send the session refuses (a channel the profile turned off, a closed call) reaches the browser.
44
+ const forward = (sent) => {
45
+ sent.catch((err) => {
46
+ serverWs.send(errorEnvelope(err, reads));
47
+ });
48
+ };
49
+ serverWs.addEventListener('message', (event) => {
50
+ try {
51
+ if (typeof event.data === 'string') {
52
+ // A message that fails its check ends the call with a `request` error (the catch below).
53
+ const msg = parseLiveClientMessage(event.data);
54
+ switch (msg.type) {
55
+ case 'audio':
56
+ forward(session.sendAudio({
57
+ data: msg.data,
58
+ mimeType: 'audio/pcm;rate=16000',
59
+ }));
60
+ return;
61
+ case 'video':
62
+ forward(session.sendVideo({ data: msg.data, mimeType: msg.mimeType }));
63
+ return;
64
+ case 'text':
65
+ forward(session.sendText(msg.text));
66
+ return;
67
+ case 'context':
68
+ forward(session.sendContext({ client: msg.context }));
69
+ return;
70
+ case 'executeTool': {
71
+ const { type: _type, output, grantId, unanswered, ...call } = msg;
72
+ if (grantId) {
73
+ if (!pageResult)
74
+ throw new Error('Page dispatch result is unavailable');
75
+ forward(pageResult({
76
+ callId: call.callId,
77
+ operationId: call.operationId,
78
+ grantId,
79
+ page: unanswered ? { unanswered: true } : { output },
80
+ }).then((settled) => {
81
+ if (settled)
82
+ serverWs.send(JSON.stringify({
83
+ type: 'executeToolResult',
84
+ callId: call.callId,
85
+ operationId: call.operationId,
86
+ status: 'settled',
87
+ }));
88
+ }));
89
+ return;
90
+ }
91
+ if (pageResult && output !== undefined)
92
+ throw new Error('Page result requires a dispatch grant');
93
+ watch.stop(call.callId, call.operationId);
94
+ void answerExecuteTool(serverWs, session, output === undefined ? call : { ...call, page: { output } }, reads);
95
+ return;
96
+ }
97
+ }
98
+ }
99
+ if (event.data instanceof ArrayBuffer || event.data instanceof Uint8Array) {
100
+ forward(session.sendAudio({
101
+ data: bytesToBase64(event.data instanceof Uint8Array ? event.data : new Uint8Array(event.data)),
102
+ mimeType: 'audio/pcm;rate=16000',
103
+ }));
104
+ }
105
+ }
106
+ catch (err) {
107
+ serverWs.send(errorEnvelope(err, reads));
108
+ }
109
+ });
110
+ }
111
+ async function pipeSessionToBrowser(serverWs, session, profileId, sessionId, traces, watch, reads, beforeEvent) {
112
+ serverWs.send(JSON.stringify({ type: 'ready', profile: profileId, sessionId }));
113
+ try {
114
+ for await (const event of session.events()) {
115
+ await beforeEvent?.(event);
116
+ if (event.type === 'error') {
117
+ serverWs.send(JSON.stringify(forClient(event, reads.clientEvents)));
118
+ try {
119
+ serverWs.close(1011, 'session error');
120
+ }
121
+ catch {
122
+ /* ignore */
123
+ }
124
+ return;
125
+ }
126
+ if (event.type === 'tool') {
127
+ const { tool } = event;
128
+ if (tool.phase === 'dispatch') {
129
+ watch.stop(tool.callId, requiredOperationId(tool));
130
+ serverWs.send(JSON.stringify({
131
+ type: 'executeToolResult',
132
+ callId: tool.callId,
133
+ operationId: requiredOperationId(tool),
134
+ status: 'dispatched',
135
+ grantId: tool.grantId,
136
+ arguments: tool.arguments,
137
+ }));
138
+ }
139
+ if (tool.phase === undefined)
140
+ watch.start(tool.callId, requiredOperationId(tool));
141
+ else if (tool.phase === 'complete' || tool.phase === 'error' || tool.phase === 'cancel') {
142
+ watch.stop(tool.callId, requiredOperationId(tool));
143
+ }
144
+ }
145
+ serverWs.send(JSON.stringify({ type: 'events', events: forClientEvents([event], reads.clientEvents) }));
146
+ }
147
+ }
148
+ catch (err) {
149
+ serverWs.send(errorEnvelope(err, reads));
150
+ }
151
+ finally {
152
+ watch.stopAll();
153
+ // The events loop ends after the session's root record is written.
154
+ traces.close();
155
+ try {
156
+ serverWs.close(1000, 'session ended');
157
+ }
158
+ catch {
159
+ /* ignore */
160
+ }
161
+ }
162
+ }
163
+ /** Run the browser's `executeTool` on the session and tell the browser what became of the call. */
164
+ async function answerExecuteTool(serverWs, session, call, reads) {
165
+ try {
166
+ const result = await session.executeTool(call);
167
+ serverWs.send(JSON.stringify(result.gated
168
+ ? {
169
+ type: 'executeToolResult',
170
+ callId: call.callId,
171
+ operationId: call.operationId,
172
+ status: 'gated',
173
+ gate: result.gated,
174
+ }
175
+ : {
176
+ type: 'executeToolResult',
177
+ callId: call.callId,
178
+ operationId: call.operationId,
179
+ status: 'settled',
180
+ }));
181
+ }
182
+ catch (err) {
183
+ // The session refused it (an unknown call, a decision it takes no more): the browser reads why.
184
+ serverWs.send(JSON.stringify({
185
+ type: 'executeToolResult',
186
+ callId: call.callId,
187
+ operationId: call.operationId,
188
+ status: 'refused',
189
+ body: errorBody(err, reads),
190
+ }));
191
+ }
192
+ }
193
+ const CLIENT_CALL_TIMEOUT_MS = 20_000;
194
+ export function attachStudioLiveSession(socket, session, profileId, sessionId, traces, labels, options = {}) {
195
+ const watch = callWatch(session, options.clientCallTimeoutMs ?? CLIENT_CALL_TIMEOUT_MS);
196
+ const reads = { labels, clientEvents: options.clientEvents };
197
+ pipeBrowserToSession(socket, session, watch, reads, options.pageResult);
198
+ socket.addEventListener('close', () => {
199
+ void session.close('client disconnected');
200
+ });
201
+ return pipeSessionToBrowser(socket, session, profileId, sessionId, traces, watch, reads, options.beforeEvent);
202
+ }