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.
- package/README.md +1 -1
- package/default-pages/application/page.html +42 -0
- package/default-pages/application/page.json +10 -0
- package/default-pages/elevenlabs_effects_studio/page.html +1363 -0
- package/default-pages/elevenlabs_effects_studio/page.json +11 -0
- package/default-pages/elevenlabs_voice_studio/page.html +801 -0
- package/default-pages/elevenlabs_voice_studio/page.json +11 -0
- package/default-pages/{json_tools.html → json_tools/page.html} +13 -11
- package/default-pages/json_tools/page.json +10 -0
- package/default-pages/my_notes/notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json +5 -0
- package/default-pages/my_notes/page.html +132 -0
- package/default-pages/{my_notes.json → my_notes/page.json} +2 -2
- package/default-pages/neon_asteroids/files/Ambient_Space.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Ambient_Space2.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Ambient_Space3.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Asteroid_Explosion.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Hyperspace_Jump.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Laser_Fire.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Menu_Navigate.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Power_Up_Collect.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Saucer_Alert.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Ship_Thrust.mp3 +0 -0
- package/default-pages/neon_asteroids/files/effects.json +74 -0
- package/default-pages/neon_asteroids/page.html +1822 -0
- package/default-pages/{neon_asteroids.json → neon_asteroids/page.json} +3 -3
- package/default-pages/{oregon_trail.html → oregon_trail/page.html} +14 -12
- package/default-pages/{oregon_trail.json → oregon_trail/page.json} +2 -2
- package/default-pages/retro_game_starter/page.html +1308 -0
- package/default-pages/retro_game_starter/page.json +12 -0
- package/default-pages/{sidebar_page.html → sidebar_page/page.html} +12 -10
- package/default-pages/sidebar_page/page.json +10 -0
- package/default-pages/{solar_explorer.html → solar_explorer/page.html} +14 -11
- package/default-pages/{solar_explorer.json → solar_explorer/page.json} +2 -2
- package/default-pages/{solar_tutorial.html → solar_tutorial/page.html} +12 -10
- package/default-pages/solar_tutorial/page.json +10 -0
- package/default-pages/{two-panel_page.html → two-panel_page/page.html} +13 -11
- package/default-pages/two-panel_page/page.json +10 -0
- package/default-pages/{us_map.html → us_map/page.html} +193 -192
- package/default-pages/{us_map.json → us_map/page.json} +12 -12
- package/default-pages/{us_map_1850.html → us_map_1850/page.html} +326 -325
- package/default-pages/{us_map_1850.json → us_map_1850/page.json} +12 -12
- package/default-pages/{western_cities_1850.html → western_cities_1850/page.html} +527 -526
- package/default-pages/{western_cities_1850.json → western_cities_1850/page.json} +12 -12
- package/default-themes/aurora-dawn.json +19 -0
- package/default-themes/aurora-dawn.v3.css +198 -0
- package/default-themes/aurora-dusk.json +19 -0
- package/default-themes/aurora-dusk.v3.css +200 -0
- package/default-themes/cosmos-dawn.json +19 -0
- package/default-themes/cosmos-dawn.v3.css +198 -0
- package/default-themes/cosmos-dusk.json +19 -0
- package/default-themes/cosmos-dusk.v3.css +200 -0
- package/default-themes/high-contrast-dark.json +19 -0
- package/default-themes/high-contrast-dark.v3.css +200 -0
- package/default-themes/high-contrast-light.json +19 -0
- package/default-themes/high-contrast-light.v3.css +198 -0
- package/default-themes/nebula-dawn.v2.css +110 -0
- package/default-themes/nebula-dawn.v3.css +199 -0
- package/default-themes/nebula-dusk.v2.css +104 -0
- package/default-themes/nebula-dusk.v3.css +201 -0
- package/default-themes/solar-flare-dawn.json +19 -0
- package/default-themes/solar-flare-dawn.v3.css +198 -0
- package/default-themes/solar-flare-dusk.json +19 -0
- package/default-themes/solar-flare-dusk.v3.css +200 -0
- package/dist/agents/index.d.ts +1 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +2 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/openclaw/gatewayManager.d.ts +4 -0
- package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -1
- package/dist/agents/openclaw/gatewayManager.js +27 -11
- package/dist/agents/openclaw/gatewayManager.js.map +1 -1
- package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -1
- package/dist/agents/openclaw/openclawProvider.js +2 -4
- package/dist/agents/openclaw/openclawProvider.js.map +1 -1
- package/dist/agents/openclaw/sshTunnelManager.d.ts +2 -0
- package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -1
- package/dist/agents/openclaw/sshTunnelManager.js +31 -12
- package/dist/agents/openclaw/sshTunnelManager.js.map +1 -1
- package/dist/builders/anthropic.d.ts +31 -0
- package/dist/builders/anthropic.d.ts.map +1 -0
- package/dist/builders/anthropic.js +227 -0
- package/dist/builders/anthropic.js.map +1 -0
- package/dist/builders/fireworksai.d.ts +9 -0
- package/dist/builders/fireworksai.d.ts.map +1 -0
- package/dist/builders/fireworksai.js +57 -0
- package/dist/builders/fireworksai.js.map +1 -0
- package/dist/builders/index.d.ts +13 -0
- package/dist/builders/index.d.ts.map +1 -0
- package/dist/builders/index.js +31 -0
- package/dist/builders/index.js.map +1 -0
- package/dist/builders/openai.d.ts +8 -0
- package/dist/builders/openai.d.ts.map +1 -0
- package/dist/builders/openai.js +87 -0
- package/dist/builders/openai.js.map +1 -0
- package/dist/builders/types.d.ts +54 -0
- package/dist/builders/types.d.ts.map +1 -0
- package/dist/builders/types.js +211 -0
- package/dist/builders/types.js.map +1 -0
- package/dist/connectors/index.d.ts.map +1 -1
- package/dist/connectors/index.js +3 -2
- package/dist/connectors/index.js.map +1 -1
- package/dist/connectors/registry.d.ts +2 -1
- package/dist/connectors/registry.d.ts.map +1 -1
- package/dist/connectors/registry.js +31 -8
- package/dist/connectors/registry.js.map +1 -1
- package/dist/customizer/Customizer.d.ts +57 -0
- package/dist/customizer/Customizer.d.ts.map +1 -0
- package/dist/customizer/Customizer.js +124 -0
- package/dist/customizer/Customizer.js.map +1 -0
- package/dist/customizer/index.d.ts.map +1 -0
- package/dist/customizer/index.js +9 -0
- package/dist/customizer/index.js.map +1 -0
- package/dist/files.d.ts +16 -0
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +60 -1
- package/dist/files.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +10 -6
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +96 -113
- package/dist/init.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +23 -10
- package/dist/migrations.js.map +1 -1
- package/dist/models/anthropic.d.ts +4 -2
- package/dist/models/anthropic.d.ts.map +1 -1
- package/dist/models/anthropic.js +33 -6
- package/dist/models/anthropic.js.map +1 -1
- package/dist/models/fireworksai.d.ts.map +1 -1
- package/dist/models/fireworksai.js +9 -1
- package/dist/models/fireworksai.js.map +1 -1
- package/dist/models/index.d.ts +1 -1
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +2 -1
- package/dist/models/index.js.map +1 -1
- package/dist/models/openai.d.ts +1 -1
- package/dist/models/openai.d.ts.map +1 -1
- package/dist/models/openai.js +24 -3
- package/dist/models/openai.js.map +1 -1
- package/dist/models/types.d.ts +20 -1
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js +6 -1
- package/dist/models/types.js.map +1 -1
- package/dist/pages.d.ts +30 -7
- package/dist/pages.d.ts.map +1 -1
- package/dist/pages.js +177 -55
- package/dist/pages.js.map +1 -1
- package/dist/service/server.d.ts.map +1 -1
- package/dist/service/server.js +37 -8
- package/dist/service/server.js.map +1 -1
- package/dist/service/transformPage.d.ts +47 -20
- package/dist/service/transformPage.d.ts.map +1 -1
- package/dist/service/transformPage.js +514 -293
- package/dist/service/transformPage.js.map +1 -1
- package/dist/service/useAgentRoutes.d.ts +2 -1
- package/dist/service/useAgentRoutes.d.ts.map +1 -1
- package/dist/service/useAgentRoutes.js +5 -2
- package/dist/service/useAgentRoutes.js.map +1 -1
- package/dist/service/useApiRoutes.d.ts.map +1 -1
- package/dist/service/useApiRoutes.js +237 -136
- package/dist/service/useApiRoutes.js.map +1 -1
- package/dist/service/useConnectorRoutes.js +6 -6
- package/dist/service/useConnectorRoutes.js.map +1 -1
- package/dist/service/useFileRoutes.d.ts +4 -0
- package/dist/service/useFileRoutes.d.ts.map +1 -0
- package/dist/service/useFileRoutes.js +122 -0
- package/dist/service/useFileRoutes.js.map +1 -0
- package/dist/service/usePageRoutes.d.ts.map +1 -1
- package/dist/service/usePageRoutes.js +648 -67
- package/dist/service/usePageRoutes.js.map +1 -1
- package/dist/service/useSharedDataRoutes.d.ts +4 -0
- package/dist/service/useSharedDataRoutes.d.ts.map +1 -0
- package/dist/service/useSharedDataRoutes.js +104 -0
- package/dist/service/useSharedDataRoutes.js.map +1 -0
- package/dist/service/useSharedFileRoutes.d.ts +4 -0
- package/dist/service/useSharedFileRoutes.d.ts.map +1 -0
- package/dist/service/useSharedFileRoutes.js +121 -0
- package/dist/service/useSharedFileRoutes.js.map +1 -0
- package/dist/settings.d.ts +1 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +1 -0
- package/dist/settings.js.map +1 -1
- package/dist/synthos-cli.d.ts.map +1 -1
- package/dist/synthos-cli.js +4 -3
- package/dist/synthos-cli.js.map +1 -1
- package/dist/themes.d.ts +1 -0
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js +28 -15
- package/dist/themes.js.map +1 -1
- package/migration-rules/v1-to-v2.md +193 -0
- package/migration-rules/v2-to-v3.md +481 -0
- package/package.json +11 -10
- package/required-pages/builder/page.html +43 -0
- package/required-pages/builder/page.json +10 -0
- package/required-pages/{pages.html → pages/page.html} +238 -233
- package/required-pages/pages/page.json +10 -0
- package/required-pages/{settings.html → settings/page.html} +389 -275
- package/required-pages/settings/page.json +10 -0
- package/required-pages/synthos_apis/page.html +846 -0
- package/required-pages/synthos_apis/page.json +10 -0
- package/required-pages/{synthos_scripts.html → synthos_scripts/page.html} +13 -11
- package/required-pages/synthos_scripts/page.json +10 -0
- package/src/agents/index.ts +1 -1
- package/src/agents/openclaw/gatewayManager.ts +22 -11
- package/src/agents/openclaw/openclawProvider.ts +2 -4
- package/src/agents/openclaw/sshTunnelManager.ts +19 -11
- package/src/builders/anthropic.ts +283 -0
- package/src/builders/fireworksai.ts +59 -0
- package/src/builders/index.ts +33 -0
- package/src/builders/openai.ts +89 -0
- package/src/builders/types.ts +261 -0
- package/src/connectors/index.ts +1 -1
- package/src/connectors/registry.ts +28 -8
- package/src/customizer/Customizer.ts +151 -0
- package/src/customizer/index.ts +5 -0
- package/src/files.ts +57 -0
- package/src/index.ts +2 -1
- package/src/init.ts +137 -123
- package/src/migrations.ts +30 -10
- package/src/models/anthropic.ts +40 -10
- package/src/models/fireworksai.ts +9 -2
- package/src/models/index.ts +1 -1
- package/src/models/openai.ts +26 -6
- package/src/models/types.ts +31 -1
- package/src/pages.ts +176 -54
- package/src/service/server.ts +36 -9
- package/src/service/transformPage.ts +557 -326
- package/src/service/useAgentRoutes.ts +7 -2
- package/src/service/useApiRoutes.ts +150 -41
- package/src/service/useConnectorRoutes.ts +7 -7
- package/src/service/useFileRoutes.ts +127 -0
- package/src/service/usePageRoutes.ts +720 -73
- package/src/service/useSharedDataRoutes.ts +106 -0
- package/src/service/useSharedFileRoutes.ts +126 -0
- package/src/settings.ts +2 -0
- package/src/synthos-cli.ts +4 -3
- package/src/themes.ts +25 -14
- package/static-files/favicon.svg +12 -0
- package/static-files/fluentlm-instructions.llmd +868 -0
- package/static-files/fluentlm-instructions.md +1595 -0
- package/static-files/fluentlm.css +4844 -0
- package/static-files/fluentlm.js +3602 -0
- package/static-files/fluentlm.min.css +1 -0
- package/static-files/fluentlm.min.js +1 -0
- package/{page-scripts/helpers-v2.js → static-files/helpers.v3.js} +82 -0
- package/static-files/page.v3.js +1290 -0
- package/static-files/recommended-frameworks.llmd +81 -0
- package/static-files/recommended-frameworks.md +137 -0
- package/static-files/retro-game.js +877 -0
- package/static-files/shell.css +797 -0
- package/static-files/theme-dark.css +169 -0
- package/static-files/theme-light.css +169 -0
- package/tests/builders.spec.ts +139 -0
- package/tests/pages.spec.ts +8 -8
- package/tests/transformPage.spec.ts +299 -360
- package/default-pages/application.html +0 -40
- package/default-pages/application.json +0 -1
- package/default-pages/json_tools.json +0 -1
- package/default-pages/my_notes.html +0 -33
- package/default-pages/neon_asteroids.html +0 -77
- package/default-pages/sidebar_page.json +0 -1
- package/default-pages/solar_tutorial.json +0 -1
- package/default-pages/two-panel_page.json +0 -1
- package/dist/agents/a2a/a2aProvider.d.ts +0 -3
- package/dist/agents/discovery.d.ts +0 -30
- package/dist/agents/openclaw/openclawProvider.d.ts +0 -3
- package/dist/agents/types.d.ts +0 -64
- package/dist/connectors/index.d.ts +0 -3
- package/dist/connectors/types.d.ts +0 -84
- package/dist/index.d.ts +0 -7
- package/dist/migrations.d.ts +0 -12
- package/dist/models/chainOfThought.d.ts +0 -12
- package/dist/models/fireworksai.d.ts +0 -30
- package/dist/models/logCompletePrompt.d.ts +0 -3
- package/dist/models/providers.d.ts +0 -8
- package/dist/models/utils.d.ts +0 -6
- package/dist/scripts.d.ts +0 -15
- package/dist/service/createCompletePrompt.d.ts +0 -5
- package/dist/service/debugLog.d.ts +0 -11
- package/dist/service/generateImage.d.ts +0 -32
- package/dist/service/index.d.ts +0 -8
- package/dist/service/modelInstructions.d.ts +0 -7
- package/dist/service/requiresSettings.d.ts +0 -3
- package/dist/service/server.d.ts +0 -4
- package/dist/service/useApiRoutes.d.ts +0 -4
- package/dist/service/useConnectorRoutes.d.ts +0 -4
- package/dist/service/useDataRoutes.d.ts +0 -4
- package/dist/service/useGatewayRoutes.d.ts +0 -4
- package/dist/service/useGatewayRoutes.d.ts.map +0 -1
- package/dist/service/useGatewayRoutes.js +0 -168
- package/dist/service/useGatewayRoutes.js.map +0 -1
- package/dist/service/usePageRoutes.d.ts +0 -5
- package/dist/synthos-cli.d.ts +0 -2
- package/page-scripts/page-v2.js +0 -656
- package/required-pages/builder.html +0 -48
- package/required-pages/builder.json +0 -1
- package/required-pages/pages.json +0 -1
- package/required-pages/settings.json +0 -1
- package/required-pages/synthos_apis.html +0 -327
- package/required-pages/synthos_apis.json +0 -1
- package/required-pages/synthos_scripts.json +0 -1
- package/src/connectors/airtable/connector.json +0 -27
- package/src/connectors/alpha-vantage/connector.json +0 -26
- package/src/connectors/brave-search/connector.json +0 -26
- package/src/connectors/cloudinary/connector.json +0 -27
- package/src/connectors/deepl/connector.json +0 -28
- package/src/connectors/elevenlabs/connector.json +0 -30
- package/src/connectors/giphy/connector.json +0 -27
- package/src/connectors/github/connector.json +0 -29
- package/src/connectors/huggingface/connector.json +0 -27
- package/src/connectors/imgur/connector.json +0 -29
- package/src/connectors/instagram/connector.json +0 -43
- package/src/connectors/jira/connector.json +0 -28
- package/src/connectors/mapbox/connector.json +0 -26
- package/src/connectors/nasa/connector.json +0 -27
- package/src/connectors/newsapi/connector.json +0 -27
- package/src/connectors/notion/connector.json +0 -28
- package/src/connectors/open-exchange-rates/connector.json +0 -27
- package/src/connectors/openweathermap/connector.json +0 -26
- package/src/connectors/pexels/connector.json +0 -27
- package/src/connectors/resend/connector.json +0 -29
- package/src/connectors/rss2json/connector.json +0 -27
- package/src/connectors/sendgrid/connector.json +0 -27
- package/src/connectors/spoonacular/connector.json +0 -28
- package/src/connectors/stability-ai/connector.json +0 -27
- package/src/connectors/twilio/connector.json +0 -28
- package/src/connectors/unsplash/connector.json +0 -27
- package/src/connectors/wolfram-alpha/connector.json +0 -26
- package/src/connectors/youtube-data/connector.json +0 -30
- /package/{dist/connectors → service-connectors}/airtable/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/alpha-vantage/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/brave-search/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/cloudinary/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/deepl/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/elevenlabs/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/giphy/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/github/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/huggingface/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/imgur/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/instagram/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/jira/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/mapbox/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/nasa/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/newsapi/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/notion/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/open-exchange-rates/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/openweathermap/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/pexels/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/resend/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/rss2json/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/sendgrid/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/spoonacular/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/stability-ai/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/twilio/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/unsplash/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/wolfram-alpha/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/youtube-data/connector.json +0 -0
package/src/models/openai.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import OpenAI from 'openai';
|
|
2
|
-
import { AgentCompletion, completePrompt, PromptCompletionArgs, RequestError } from './types';
|
|
2
|
+
import { AgentCompletion, completePrompt, PromptCompletionArgs, RequestError, isMultimodalContent } from './types';
|
|
3
3
|
|
|
4
4
|
export interface OpenaiArgs {
|
|
5
5
|
apiKey: string;
|
|
@@ -15,23 +15,43 @@ export interface OpenaiArgs {
|
|
|
15
15
|
* Pure function — no SDK dependency.
|
|
16
16
|
*/
|
|
17
17
|
export function buildOpenAIRequest(args: PromptCompletionArgs): {
|
|
18
|
-
input: { role: string; content: string }[];
|
|
18
|
+
input: { role: string; content: string | any[] }[];
|
|
19
19
|
text?: { format: any };
|
|
20
20
|
} {
|
|
21
|
-
const input: { role: string; content: string }[] = [];
|
|
21
|
+
const input: { role: string; content: string | any[] }[] = [];
|
|
22
22
|
if (args.history) {
|
|
23
23
|
for (const msg of args.history) {
|
|
24
24
|
input.push({ role: msg.role, content: msg.content });
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
|
|
28
|
+
// Build user content — multimodal when ContentBlock[] is provided
|
|
29
|
+
const promptContent = args.prompt.content;
|
|
30
|
+
if (isMultimodalContent(promptContent)) {
|
|
31
|
+
const parts: any[] = promptContent.map(block => {
|
|
32
|
+
if (block.type === 'text') {
|
|
33
|
+
return { type: 'input_text', text: block.text };
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
type: 'input_image',
|
|
37
|
+
image_url: `data:${block.mediaType};base64,${block.data}`,
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
input.push({ role: 'user', content: parts });
|
|
41
|
+
} else {
|
|
42
|
+
input.push({ role: 'user', content: promptContent });
|
|
43
|
+
}
|
|
28
44
|
|
|
29
45
|
if (args.jsonMode || args.jsonSchema) {
|
|
30
|
-
const inputText = input.map(m => m.content).join(' ');
|
|
46
|
+
const inputText = input.map(m => typeof m.content === 'string' ? m.content : '').join(' ');
|
|
31
47
|
if (!/json/i.test(inputText)) {
|
|
32
48
|
const last = input[input.length - 1];
|
|
33
49
|
if (last) {
|
|
34
|
-
last.content
|
|
50
|
+
if (typeof last.content === 'string') {
|
|
51
|
+
last.content += '\nReturn JSON.';
|
|
52
|
+
} else if (Array.isArray(last.content)) {
|
|
53
|
+
last.content.push({ type: 'input_text', text: '\nReturn JSON.' });
|
|
54
|
+
}
|
|
35
55
|
}
|
|
36
56
|
}
|
|
37
57
|
}
|
package/src/models/types.ts
CHANGED
|
@@ -25,6 +25,30 @@ export interface Provider {
|
|
|
25
25
|
detectModel(model: string): boolean;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Multimodal content
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
export interface TextBlock {
|
|
33
|
+
type: 'text';
|
|
34
|
+
text: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ImageBlock {
|
|
38
|
+
type: 'image';
|
|
39
|
+
mediaType: string;
|
|
40
|
+
data: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type ContentBlock = TextBlock | ImageBlock;
|
|
44
|
+
|
|
45
|
+
export type MessageContent = string | ContentBlock[];
|
|
46
|
+
|
|
47
|
+
/** Type guard: returns true when content is a multimodal ContentBlock array. */
|
|
48
|
+
export function isMultimodalContent(content: MessageContent): content is ContentBlock[] {
|
|
49
|
+
return Array.isArray(content);
|
|
50
|
+
}
|
|
51
|
+
|
|
28
52
|
// ---------------------------------------------------------------------------
|
|
29
53
|
// Messages
|
|
30
54
|
// ---------------------------------------------------------------------------
|
|
@@ -39,8 +63,10 @@ export interface SystemMessage extends Message {
|
|
|
39
63
|
role: 'system';
|
|
40
64
|
}
|
|
41
65
|
|
|
42
|
-
export interface UserMessage
|
|
66
|
+
export interface UserMessage {
|
|
43
67
|
role: 'user';
|
|
68
|
+
content: MessageContent;
|
|
69
|
+
name?: string;
|
|
44
70
|
}
|
|
45
71
|
|
|
46
72
|
// ---------------------------------------------------------------------------
|
|
@@ -61,6 +87,10 @@ export interface PromptCompletionArgs {
|
|
|
61
87
|
jsonMode?: boolean;
|
|
62
88
|
/** JSON schema for structured output. When provided, the model is asked to return JSON conforming to this schema. */
|
|
63
89
|
jsonSchema?: Record<string, unknown>;
|
|
90
|
+
/** When true, system content is wrapped with cache_control for Anthropic prompt caching. */
|
|
91
|
+
cacheSystem?: boolean;
|
|
92
|
+
/** JSON schema for structured output via constrained decoding (Anthropic output_config). */
|
|
93
|
+
outputSchema?: Record<string, unknown>;
|
|
64
94
|
}
|
|
65
95
|
|
|
66
96
|
export type completePrompt<TValue = string> = (args: PromptCompletionArgs) => Promise<AgentCompletion<TValue>>;
|
package/src/pages.ts
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
|
-
import {checkIfExists, deleteFile, deleteFolder, ensureFolderExists, listFiles, listFolders, loadFile, saveFile} from './files';
|
|
1
|
+
import {checkIfExists, copyFolderRecursive, deleteFile, deleteFolder, ensureFolderExists, listFiles, listFolders, loadFile, saveFile} from './files';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Derive the list of required page names by scanning *.html files
|
|
6
|
+
* across one or more requiredPages folders.
|
|
7
|
+
*/
|
|
8
|
+
export async function getRequiredPages(requiredPagesFolders: string[]): Promise<string[]> {
|
|
9
|
+
const result: string[] = [];
|
|
10
|
+
const seen = new Set<string>();
|
|
11
|
+
for (const folder of requiredPagesFolders) {
|
|
12
|
+
if (!await checkIfExists(folder)) continue;
|
|
13
|
+
const entries = await listFolders(folder);
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
if (seen.has(entry)) continue;
|
|
16
|
+
if (await checkIfExists(path.join(folder, entry, 'page.html'))) {
|
|
17
|
+
seen.add(entry);
|
|
18
|
+
result.push(entry);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
8
24
|
|
|
9
|
-
export const PAGE_VERSION =
|
|
25
|
+
export const PAGE_VERSION = 3;
|
|
10
26
|
|
|
11
27
|
export interface PageInfo {
|
|
12
28
|
name: string;
|
|
@@ -22,8 +38,8 @@ export interface PageInfo {
|
|
|
22
38
|
|
|
23
39
|
export type PageMetadata = Omit<PageInfo, 'name'>;
|
|
24
40
|
|
|
25
|
-
export async function loadPageMetadata(pagesFolder: string, name: string,
|
|
26
|
-
// 1. Try user override:
|
|
41
|
+
export async function loadPageMetadata(pagesFolder: string, name: string, fallbackFolders?: string[]): Promise<PageMetadata | undefined> {
|
|
42
|
+
// 1. Try user override: <localFolder>/pages/<name>/page.json
|
|
27
43
|
const metadataPath = path.join(pagesFolder, 'pages', name, 'page.json');
|
|
28
44
|
if (await checkIfExists(metadataPath)) {
|
|
29
45
|
try {
|
|
@@ -35,16 +51,18 @@ export async function loadPageMetadata(pagesFolder: string, name: string, fallba
|
|
|
35
51
|
}
|
|
36
52
|
}
|
|
37
53
|
|
|
38
|
-
// 2. Try fallback: fallbackFolder/<name
|
|
39
|
-
if (
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
// 2. Try fallback folders: fallbackFolder/<name>/page.json
|
|
55
|
+
if (fallbackFolders) {
|
|
56
|
+
for (const folder of fallbackFolders) {
|
|
57
|
+
const candidate = path.join(folder, name, 'page.json');
|
|
58
|
+
if (await checkIfExists(candidate)) {
|
|
59
|
+
try {
|
|
60
|
+
const raw = await loadFile(candidate);
|
|
61
|
+
const parsed = JSON.parse(raw);
|
|
62
|
+
return parseMetadata(parsed);
|
|
63
|
+
} catch {
|
|
64
|
+
// fall through
|
|
65
|
+
}
|
|
48
66
|
}
|
|
49
67
|
}
|
|
50
68
|
}
|
|
@@ -83,7 +101,7 @@ const DEFAULT_METADATA: PageMetadata = {
|
|
|
83
101
|
mode: 'unlocked',
|
|
84
102
|
};
|
|
85
103
|
|
|
86
|
-
export async function listPages(pagesFolder: string,
|
|
104
|
+
export async function listPages(pagesFolder: string, fallbackPagesFolders: string[]): Promise<PageInfo[]> {
|
|
87
105
|
const pageMap = new Map<string, PageInfo>();
|
|
88
106
|
|
|
89
107
|
// Folder-based pages under pages/ subdirectory
|
|
@@ -128,13 +146,15 @@ export async function listPages(pagesFolder: string, fallbackPagesFolder: string
|
|
|
128
146
|
}
|
|
129
147
|
}
|
|
130
148
|
|
|
131
|
-
// Add pages from fallback (required) pages
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
149
|
+
// Add pages from fallback (required) pages folders
|
|
150
|
+
for (const folder of fallbackPagesFolders) {
|
|
151
|
+
if (!await checkIfExists(folder)) continue;
|
|
152
|
+
const dirs = await listFolders(folder);
|
|
153
|
+
for (const name of dirs) {
|
|
154
|
+
if (pageMap.has(name)) continue;
|
|
155
|
+
if (!await checkIfExists(path.join(folder, name, 'page.html'))) continue;
|
|
156
|
+
// System page not yet in map — check for user override, then fallback page.json
|
|
157
|
+
const metadata = await loadPageMetadata(pagesFolder, name, fallbackPagesFolders);
|
|
138
158
|
pageMap.set(name, {
|
|
139
159
|
name,
|
|
140
160
|
title: metadata?.title ?? '',
|
|
@@ -156,22 +176,27 @@ export async function listPages(pagesFolder: string, fallbackPagesFolder: string
|
|
|
156
176
|
return entries;
|
|
157
177
|
}
|
|
158
178
|
|
|
159
|
-
export async function loadPageState(pagesFolder: string, name: string
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
if (await checkIfExists(folderPath)) {
|
|
166
|
-
_pages[name] = await loadFile(folderPath);
|
|
167
|
-
} else if (await checkIfExists(flatPath)) {
|
|
168
|
-
_pages[name] = await loadFile(flatPath);
|
|
169
|
-
} else {
|
|
170
|
-
return undefined;
|
|
171
|
-
}
|
|
179
|
+
export async function loadPageState(pagesFolder: string, name: string): Promise<string|undefined> {
|
|
180
|
+
// Check for working-state version files first
|
|
181
|
+
const latestVersion = await getLatestVersion(pagesFolder, name);
|
|
182
|
+
if (latestVersion > 0) {
|
|
183
|
+
const versionHtml = await loadPageVersion(pagesFolder, name, latestVersion);
|
|
184
|
+
if (versionHtml) return versionHtml;
|
|
172
185
|
}
|
|
173
186
|
|
|
174
|
-
|
|
187
|
+
// Fall back to saved baseline
|
|
188
|
+
const folderPath = path.join(pagesFolder, 'pages', name, 'page.html');
|
|
189
|
+
const directFolderPath = path.join(pagesFolder, name, 'page.html');
|
|
190
|
+
const flatPath = path.join(pagesFolder, `${name}.html`);
|
|
191
|
+
|
|
192
|
+
if (await checkIfExists(folderPath)) {
|
|
193
|
+
return loadFile(folderPath);
|
|
194
|
+
} else if (await checkIfExists(directFolderPath)) {
|
|
195
|
+
return loadFile(directFolderPath);
|
|
196
|
+
} else if (await checkIfExists(flatPath)) {
|
|
197
|
+
return loadFile(flatPath);
|
|
198
|
+
}
|
|
199
|
+
return undefined;
|
|
175
200
|
}
|
|
176
201
|
|
|
177
202
|
export function normalizePageName(name: string|undefined): string|undefined {
|
|
@@ -179,7 +204,6 @@ export function normalizePageName(name: string|undefined): string|undefined {
|
|
|
179
204
|
}
|
|
180
205
|
|
|
181
206
|
export async function savePageState(pagesFolder: string, name: string, content: string, title?: string, categories?: string[]): Promise<void> {
|
|
182
|
-
_pages[name] = content;
|
|
183
207
|
const pageFolder = path.join(pagesFolder, 'pages', name);
|
|
184
208
|
await ensureFolderExists(pageFolder);
|
|
185
209
|
await saveFile(path.join(pageFolder, 'page.html'), content);
|
|
@@ -202,10 +226,6 @@ export async function savePageState(pagesFolder: string, name: string, content:
|
|
|
202
226
|
}
|
|
203
227
|
}
|
|
204
228
|
|
|
205
|
-
export function updatePageState(name: string, content: string): void {
|
|
206
|
-
_pages[name] = content;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
229
|
export async function deletePage(pagesFolder: string, name: string): Promise<void> {
|
|
210
230
|
// Delete folder-based page: <pagesFolder>/pages/<name>/
|
|
211
231
|
const folderPath = path.join(pagesFolder, 'pages', name);
|
|
@@ -219,8 +239,65 @@ export async function deletePage(pagesFolder: string, name: string): Promise<voi
|
|
|
219
239
|
await deleteFile(flatPath);
|
|
220
240
|
}
|
|
221
241
|
|
|
222
|
-
|
|
223
|
-
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ---------------------------------------------------------------------------
|
|
245
|
+
// Page versioning — per-edit version snapshots for undo support
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Save a version snapshot: <pagesFolder>/pages/<name>/page.v<version>.html
|
|
250
|
+
*/
|
|
251
|
+
export async function savePageVersion(pagesFolder: string, name: string, version: number, html: string): Promise<void> {
|
|
252
|
+
const pageFolder = path.join(pagesFolder, 'pages', name);
|
|
253
|
+
await ensureFolderExists(pageFolder);
|
|
254
|
+
await saveFile(path.join(pageFolder, `page.v${version}.html`), html);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Load a version snapshot (returns undefined if the file doesn't exist).
|
|
259
|
+
*/
|
|
260
|
+
export async function loadPageVersion(pagesFolder: string, name: string, version: number): Promise<string | undefined> {
|
|
261
|
+
const filePath = path.join(pagesFolder, 'pages', name, `page.v${version}.html`);
|
|
262
|
+
if (!await checkIfExists(filePath)) return undefined;
|
|
263
|
+
return loadFile(filePath);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Scan page.v*.html files and return the highest version number (0 if none).
|
|
268
|
+
*/
|
|
269
|
+
export async function getLatestVersion(pagesFolder: string, name: string): Promise<number> {
|
|
270
|
+
const pageFolder = path.join(pagesFolder, 'pages', name);
|
|
271
|
+
if (!await checkIfExists(pageFolder)) return 0;
|
|
272
|
+
const files = await listFiles(pageFolder);
|
|
273
|
+
let max = 0;
|
|
274
|
+
for (const file of files) {
|
|
275
|
+
const match = file.match(/^page\.v(\d+)\.html$/);
|
|
276
|
+
if (match) {
|
|
277
|
+
const v = parseInt(match[1], 10);
|
|
278
|
+
if (v > max) max = v;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return max;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Delete all page.v*.html version files for a page.
|
|
286
|
+
*/
|
|
287
|
+
export async function clearVersions(pagesFolder: string, name: string): Promise<void> {
|
|
288
|
+
const pageFolder = path.join(pagesFolder, 'pages', name);
|
|
289
|
+
if (!await checkIfExists(pageFolder)) return;
|
|
290
|
+
const files = await listFiles(pageFolder);
|
|
291
|
+
for (const file of files) {
|
|
292
|
+
if (/^page\.v\d+\.html$/.test(file)) {
|
|
293
|
+
await deleteFile(path.join(pageFolder, file));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export interface CopyPageOptions {
|
|
299
|
+
copyTables?: boolean; // default false
|
|
300
|
+
copyFiles?: boolean; // default true
|
|
224
301
|
}
|
|
225
302
|
|
|
226
303
|
export async function copyPage(
|
|
@@ -229,14 +306,36 @@ export async function copyPage(
|
|
|
229
306
|
targetName: string,
|
|
230
307
|
title: string,
|
|
231
308
|
categories: string[],
|
|
232
|
-
|
|
309
|
+
requiredPagesFolders: string[],
|
|
310
|
+
options?: CopyPageOptions
|
|
233
311
|
): Promise<void> {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
312
|
+
const copyTables = options?.copyTables ?? false;
|
|
313
|
+
const copyFiles = options?.copyFiles ?? true;
|
|
314
|
+
|
|
315
|
+
// Resolve source page folder: user pages first, then required pages
|
|
316
|
+
let sourceFolder: string | undefined;
|
|
317
|
+
const userSourceFolder = path.join(pagesFolder, 'pages', sourceName);
|
|
318
|
+
if (await checkIfExists(path.join(userSourceFolder, 'page.html'))) {
|
|
319
|
+
sourceFolder = userSourceFolder;
|
|
320
|
+
} else {
|
|
321
|
+
for (const folder of requiredPagesFolders) {
|
|
322
|
+
const candidate = path.join(folder, sourceName);
|
|
323
|
+
if (await checkIfExists(path.join(candidate, 'page.html'))) {
|
|
324
|
+
sourceFolder = candidate;
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Load source HTML
|
|
331
|
+
let html: string | undefined;
|
|
332
|
+
if (sourceFolder) {
|
|
333
|
+
html = await loadFile(path.join(sourceFolder, 'page.html'));
|
|
334
|
+
} else {
|
|
335
|
+
// Try legacy flat file
|
|
336
|
+
const flatPath = path.join(pagesFolder, `${sourceName}.html`);
|
|
337
|
+
if (await checkIfExists(flatPath)) {
|
|
338
|
+
html = await loadFile(flatPath);
|
|
240
339
|
}
|
|
241
340
|
}
|
|
242
341
|
|
|
@@ -260,4 +359,27 @@ export async function copyPage(
|
|
|
260
359
|
mode: 'unlocked',
|
|
261
360
|
};
|
|
262
361
|
await savePageMetadata(pagesFolder, targetName, metadata);
|
|
362
|
+
|
|
363
|
+
// Copy additional content from source if a folder was resolved
|
|
364
|
+
if (sourceFolder) {
|
|
365
|
+
const targetFolder = path.join(pagesFolder, 'pages', targetName);
|
|
366
|
+
|
|
367
|
+
if (copyTables) {
|
|
368
|
+
const entries = await listFolders(sourceFolder);
|
|
369
|
+
for (const entry of entries) {
|
|
370
|
+
if (entry === 'files') continue; // handled separately
|
|
371
|
+
await copyFolderRecursive(
|
|
372
|
+
path.join(sourceFolder, entry),
|
|
373
|
+
path.join(targetFolder, entry)
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (copyFiles) {
|
|
379
|
+
const filesDir = path.join(sourceFolder, 'files');
|
|
380
|
+
if (await checkIfExists(filesDir)) {
|
|
381
|
+
await copyFolderRecursive(filesDir, path.join(targetFolder, 'files'));
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
263
385
|
}
|
package/src/service/server.ts
CHANGED
|
@@ -3,11 +3,15 @@ import { usePageRoutes } from './usePageRoutes';
|
|
|
3
3
|
import { useApiRoutes } from './useApiRoutes';
|
|
4
4
|
import { SynthOSConfig } from '../init';
|
|
5
5
|
import { useDataRoutes } from './useDataRoutes';
|
|
6
|
+
import { useFileRoutes } from './useFileRoutes';
|
|
7
|
+
import { useSharedDataRoutes } from './useSharedDataRoutes';
|
|
8
|
+
import { useSharedFileRoutes } from './useSharedFileRoutes';
|
|
6
9
|
import { useConnectorRoutes } from './useConnectorRoutes';
|
|
7
10
|
import { useAgentRoutes } from './useAgentRoutes';
|
|
8
11
|
import { cyan, yellow, formatTime } from './debugLog';
|
|
12
|
+
import { customizer as defaultCustomizer, Customizer } from '../customizer';
|
|
9
13
|
|
|
10
|
-
export function server(config: SynthOSConfig): Application {
|
|
14
|
+
export function server(config: SynthOSConfig, customizer: Customizer = defaultCustomizer): Application {
|
|
11
15
|
const app = express();
|
|
12
16
|
|
|
13
17
|
// Debug request-logging middleware
|
|
@@ -25,23 +29,46 @@ export function server(config: SynthOSConfig): Application {
|
|
|
25
29
|
// Middleware to parse URL-encoded data (form data)
|
|
26
30
|
app.use(express.urlencoded({ extended: true }));
|
|
27
31
|
|
|
28
|
-
// Middleware to parse JSON data
|
|
29
|
-
app.use(express.json());
|
|
32
|
+
// Middleware to parse JSON data (10 MB limit for image attachments)
|
|
33
|
+
app.use(express.json({ limit: '10mb' }));
|
|
34
|
+
|
|
35
|
+
// Favicon — serve from static files
|
|
36
|
+
app.get('/favicon.ico', (_req, res) => res.redirect('/static/favicon.svg'));
|
|
37
|
+
app.get('/favicon.svg', (_req, res) => res.redirect('/static/favicon.svg'));
|
|
38
|
+
|
|
39
|
+
// Serve static files from staticFilesFolders (first folder wins)
|
|
40
|
+
for (const folder of config.staticFilesFolders) {
|
|
41
|
+
app.use('/static', express.static(folder, { maxAge: '1h' }));
|
|
42
|
+
}
|
|
30
43
|
|
|
31
44
|
// Page handling routes
|
|
32
|
-
usePageRoutes(config, app);
|
|
45
|
+
if (customizer.isEnabled('pages')) usePageRoutes(config, app, customizer);
|
|
33
46
|
|
|
34
47
|
// API routes
|
|
35
|
-
useApiRoutes(config, app);
|
|
48
|
+
if (customizer.isEnabled('api')) useApiRoutes(config, app, customizer);
|
|
36
49
|
|
|
37
50
|
// Connector routes
|
|
38
|
-
useConnectorRoutes(config, app);
|
|
51
|
+
if (customizer.isEnabled('connectors')) useConnectorRoutes(config, app);
|
|
39
52
|
|
|
40
53
|
// Agent routes
|
|
41
|
-
useAgentRoutes(config, app);
|
|
54
|
+
if (customizer.isEnabled('agents')) useAgentRoutes(config, app, customizer);
|
|
42
55
|
|
|
43
56
|
// Data routes
|
|
44
|
-
useDataRoutes(config, app);
|
|
57
|
+
if (customizer.isEnabled('data')) useDataRoutes(config, app);
|
|
58
|
+
|
|
59
|
+
// File routes
|
|
60
|
+
if (customizer.isEnabled('files')) useFileRoutes(config, app);
|
|
61
|
+
|
|
62
|
+
// Shared data routes
|
|
63
|
+
if (customizer.isEnabled('shared-data')) useSharedDataRoutes(config, app);
|
|
64
|
+
|
|
65
|
+
// Shared file routes
|
|
66
|
+
if (customizer.isEnabled('shared-files')) useSharedFileRoutes(config, app);
|
|
67
|
+
|
|
68
|
+
// Custom routes from the Customizer
|
|
69
|
+
for (const installer of customizer.getExtraRoutes()) {
|
|
70
|
+
installer(config, app);
|
|
71
|
+
}
|
|
45
72
|
|
|
46
73
|
return app;
|
|
47
|
-
}
|
|
74
|
+
}
|