synthos 0.7.2 → 0.8.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 +215 -65
- package/default-pages/application.json +1 -0
- package/default-pages/json_tools.json +1 -1
- package/default-pages/oregon_trail.html +321 -0
- package/default-pages/oregon_trail.json +12 -0
- package/default-pages/sidebar_page.json +1 -0
- package/default-pages/solar_explorer.html +10 -18
- package/default-pages/solar_explorer.json +2 -2
- package/default-pages/two-panel_page.json +1 -0
- package/default-pages/us_map.html +192 -0
- package/default-pages/us_map.json +12 -0
- package/default-pages/us_map_1850.html +325 -0
- package/default-pages/us_map_1850.json +12 -0
- package/default-pages/western_cities_1850.html +526 -0
- package/default-pages/western_cities_1850.json +12 -0
- package/default-themes/{nebula-dawn.css → nebula-dawn.v2.css} +24 -0
- package/default-themes/{nebula-dusk.css → nebula-dusk.v2.css} +24 -0
- package/dist/agents/a2a/a2aProvider.d.ts +3 -0
- package/dist/agents/a2a/a2aProvider.d.ts.map +1 -0
- package/dist/agents/a2a/a2aProvider.js +126 -0
- package/dist/agents/a2a/a2aProvider.js.map +1 -0
- package/dist/agents/discovery.d.ts +30 -0
- package/dist/agents/discovery.d.ts.map +1 -0
- package/dist/agents/discovery.js +52 -0
- package/dist/agents/discovery.js.map +1 -0
- package/dist/agents/index.d.ts +7 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +19 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/openclaw/gatewayManager.d.ts +113 -0
- package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -0
- package/dist/agents/openclaw/gatewayManager.js +470 -0
- package/dist/agents/openclaw/gatewayManager.js.map +1 -0
- package/dist/agents/openclaw/openclawProvider.d.ts +3 -0
- package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -0
- package/dist/agents/openclaw/openclawProvider.js +239 -0
- package/dist/agents/openclaw/openclawProvider.js.map +1 -0
- package/dist/agents/openclaw/sshTunnelManager.d.ts +23 -0
- package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -0
- package/dist/agents/openclaw/sshTunnelManager.js +340 -0
- package/dist/agents/openclaw/sshTunnelManager.js.map +1 -0
- package/dist/agents/types.d.ts +64 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +6 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/connectors/airtable/connector.json +27 -0
- package/dist/connectors/alpha-vantage/connector.json +26 -0
- package/dist/connectors/brave-search/connector.json +26 -0
- package/dist/connectors/cloudinary/connector.json +27 -0
- package/dist/connectors/deepl/connector.json +28 -0
- package/dist/connectors/elevenlabs/connector.json +30 -0
- package/dist/connectors/giphy/connector.json +27 -0
- package/dist/connectors/github/connector.json +29 -0
- package/dist/connectors/huggingface/connector.json +27 -0
- package/dist/connectors/imgur/connector.json +29 -0
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.d.ts.map +1 -1
- package/dist/connectors/instagram/connector.json +43 -0
- package/dist/connectors/jira/connector.json +28 -0
- package/dist/connectors/mapbox/connector.json +26 -0
- package/dist/connectors/nasa/connector.json +27 -0
- package/dist/connectors/newsapi/connector.json +27 -0
- package/dist/connectors/notion/connector.json +28 -0
- package/dist/connectors/open-exchange-rates/connector.json +27 -0
- package/dist/connectors/openweathermap/connector.json +26 -0
- package/dist/connectors/pexels/connector.json +27 -0
- package/dist/connectors/registry.d.ts.map +1 -1
- package/dist/connectors/registry.js +42 -96
- package/dist/connectors/registry.js.map +1 -1
- package/dist/connectors/resend/connector.json +29 -0
- package/dist/connectors/rss2json/connector.json +27 -0
- package/dist/connectors/sendgrid/connector.json +27 -0
- package/dist/connectors/spoonacular/connector.json +28 -0
- package/dist/connectors/stability-ai/connector.json +27 -0
- package/dist/connectors/twilio/connector.json +28 -0
- package/dist/connectors/types.d.ts +23 -0
- package/dist/connectors/types.d.ts.map +1 -1
- package/dist/connectors/unsplash/connector.json +27 -0
- package/dist/connectors/wolfram-alpha/connector.json +26 -0
- package/dist/connectors/youtube-data/connector.json +30 -0
- package/dist/files.d.ts +1 -0
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +16 -1
- package/dist/files.js.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +28 -0
- package/dist/init.js.map +1 -1
- package/dist/migrations.d.ts +3 -2
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +122 -138
- package/dist/migrations.js.map +1 -1
- package/dist/models/anthropic.d.ts +22 -0
- package/dist/models/anthropic.d.ts.map +1 -0
- package/dist/models/anthropic.js +76 -0
- package/dist/models/anthropic.js.map +1 -0
- package/dist/models/chainOfThought.d.ts +12 -0
- package/dist/models/chainOfThought.d.ts.map +1 -0
- package/dist/models/chainOfThought.js +45 -0
- package/dist/models/chainOfThought.js.map +1 -0
- package/dist/models/fireworksai.d.ts +30 -0
- package/dist/models/fireworksai.d.ts.map +1 -0
- package/dist/models/fireworksai.js +133 -0
- package/dist/models/fireworksai.js.map +1 -0
- package/dist/models/index.d.ts +7 -1
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +19 -1
- package/dist/models/index.js.map +1 -1
- package/dist/models/logCompletePrompt.d.ts +3 -0
- package/dist/models/logCompletePrompt.d.ts.map +1 -0
- package/dist/models/logCompletePrompt.js +23 -0
- package/dist/models/logCompletePrompt.js.map +1 -0
- package/dist/models/openai.d.ts +24 -0
- package/dist/models/openai.d.ts.map +1 -0
- package/dist/models/openai.js +80 -0
- package/dist/models/openai.js.map +1 -0
- package/dist/models/providers.d.ts +1 -0
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/providers.js +12 -4
- package/dist/models/providers.js.map +1 -1
- package/dist/models/types.d.ts +34 -2
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js +16 -0
- package/dist/models/types.js.map +1 -1
- package/dist/models/utils.d.ts +6 -0
- package/dist/models/utils.d.ts.map +1 -0
- package/dist/models/utils.js +21 -0
- package/dist/models/utils.js.map +1 -0
- package/dist/scripts.d.ts +2 -1
- package/dist/scripts.d.ts.map +1 -1
- package/dist/scripts.js +4 -3
- package/dist/scripts.js.map +1 -1
- package/dist/service/createCompletePrompt.d.ts +1 -1
- package/dist/service/createCompletePrompt.d.ts.map +1 -1
- package/dist/service/createCompletePrompt.js +9 -6
- package/dist/service/createCompletePrompt.js.map +1 -1
- package/dist/service/generateImage.d.ts +1 -1
- package/dist/service/generateImage.d.ts.map +1 -1
- package/dist/service/generateImage.js +3 -3
- package/dist/service/generateImage.js.map +1 -1
- package/dist/service/server.d.ts.map +1 -1
- package/dist/service/server.js +3 -0
- package/dist/service/server.js.map +1 -1
- package/dist/service/transformPage.d.ts +4 -2
- package/dist/service/transformPage.d.ts.map +1 -1
- package/dist/service/transformPage.js +74 -6
- package/dist/service/transformPage.js.map +1 -1
- package/dist/service/useAgentRoutes.d.ts +4 -0
- package/dist/service/useAgentRoutes.d.ts.map +1 -0
- package/dist/service/useAgentRoutes.js +389 -0
- package/dist/service/useAgentRoutes.js.map +1 -0
- package/dist/service/useApiRoutes.d.ts.map +1 -1
- package/dist/service/useApiRoutes.js +157 -16
- package/dist/service/useApiRoutes.js.map +1 -1
- package/dist/service/useConnectorRoutes.d.ts.map +1 -1
- package/dist/service/useConnectorRoutes.js +14 -3
- package/dist/service/useConnectorRoutes.js.map +1 -1
- package/dist/service/useGatewayRoutes.d.ts +4 -0
- package/dist/service/useGatewayRoutes.d.ts.map +1 -0
- package/dist/service/useGatewayRoutes.js +168 -0
- package/dist/service/useGatewayRoutes.js.map +1 -0
- package/dist/service/usePageRoutes.d.ts.map +1 -1
- package/dist/service/usePageRoutes.js +16 -5
- package/dist/service/usePageRoutes.js.map +1 -1
- package/dist/settings.d.ts +2 -1
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +4 -8
- package/dist/settings.js.map +1 -1
- package/dist/themes.d.ts +14 -0
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js +86 -13
- package/dist/themes.js.map +1 -1
- package/package.json +8 -5
- package/page-scripts/helpers-v2.js +101 -0
- package/page-scripts/page-v2.js +47 -6
- package/required-pages/builder.html +1 -27
- package/required-pages/pages.html +745 -22
- package/required-pages/settings.html +819 -21
- package/required-pages/synthos_apis.html +56 -1
- package/src/agents/a2a/a2aProvider.ts +110 -0
- package/src/agents/discovery.ts +74 -0
- package/src/agents/index.ts +6 -0
- package/src/agents/openclaw/gatewayManager.ts +559 -0
- package/src/agents/openclaw/openclawProvider.ts +261 -0
- package/src/agents/openclaw/sshTunnelManager.ts +385 -0
- package/src/agents/types.ts +82 -0
- package/src/connectors/airtable/connector.json +27 -0
- package/src/connectors/alpha-vantage/connector.json +26 -0
- package/src/connectors/brave-search/connector.json +26 -0
- package/src/connectors/cloudinary/connector.json +27 -0
- package/src/connectors/deepl/connector.json +28 -0
- package/src/connectors/elevenlabs/connector.json +30 -0
- package/src/connectors/giphy/connector.json +27 -0
- package/src/connectors/github/connector.json +29 -0
- package/src/connectors/huggingface/connector.json +27 -0
- package/src/connectors/imgur/connector.json +29 -0
- package/src/connectors/index.ts +2 -0
- package/src/connectors/instagram/connector.json +43 -0
- package/src/connectors/jira/connector.json +28 -0
- package/src/connectors/mapbox/connector.json +26 -0
- package/src/connectors/nasa/connector.json +27 -0
- package/src/connectors/newsapi/connector.json +27 -0
- package/src/connectors/notion/connector.json +28 -0
- package/src/connectors/open-exchange-rates/connector.json +27 -0
- package/src/connectors/openweathermap/connector.json +26 -0
- package/src/connectors/pexels/connector.json +27 -0
- package/src/connectors/registry.ts +21 -97
- package/src/connectors/resend/connector.json +29 -0
- package/src/connectors/rss2json/connector.json +27 -0
- package/src/connectors/sendgrid/connector.json +27 -0
- package/src/connectors/spoonacular/connector.json +28 -0
- package/src/connectors/stability-ai/connector.json +27 -0
- package/src/connectors/twilio/connector.json +28 -0
- package/src/connectors/types.ts +25 -0
- package/src/connectors/unsplash/connector.json +27 -0
- package/src/connectors/wolfram-alpha/connector.json +26 -0
- package/src/connectors/youtube-data/connector.json +30 -0
- package/src/files.ts +14 -0
- package/src/init.ts +27 -0
- package/src/migrations.ts +121 -138
- package/src/models/anthropic.ts +89 -0
- package/src/models/chainOfThought.ts +56 -0
- package/src/models/fireworksai.ts +136 -0
- package/src/models/index.ts +7 -1
- package/src/models/logCompletePrompt.ts +25 -0
- package/src/models/openai.ts +90 -0
- package/src/models/providers.ts +12 -3
- package/src/models/types.ts +67 -2
- package/src/models/utils.ts +16 -0
- package/src/scripts.ts +2 -2
- package/src/service/createCompletePrompt.ts +3 -1
- package/src/service/generateImage.ts +2 -2
- package/src/service/server.ts +4 -0
- package/src/service/transformPage.ts +81 -8
- package/src/service/useAgentRoutes.ts +423 -0
- package/src/service/useApiRoutes.ts +173 -18
- package/src/service/useConnectorRoutes.ts +14 -3
- package/src/service/usePageRoutes.ts +20 -6
- package/src/settings.ts +6 -10
- package/src/themes.ts +84 -12
- package/tests/anthropic.spec.ts +84 -0
- package/tests/chainOfThought.spec.ts +108 -0
- package/tests/ensureScripts.spec.ts +82 -0
- package/tests/files.spec.ts +233 -0
- package/tests/fireworksai.spec.ts +92 -0
- package/tests/logCompletePrompt.spec.ts +74 -0
- package/tests/migrations.spec.ts +79 -1
- package/tests/openai.spec.ts +71 -0
- package/tests/pages.spec.ts +226 -1
- package/tests/providers.spec.ts +144 -0
- package/tests/scripts.spec.ts +209 -0
- package/tests/transformPage.spec.ts +517 -0
- package/tests/types.spec.ts +23 -0
- package/default-pages/app_builder.json +0 -1
- package/default-pages/sidebar_builder.json +0 -1
- package/default-pages/two-panel_builder.json +0 -1
- package/images/home.png +0 -0
- package/images/page-management.png +0 -0
- package/images/settings.png +0 -0
- package/images/synthos-square.png +0 -0
- /package/default-pages/{app_builder.html → application.html} +0 -0
- /package/default-pages/{sidebar_builder.html → sidebar_page.html} +0 -0
- /package/default-pages/{two-panel_builder.html → two-panel_page.html} +0 -0
package/src/migrations.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as cheerio from 'cheerio';
|
|
2
|
-
import
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { completePrompt } from './models';
|
|
3
5
|
import { deduplicateInlineScripts } from './service/transformPage';
|
|
4
6
|
|
|
5
7
|
/**
|
|
@@ -26,128 +28,57 @@ export async function migratePage(html: string, fromVersion: number, toVersion:
|
|
|
26
28
|
return current;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
/** CSS
|
|
31
|
+
/** CSS selectors provided by the shared theme — used by post-processing to strip leftovers. */
|
|
30
32
|
const SHARED_CSS_SELECTORS = [
|
|
31
|
-
|
|
32
|
-
'body',
|
|
33
|
-
|
|
34
|
-
'.chat-header',
|
|
35
|
-
'.chat-
|
|
36
|
-
'.chat-message',
|
|
37
|
-
'.
|
|
38
|
-
'.chat-message strong',
|
|
39
|
-
'.chat-message pre',
|
|
40
|
-
'.chat-message code',
|
|
41
|
-
'.chat-message a',
|
|
42
|
-
'.link-group',
|
|
43
|
-
'.link-group a',
|
|
33
|
+
// Base
|
|
34
|
+
':root', '*', 'body', 'html',
|
|
35
|
+
// Chat panel
|
|
36
|
+
'.chat-panel', '.chat-header', '.chat-messages',
|
|
37
|
+
'.chat-message', '.chat-message p', '.chat-message p strong', '.chat-message p code',
|
|
38
|
+
'.chat-message strong', '.chat-message pre', '.chat-message code', '.chat-message a',
|
|
39
|
+
'.link-group', '.link-group a', '.link-group a:hover',
|
|
44
40
|
'form',
|
|
45
|
-
'.chat-input',
|
|
46
|
-
'.chat-submit',
|
|
47
|
-
'.
|
|
48
|
-
|
|
49
|
-
'.viewer-panel',
|
|
50
|
-
|
|
51
|
-
'.
|
|
52
|
-
|
|
41
|
+
'.chat-input', '.chat-input:focus', '.chat-input::placeholder', '.chat-input:disabled',
|
|
42
|
+
'.chat-submit', '.chat-submit:hover', '.chat-submit:active', '.chat-submit:disabled',
|
|
43
|
+
'.chat-input-wrapper', '.chat-input-wrapper .chat-input',
|
|
44
|
+
// Viewer panel
|
|
45
|
+
'.viewer-panel', '.viewer-panel::before', '.viewer-panel.full-viewer',
|
|
46
|
+
// Loading
|
|
47
|
+
'.loading-overlay', '.spinner', '#loadingOverlay',
|
|
48
|
+
// Chat toggle
|
|
49
|
+
'.chat-toggle', '.chat-toggle:hover', '.chat-toggle-dots', '.chat-toggle-dot',
|
|
50
|
+
'.chat-toggle:hover .chat-toggle-dot',
|
|
51
|
+
'body.chat-collapsed .chat-panel', 'body.chat-collapsed .chat-toggle',
|
|
52
|
+
// Modal system
|
|
53
|
+
'.modal-overlay', '.modal-overlay.show', '.modal-content', '.modal-header',
|
|
54
|
+
'.modal-body', '.modal-footer', '.modal-footer-right',
|
|
55
|
+
'.modal-btn', '.modal-btn-primary', '.modal-btn-primary:hover',
|
|
56
|
+
'.modal-btn-secondary', '.modal-btn-secondary:hover',
|
|
57
|
+
'.modal-btn-danger', '.modal-btn-danger:hover',
|
|
58
|
+
// Form elements
|
|
59
|
+
'.form-group', '.form-group:last-child', '.form-label',
|
|
60
|
+
'.form-input', '.form-input:focus', '.form-input:read-only', '.form-input::placeholder',
|
|
61
|
+
'.checkbox-label', '.checkbox-label input[type="checkbox"]', '.checkbox-label span',
|
|
62
|
+
// Brainstorm
|
|
63
|
+
'.brainstorm-icon-btn', '.brainstorm-icon-btn:hover',
|
|
64
|
+
'.brainstorm-modal .modal-content', '.brainstorm-modal .modal-header',
|
|
65
|
+
'.brainstorm-close-btn', '.brainstorm-close-btn:hover',
|
|
66
|
+
'.brainstorm-messages', '.brainstorm-message', '.brainstorm-user', '.brainstorm-assistant',
|
|
67
|
+
'.brainstorm-input-row', '.brainstorm-input', '.brainstorm-input:focus', '.brainstorm-input::placeholder',
|
|
68
|
+
'.brainstorm-send-btn', '.brainstorm-send-btn:hover', '.brainstorm-send-btn:disabled',
|
|
69
|
+
'.brainstorm-assistant p', '.brainstorm-assistant pre', '.brainstorm-assistant code',
|
|
70
|
+
'.brainstorm-build-row', '.brainstorm-build-btn', '.brainstorm-build-btn:hover',
|
|
71
|
+
'.brainstorm-suggestions', '.brainstorm-suggestion-chip',
|
|
72
|
+
'.brainstorm-suggestion-chip:hover', '.brainstorm-suggestion-chip:disabled',
|
|
73
|
+
'.brainstorm-thinking',
|
|
53
74
|
];
|
|
54
75
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
## Rules — What to REMOVE
|
|
58
|
-
|
|
59
|
-
1. **Shared CSS rules** — Remove CSS rules that match these selectors **exactly** (they are now in theme.css):
|
|
60
|
-
\`*\`, \`body\`, \`.chat-panel\`, \`.chat-header\`, \`.chat-messages\`, \`.chat-message\` (and descendants like \`.chat-message p\`, \`.chat-message strong\`, \`.chat-message pre\`, \`.chat-message code\`, \`.chat-message a\`), \`.link-group\`, \`.link-group a\`, \`form\`, \`.chat-input\`, \`.chat-submit\`, \`.loading-overlay\`, \`.spinner\`, \`.viewer-panel\`, \`#loadingOverlay\`, \`.chat-submit:disabled\`, \`.chat-input:disabled\`
|
|
61
|
-
Also remove any \`@keyframes spin\` and scrollbar pseudo-element rules (\`::-webkit-scrollbar\`, \`::-webkit-scrollbar-track\`, \`::-webkit-scrollbar-thumb\`).
|
|
62
|
-
**Important:** Only remove rules matching these selectors exactly. Do NOT remove pseudo-element variants (\`.viewer-panel::before\`, \`.viewer-panel::after\`), pseudo-class variants (\`.chat-input:focus\`, \`.chat-submit:hover\`), or any other compound selectors that extend the shared selectors — those are page-specific styles and must be preserved. Also preserve any \`@keyframes\` referenced by page-specific rules (e.g. if a page has \`.viewer-panel::before\` using a custom animation, keep that \`@keyframes\`).
|
|
63
|
-
|
|
64
|
-
2. **Shared inline JS** — Remove these specific code blocks from \`<script>\` tags:
|
|
65
|
-
- \`document.getElementById('chatInput').focus()\` line
|
|
66
|
-
- \`chatForm\` submit event listener (the one with setTimeout and loading overlay)
|
|
67
|
-
- \`saveLink\` click handler
|
|
68
|
-
- \`resetLink\` click handler
|
|
69
|
-
- \`window.onload\` that ONLY scrolls chatMessages (keep other onload logic!)
|
|
70
|
-
- Chat panel toggle IIFE (references \`synthos-chat-collapsed\`)
|
|
71
|
-
- Focus management IIFE (references \`stopImmediatePropagation\`)
|
|
72
|
-
- \`// Basic chat functionality\` comment
|
|
73
|
-
|
|
74
|
-
3. **Empty \`<script>\` tags** — If a script block becomes empty after stripping, remove it entirely.
|
|
75
|
-
|
|
76
|
-
## Rules — What to ADD
|
|
77
|
-
|
|
78
|
-
1. In \`<head>\`, add these two lines right after the \`<title>\` tag (if not already present):
|
|
79
|
-
\`\`\`
|
|
80
|
-
<script src="/api/theme-info.js"></script>
|
|
81
|
-
<link rel="stylesheet" href="/api/theme.css">
|
|
82
|
-
\`\`\`
|
|
83
|
-
|
|
84
|
-
## Rules — What to TRANSFORM
|
|
85
|
-
|
|
86
|
-
### Data/Table API migration
|
|
87
|
-
The data API changed from global tables to **page-scoped** tables:
|
|
88
|
-
- Old: \`/api/data/:table\` → New: \`/api/data/:page/:table\`
|
|
89
|
-
- Old: \`/api/data/:table/:id\` → New: \`/api/data/:page/:table/:id\`
|
|
90
|
-
- Tables are now stored as sub-folders of each page's folder.
|
|
91
|
-
- **Raw fetch() calls** must be updated: e.g. \`fetch('/api/data/notes')\` → \`fetch('/api/data/' + pageName + '/notes')\`
|
|
92
|
-
- **synthos.data.\* helpers** handle this automatically — they read the current page name from \`window.pageInfo.name\`. Prefer converting raw fetch data calls to use the helpers instead:
|
|
93
|
-
- \`fetch('/api/data/notes')\` → \`synthos.data.list('notes')\`
|
|
94
|
-
- \`fetch('/api/data/notes/' + id)\` → \`synthos.data.get('notes', id)\`
|
|
95
|
-
- \`fetch('/api/data/notes', { method: 'POST', ... })\` → \`synthos.data.save('notes', row)\`
|
|
96
|
-
- \`fetch('/api/data/notes/' + id, { method: 'DELETE' })\` → \`synthos.data.remove('notes', id)\`
|
|
97
|
-
|
|
98
|
-
### Color variables
|
|
99
|
-
Replace hardcoded Nebula Dusk colors with CSS variables in **page-specific** CSS only:
|
|
100
|
-
| Hardcoded | CSS Variable |
|
|
101
|
-
|-----------|-------------|
|
|
102
|
-
| \`#667eea\` | \`var(--accent-primary)\` |
|
|
103
|
-
| \`#764ba2\` | \`var(--accent-secondary)\` |
|
|
104
|
-
| \`#f093fb\` | \`var(--accent-tertiary)\` |
|
|
105
|
-
| \`#b794f6\` | \`var(--text-secondary)\` |
|
|
106
|
-
| \`#e0e0e0\` | \`var(--text-primary)\` |
|
|
107
|
-
| \`rgba(138, 43, 226, 0.3)\` or similar purple rgba | \`var(--border-color)\` or \`var(--accent-glow)\` (use border-color for borders, accent-glow for shadows) |
|
|
108
|
-
| \`#1a1a2e\` | \`var(--bg-primary)\` |
|
|
109
|
-
| \`#16213e\` | \`var(--bg-secondary)\` |
|
|
110
|
-
| \`#0f0f23\` | \`var(--bg-tertiary)\` |
|
|
111
|
-
|
|
112
|
-
For gradients using these colors (e.g. \`linear-gradient(135deg, #667eea, #764ba2)\`), replace with \`linear-gradient(135deg, var(--accent-primary), var(--accent-secondary))\`.
|
|
113
|
-
|
|
114
|
-
## Rules — What to PRESERVE (do NOT modify)
|
|
115
|
-
|
|
116
|
-
- ALL viewer-panel HTML content (games, presentations, tools, etc.)
|
|
117
|
-
- ALL page-specific JavaScript (game logic, presentation logic, keyboard handlers, etc.)
|
|
118
|
-
- ALL page-specific CSS (game styles, presentation styles, layout rules for non-shared classes)
|
|
119
|
-
- Chat message history in \`.chat-messages\`
|
|
120
|
-
- \`<div id="thoughts">\` content
|
|
121
|
-
- External CDN script tags (\`<script src="...">\`)
|
|
122
|
-
- The two-panel layout structure (chat-panel + viewer-panel)
|
|
123
|
-
- The \`<div id="loadingOverlay" class="loading-overlay"><div class="spinner"></div></div>\` element
|
|
124
|
-
- The chat form, link-group, chat-header elements (structure only, their CSS is handled by theme)
|
|
125
|
-
|
|
126
|
-
## V2 page structure example
|
|
127
|
-
|
|
128
|
-
\`\`\`html
|
|
129
|
-
<!DOCTYPE html>
|
|
130
|
-
<html lang="en">
|
|
131
|
-
<head>
|
|
132
|
-
<meta charset="UTF-8">
|
|
133
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
134
|
-
<title>SynthOS - Page Title</title>
|
|
135
|
-
<script src="/api/theme-info.js"></script>
|
|
136
|
-
<link rel="stylesheet" href="/api/theme.css">
|
|
137
|
-
<style>
|
|
138
|
-
/* Only page-specific styles here — no shared chat/layout CSS */
|
|
139
|
-
.my-custom-element {
|
|
140
|
-
color: var(--text-primary);
|
|
141
|
-
background: var(--bg-secondary);
|
|
142
|
-
}
|
|
143
|
-
</style>
|
|
144
|
-
<!-- external CDN scripts if needed -->
|
|
145
|
-
</head>
|
|
146
|
-
<body>
|
|
76
|
+
/** Default chat panel HTML — restored by post-processing if the LLM removes it. */
|
|
77
|
+
const DEFAULT_CHAT_PANEL = `
|
|
147
78
|
<div class="chat-panel">
|
|
148
79
|
<div class="chat-header">SynthOS</div>
|
|
149
80
|
<div class="chat-messages" id="chatMessages">
|
|
150
|
-
|
|
81
|
+
<div class="chat-message"><p>Welcome! How can I help you?</p></div>
|
|
151
82
|
</div>
|
|
152
83
|
<div class="link-group">
|
|
153
84
|
<a href="#" id="saveLink">Save</a>
|
|
@@ -158,32 +89,26 @@ For gradients using these colors (e.g. \`linear-gradient(135deg, #667eea, #764ba
|
|
|
158
89
|
<input type="text" class="chat-input" id="chatInput" name="message" placeholder="Type a message...">
|
|
159
90
|
<button type="submit" class="chat-submit">Send</button>
|
|
160
91
|
</form>
|
|
161
|
-
</div
|
|
162
|
-
<div class="viewer-panel" id="viewerPanel">
|
|
163
|
-
<!-- page content preserved -->
|
|
164
|
-
<div id="loadingOverlay" class="loading-overlay"><div class="spinner"></div></div>
|
|
165
|
-
</div>
|
|
166
|
-
<div id="thoughts" style="display: none;">...</div>
|
|
167
|
-
<script>
|
|
168
|
-
// Only page-specific JS here — no shared chat handlers
|
|
169
|
-
</script>
|
|
170
|
-
</body>
|
|
171
|
-
</html>
|
|
172
|
-
\`\`\`
|
|
92
|
+
</div>`;
|
|
173
93
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Load migration rules from the migration-rules/ folder.
|
|
96
|
+
*/
|
|
97
|
+
async function loadMigrationRules(filename: string): Promise<string> {
|
|
98
|
+
const rulesPath = path.join(__dirname, '..', 'migration-rules', filename);
|
|
99
|
+
return await fs.readFile(rulesPath, 'utf8');
|
|
100
|
+
}
|
|
177
101
|
|
|
178
102
|
/**
|
|
179
103
|
* v1 -> v2: LLM-based migration that strips shared code and adds theme support.
|
|
180
104
|
* Post-processes with cheerio to verify critical elements are present.
|
|
181
105
|
*/
|
|
182
106
|
async function migrateV1toV2(html: string, completePrompt: completePrompt): Promise<string> {
|
|
183
|
-
const
|
|
107
|
+
const rules = await loadMigrationRules('v1-to-v2.md');
|
|
108
|
+
const system = { role: 'system' as const, content: rules };
|
|
184
109
|
const prompt = { role: 'user' as const, content: `Convert this v1 page to v2 format:\n\n${html}` };
|
|
185
110
|
|
|
186
|
-
const result = await completePrompt({ prompt, system
|
|
111
|
+
const result = await completePrompt({ prompt, system });
|
|
187
112
|
if (!result.completed || !result.value) {
|
|
188
113
|
throw new Error('LLM migration failed: ' + (result.error?.message ?? 'no response'));
|
|
189
114
|
}
|
|
@@ -195,16 +120,72 @@ async function migrateV1toV2(html: string, completePrompt: completePrompt): Prom
|
|
|
195
120
|
}
|
|
196
121
|
|
|
197
122
|
// Post-process with cheerio to verify and fix critical elements
|
|
198
|
-
migrated = postProcessV2(migrated);
|
|
123
|
+
migrated = postProcessV2(migrated, html);
|
|
199
124
|
|
|
200
125
|
return migrated;
|
|
201
126
|
}
|
|
202
127
|
|
|
203
128
|
/**
|
|
204
129
|
* Cheerio-based post-processing to verify the LLM output meets v2 requirements.
|
|
130
|
+
* Uses the original HTML as a fallback source for critical elements.
|
|
205
131
|
*/
|
|
206
|
-
export function postProcessV2(html: string): string {
|
|
132
|
+
export function postProcessV2(html: string, originalHtml?: string): string {
|
|
207
133
|
const $ = cheerio.load(html, { decodeEntities: false });
|
|
134
|
+
const $original = originalHtml ? cheerio.load(originalHtml, { decodeEntities: false }) : null;
|
|
135
|
+
|
|
136
|
+
// --- Critical structural checks ---
|
|
137
|
+
|
|
138
|
+
// Ensure chat-panel exists with chatForm
|
|
139
|
+
if ($('#chatForm').length === 0) {
|
|
140
|
+
if ($('.chat-panel').length > 0) {
|
|
141
|
+
// Chat panel exists but form is missing — restore form from original or default
|
|
142
|
+
const originalForm = $original?.('#chatForm').parent('.chat-panel');
|
|
143
|
+
if (originalForm && originalForm.length > 0) {
|
|
144
|
+
$('.chat-panel').replaceWith(originalForm.html()!);
|
|
145
|
+
} else {
|
|
146
|
+
// Append default form
|
|
147
|
+
$('.chat-panel').append(`
|
|
148
|
+
<form action="/" method="POST" id="chatForm">
|
|
149
|
+
<input type="text" class="chat-input" id="chatInput" name="message" placeholder="Type a message...">
|
|
150
|
+
<button type="submit" class="chat-submit">Send</button>
|
|
151
|
+
</form>`);
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
// Entire chat panel is missing — restore from original or use default
|
|
155
|
+
const originalPanel = $original?.('.chat-panel');
|
|
156
|
+
if (originalPanel && originalPanel.length > 0) {
|
|
157
|
+
$('body').prepend($.html(originalPanel));
|
|
158
|
+
} else {
|
|
159
|
+
$('body').prepend(DEFAULT_CHAT_PANEL);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Ensure thoughts div exists
|
|
165
|
+
if ($('#thoughts').length === 0) {
|
|
166
|
+
const originalThoughts = $original?.('#thoughts');
|
|
167
|
+
if (originalThoughts && originalThoughts.length > 0) {
|
|
168
|
+
$('body').append($.html(originalThoughts));
|
|
169
|
+
} else {
|
|
170
|
+
$('body').append('<div id="thoughts" style="display: none;"></div>');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Ensure loadingOverlay exists inside viewer-panel
|
|
175
|
+
const overlay = $('#loadingOverlay');
|
|
176
|
+
const viewerPanel = $('.viewer-panel');
|
|
177
|
+
if (overlay.length === 0 && viewerPanel.length > 0) {
|
|
178
|
+
viewerPanel.append('<div id="loadingOverlay" class="loading-overlay"><div class="spinner"></div></div>');
|
|
179
|
+
} else if (overlay.length > 0 && viewerPanel.length > 0) {
|
|
180
|
+
// Move inside viewer-panel if it's outside
|
|
181
|
+
if (overlay.closest('.viewer-panel').length === 0) {
|
|
182
|
+
const overlayHtml = $.html(overlay);
|
|
183
|
+
overlay.remove();
|
|
184
|
+
viewerPanel.append(overlayHtml);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// --- Theme refs ---
|
|
208
189
|
|
|
209
190
|
// Ensure theme-info.js is in <head>
|
|
210
191
|
if ($('script[src="/api/theme-info.js"]').length === 0) {
|
|
@@ -226,7 +207,8 @@ export function postProcessV2(html: string): string {
|
|
|
226
207
|
}
|
|
227
208
|
}
|
|
228
209
|
|
|
229
|
-
//
|
|
210
|
+
// --- Strip leftover shared CSS ---
|
|
211
|
+
|
|
230
212
|
$('style').each(function (_, el) {
|
|
231
213
|
let css = $(el).html() ?? '';
|
|
232
214
|
for (const selector of SHARED_CSS_SELECTORS) {
|
|
@@ -236,10 +218,11 @@ export function postProcessV2(html: string): string {
|
|
|
236
218
|
const pattern = new RegExp(`(?:^|\\n)\\s*${escaped}\\s*\\{[^}]*\\}`, 'g');
|
|
237
219
|
css = css.replace(pattern, '');
|
|
238
220
|
}
|
|
239
|
-
// Remove @keyframes spin
|
|
221
|
+
// Remove @keyframes spin and nebula-pulse
|
|
240
222
|
css = css.replace(/@keyframes\s+spin\s*\{[^}]*(?:\{[^}]*\}[^}]*)*\}/g, '');
|
|
223
|
+
css = css.replace(/@keyframes\s+nebula-pulse\s*\{[^}]*(?:\{[^}]*\}[^}]*)*\}/g, '');
|
|
241
224
|
// Remove scrollbar pseudo-element rules
|
|
242
|
-
css = css.replace(/(?:^|\n)\s*(?:\*|body|)::-webkit-scrollbar(?:-(?:track|thumb))?\s*\{[^}]*\}/g, '');
|
|
225
|
+
css = css.replace(/(?:^|\n)\s*(?:\*|body|)::-webkit-scrollbar(?:-(?:track|thumb|corner))?(?::hover)?\s*\{[^}]*\}/g, '');
|
|
243
226
|
$(el).html(css);
|
|
244
227
|
});
|
|
245
228
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import { AgentCompletion, completePrompt, PromptCompletionArgs, RequestError } from './types';
|
|
3
|
+
|
|
4
|
+
export interface AnthropicArgs {
|
|
5
|
+
apiKey: string;
|
|
6
|
+
model: string;
|
|
7
|
+
baseURL?: string;
|
|
8
|
+
temperature?: number;
|
|
9
|
+
maxRetries?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Build the messages array and system content for an Anthropic API request.
|
|
14
|
+
* Pure function — no SDK dependency.
|
|
15
|
+
*/
|
|
16
|
+
export function buildAnthropicRequest(args: PromptCompletionArgs, defaultTemp: number): {
|
|
17
|
+
messages: { role: string; content: string }[];
|
|
18
|
+
system: string | undefined;
|
|
19
|
+
temperature: number;
|
|
20
|
+
} {
|
|
21
|
+
const reqTemp = args.temperature ?? defaultTemp;
|
|
22
|
+
|
|
23
|
+
const messages: { role: string; content: string }[] = [];
|
|
24
|
+
if (args.history) {
|
|
25
|
+
for (const msg of args.history) {
|
|
26
|
+
messages.push({ role: msg.role, content: msg.content });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const useJsonPrefill = args.jsonMode || args.jsonSchema;
|
|
31
|
+
if (useJsonPrefill) {
|
|
32
|
+
messages.push({ role: 'user', content: args.prompt.content });
|
|
33
|
+
messages.push({ role: 'assistant', content: '{' });
|
|
34
|
+
} else {
|
|
35
|
+
messages.push({ role: 'user', content: args.prompt.content });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let system = args.system?.content;
|
|
39
|
+
if (args.jsonSchema) {
|
|
40
|
+
const schemaInstruction = `\n\nYou must return valid JSON conforming to this schema:\n${JSON.stringify(args.jsonSchema)}`;
|
|
41
|
+
system = system ? system + schemaInstruction : schemaInstruction;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return { messages, system, temperature: reqTemp };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function anthropic(args: AnthropicArgs): completePrompt {
|
|
48
|
+
const { apiKey, model, baseURL, temperature = 0.0, maxRetries } = args;
|
|
49
|
+
|
|
50
|
+
const client = new Anthropic({ apiKey, baseURL, maxRetries });
|
|
51
|
+
|
|
52
|
+
return async (completionArgs: PromptCompletionArgs): Promise<AgentCompletion<string>> => {
|
|
53
|
+
const { messages, system: systemContent, temperature: reqTemp } = buildAnthropicRequest(completionArgs, temperature);
|
|
54
|
+
|
|
55
|
+
const useJsonPrefill = completionArgs.jsonMode || completionArgs.jsonSchema;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const stream = await client.messages.create({
|
|
59
|
+
model,
|
|
60
|
+
max_tokens: 32768,
|
|
61
|
+
temperature: reqTemp,
|
|
62
|
+
system: systemContent,
|
|
63
|
+
messages: messages as Anthropic.MessageParam[],
|
|
64
|
+
stream: true,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
let text = '';
|
|
68
|
+
for await (const event of stream) {
|
|
69
|
+
if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
|
|
70
|
+
text += event.delta.text;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (useJsonPrefill) {
|
|
75
|
+
text = '{' + text;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { completed: true, value: text };
|
|
79
|
+
} catch (err: unknown) {
|
|
80
|
+
let error: Error;
|
|
81
|
+
if (err instanceof Anthropic.APIError && (err as any).status !== undefined) {
|
|
82
|
+
error = new RequestError(err.message, (err as any).status, err.name);
|
|
83
|
+
} else {
|
|
84
|
+
error = err as Error;
|
|
85
|
+
}
|
|
86
|
+
return { completed: false, error };
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { AgentCompletion, AgentArgs, SystemMessage, UserMessage } from './types';
|
|
2
|
+
|
|
3
|
+
export interface ExplainedAnswer {
|
|
4
|
+
explanation: string;
|
|
5
|
+
answer: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ChainOfThoughtArgs extends AgentArgs {
|
|
9
|
+
question: string;
|
|
10
|
+
temperature?: number;
|
|
11
|
+
instructions?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function chainOfThought(args: ChainOfThoughtArgs): Promise<AgentCompletion<ExplainedAnswer>> {
|
|
15
|
+
const { completePrompt, question, temperature, instructions } = args;
|
|
16
|
+
|
|
17
|
+
const systemContent = instructions
|
|
18
|
+
? `${instructions}\n\nYou must return your response as a JSON object with "explanation" and "answer" fields.`
|
|
19
|
+
: 'You must return your response as a JSON object with "explanation" and "answer" fields.';
|
|
20
|
+
|
|
21
|
+
const system: SystemMessage = { role: 'system', content: systemContent };
|
|
22
|
+
const prompt: UserMessage = { role: 'user', content: question };
|
|
23
|
+
|
|
24
|
+
const result = await completePrompt({ prompt, system, temperature, jsonMode: true });
|
|
25
|
+
|
|
26
|
+
if (!result.completed || !result.value) {
|
|
27
|
+
return { completed: false, error: result.error };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
let parsed: any;
|
|
32
|
+
if (typeof result.value === 'object') {
|
|
33
|
+
parsed = result.value;
|
|
34
|
+
} else {
|
|
35
|
+
let text = result.value as string;
|
|
36
|
+
// Strip markdown code fences if present
|
|
37
|
+
text = text.replace(/^```(?:json)?\s*/i, '').replace(/\s*```\s*$/, '');
|
|
38
|
+
// Extract the first JSON object from the text
|
|
39
|
+
const start = text.indexOf('{');
|
|
40
|
+
const end = text.lastIndexOf('}');
|
|
41
|
+
if (start !== -1 && end > start) {
|
|
42
|
+
text = text.substring(start, end + 1);
|
|
43
|
+
}
|
|
44
|
+
parsed = JSON.parse(text);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
completed: true,
|
|
48
|
+
value: {
|
|
49
|
+
explanation: parsed.explanation ?? '',
|
|
50
|
+
answer: parsed.answer ?? '',
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
} catch {
|
|
54
|
+
return { completed: false, error: new Error('Failed to parse chain-of-thought response') };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { AgentCompletion, completePrompt, PromptCompletionArgs, RequestError } from './types';
|
|
3
|
+
|
|
4
|
+
export interface FireworksAIArgs {
|
|
5
|
+
apiKey: string;
|
|
6
|
+
model: string;
|
|
7
|
+
temperature?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Known short-name → full Fireworks model path mappings. */
|
|
11
|
+
const FIREWORKS_MODEL_MAP: Record<string, string> = {
|
|
12
|
+
'fireworks-glm-5': 'accounts/fireworks/models/glm-5',
|
|
13
|
+
'fireworks-minimax-m2p5': 'accounts/fireworks/models/minimax-m2p5',
|
|
14
|
+
'fireworks-kimi-k2p5': 'accounts/fireworks/models/kimi-k2p5',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const FIREWORKS_BASE_URL = 'https://api.fireworks.ai/inference/v1';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Extract JSON from a string that may be wrapped in markdown fences or prose.
|
|
21
|
+
* Returns the original string if no JSON object/array is found.
|
|
22
|
+
*/
|
|
23
|
+
export function extractJSON(text: string): string {
|
|
24
|
+
// Strip markdown code fences (```json ... ``` or ``` ... ```)
|
|
25
|
+
const fenceMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?\s*```/);
|
|
26
|
+
if (fenceMatch) {
|
|
27
|
+
return fenceMatch[1].trim();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Find the first top-level { ... } or [ ... ]
|
|
31
|
+
const start = text.search(/[\[{]/);
|
|
32
|
+
if (start === -1) return text;
|
|
33
|
+
|
|
34
|
+
const open = text[start];
|
|
35
|
+
const close = open === '{' ? '}' : ']';
|
|
36
|
+
let depth = 0;
|
|
37
|
+
let inString = false;
|
|
38
|
+
let escape = false;
|
|
39
|
+
for (let i = start; i < text.length; i++) {
|
|
40
|
+
const ch = text[i];
|
|
41
|
+
if (escape) { escape = false; continue; }
|
|
42
|
+
if (ch === '\\' && inString) { escape = true; continue; }
|
|
43
|
+
if (ch === '"') { inString = !inString; continue; }
|
|
44
|
+
if (inString) continue;
|
|
45
|
+
if (ch === open || ch === (open === '{' ? '[' : '{')) depth++;
|
|
46
|
+
else if (ch === close || ch === (close === '}' ? ']' : '}')) depth--;
|
|
47
|
+
if (depth === 0) {
|
|
48
|
+
return text.slice(start, i + 1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Fallback: return from the first brace to end
|
|
53
|
+
return text.slice(start);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Resolve a short Fireworks model name to the full API path.
|
|
58
|
+
* Returns the input unchanged if not a known short name.
|
|
59
|
+
*/
|
|
60
|
+
export function resolveFireworksModel(model: string): string {
|
|
61
|
+
return FIREWORKS_MODEL_MAP[model] || model;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Build the messages array, temperature, and JSON flag for a FireworksAI request.
|
|
66
|
+
* Pure function — no SDK dependency.
|
|
67
|
+
*/
|
|
68
|
+
export function buildFireworksRequest(args: PromptCompletionArgs, defaultTemp: number): {
|
|
69
|
+
messages: { role: string; content: string }[];
|
|
70
|
+
temperature: number;
|
|
71
|
+
useJson: boolean;
|
|
72
|
+
} {
|
|
73
|
+
const temperature = args.temperature ?? defaultTemp;
|
|
74
|
+
const useJson = !!(args.jsonMode || args.jsonSchema);
|
|
75
|
+
|
|
76
|
+
const messages: { role: string; content: string }[] = [];
|
|
77
|
+
if (args.system) {
|
|
78
|
+
messages.push({ role: 'system', content: args.system.content });
|
|
79
|
+
}
|
|
80
|
+
if (args.history) {
|
|
81
|
+
for (const msg of args.history) {
|
|
82
|
+
messages.push({ role: msg.role, content: msg.content });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let userContent = args.prompt.content;
|
|
87
|
+
if (useJson) {
|
|
88
|
+
userContent += '\n\nRespond with valid JSON only. No markdown fences.';
|
|
89
|
+
}
|
|
90
|
+
messages.push({ role: 'user', content: userContent });
|
|
91
|
+
|
|
92
|
+
return { messages, temperature, useJson };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function fireworksai(args: FireworksAIArgs): completePrompt {
|
|
96
|
+
const { apiKey, temperature = 0.0 } = args;
|
|
97
|
+
const model = resolveFireworksModel(args.model);
|
|
98
|
+
|
|
99
|
+
const client = new OpenAI({ apiKey, baseURL: FIREWORKS_BASE_URL });
|
|
100
|
+
|
|
101
|
+
return async (completionArgs: PromptCompletionArgs): Promise<AgentCompletion<string>> => {
|
|
102
|
+
const { messages, temperature: reqTemp, useJson } = buildFireworksRequest(completionArgs, temperature);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const response = await client.chat.completions.create({
|
|
106
|
+
model,
|
|
107
|
+
messages: messages as OpenAI.ChatCompletionMessageParam[],
|
|
108
|
+
temperature: reqTemp,
|
|
109
|
+
max_tokens: 32768,
|
|
110
|
+
...(useJson ? { response_format: { type: 'json_object' } } : {}),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const choice = response.choices[0];
|
|
114
|
+
if (!choice?.message) {
|
|
115
|
+
return { completed: false, error: new Error('No response choice returned') };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let text = choice.message.content ?? '';
|
|
119
|
+
|
|
120
|
+
// Robust JSON extraction as a safety net
|
|
121
|
+
if (useJson && text) {
|
|
122
|
+
text = extractJSON(text);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { completed: true, value: text };
|
|
126
|
+
} catch (err: unknown) {
|
|
127
|
+
let error: Error;
|
|
128
|
+
if (err instanceof OpenAI.APIError && (err as any).status !== undefined) {
|
|
129
|
+
error = new RequestError(err.message, (err as any).status, err.name ?? 'APIError');
|
|
130
|
+
} else {
|
|
131
|
+
error = err as Error;
|
|
132
|
+
}
|
|
133
|
+
return { completed: false, error };
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
package/src/models/index.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
|
-
export { ProviderName, ProviderConfig, ModelEntry, Provider } from './types';
|
|
1
|
+
export { ProviderName, ProviderConfig, ModelEntry, Provider, SystemMessage, UserMessage, Message, AgentCompletion, completePrompt, PromptCompletionArgs, AgentArgs, RequestError } from './types';
|
|
2
2
|
export { AnthropicProvider, OpenAIProvider, PROVIDERS, getProvider, detectProvider } from './providers';
|
|
3
|
+
export { anthropic, AnthropicArgs, buildAnthropicRequest } from './anthropic';
|
|
4
|
+
export { openai, OpenaiArgs, buildOpenAIRequest } from './openai';
|
|
5
|
+
export { fireworksai, FireworksAIArgs, resolveFireworksModel, buildFireworksRequest } from './fireworksai';
|
|
6
|
+
export { chainOfThought, ChainOfThoughtArgs, ExplainedAnswer } from './chainOfThought';
|
|
7
|
+
export { logCompletePrompt } from './logCompletePrompt';
|
|
8
|
+
export { variableToString } from './utils';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AgentCompletion, completePrompt, PromptCompletionArgs } from './types';
|
|
2
|
+
|
|
3
|
+
export function logCompletePrompt<TValue = string>(
|
|
4
|
+
inner: completePrompt<TValue>,
|
|
5
|
+
logDetails?: boolean
|
|
6
|
+
): completePrompt<TValue> {
|
|
7
|
+
return async (args: PromptCompletionArgs): Promise<AgentCompletion<TValue>> => {
|
|
8
|
+
const result = await inner(args);
|
|
9
|
+
|
|
10
|
+
if (result.completed) {
|
|
11
|
+
const value = typeof result.value === 'string'
|
|
12
|
+
? result.value
|
|
13
|
+
: JSON.stringify(result.value, null, 2);
|
|
14
|
+
console.log(`\x1b[32m${value}\x1b[0m`);
|
|
15
|
+
} else if (result.error) {
|
|
16
|
+
console.log(`\x1b[31m${result.error.message}\x1b[0m`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (logDetails) {
|
|
20
|
+
console.log('─'.repeat(80));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
}
|