synthos 0.8.0 → 0.9.0

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 (359) hide show
  1. package/README.md +1 -1
  2. package/default-pages/application/page.html +42 -0
  3. package/default-pages/application/page.json +10 -0
  4. package/default-pages/elevenlabs_effects_studio/page.html +1363 -0
  5. package/default-pages/elevenlabs_effects_studio/page.json +11 -0
  6. package/default-pages/elevenlabs_voice_studio/page.html +801 -0
  7. package/default-pages/elevenlabs_voice_studio/page.json +11 -0
  8. package/default-pages/{json_tools.html → json_tools/page.html} +13 -11
  9. package/default-pages/json_tools/page.json +10 -0
  10. package/default-pages/my_notes/notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json +5 -0
  11. package/default-pages/my_notes/page.html +132 -0
  12. package/default-pages/{my_notes.json → my_notes/page.json} +2 -2
  13. package/default-pages/neon_asteroids/files/Ambient_Space.mp3 +0 -0
  14. package/default-pages/neon_asteroids/files/Ambient_Space2.mp3 +0 -0
  15. package/default-pages/neon_asteroids/files/Ambient_Space3.mp3 +0 -0
  16. package/default-pages/neon_asteroids/files/Asteroid_Explosion.mp3 +0 -0
  17. package/default-pages/neon_asteroids/files/Hyperspace_Jump.mp3 +0 -0
  18. package/default-pages/neon_asteroids/files/Laser_Fire.mp3 +0 -0
  19. package/default-pages/neon_asteroids/files/Menu_Navigate.mp3 +0 -0
  20. package/default-pages/neon_asteroids/files/Power_Up_Collect.mp3 +0 -0
  21. package/default-pages/neon_asteroids/files/Saucer_Alert.mp3 +0 -0
  22. package/default-pages/neon_asteroids/files/Ship_Thrust.mp3 +0 -0
  23. package/default-pages/neon_asteroids/files/effects.json +74 -0
  24. package/default-pages/neon_asteroids/page.html +1822 -0
  25. package/default-pages/{neon_asteroids.json → neon_asteroids/page.json} +3 -3
  26. package/default-pages/{oregon_trail.html → oregon_trail/page.html} +14 -12
  27. package/default-pages/{oregon_trail.json → oregon_trail/page.json} +2 -2
  28. package/default-pages/retro_game_starter/page.html +1308 -0
  29. package/default-pages/retro_game_starter/page.json +12 -0
  30. package/default-pages/{sidebar_page.html → sidebar_page/page.html} +12 -10
  31. package/default-pages/sidebar_page/page.json +10 -0
  32. package/default-pages/{solar_explorer.html → solar_explorer/page.html} +14 -11
  33. package/default-pages/{solar_explorer.json → solar_explorer/page.json} +2 -2
  34. package/default-pages/{solar_tutorial.html → solar_tutorial/page.html} +12 -10
  35. package/default-pages/solar_tutorial/page.json +10 -0
  36. package/default-pages/{two-panel_page.html → two-panel_page/page.html} +13 -11
  37. package/default-pages/two-panel_page/page.json +10 -0
  38. package/default-pages/{us_map.html → us_map/page.html} +193 -192
  39. package/default-pages/{us_map.json → us_map/page.json} +12 -12
  40. package/default-pages/{us_map_1850.html → us_map_1850/page.html} +326 -325
  41. package/default-pages/{us_map_1850.json → us_map_1850/page.json} +12 -12
  42. package/default-pages/{western_cities_1850.html → western_cities_1850/page.html} +527 -526
  43. package/default-pages/{western_cities_1850.json → western_cities_1850/page.json} +12 -12
  44. package/default-themes/aurora-dawn.json +19 -0
  45. package/default-themes/aurora-dawn.v3.css +198 -0
  46. package/default-themes/aurora-dusk.json +19 -0
  47. package/default-themes/aurora-dusk.v3.css +200 -0
  48. package/default-themes/cosmos-dawn.json +19 -0
  49. package/default-themes/cosmos-dawn.v3.css +198 -0
  50. package/default-themes/cosmos-dusk.json +19 -0
  51. package/default-themes/cosmos-dusk.v3.css +200 -0
  52. package/default-themes/high-contrast-dark.json +19 -0
  53. package/default-themes/high-contrast-dark.v3.css +200 -0
  54. package/default-themes/high-contrast-light.json +19 -0
  55. package/default-themes/high-contrast-light.v3.css +198 -0
  56. package/default-themes/nebula-dawn.v2.css +110 -0
  57. package/default-themes/nebula-dawn.v3.css +199 -0
  58. package/default-themes/nebula-dusk.v2.css +104 -0
  59. package/default-themes/nebula-dusk.v3.css +201 -0
  60. package/default-themes/solar-flare-dawn.json +19 -0
  61. package/default-themes/solar-flare-dawn.v3.css +198 -0
  62. package/default-themes/solar-flare-dusk.json +19 -0
  63. package/default-themes/solar-flare-dusk.v3.css +200 -0
  64. package/dist/agents/index.d.ts +1 -1
  65. package/dist/agents/index.d.ts.map +1 -1
  66. package/dist/agents/index.js +2 -1
  67. package/dist/agents/index.js.map +1 -1
  68. package/dist/agents/openclaw/gatewayManager.d.ts +4 -0
  69. package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -1
  70. package/dist/agents/openclaw/gatewayManager.js +27 -11
  71. package/dist/agents/openclaw/gatewayManager.js.map +1 -1
  72. package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -1
  73. package/dist/agents/openclaw/openclawProvider.js +2 -4
  74. package/dist/agents/openclaw/openclawProvider.js.map +1 -1
  75. package/dist/agents/openclaw/sshTunnelManager.d.ts +2 -0
  76. package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -1
  77. package/dist/agents/openclaw/sshTunnelManager.js +31 -12
  78. package/dist/agents/openclaw/sshTunnelManager.js.map +1 -1
  79. package/dist/builders/anthropic.d.ts +31 -0
  80. package/dist/builders/anthropic.d.ts.map +1 -0
  81. package/dist/builders/anthropic.js +227 -0
  82. package/dist/builders/anthropic.js.map +1 -0
  83. package/dist/builders/fireworksai.d.ts +9 -0
  84. package/dist/builders/fireworksai.d.ts.map +1 -0
  85. package/dist/builders/fireworksai.js +57 -0
  86. package/dist/builders/fireworksai.js.map +1 -0
  87. package/dist/builders/index.d.ts +13 -0
  88. package/dist/builders/index.d.ts.map +1 -0
  89. package/dist/builders/index.js +31 -0
  90. package/dist/builders/index.js.map +1 -0
  91. package/dist/builders/openai.d.ts +8 -0
  92. package/dist/builders/openai.d.ts.map +1 -0
  93. package/dist/builders/openai.js +87 -0
  94. package/dist/builders/openai.js.map +1 -0
  95. package/dist/builders/types.d.ts +54 -0
  96. package/dist/builders/types.d.ts.map +1 -0
  97. package/dist/builders/types.js +211 -0
  98. package/dist/builders/types.js.map +1 -0
  99. package/dist/connectors/index.d.ts.map +1 -1
  100. package/dist/connectors/index.js +3 -2
  101. package/dist/connectors/index.js.map +1 -1
  102. package/dist/connectors/registry.d.ts +2 -1
  103. package/dist/connectors/registry.d.ts.map +1 -1
  104. package/dist/connectors/registry.js +31 -8
  105. package/dist/connectors/registry.js.map +1 -1
  106. package/dist/customizer/Customizer.d.ts +57 -0
  107. package/dist/customizer/Customizer.d.ts.map +1 -0
  108. package/dist/customizer/Customizer.js +124 -0
  109. package/dist/customizer/Customizer.js.map +1 -0
  110. package/dist/customizer/index.d.ts.map +1 -0
  111. package/dist/customizer/index.js +9 -0
  112. package/dist/customizer/index.js.map +1 -0
  113. package/dist/files.d.ts +16 -0
  114. package/dist/files.d.ts.map +1 -1
  115. package/dist/files.js +60 -1
  116. package/dist/files.js.map +1 -1
  117. package/dist/index.d.ts.map +1 -1
  118. package/dist/index.js +1 -0
  119. package/dist/index.js.map +1 -1
  120. package/dist/init.d.ts +10 -6
  121. package/dist/init.d.ts.map +1 -1
  122. package/dist/init.js +96 -113
  123. package/dist/init.js.map +1 -1
  124. package/dist/migrations.d.ts.map +1 -1
  125. package/dist/migrations.js +23 -10
  126. package/dist/migrations.js.map +1 -1
  127. package/dist/models/anthropic.d.ts +4 -2
  128. package/dist/models/anthropic.d.ts.map +1 -1
  129. package/dist/models/anthropic.js +33 -6
  130. package/dist/models/anthropic.js.map +1 -1
  131. package/dist/models/fireworksai.d.ts.map +1 -1
  132. package/dist/models/fireworksai.js +9 -1
  133. package/dist/models/fireworksai.js.map +1 -1
  134. package/dist/models/index.d.ts +1 -1
  135. package/dist/models/index.d.ts.map +1 -1
  136. package/dist/models/index.js +2 -1
  137. package/dist/models/index.js.map +1 -1
  138. package/dist/models/openai.d.ts +1 -1
  139. package/dist/models/openai.d.ts.map +1 -1
  140. package/dist/models/openai.js +24 -3
  141. package/dist/models/openai.js.map +1 -1
  142. package/dist/models/types.d.ts +20 -1
  143. package/dist/models/types.d.ts.map +1 -1
  144. package/dist/models/types.js +6 -1
  145. package/dist/models/types.js.map +1 -1
  146. package/dist/pages.d.ts +30 -7
  147. package/dist/pages.d.ts.map +1 -1
  148. package/dist/pages.js +177 -55
  149. package/dist/pages.js.map +1 -1
  150. package/dist/service/server.d.ts.map +1 -1
  151. package/dist/service/server.js +37 -8
  152. package/dist/service/server.js.map +1 -1
  153. package/dist/service/transformPage.d.ts +47 -20
  154. package/dist/service/transformPage.d.ts.map +1 -1
  155. package/dist/service/transformPage.js +514 -293
  156. package/dist/service/transformPage.js.map +1 -1
  157. package/dist/service/useAgentRoutes.d.ts +2 -1
  158. package/dist/service/useAgentRoutes.d.ts.map +1 -1
  159. package/dist/service/useAgentRoutes.js +5 -2
  160. package/dist/service/useAgentRoutes.js.map +1 -1
  161. package/dist/service/useApiRoutes.d.ts.map +1 -1
  162. package/dist/service/useApiRoutes.js +237 -136
  163. package/dist/service/useApiRoutes.js.map +1 -1
  164. package/dist/service/useConnectorRoutes.js +6 -6
  165. package/dist/service/useConnectorRoutes.js.map +1 -1
  166. package/dist/service/useFileRoutes.d.ts +4 -0
  167. package/dist/service/useFileRoutes.d.ts.map +1 -0
  168. package/dist/service/useFileRoutes.js +122 -0
  169. package/dist/service/useFileRoutes.js.map +1 -0
  170. package/dist/service/usePageRoutes.d.ts.map +1 -1
  171. package/dist/service/usePageRoutes.js +648 -67
  172. package/dist/service/usePageRoutes.js.map +1 -1
  173. package/dist/service/useSharedDataRoutes.d.ts +4 -0
  174. package/dist/service/useSharedDataRoutes.d.ts.map +1 -0
  175. package/dist/service/useSharedDataRoutes.js +104 -0
  176. package/dist/service/useSharedDataRoutes.js.map +1 -0
  177. package/dist/service/useSharedFileRoutes.d.ts +4 -0
  178. package/dist/service/useSharedFileRoutes.d.ts.map +1 -0
  179. package/dist/service/useSharedFileRoutes.js +121 -0
  180. package/dist/service/useSharedFileRoutes.js.map +1 -0
  181. package/dist/settings.d.ts +1 -0
  182. package/dist/settings.d.ts.map +1 -1
  183. package/dist/settings.js +1 -0
  184. package/dist/settings.js.map +1 -1
  185. package/dist/synthos-cli.d.ts.map +1 -1
  186. package/dist/synthos-cli.js +4 -3
  187. package/dist/synthos-cli.js.map +1 -1
  188. package/dist/themes.d.ts +1 -0
  189. package/dist/themes.d.ts.map +1 -1
  190. package/dist/themes.js +28 -15
  191. package/dist/themes.js.map +1 -1
  192. package/migration-rules/v1-to-v2.md +193 -0
  193. package/migration-rules/v2-to-v3.md +481 -0
  194. package/package.json +11 -10
  195. package/required-pages/builder/page.html +43 -0
  196. package/required-pages/builder/page.json +10 -0
  197. package/required-pages/{pages.html → pages/page.html} +238 -233
  198. package/required-pages/pages/page.json +10 -0
  199. package/required-pages/{settings.html → settings/page.html} +389 -275
  200. package/required-pages/settings/page.json +10 -0
  201. package/required-pages/synthos_apis/page.html +846 -0
  202. package/required-pages/synthos_apis/page.json +10 -0
  203. package/required-pages/{synthos_scripts.html → synthos_scripts/page.html} +13 -11
  204. package/required-pages/synthos_scripts/page.json +10 -0
  205. package/src/agents/index.ts +1 -1
  206. package/src/agents/openclaw/gatewayManager.ts +22 -11
  207. package/src/agents/openclaw/openclawProvider.ts +2 -4
  208. package/src/agents/openclaw/sshTunnelManager.ts +19 -11
  209. package/src/builders/anthropic.ts +283 -0
  210. package/src/builders/fireworksai.ts +59 -0
  211. package/src/builders/index.ts +33 -0
  212. package/src/builders/openai.ts +89 -0
  213. package/src/builders/types.ts +261 -0
  214. package/src/connectors/index.ts +1 -1
  215. package/src/connectors/registry.ts +28 -8
  216. package/src/customizer/Customizer.ts +151 -0
  217. package/src/customizer/index.ts +5 -0
  218. package/src/files.ts +57 -0
  219. package/src/index.ts +2 -1
  220. package/src/init.ts +137 -123
  221. package/src/migrations.ts +30 -10
  222. package/src/models/anthropic.ts +40 -10
  223. package/src/models/fireworksai.ts +9 -2
  224. package/src/models/index.ts +1 -1
  225. package/src/models/openai.ts +26 -6
  226. package/src/models/types.ts +31 -1
  227. package/src/pages.ts +176 -54
  228. package/src/service/server.ts +36 -9
  229. package/src/service/transformPage.ts +557 -326
  230. package/src/service/useAgentRoutes.ts +7 -2
  231. package/src/service/useApiRoutes.ts +150 -41
  232. package/src/service/useConnectorRoutes.ts +7 -7
  233. package/src/service/useFileRoutes.ts +127 -0
  234. package/src/service/usePageRoutes.ts +720 -73
  235. package/src/service/useSharedDataRoutes.ts +106 -0
  236. package/src/service/useSharedFileRoutes.ts +126 -0
  237. package/src/settings.ts +2 -0
  238. package/src/synthos-cli.ts +4 -3
  239. package/src/themes.ts +25 -14
  240. package/static-files/favicon.svg +12 -0
  241. package/static-files/fluentlm-instructions.llmd +868 -0
  242. package/static-files/fluentlm-instructions.md +1595 -0
  243. package/static-files/fluentlm.css +4844 -0
  244. package/static-files/fluentlm.js +3602 -0
  245. package/static-files/fluentlm.min.css +1 -0
  246. package/static-files/fluentlm.min.js +1 -0
  247. package/{page-scripts/helpers-v2.js → static-files/helpers.v3.js} +82 -0
  248. package/static-files/page.v3.js +1290 -0
  249. package/static-files/recommended-frameworks.llmd +81 -0
  250. package/static-files/recommended-frameworks.md +137 -0
  251. package/static-files/retro-game.js +877 -0
  252. package/static-files/shell.css +797 -0
  253. package/static-files/theme-dark.css +169 -0
  254. package/static-files/theme-light.css +169 -0
  255. package/tests/builders.spec.ts +139 -0
  256. package/tests/pages.spec.ts +8 -8
  257. package/tests/transformPage.spec.ts +299 -360
  258. package/default-pages/application.html +0 -40
  259. package/default-pages/application.json +0 -1
  260. package/default-pages/json_tools.json +0 -1
  261. package/default-pages/my_notes.html +0 -33
  262. package/default-pages/neon_asteroids.html +0 -77
  263. package/default-pages/sidebar_page.json +0 -1
  264. package/default-pages/solar_tutorial.json +0 -1
  265. package/default-pages/two-panel_page.json +0 -1
  266. package/dist/agents/a2a/a2aProvider.d.ts +0 -3
  267. package/dist/agents/discovery.d.ts +0 -30
  268. package/dist/agents/openclaw/openclawProvider.d.ts +0 -3
  269. package/dist/agents/types.d.ts +0 -64
  270. package/dist/connectors/index.d.ts +0 -3
  271. package/dist/connectors/types.d.ts +0 -84
  272. package/dist/index.d.ts +0 -7
  273. package/dist/migrations.d.ts +0 -12
  274. package/dist/models/chainOfThought.d.ts +0 -12
  275. package/dist/models/fireworksai.d.ts +0 -30
  276. package/dist/models/logCompletePrompt.d.ts +0 -3
  277. package/dist/models/providers.d.ts +0 -8
  278. package/dist/models/utils.d.ts +0 -6
  279. package/dist/scripts.d.ts +0 -15
  280. package/dist/service/createCompletePrompt.d.ts +0 -5
  281. package/dist/service/debugLog.d.ts +0 -11
  282. package/dist/service/generateImage.d.ts +0 -32
  283. package/dist/service/index.d.ts +0 -8
  284. package/dist/service/modelInstructions.d.ts +0 -7
  285. package/dist/service/requiresSettings.d.ts +0 -3
  286. package/dist/service/server.d.ts +0 -4
  287. package/dist/service/useApiRoutes.d.ts +0 -4
  288. package/dist/service/useConnectorRoutes.d.ts +0 -4
  289. package/dist/service/useDataRoutes.d.ts +0 -4
  290. package/dist/service/useGatewayRoutes.d.ts +0 -4
  291. package/dist/service/useGatewayRoutes.d.ts.map +0 -1
  292. package/dist/service/useGatewayRoutes.js +0 -168
  293. package/dist/service/useGatewayRoutes.js.map +0 -1
  294. package/dist/service/usePageRoutes.d.ts +0 -5
  295. package/dist/synthos-cli.d.ts +0 -2
  296. package/page-scripts/page-v2.js +0 -656
  297. package/required-pages/builder.html +0 -48
  298. package/required-pages/builder.json +0 -1
  299. package/required-pages/pages.json +0 -1
  300. package/required-pages/settings.json +0 -1
  301. package/required-pages/synthos_apis.html +0 -327
  302. package/required-pages/synthos_apis.json +0 -1
  303. package/required-pages/synthos_scripts.json +0 -1
  304. package/src/connectors/airtable/connector.json +0 -27
  305. package/src/connectors/alpha-vantage/connector.json +0 -26
  306. package/src/connectors/brave-search/connector.json +0 -26
  307. package/src/connectors/cloudinary/connector.json +0 -27
  308. package/src/connectors/deepl/connector.json +0 -28
  309. package/src/connectors/elevenlabs/connector.json +0 -30
  310. package/src/connectors/giphy/connector.json +0 -27
  311. package/src/connectors/github/connector.json +0 -29
  312. package/src/connectors/huggingface/connector.json +0 -27
  313. package/src/connectors/imgur/connector.json +0 -29
  314. package/src/connectors/instagram/connector.json +0 -43
  315. package/src/connectors/jira/connector.json +0 -28
  316. package/src/connectors/mapbox/connector.json +0 -26
  317. package/src/connectors/nasa/connector.json +0 -27
  318. package/src/connectors/newsapi/connector.json +0 -27
  319. package/src/connectors/notion/connector.json +0 -28
  320. package/src/connectors/open-exchange-rates/connector.json +0 -27
  321. package/src/connectors/openweathermap/connector.json +0 -26
  322. package/src/connectors/pexels/connector.json +0 -27
  323. package/src/connectors/resend/connector.json +0 -29
  324. package/src/connectors/rss2json/connector.json +0 -27
  325. package/src/connectors/sendgrid/connector.json +0 -27
  326. package/src/connectors/spoonacular/connector.json +0 -28
  327. package/src/connectors/stability-ai/connector.json +0 -27
  328. package/src/connectors/twilio/connector.json +0 -28
  329. package/src/connectors/unsplash/connector.json +0 -27
  330. package/src/connectors/wolfram-alpha/connector.json +0 -26
  331. package/src/connectors/youtube-data/connector.json +0 -30
  332. /package/{dist/connectors → service-connectors}/airtable/connector.json +0 -0
  333. /package/{dist/connectors → service-connectors}/alpha-vantage/connector.json +0 -0
  334. /package/{dist/connectors → service-connectors}/brave-search/connector.json +0 -0
  335. /package/{dist/connectors → service-connectors}/cloudinary/connector.json +0 -0
  336. /package/{dist/connectors → service-connectors}/deepl/connector.json +0 -0
  337. /package/{dist/connectors → service-connectors}/elevenlabs/connector.json +0 -0
  338. /package/{dist/connectors → service-connectors}/giphy/connector.json +0 -0
  339. /package/{dist/connectors → service-connectors}/github/connector.json +0 -0
  340. /package/{dist/connectors → service-connectors}/huggingface/connector.json +0 -0
  341. /package/{dist/connectors → service-connectors}/imgur/connector.json +0 -0
  342. /package/{dist/connectors → service-connectors}/instagram/connector.json +0 -0
  343. /package/{dist/connectors → service-connectors}/jira/connector.json +0 -0
  344. /package/{dist/connectors → service-connectors}/mapbox/connector.json +0 -0
  345. /package/{dist/connectors → service-connectors}/nasa/connector.json +0 -0
  346. /package/{dist/connectors → service-connectors}/newsapi/connector.json +0 -0
  347. /package/{dist/connectors → service-connectors}/notion/connector.json +0 -0
  348. /package/{dist/connectors → service-connectors}/open-exchange-rates/connector.json +0 -0
  349. /package/{dist/connectors → service-connectors}/openweathermap/connector.json +0 -0
  350. /package/{dist/connectors → service-connectors}/pexels/connector.json +0 -0
  351. /package/{dist/connectors → service-connectors}/resend/connector.json +0 -0
  352. /package/{dist/connectors → service-connectors}/rss2json/connector.json +0 -0
  353. /package/{dist/connectors → service-connectors}/sendgrid/connector.json +0 -0
  354. /package/{dist/connectors → service-connectors}/spoonacular/connector.json +0 -0
  355. /package/{dist/connectors → service-connectors}/stability-ai/connector.json +0 -0
  356. /package/{dist/connectors → service-connectors}/twilio/connector.json +0 -0
  357. /package/{dist/connectors → service-connectors}/unsplash/connector.json +0 -0
  358. /package/{dist/connectors → service-connectors}/wolfram-alpha/connector.json +0 -0
  359. /package/{dist/connectors → service-connectors}/youtube-data/connector.json +0 -0
@@ -0,0 +1,59 @@
1
+ import { completePrompt } from '../models';
2
+ import { getTransformInstr } from '../service/transformPage';
3
+ import { parseBuilderResponse } from './anthropic';
4
+ import { Builder, BuilderResult, CHANGE_OPS_FORMAT_INSTRUCTION } from './types';
5
+
6
+ /**
7
+ * Create a FireworksAI-tuned builder.
8
+ * Currently identical to the Anthropic builder — separate file enables
9
+ * future per-provider tuning.
10
+ */
11
+ export function createFireworksAIBuilder(complete: completePrompt, userInstructions?: string, productName?: string): Builder {
12
+ const name = productName ?? 'SynthOS';
13
+
14
+ return {
15
+ async run(currentPage, additionalSections, userMessage, newBuild, _attachments?): Promise<BuilderResult> {
16
+ try {
17
+ // -- System message --
18
+ const systemParts: string[] = [
19
+ `${currentPage.title}\n${currentPage.content}`,
20
+ ];
21
+ for (const section of additionalSections) {
22
+ if (section.content) {
23
+ systemParts.push(`${section.title}\n${section.content}`);
24
+ }
25
+ }
26
+ const systemContent = systemParts.join('\n\n');
27
+
28
+ // -- User message --
29
+ const instructionParts: string[] = [];
30
+ if (userInstructions?.trim()) {
31
+ instructionParts.push(userInstructions);
32
+ }
33
+ for (const section of additionalSections) {
34
+ if (section.instructions?.trim()) {
35
+ instructionParts.push(section.instructions);
36
+ }
37
+ }
38
+ instructionParts.push(getTransformInstr(name));
39
+ instructionParts.push(CHANGE_OPS_FORMAT_INSTRUCTION);
40
+
41
+ const instructions = instructionParts.filter(s => s.trim() !== '').join('\n');
42
+ const promptContent = `<USER_MESSAGE>\n${userMessage}\n\n<INSTRUCTIONS>\n${instructions}`;
43
+
44
+ const result = await complete({
45
+ system: { role: 'system', content: systemContent },
46
+ prompt: { role: 'user', content: promptContent },
47
+ });
48
+
49
+ if (!result.completed) {
50
+ return { kind: 'error', error: result.error ?? new Error('Model call failed') };
51
+ }
52
+
53
+ return parseBuilderResponse(result.value!);
54
+ } catch (err: unknown) {
55
+ return { kind: 'error', error: err instanceof Error ? err : new Error(String(err)) };
56
+ }
57
+ }
58
+ };
59
+ }
@@ -0,0 +1,33 @@
1
+ import { ProviderName, completePrompt } from '../models';
2
+ import { createAnthropicBuilder, AnthropicBuilderOptions } from './anthropic';
3
+ import { createOpenAIBuilder } from './openai';
4
+ import { createFireworksAIBuilder } from './fireworksai';
5
+ import { Builder } from './types';
6
+
7
+ export { ContextSection, BuilderResult, Builder, Attachment } from './types';
8
+ export { createAnthropicBuilder, AnthropicBuilderOptions } from './anthropic';
9
+ export { createOpenAIBuilder } from './openai';
10
+ export { createFireworksAIBuilder } from './fireworksai';
11
+ export { parseBuilderResponse } from './anthropic';
12
+
13
+ /**
14
+ * Factory that creates a provider-specific builder.
15
+ */
16
+ export function createBuilder(
17
+ provider: ProviderName,
18
+ complete: completePrompt,
19
+ userInstructions?: string,
20
+ productName?: string,
21
+ options?: AnthropicBuilderOptions
22
+ ): Builder {
23
+ switch (provider) {
24
+ case 'Anthropic':
25
+ return createAnthropicBuilder(complete, userInstructions, productName, options);
26
+ case 'OpenAI':
27
+ return createOpenAIBuilder(complete, userInstructions, productName);
28
+ case 'FireworksAI':
29
+ return createFireworksAIBuilder(complete, userInstructions, productName);
30
+ default:
31
+ throw new Error(`Unknown provider: ${provider}`);
32
+ }
33
+ }
@@ -0,0 +1,89 @@
1
+ import { completePrompt, ContentBlock } from '../models';
2
+ import { getTransformInstr } from '../service/transformPage';
3
+ import { parseBuilderResponse } from './anthropic';
4
+ import { Builder, BuilderResult, OPENAI_CHANGE_OPS_SCHEMA } from './types';
5
+
6
+ /**
7
+ * Create an OpenAI-tuned builder.
8
+ * Uses OpenAI structured outputs (json_schema) for reliable JSON responses.
9
+ */
10
+ export function createOpenAIBuilder(complete: completePrompt, userInstructions?: string, productName?: string): Builder {
11
+ const name = productName ?? 'SynthOS';
12
+
13
+ return {
14
+ async run(currentPage, additionalSections, userMessage, newBuild, attachments?): Promise<BuilderResult> {
15
+ try {
16
+ // -- System message --
17
+ const systemParts: string[] = [
18
+ `${currentPage.title}\n${currentPage.content}`,
19
+ ];
20
+ for (const section of additionalSections) {
21
+ if (section.content) {
22
+ systemParts.push(`${section.title}\n${section.content}`);
23
+ }
24
+ }
25
+ const systemContent = systemParts.join('\n\n');
26
+
27
+ // -- User message --
28
+ const instructionParts: string[] = [];
29
+ if (userInstructions?.trim()) {
30
+ instructionParts.push(userInstructions);
31
+ }
32
+ for (const section of additionalSections) {
33
+ if (section.instructions?.trim()) {
34
+ instructionParts.push(section.instructions);
35
+ }
36
+ }
37
+ instructionParts.push(getTransformInstr(name));
38
+
39
+ const instructions = instructionParts.filter(s => s.trim() !== '').join('\n');
40
+ const promptText = `<USER_MESSAGE>\n${userMessage}\n\n<INSTRUCTIONS>\n${instructions}`;
41
+
42
+ // Build prompt content — multimodal when image attachments are present
43
+ const imageAttachments = (attachments ?? []).filter(a => a.mediaType.startsWith('image/'));
44
+ let promptContent: string | ContentBlock[];
45
+ if (imageAttachments.length > 0) {
46
+ const blocks: ContentBlock[] = [{ type: 'text', text: promptText }];
47
+ for (const att of imageAttachments) {
48
+ blocks.push({ type: 'image', mediaType: att.mediaType, data: att.data });
49
+ }
50
+ promptContent = blocks;
51
+ } else {
52
+ promptContent = promptText;
53
+ }
54
+
55
+ const result = await complete({
56
+ system: { role: 'system', content: systemContent },
57
+ prompt: { role: 'user', content: promptContent },
58
+ jsonSchema: OPENAI_CHANGE_OPS_SCHEMA,
59
+ });
60
+
61
+ if (!result.completed) {
62
+ return { kind: 'error', error: result.error ?? new Error('Model call failed') };
63
+ }
64
+
65
+ // Unwrap the { changes: [...] } envelope from structured output
66
+ return parseOpenAIResponse(result.value!);
67
+ } catch (err: unknown) {
68
+ return { kind: 'error', error: err instanceof Error ? err : new Error(String(err)) };
69
+ }
70
+ }
71
+ };
72
+ }
73
+
74
+ /**
75
+ * Parse the OpenAI structured output response.
76
+ * The schema wraps the array in { changes: [...] }, so unwrap before
77
+ * delegating to the shared parser.
78
+ */
79
+ function parseOpenAIResponse(raw: string): BuilderResult {
80
+ try {
81
+ const parsed = JSON.parse(raw);
82
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed) && Array.isArray(parsed.changes)) {
83
+ return { kind: 'transforms', changes: parsed.changes };
84
+ }
85
+ } catch {
86
+ // fall through to shared parser
87
+ }
88
+ return parseBuilderResponse(raw);
89
+ }
@@ -0,0 +1,261 @@
1
+ import { ChangeList } from '../service/transformPage';
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Change operations output format — text instruction for non-structured builders
5
+ // ---------------------------------------------------------------------------
6
+
7
+ /**
8
+ * Text instruction that tells the model to return a JSON array of change operations.
9
+ * Append this to <INSTRUCTIONS> for builders that don't support structured outputs.
10
+ */
11
+ export const CHANGE_OPS_FORMAT_INSTRUCTION = `Return a JSON array of change operations to apply to the page. Do NOT return the full HTML page.
12
+
13
+ Each operation must be one of:
14
+ { "op": "update", "nodeId": "<data-node-id>", "html": "<new innerHTML>" }
15
+ — replaces the innerHTML of the target element
16
+
17
+ { "op": "replace", "nodeId": "<data-node-id>", "html": "<new outerHTML>" }
18
+ — replaces the entire element (outerHTML) with new markup
19
+
20
+ { "op": "delete", "nodeId": "<data-node-id>" }
21
+ — removes the element from the page
22
+
23
+ { "op": "insert", "parentId": "<data-node-id>", "position": "prepend"|"append"|"before"|"after", "html": "<new element HTML>" }
24
+ — inserts new HTML relative to the parent element
25
+
26
+ { "op": "style-element", "nodeId": "<data-node-id>", "style": "<css style string>" }
27
+ — sets the style attribute of the target element (must be unlocked)
28
+
29
+ { "op": "search-replace", "nodeId": "<data-node-id>", "search": "<exact text to find>", "replace": "<replacement text>" }
30
+ — finds exact text within a script/style block and replaces it. Use empty string for replace to delete.
31
+
32
+ { "op": "search-insert", "nodeId": "<data-node-id>", "after": "<exact text to find>", "content": "<new lines to insert>" }
33
+ — inserts new content immediately after the matched text in a script/style block.
34
+
35
+ For partial edits to large scripts/styles, use search-replace or search-insert instead of
36
+ replacing the entire block with update.
37
+ Copy the search/after text exactly as it appears in the source.
38
+ When making multiple edits to the same block, ensure each search string targets distinct text.
39
+ To delete code, use search-replace with an empty replace string.
40
+
41
+ Return ONLY the JSON array. Example:
42
+ [
43
+ { "op": "update", "nodeId": "5", "html": "<p>Hello world</p>" },
44
+ { "op": "insert", "parentId": "3", "position": "append", "html": "<div class=\\"msg\\">New message</div>" }
45
+ ]`;
46
+
47
+ // ---------------------------------------------------------------------------
48
+ // Change operations JSON schema — for structured output (constrained decoding)
49
+ // ---------------------------------------------------------------------------
50
+
51
+ /**
52
+ * JSON schema matching the ChangeOp union type for Anthropic structured outputs.
53
+ * The top-level schema is an array of change operations.
54
+ */
55
+ export const CHANGE_OPS_SCHEMA: Record<string, unknown> = {
56
+ type: 'array',
57
+ items: {
58
+ anyOf: [
59
+ {
60
+ type: 'object',
61
+ properties: {
62
+ op: { type: 'string', const: 'update' },
63
+ nodeId: { type: 'string' },
64
+ html: { type: 'string' },
65
+ },
66
+ required: ['op', 'nodeId', 'html'],
67
+ additionalProperties: false,
68
+ },
69
+ {
70
+ type: 'object',
71
+ properties: {
72
+ op: { type: 'string', const: 'replace' },
73
+ nodeId: { type: 'string' },
74
+ html: { type: 'string' },
75
+ },
76
+ required: ['op', 'nodeId', 'html'],
77
+ additionalProperties: false,
78
+ },
79
+ {
80
+ type: 'object',
81
+ properties: {
82
+ op: { type: 'string', const: 'delete' },
83
+ nodeId: { type: 'string' },
84
+ },
85
+ required: ['op', 'nodeId'],
86
+ additionalProperties: false,
87
+ },
88
+ {
89
+ type: 'object',
90
+ properties: {
91
+ op: { type: 'string', const: 'insert' },
92
+ parentId: { type: 'string' },
93
+ position: { type: 'string', enum: ['prepend', 'append', 'before', 'after'] },
94
+ html: { type: 'string' },
95
+ },
96
+ required: ['op', 'parentId', 'position', 'html'],
97
+ additionalProperties: false,
98
+ },
99
+ {
100
+ type: 'object',
101
+ properties: {
102
+ op: { type: 'string', const: 'style-element' },
103
+ nodeId: { type: 'string' },
104
+ style: { type: 'string' },
105
+ },
106
+ required: ['op', 'nodeId', 'style'],
107
+ additionalProperties: false,
108
+ },
109
+ {
110
+ type: 'object',
111
+ properties: {
112
+ op: { type: 'string', const: 'search-replace' },
113
+ nodeId: { type: 'string' },
114
+ search: { type: 'string' },
115
+ replace: { type: 'string' },
116
+ },
117
+ required: ['op', 'nodeId', 'search', 'replace'],
118
+ additionalProperties: false,
119
+ },
120
+ {
121
+ type: 'object',
122
+ properties: {
123
+ op: { type: 'string', const: 'search-insert' },
124
+ nodeId: { type: 'string' },
125
+ after: { type: 'string' },
126
+ content: { type: 'string' },
127
+ },
128
+ required: ['op', 'nodeId', 'after', 'content'],
129
+ additionalProperties: false,
130
+ },
131
+ ],
132
+ },
133
+ };
134
+
135
+ /**
136
+ * Variant of CHANGE_OPS_SCHEMA that omits ranged write operations (search-replace, search-insert).
137
+ * Used for medium/hard/re-write changes where the model should replace full blocks instead of
138
+ * attempting partial edits.
139
+ */
140
+ export const CHANGE_OPS_SCHEMA_NO_RANGED: Record<string, unknown> = {
141
+ type: 'array',
142
+ items: {
143
+ anyOf: [
144
+ {
145
+ type: 'object',
146
+ properties: {
147
+ op: { type: 'string', const: 'update' },
148
+ nodeId: { type: 'string' },
149
+ html: { type: 'string' },
150
+ },
151
+ required: ['op', 'nodeId', 'html'],
152
+ additionalProperties: false,
153
+ },
154
+ {
155
+ type: 'object',
156
+ properties: {
157
+ op: { type: 'string', const: 'replace' },
158
+ nodeId: { type: 'string' },
159
+ html: { type: 'string' },
160
+ },
161
+ required: ['op', 'nodeId', 'html'],
162
+ additionalProperties: false,
163
+ },
164
+ {
165
+ type: 'object',
166
+ properties: {
167
+ op: { type: 'string', const: 'delete' },
168
+ nodeId: { type: 'string' },
169
+ },
170
+ required: ['op', 'nodeId'],
171
+ additionalProperties: false,
172
+ },
173
+ {
174
+ type: 'object',
175
+ properties: {
176
+ op: { type: 'string', const: 'insert' },
177
+ parentId: { type: 'string' },
178
+ position: { type: 'string', enum: ['prepend', 'append', 'before', 'after'] },
179
+ html: { type: 'string' },
180
+ },
181
+ required: ['op', 'parentId', 'position', 'html'],
182
+ additionalProperties: false,
183
+ },
184
+ {
185
+ type: 'object',
186
+ properties: {
187
+ op: { type: 'string', const: 'style-element' },
188
+ nodeId: { type: 'string' },
189
+ style: { type: 'string' },
190
+ },
191
+ required: ['op', 'nodeId', 'style'],
192
+ additionalProperties: false,
193
+ },
194
+ ],
195
+ },
196
+ };
197
+
198
+ /**
199
+ * Text instruction variant for no-ranged-writes mode.
200
+ * Tells the model to use `update` for full innerHTML replacement instead of partial edits.
201
+ */
202
+ export const CHANGE_OPS_FORMAT_INSTRUCTION_NO_RANGED = `For script and style blocks, use "update" to replace the full innerHTML or "replace" to replace the full outerHTML. Do NOT use partial search-replace edits.`;
203
+
204
+ /**
205
+ * OpenAI structured outputs require a root-level object.
206
+ * This wraps CHANGE_OPS_SCHEMA in { changes: [...] }.
207
+ */
208
+ export const OPENAI_CHANGE_OPS_SCHEMA: Record<string, unknown> = {
209
+ type: 'object',
210
+ properties: {
211
+ changes: CHANGE_OPS_SCHEMA,
212
+ },
213
+ required: ['changes'],
214
+ additionalProperties: false,
215
+ };
216
+
217
+ // ---------------------------------------------------------------------------
218
+ // Context sections — structured blocks passed to the builder
219
+ // ---------------------------------------------------------------------------
220
+
221
+ export interface ContextSection {
222
+ /** Section title, e.g. "<CURRENT_PAGE>", "<SERVER_SCRIPTS>" */
223
+ title: string;
224
+ /** The text body of this section */
225
+ content: string;
226
+ /** How the model should work with this section (appended to instructions) */
227
+ instructions: string;
228
+ }
229
+
230
+ // ---------------------------------------------------------------------------
231
+ // Builder result — discriminated union returned by Builder.run()
232
+ // ---------------------------------------------------------------------------
233
+
234
+ export type BuilderResult =
235
+ | { kind: 'transforms'; changes: ChangeList }
236
+ | { kind: 'reply'; text: string }
237
+ | { kind: 'error'; error: Error };
238
+
239
+ // ---------------------------------------------------------------------------
240
+ // Attachments — images/files sent alongside the user message
241
+ // ---------------------------------------------------------------------------
242
+
243
+ export interface Attachment {
244
+ mediaType: string;
245
+ data: string;
246
+ name?: string;
247
+ }
248
+
249
+ // ---------------------------------------------------------------------------
250
+ // Builder interface
251
+ // ---------------------------------------------------------------------------
252
+
253
+ export interface Builder {
254
+ run(
255
+ currentPage: ContextSection,
256
+ additionalSections: ContextSection[],
257
+ userMessage: string,
258
+ newBuild: boolean,
259
+ attachments?: Attachment[]
260
+ ): Promise<BuilderResult>;
261
+ }
@@ -1,4 +1,4 @@
1
- export { CONNECTOR_REGISTRY } from './registry';
1
+ export { loadConnectorRegistry, getConnectorRegistry } from './registry';
2
2
  export type {
3
3
  AuthStrategy,
4
4
  ConnectorField,
@@ -2,8 +2,6 @@ import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { ConnectorDefinition, ConnectorJson } from './types';
4
4
 
5
- const connectorsDir = __dirname;
6
-
7
5
  function loadConnectorJson(dir: string): ConnectorDefinition | null {
8
6
  const file = path.join(dir, 'connector.json');
9
7
  if (!fs.existsSync(file)) return null;
@@ -14,9 +12,31 @@ function loadConnectorJson(dir: string): ConnectorDefinition | null {
14
12
  };
15
13
  }
16
14
 
17
- export const CONNECTOR_REGISTRY: ConnectorDefinition[] = fs
18
- .readdirSync(connectorsDir, { withFileTypes: true })
19
- .filter(d => d.isDirectory())
20
- .map(d => loadConnectorJson(path.join(connectorsDir, d.name)))
21
- .filter((d): d is ConnectorDefinition => d !== null)
22
- .sort((a, b) => a.name.localeCompare(b.name));
15
+ export function loadConnectorRegistry(connectorsDirs: string[]): ConnectorDefinition[] {
16
+ const seen = new Set<string>();
17
+ const results: ConnectorDefinition[] = [];
18
+ for (const dir of connectorsDirs) {
19
+ if (!fs.existsSync(dir)) continue;
20
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
21
+ .filter(d => d.isDirectory());
22
+ for (const d of entries) {
23
+ const def = loadConnectorJson(path.join(dir, d.name));
24
+ if (def && !seen.has(def.id)) {
25
+ seen.add(def.id);
26
+ results.push(def);
27
+ }
28
+ }
29
+ }
30
+ return results.sort((a, b) => a.name.localeCompare(b.name));
31
+ }
32
+
33
+ let _registry: ConnectorDefinition[] | undefined;
34
+ let _registryKey: string | undefined;
35
+ export function getConnectorRegistry(connectorsDirs?: string[]): ConnectorDefinition[] {
36
+ const key = connectorsDirs ? connectorsDirs.join('|') : undefined;
37
+ if (!_registry || (connectorsDirs && key !== _registryKey)) {
38
+ _registry = loadConnectorRegistry(connectorsDirs ?? [path.join(__dirname, '../../service-connectors')]);
39
+ _registryKey = key;
40
+ }
41
+ return _registry;
42
+ }
@@ -0,0 +1,151 @@
1
+ import { Application } from 'express';
2
+ import { SynthOSConfig } from '../init';
3
+ import { ContextSection } from '../builders/types';
4
+
5
+ export type RouteInstaller = (config: SynthOSConfig, app: Application) => void;
6
+
7
+ export class Customizer {
8
+ protected disabled: Set<string> = new Set();
9
+ protected extraRoutes: RouteInstaller[] = [];
10
+
11
+ /** Route hints for the LLM prompt (fork developers can add custom hints). */
12
+ protected routeHintEntries: { hints: string }[] = [];
13
+
14
+ /** Custom instructions appended to transformPage's instruction block. */
15
+ protected customTransformInstructions: string[] = [];
16
+
17
+ /** Custom context sections appended to the builder's additional sections. */
18
+ protected customContextSections: ContextSection[] = [];
19
+
20
+ // --- Local data folder ---
21
+ // Override in a derived class to change the local project folder name.
22
+
23
+ /** Name of the local data folder created in the user's project directory. */
24
+ get localFolder(): string {
25
+ return '.synthos';
26
+ }
27
+
28
+ // --- Content folder paths ---
29
+ // Override these in a derived class to point to your fork's folders.
30
+ // Each getter returns `string[]`. The sentinel value `'default'` is
31
+ // resolved by `createConfig()` to the built-in SynthOS folder for that
32
+ // getter. Forks can return additional paths alongside (or instead of)
33
+ // `'default'` to layer custom folders.
34
+
35
+ /** Folders containing built-in system pages (builder, settings, etc.) */
36
+ get requiredPagesFolders(): string[] {
37
+ return ['default'];
38
+ }
39
+
40
+ /** Folders containing starter page templates copied on init */
41
+ get defaultPagesFolders(): string[] {
42
+ return ['default'];
43
+ }
44
+
45
+ /** Folders containing theme CSS/JSON files */
46
+ get defaultThemesFolders(): string[] {
47
+ return ['default'];
48
+ }
49
+
50
+ /** Folders containing versioned static files (page-v2.js, helpers-v2.js, etc.) */
51
+ get staticFilesFolders(): string[] {
52
+ return ['default'];
53
+ }
54
+
55
+ /** Folders containing connector JSON definitions */
56
+ get serviceConnectorsFolders(): string[] {
57
+ return ['default'];
58
+ }
59
+
60
+ /** Folders containing default scripts copied on init */
61
+ get defaultScriptsFolders(): string[] {
62
+ return ['default'];
63
+ }
64
+
65
+ /** Route path for the "browse all pages/tabs" listing page.
66
+ * Override in a derived class to change the redirect target for outdated pages. */
67
+ get tabsListRoute(): string {
68
+ return '/pages';
69
+ }
70
+
71
+ /** Product name used in LLM prompts and branding strings.
72
+ * Override in a derived class for white-labeling. */
73
+ get productName(): string {
74
+ return 'SynthOS';
75
+ }
76
+
77
+ // --- Feature group control ---
78
+ // Built-in groups: 'pages', 'api', 'connectors', 'agents',
79
+ // 'data', 'brainstorm', 'search', 'scripts'
80
+
81
+ disable(...groups: string[]): this {
82
+ for (const g of groups) this.disabled.add(g);
83
+ return this;
84
+ }
85
+
86
+ enable(...groups: string[]): this {
87
+ for (const g of groups) this.disabled.delete(g);
88
+ return this;
89
+ }
90
+
91
+ isEnabled(group: string): boolean {
92
+ return !this.disabled.has(group);
93
+ }
94
+
95
+ // --- Custom routes ---
96
+
97
+ addRoutes(...installers: (RouteInstaller | { installer: RouteInstaller; hints: string })[]): this {
98
+ for (const entry of installers) {
99
+ if (typeof entry === 'function') {
100
+ this.extraRoutes.push(entry);
101
+ } else {
102
+ this.extraRoutes.push(entry.installer);
103
+ this.routeHintEntries.push({ hints: entry.hints });
104
+ }
105
+ }
106
+ return this;
107
+ }
108
+
109
+ getExtraRoutes(): RouteInstaller[] {
110
+ return this.extraRoutes;
111
+ }
112
+
113
+ // --- Route hints ---
114
+
115
+ /** Add route hints that will be shown to the LLM in transformPage. */
116
+ addRouteHints(...hints: string[]): this {
117
+ for (const h of hints) this.routeHintEntries.push({ hints: h });
118
+ return this;
119
+ }
120
+
121
+ /** Get all custom route hints. */
122
+ getRouteHints(): string[] {
123
+ return this.routeHintEntries.map(e => e.hints);
124
+ }
125
+
126
+ // --- Custom transform instructions ---
127
+
128
+ /** Add custom instructions for the transformPage LLM prompt. */
129
+ addTransformInstructions(...instructions: string[]): this {
130
+ this.customTransformInstructions.push(...instructions);
131
+ return this;
132
+ }
133
+
134
+ /** Get custom transform instructions. */
135
+ getTransformInstructions(): string[] {
136
+ return this.customTransformInstructions;
137
+ }
138
+
139
+ // --- Custom context sections ---
140
+
141
+ /** Add custom context sections for the builder. */
142
+ addContextSections(...sections: ContextSection[]): this {
143
+ this.customContextSections.push(...sections);
144
+ return this;
145
+ }
146
+
147
+ /** Get custom context sections. */
148
+ getContextSections(): ContextSection[] {
149
+ return this.customContextSections;
150
+ }
151
+ }
@@ -0,0 +1,5 @@
1
+ export { Customizer, RouteInstaller } from './Customizer';
2
+ import { Customizer } from './Customizer';
3
+
4
+ // Default instance — replace with an App specific customizer
5
+ export const customizer = new Customizer();