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.
Files changed (262) hide show
  1. package/README.md +215 -65
  2. package/default-pages/application.json +1 -0
  3. package/default-pages/json_tools.json +1 -1
  4. package/default-pages/oregon_trail.html +321 -0
  5. package/default-pages/oregon_trail.json +12 -0
  6. package/default-pages/sidebar_page.json +1 -0
  7. package/default-pages/solar_explorer.html +10 -18
  8. package/default-pages/solar_explorer.json +2 -2
  9. package/default-pages/two-panel_page.json +1 -0
  10. package/default-pages/us_map.html +192 -0
  11. package/default-pages/us_map.json +12 -0
  12. package/default-pages/us_map_1850.html +325 -0
  13. package/default-pages/us_map_1850.json +12 -0
  14. package/default-pages/western_cities_1850.html +526 -0
  15. package/default-pages/western_cities_1850.json +12 -0
  16. package/default-themes/{nebula-dawn.css → nebula-dawn.v2.css} +24 -0
  17. package/default-themes/{nebula-dusk.css → nebula-dusk.v2.css} +24 -0
  18. package/dist/agents/a2a/a2aProvider.d.ts +3 -0
  19. package/dist/agents/a2a/a2aProvider.d.ts.map +1 -0
  20. package/dist/agents/a2a/a2aProvider.js +126 -0
  21. package/dist/agents/a2a/a2aProvider.js.map +1 -0
  22. package/dist/agents/discovery.d.ts +30 -0
  23. package/dist/agents/discovery.d.ts.map +1 -0
  24. package/dist/agents/discovery.js +52 -0
  25. package/dist/agents/discovery.js.map +1 -0
  26. package/dist/agents/index.d.ts +7 -0
  27. package/dist/agents/index.d.ts.map +1 -0
  28. package/dist/agents/index.js +19 -0
  29. package/dist/agents/index.js.map +1 -0
  30. package/dist/agents/openclaw/gatewayManager.d.ts +113 -0
  31. package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -0
  32. package/dist/agents/openclaw/gatewayManager.js +470 -0
  33. package/dist/agents/openclaw/gatewayManager.js.map +1 -0
  34. package/dist/agents/openclaw/openclawProvider.d.ts +3 -0
  35. package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -0
  36. package/dist/agents/openclaw/openclawProvider.js +239 -0
  37. package/dist/agents/openclaw/openclawProvider.js.map +1 -0
  38. package/dist/agents/openclaw/sshTunnelManager.d.ts +23 -0
  39. package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -0
  40. package/dist/agents/openclaw/sshTunnelManager.js +340 -0
  41. package/dist/agents/openclaw/sshTunnelManager.js.map +1 -0
  42. package/dist/agents/types.d.ts +64 -0
  43. package/dist/agents/types.d.ts.map +1 -0
  44. package/dist/agents/types.js +6 -0
  45. package/dist/agents/types.js.map +1 -0
  46. package/dist/connectors/airtable/connector.json +27 -0
  47. package/dist/connectors/alpha-vantage/connector.json +26 -0
  48. package/dist/connectors/brave-search/connector.json +26 -0
  49. package/dist/connectors/cloudinary/connector.json +27 -0
  50. package/dist/connectors/deepl/connector.json +28 -0
  51. package/dist/connectors/elevenlabs/connector.json +30 -0
  52. package/dist/connectors/giphy/connector.json +27 -0
  53. package/dist/connectors/github/connector.json +29 -0
  54. package/dist/connectors/huggingface/connector.json +27 -0
  55. package/dist/connectors/imgur/connector.json +29 -0
  56. package/dist/connectors/index.d.ts +1 -1
  57. package/dist/connectors/index.d.ts.map +1 -1
  58. package/dist/connectors/instagram/connector.json +43 -0
  59. package/dist/connectors/jira/connector.json +28 -0
  60. package/dist/connectors/mapbox/connector.json +26 -0
  61. package/dist/connectors/nasa/connector.json +27 -0
  62. package/dist/connectors/newsapi/connector.json +27 -0
  63. package/dist/connectors/notion/connector.json +28 -0
  64. package/dist/connectors/open-exchange-rates/connector.json +27 -0
  65. package/dist/connectors/openweathermap/connector.json +26 -0
  66. package/dist/connectors/pexels/connector.json +27 -0
  67. package/dist/connectors/registry.d.ts.map +1 -1
  68. package/dist/connectors/registry.js +42 -96
  69. package/dist/connectors/registry.js.map +1 -1
  70. package/dist/connectors/resend/connector.json +29 -0
  71. package/dist/connectors/rss2json/connector.json +27 -0
  72. package/dist/connectors/sendgrid/connector.json +27 -0
  73. package/dist/connectors/spoonacular/connector.json +28 -0
  74. package/dist/connectors/stability-ai/connector.json +27 -0
  75. package/dist/connectors/twilio/connector.json +28 -0
  76. package/dist/connectors/types.d.ts +23 -0
  77. package/dist/connectors/types.d.ts.map +1 -1
  78. package/dist/connectors/unsplash/connector.json +27 -0
  79. package/dist/connectors/wolfram-alpha/connector.json +26 -0
  80. package/dist/connectors/youtube-data/connector.json +30 -0
  81. package/dist/files.d.ts +1 -0
  82. package/dist/files.d.ts.map +1 -1
  83. package/dist/files.js +16 -1
  84. package/dist/files.js.map +1 -1
  85. package/dist/init.d.ts.map +1 -1
  86. package/dist/init.js +28 -0
  87. package/dist/init.js.map +1 -1
  88. package/dist/migrations.d.ts +3 -2
  89. package/dist/migrations.d.ts.map +1 -1
  90. package/dist/migrations.js +122 -138
  91. package/dist/migrations.js.map +1 -1
  92. package/dist/models/anthropic.d.ts +22 -0
  93. package/dist/models/anthropic.d.ts.map +1 -0
  94. package/dist/models/anthropic.js +76 -0
  95. package/dist/models/anthropic.js.map +1 -0
  96. package/dist/models/chainOfThought.d.ts +12 -0
  97. package/dist/models/chainOfThought.d.ts.map +1 -0
  98. package/dist/models/chainOfThought.js +45 -0
  99. package/dist/models/chainOfThought.js.map +1 -0
  100. package/dist/models/fireworksai.d.ts +30 -0
  101. package/dist/models/fireworksai.d.ts.map +1 -0
  102. package/dist/models/fireworksai.js +133 -0
  103. package/dist/models/fireworksai.js.map +1 -0
  104. package/dist/models/index.d.ts +7 -1
  105. package/dist/models/index.d.ts.map +1 -1
  106. package/dist/models/index.js +19 -1
  107. package/dist/models/index.js.map +1 -1
  108. package/dist/models/logCompletePrompt.d.ts +3 -0
  109. package/dist/models/logCompletePrompt.d.ts.map +1 -0
  110. package/dist/models/logCompletePrompt.js +23 -0
  111. package/dist/models/logCompletePrompt.js.map +1 -0
  112. package/dist/models/openai.d.ts +24 -0
  113. package/dist/models/openai.d.ts.map +1 -0
  114. package/dist/models/openai.js +80 -0
  115. package/dist/models/openai.js.map +1 -0
  116. package/dist/models/providers.d.ts +1 -0
  117. package/dist/models/providers.d.ts.map +1 -1
  118. package/dist/models/providers.js +12 -4
  119. package/dist/models/providers.js.map +1 -1
  120. package/dist/models/types.d.ts +34 -2
  121. package/dist/models/types.d.ts.map +1 -1
  122. package/dist/models/types.js +16 -0
  123. package/dist/models/types.js.map +1 -1
  124. package/dist/models/utils.d.ts +6 -0
  125. package/dist/models/utils.d.ts.map +1 -0
  126. package/dist/models/utils.js +21 -0
  127. package/dist/models/utils.js.map +1 -0
  128. package/dist/scripts.d.ts +2 -1
  129. package/dist/scripts.d.ts.map +1 -1
  130. package/dist/scripts.js +4 -3
  131. package/dist/scripts.js.map +1 -1
  132. package/dist/service/createCompletePrompt.d.ts +1 -1
  133. package/dist/service/createCompletePrompt.d.ts.map +1 -1
  134. package/dist/service/createCompletePrompt.js +9 -6
  135. package/dist/service/createCompletePrompt.js.map +1 -1
  136. package/dist/service/generateImage.d.ts +1 -1
  137. package/dist/service/generateImage.d.ts.map +1 -1
  138. package/dist/service/generateImage.js +3 -3
  139. package/dist/service/generateImage.js.map +1 -1
  140. package/dist/service/server.d.ts.map +1 -1
  141. package/dist/service/server.js +3 -0
  142. package/dist/service/server.js.map +1 -1
  143. package/dist/service/transformPage.d.ts +4 -2
  144. package/dist/service/transformPage.d.ts.map +1 -1
  145. package/dist/service/transformPage.js +74 -6
  146. package/dist/service/transformPage.js.map +1 -1
  147. package/dist/service/useAgentRoutes.d.ts +4 -0
  148. package/dist/service/useAgentRoutes.d.ts.map +1 -0
  149. package/dist/service/useAgentRoutes.js +389 -0
  150. package/dist/service/useAgentRoutes.js.map +1 -0
  151. package/dist/service/useApiRoutes.d.ts.map +1 -1
  152. package/dist/service/useApiRoutes.js +157 -16
  153. package/dist/service/useApiRoutes.js.map +1 -1
  154. package/dist/service/useConnectorRoutes.d.ts.map +1 -1
  155. package/dist/service/useConnectorRoutes.js +14 -3
  156. package/dist/service/useConnectorRoutes.js.map +1 -1
  157. package/dist/service/useGatewayRoutes.d.ts +4 -0
  158. package/dist/service/useGatewayRoutes.d.ts.map +1 -0
  159. package/dist/service/useGatewayRoutes.js +168 -0
  160. package/dist/service/useGatewayRoutes.js.map +1 -0
  161. package/dist/service/usePageRoutes.d.ts.map +1 -1
  162. package/dist/service/usePageRoutes.js +16 -5
  163. package/dist/service/usePageRoutes.js.map +1 -1
  164. package/dist/settings.d.ts +2 -1
  165. package/dist/settings.d.ts.map +1 -1
  166. package/dist/settings.js +4 -8
  167. package/dist/settings.js.map +1 -1
  168. package/dist/themes.d.ts +14 -0
  169. package/dist/themes.d.ts.map +1 -1
  170. package/dist/themes.js +86 -13
  171. package/dist/themes.js.map +1 -1
  172. package/package.json +8 -5
  173. package/page-scripts/helpers-v2.js +101 -0
  174. package/page-scripts/page-v2.js +47 -6
  175. package/required-pages/builder.html +1 -27
  176. package/required-pages/pages.html +745 -22
  177. package/required-pages/settings.html +819 -21
  178. package/required-pages/synthos_apis.html +56 -1
  179. package/src/agents/a2a/a2aProvider.ts +110 -0
  180. package/src/agents/discovery.ts +74 -0
  181. package/src/agents/index.ts +6 -0
  182. package/src/agents/openclaw/gatewayManager.ts +559 -0
  183. package/src/agents/openclaw/openclawProvider.ts +261 -0
  184. package/src/agents/openclaw/sshTunnelManager.ts +385 -0
  185. package/src/agents/types.ts +82 -0
  186. package/src/connectors/airtable/connector.json +27 -0
  187. package/src/connectors/alpha-vantage/connector.json +26 -0
  188. package/src/connectors/brave-search/connector.json +26 -0
  189. package/src/connectors/cloudinary/connector.json +27 -0
  190. package/src/connectors/deepl/connector.json +28 -0
  191. package/src/connectors/elevenlabs/connector.json +30 -0
  192. package/src/connectors/giphy/connector.json +27 -0
  193. package/src/connectors/github/connector.json +29 -0
  194. package/src/connectors/huggingface/connector.json +27 -0
  195. package/src/connectors/imgur/connector.json +29 -0
  196. package/src/connectors/index.ts +2 -0
  197. package/src/connectors/instagram/connector.json +43 -0
  198. package/src/connectors/jira/connector.json +28 -0
  199. package/src/connectors/mapbox/connector.json +26 -0
  200. package/src/connectors/nasa/connector.json +27 -0
  201. package/src/connectors/newsapi/connector.json +27 -0
  202. package/src/connectors/notion/connector.json +28 -0
  203. package/src/connectors/open-exchange-rates/connector.json +27 -0
  204. package/src/connectors/openweathermap/connector.json +26 -0
  205. package/src/connectors/pexels/connector.json +27 -0
  206. package/src/connectors/registry.ts +21 -97
  207. package/src/connectors/resend/connector.json +29 -0
  208. package/src/connectors/rss2json/connector.json +27 -0
  209. package/src/connectors/sendgrid/connector.json +27 -0
  210. package/src/connectors/spoonacular/connector.json +28 -0
  211. package/src/connectors/stability-ai/connector.json +27 -0
  212. package/src/connectors/twilio/connector.json +28 -0
  213. package/src/connectors/types.ts +25 -0
  214. package/src/connectors/unsplash/connector.json +27 -0
  215. package/src/connectors/wolfram-alpha/connector.json +26 -0
  216. package/src/connectors/youtube-data/connector.json +30 -0
  217. package/src/files.ts +14 -0
  218. package/src/init.ts +27 -0
  219. package/src/migrations.ts +121 -138
  220. package/src/models/anthropic.ts +89 -0
  221. package/src/models/chainOfThought.ts +56 -0
  222. package/src/models/fireworksai.ts +136 -0
  223. package/src/models/index.ts +7 -1
  224. package/src/models/logCompletePrompt.ts +25 -0
  225. package/src/models/openai.ts +90 -0
  226. package/src/models/providers.ts +12 -3
  227. package/src/models/types.ts +67 -2
  228. package/src/models/utils.ts +16 -0
  229. package/src/scripts.ts +2 -2
  230. package/src/service/createCompletePrompt.ts +3 -1
  231. package/src/service/generateImage.ts +2 -2
  232. package/src/service/server.ts +4 -0
  233. package/src/service/transformPage.ts +81 -8
  234. package/src/service/useAgentRoutes.ts +423 -0
  235. package/src/service/useApiRoutes.ts +173 -18
  236. package/src/service/useConnectorRoutes.ts +14 -3
  237. package/src/service/usePageRoutes.ts +20 -6
  238. package/src/settings.ts +6 -10
  239. package/src/themes.ts +84 -12
  240. package/tests/anthropic.spec.ts +84 -0
  241. package/tests/chainOfThought.spec.ts +108 -0
  242. package/tests/ensureScripts.spec.ts +82 -0
  243. package/tests/files.spec.ts +233 -0
  244. package/tests/fireworksai.spec.ts +92 -0
  245. package/tests/logCompletePrompt.spec.ts +74 -0
  246. package/tests/migrations.spec.ts +79 -1
  247. package/tests/openai.spec.ts +71 -0
  248. package/tests/pages.spec.ts +226 -1
  249. package/tests/providers.spec.ts +144 -0
  250. package/tests/scripts.spec.ts +209 -0
  251. package/tests/transformPage.spec.ts +517 -0
  252. package/tests/types.spec.ts +23 -0
  253. package/default-pages/app_builder.json +0 -1
  254. package/default-pages/sidebar_builder.json +0 -1
  255. package/default-pages/two-panel_builder.json +0 -1
  256. package/images/home.png +0 -0
  257. package/images/page-management.png +0 -0
  258. package/images/settings.png +0 -0
  259. package/images/synthos-square.png +0 -0
  260. /package/default-pages/{app_builder.html → application.html} +0 -0
  261. /package/default-pages/{sidebar_builder.html → sidebar_page.html} +0 -0
  262. /package/default-pages/{two-panel_builder.html → two-panel_page.html} +0 -0
@@ -0,0 +1,90 @@
1
+ import OpenAI from 'openai';
2
+ import { AgentCompletion, completePrompt, PromptCompletionArgs, RequestError } from './types';
3
+
4
+ export interface OpenaiArgs {
5
+ apiKey: string;
6
+ model: string;
7
+ baseURL?: string;
8
+ organization?: string;
9
+ project?: string;
10
+ temperature?: number;
11
+ }
12
+
13
+ /**
14
+ * Build the input messages and text format config for an OpenAI Responses API request.
15
+ * Pure function — no SDK dependency.
16
+ */
17
+ export function buildOpenAIRequest(args: PromptCompletionArgs): {
18
+ input: { role: string; content: string }[];
19
+ text?: { format: any };
20
+ } {
21
+ const input: { role: string; content: string }[] = [];
22
+ if (args.history) {
23
+ for (const msg of args.history) {
24
+ input.push({ role: msg.role, content: msg.content });
25
+ }
26
+ }
27
+ input.push({ role: 'user', content: args.prompt.content });
28
+
29
+ if (args.jsonMode || args.jsonSchema) {
30
+ const inputText = input.map(m => m.content).join(' ');
31
+ if (!/json/i.test(inputText)) {
32
+ const last = input[input.length - 1];
33
+ if (last) {
34
+ last.content += '\nReturn JSON.';
35
+ }
36
+ }
37
+ }
38
+
39
+ let text: { format: any } | undefined;
40
+ if (args.jsonSchema) {
41
+ text = {
42
+ format: {
43
+ type: 'json_schema',
44
+ name: 'response',
45
+ strict: true,
46
+ schema: args.jsonSchema,
47
+ },
48
+ };
49
+ } else if (args.jsonMode) {
50
+ text = {
51
+ format: { type: 'json_object' },
52
+ };
53
+ }
54
+
55
+ return { input, text };
56
+ }
57
+
58
+ export function openai(args: OpenaiArgs): completePrompt {
59
+ const { apiKey, model, baseURL, organization, project } = args;
60
+
61
+ const client = new OpenAI({ apiKey, baseURL, organization, project });
62
+
63
+ return async (completionArgs: PromptCompletionArgs): Promise<AgentCompletion<string>> => {
64
+ const { input, text } = buildOpenAIRequest(completionArgs);
65
+
66
+ try {
67
+ const response = await client.responses.create({
68
+ model,
69
+ instructions: completionArgs.system?.content,
70
+ input: input as OpenAI.Responses.ResponseInputItem[],
71
+ ...(text ? { text } : {}),
72
+ });
73
+
74
+ const output = response.output_text;
75
+ if (output === undefined || output === null) {
76
+ return { completed: false, error: new Error('No response output returned') };
77
+ }
78
+
79
+ return { completed: true, value: output };
80
+ } catch (err: unknown) {
81
+ let error: Error;
82
+ if (err instanceof OpenAI.APIError && (err as any).status !== undefined) {
83
+ error = new RequestError(err.message, (err as any).status, err.name ?? 'APIError');
84
+ } else {
85
+ error = err as Error;
86
+ }
87
+ return { completed: false, error };
88
+ }
89
+ };
90
+ }
@@ -3,7 +3,7 @@ import { Provider, ProviderName } from './types';
3
3
  export const AnthropicProvider: Provider = {
4
4
  name: 'Anthropic',
5
5
  builderModels: ['claude-opus-4-6', 'claude-sonnet-4-5'],
6
- chatModels: ['claude-haiku-4-5', 'claude-sonnet-4-5'],
6
+ chatModels: ['claude-sonnet-4-5','claude-haiku-4-5'],
7
7
  detectModel(model: string): boolean {
8
8
  return model.startsWith('claude-');
9
9
  }
@@ -14,11 +14,20 @@ export const OpenAIProvider: Provider = {
14
14
  builderModels: ['gpt-5.2', 'gpt-5.2-codex'],
15
15
  chatModels: ['gpt-5-nano', 'gpt-5-mini', 'gpt-4.1'],
16
16
  detectModel(model: string): boolean {
17
- return model.startsWith('gpt-') || model.startsWith('GPT-');
17
+ return model.startsWith('gpt-');
18
18
  }
19
19
  };
20
20
 
21
- export const PROVIDERS: Provider[] = [AnthropicProvider, OpenAIProvider];
21
+ export const FireworksAIProvider: Provider = {
22
+ name: 'FireworksAI',
23
+ builderModels: ['fireworks-glm-5'],
24
+ chatModels: ['fireworks-minimax-m2p5', 'fireworks-kimi-k2p5', 'fireworks-glm-5'],
25
+ detectModel(model: string): boolean {
26
+ return model.startsWith('fireworks-');
27
+ }
28
+ };
29
+
30
+ export const PROVIDERS: Provider[] = [AnthropicProvider, OpenAIProvider, FireworksAIProvider];
22
31
 
23
32
  export function getProvider(name: ProviderName): Provider {
24
33
  const provider = PROVIDERS.find(p => p.name === name);
@@ -1,9 +1,12 @@
1
- export type ProviderName = 'Anthropic' | 'OpenAI';
1
+ // ---------------------------------------------------------------------------
2
+ // Provider types
3
+ // ---------------------------------------------------------------------------
4
+
5
+ export type ProviderName = 'Anthropic' | 'OpenAI' | 'FireworksAI';
2
6
 
3
7
  export interface ProviderConfig {
4
8
  apiKey: string;
5
9
  model: string;
6
- maxTokens: number;
7
10
  }
8
11
 
9
12
  export interface ModelEntry {
@@ -21,3 +24,65 @@ export interface Provider {
21
24
  chatModels: string[];
22
25
  detectModel(model: string): boolean;
23
26
  }
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Messages
30
+ // ---------------------------------------------------------------------------
31
+
32
+ export interface Message {
33
+ role: string;
34
+ content: string;
35
+ name?: string;
36
+ }
37
+
38
+ export interface SystemMessage extends Message {
39
+ role: 'system';
40
+ }
41
+
42
+ export interface UserMessage extends Message {
43
+ role: 'user';
44
+ }
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Completions
48
+ // ---------------------------------------------------------------------------
49
+
50
+ export interface AgentCompletion<TValue> {
51
+ completed: boolean;
52
+ value?: TValue;
53
+ error?: Error;
54
+ }
55
+
56
+ export interface PromptCompletionArgs {
57
+ prompt: UserMessage;
58
+ system?: SystemMessage;
59
+ history?: Message[];
60
+ temperature?: number;
61
+ jsonMode?: boolean;
62
+ /** JSON schema for structured output. When provided, the model is asked to return JSON conforming to this schema. */
63
+ jsonSchema?: Record<string, unknown>;
64
+ }
65
+
66
+ export type completePrompt<TValue = string> = (args: PromptCompletionArgs) => Promise<AgentCompletion<TValue>>;
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // Agent args
70
+ // ---------------------------------------------------------------------------
71
+
72
+ export interface AgentArgs {
73
+ completePrompt: completePrompt<any>;
74
+ }
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // Errors
78
+ // ---------------------------------------------------------------------------
79
+
80
+ export class RequestError extends Error {
81
+ readonly status: number;
82
+
83
+ constructor(message: string, status: number, name?: string) {
84
+ super(message);
85
+ this.status = status;
86
+ this.name = name ?? 'RequestError';
87
+ }
88
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Convert any value to a string suitable for template substitution.
3
+ * Replaces double quotes and line feeds with spaces.
4
+ */
5
+ export function variableToString(variable: any): string {
6
+ if (variable === null || variable === undefined) {
7
+ return '';
8
+ }
9
+ if (typeof variable === 'string') {
10
+ return variable;
11
+ }
12
+ if (typeof variable === 'object') {
13
+ return JSON.stringify(variable);
14
+ }
15
+ return variable.toString();
16
+ }
package/src/scripts.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AgentCompletion, variableToString } from 'agentm-core';
1
+ import { AgentCompletion, variableToString } from './models';
2
2
  import { spawn } from 'child_process';
3
3
  import path from 'path';
4
4
  import { loadFile, listFiles, checkIfExists } from './files';
@@ -122,7 +122,7 @@ function spawnProcess(command: string, args: string[]): Promise<ExecuteScriptRes
122
122
  });
123
123
  }
124
124
 
125
- function composeArguments(template: string, variables: Record<string, any>): string {
125
+ export function composeArguments(template: string, variables: Record<string, any>): string {
126
126
  return template.replace(/{{\s*([^}\s]+)\s*}}/g, (match, name) => {
127
127
  // Convert the variable to a string and replace double quotes and line feeds with spaces
128
128
  return variableToString(variables[name]);
@@ -1,4 +1,4 @@
1
- import {anthropic, completePrompt, logCompletePrompt, openai} from 'agentm-core';
1
+ import { anthropic, completePrompt, fireworksai, logCompletePrompt, openai } from '../models';
2
2
  import { getModelEntry, loadSettings } from '../settings';
3
3
  import { PROVIDERS } from '../models';
4
4
 
@@ -22,6 +22,8 @@ export async function createCompletePrompt(pagesFolder: string, use: 'builder' |
22
22
  const apiKey = entry.configuration.apiKey;
23
23
  if (entry.provider === 'Anthropic') {
24
24
  modelInstance = anthropic({apiKey, model});
25
+ } else if (entry.provider === 'FireworksAI') {
26
+ modelInstance = fireworksai({apiKey, model});
25
27
  } else {
26
28
  modelInstance = openai({apiKey, model});
27
29
  }
@@ -1,5 +1,5 @@
1
1
  import OpenAI from "openai";
2
- import { AgentCompletion, RequestError } from "agentm-core";
2
+ import { AgentCompletion, RequestError } from "../models";
3
3
  import { loadFile } from "../files";
4
4
  import path from "path";
5
5
 
@@ -81,7 +81,7 @@ export async function generateImage(args: OpenaiGenerateImageArgs): Promise<Agen
81
81
  style
82
82
  });
83
83
 
84
- if (response.data.length > 0 && response.data[0].b64_json !== undefined) {
84
+ if (response.data && response.data.length > 0 && response.data[0].b64_json !== undefined) {
85
85
  const url = `data:image/png;base64,${response.data[0].b64_json}`
86
86
  return { completed: true, value: { url } };
87
87
  } else {
@@ -4,6 +4,7 @@ import { useApiRoutes } from './useApiRoutes';
4
4
  import { SynthOSConfig } from '../init';
5
5
  import { useDataRoutes } from './useDataRoutes';
6
6
  import { useConnectorRoutes } from './useConnectorRoutes';
7
+ import { useAgentRoutes } from './useAgentRoutes';
7
8
  import { cyan, yellow, formatTime } from './debugLog';
8
9
 
9
10
  export function server(config: SynthOSConfig): Application {
@@ -36,6 +37,9 @@ export function server(config: SynthOSConfig): Application {
36
37
  // Connector routes
37
38
  useConnectorRoutes(config, app);
38
39
 
40
+ // Agent routes
41
+ useAgentRoutes(config, app);
42
+
39
43
  // Data routes
40
44
  useDataRoutes(config, app);
41
45
 
@@ -1,8 +1,9 @@
1
- import { AgentArgs, AgentCompletion, SystemMessage, UserMessage } from "agentm-core";
1
+ import { AgentArgs, AgentCompletion, SystemMessage, UserMessage } from "../models";
2
2
  import { listScripts } from "../scripts";
3
3
  import * as cheerio from "cheerio";
4
4
  import { ThemeInfo } from "../themes";
5
5
  import { CONNECTOR_REGISTRY, ConnectorsConfig, ConnectorOAuthConfig } from "../connectors";
6
+ import { AgentConfig } from "../agents";
6
7
 
7
8
  // ---------------------------------------------------------------------------
8
9
  // Types
@@ -12,7 +13,6 @@ export interface TransformPageArgs extends AgentArgs {
12
13
  pagesFolder: string;
13
14
  pageState: string;
14
15
  message: string;
15
- maxTokens: number;
16
16
  instructions?: string;
17
17
  /** Provider-specific formatting instructions injected into the prompt. */
18
18
  modelInstructions?: string;
@@ -22,6 +22,8 @@ export interface TransformPageArgs extends AgentArgs {
22
22
  mode?: 'unlocked' | 'locked';
23
23
  /** User's configured connectors (from settings). */
24
24
  configuredConnectors?: ConnectorsConfig;
25
+ /** User's configured A2A agents (from settings). */
26
+ configuredAgents?: AgentConfig[];
25
27
  }
26
28
 
27
29
  export type ChangeOp =
@@ -53,7 +55,7 @@ export interface TransformPageResult {
53
55
  }
54
56
 
55
57
  export async function transformPage(args: TransformPageArgs): Promise<AgentCompletion<TransformPageResult>> {
56
- const { pagesFolder, pageState, message, maxTokens, completePrompt } = args;
58
+ const { pagesFolder, pageState, message, completePrompt } = args;
57
59
 
58
60
  // 1. Assign data-node-id to every element
59
61
  const { html: annotatedHtml } = assignNodeIds(pageState);
@@ -71,7 +73,7 @@ export async function transformPage(args: TransformPageArgs): Promise<AgentCompl
71
73
  const colorList = Object.entries(colors)
72
74
  .map(([name, value]) => ` --${name}: ${value}`)
73
75
  .join('\n');
74
- themeBlock += `Mode: ${mode}\nCSS custom properties (use instead of hardcoded values):\n${colorList}\n\nShared shell classes (pre-styled by theme, do not redefine):\n .chat-panel — Left sidebar container (30% width)\n .chat-header — Chat panel title bar\n .chat-messages — Scrollable message container\n .chat-message — Individual message wrapper\n .link-group — Navigation links row (Save, Pages, Reset)\n .chat-input — Message text input\n .chat-submit — Send button\n .viewer-panel — Right content area (70% width)\n .loading-overlay — Full-screen loading overlay\n .spinner — Animated loading spinner\n\nPage title bars: To align with the chat header, apply these styles:\n min-height: var(--header-min-height);\n padding: var(--header-padding-vertical) var(--header-padding-horizontal);\n line-height: var(--header-line-height);\n display: flex; align-items: center; justify-content: center; box-sizing: border-box;\n\nFull-viewer mode: For games, animations, or full-screen content, add class "full-viewer" to the viewer-panel element to remove its padding.\n\nChat panel behaviours (auto-injected via page script — do NOT recreate in page code):\n The server injects page-v2.js after transformation. It provides:\n - Form submit handler: sets action to window.location.pathname, shows #loadingOverlay, disables inputs\n - Save/Reset link handlers (#saveLink, #resetLink)\n - Chat scroll to bottom (#chatMessages)\n - Chat toggle button (.chat-toggle) — created dynamically if not in markup\n - .chat-input-wrapper — wraps #chatInput with a brainstorm icon button\n - Brainstorm modal (#brainstormModal) — LLM-powered brainstorm UI, created dynamically\n - Focus management — keeps keyboard input directed to #chatInput\n\n Do NOT:\n - Create your own form submit handler, toggle button, or input wrapper\n - Modify or replace .chat-panel, .chat-header, .link-group, #chatForm, or .chat-toggle\n - INSERT new <script> blocks that duplicate existing ones — when fixing JavaScript, UPDATE or REPLACE the existing script's nodeId instead. Always give inline scripts a unique id attribute.\n - Set the form action attribute (page-v2.js sets it dynamically)\n - Include these CSS rules (in the theme): #loadingOverlay position, .chat-submit:disabled, .chat-input:disabled\n\n To add chat messages: use insert with parentId of #chatMessages and position "append".\n #chatMessages is the only unlocked element inside .chat-panel.\n\nThe <html> element has class "${mode}-mode". Always add .light-mode CSS overrides for any page-specific styles so the page works in both light and dark themes, unless the user has explicitly requested a very specific color scheme.`;
76
+ themeBlock += `Mode: ${mode}\nCSS custom properties (use instead of hardcoded values):\n${colorList}\n\nShared shell classes (pre-styled by theme, do not redefine):\n .chat-panel — Left sidebar container (30% width)\n .chat-header — Chat panel title bar\n .chat-messages — Scrollable message container\n .chat-message — Individual message wrapper\n .link-group — Navigation links row (Save, Pages, Reset)\n .chat-input — Message text input\n .chat-submit — Send button\n .viewer-panel — Right content area (70% width)\n .loading-overlay — Full-screen loading overlay\n .spinner — Animated loading spinner\n .modal-overlay — Full-screen modal backdrop (position:fixed, z-index:2000, backdrop-filter:blur). Add class "show" to display.\n .modal-content — Centered modal container\n .modal-header — Gradient header bar\n .modal-body — Modal content area\n .modal-footer — Bottom action bar (flex, space-between)\n .modal-footer-right — Right-aligned button group\n\nModals and popups: ALWAYS use the theme\'s .modal-overlay class for any modal or popup overlay. Do NOT create custom overlay classes with position:fixed and z-index. Structure:\n <div class="modal-overlay" id="myModal">\n <div class="modal-content">\n <div class="modal-header">Title</div>\n <div class="modal-body">Content</div>\n <div class="modal-footer"><div class="modal-footer-right"><button>OK</button></div></div>\n </div>\n </div>\nShow/hide by toggling the "show" class: el.classList.add(\'show\') / el.classList.remove(\'show\'). This ensures correct z-index layering above the chat toggle and other UI elements.\n\nPage title bars: To align with the chat header, apply these styles:\n min-height: var(--header-min-height);\n padding: var(--header-padding-vertical) var(--header-padding-horizontal);\n line-height: var(--header-line-height);\n display: flex; align-items: center; justify-content: center; box-sizing: border-box;\n\nFull-viewer mode: For games, animations, or full-screen content, add class "full-viewer" to the viewer-panel element to remove its padding.\n\nChat panel behaviours (auto-injected via page script — do NOT recreate in page code):\n The server injects page-v2.js after transformation. It provides:\n - Form submit handler: sets action to window.location.pathname, shows #loadingOverlay, disables inputs\n - Save/Reset link handlers (#saveLink, #resetLink)\n - Chat scroll to bottom (#chatMessages)\n - Chat toggle button (.chat-toggle) — created dynamically if not in markup\n - .chat-input-wrapper — wraps #chatInput with a brainstorm icon button\n - Brainstorm modal (#brainstormModal) — LLM-powered brainstorm UI, created dynamically\n - Focus management — keeps keyboard input directed to #chatInput\n\n Do NOT:\n - Create your own form submit handler, toggle button, or input wrapper\n - Modify or replace .chat-panel, .chat-header, .link-group, #chatForm, or .chat-toggle\n - INSERT new <script> blocks that duplicate existing ones — when fixing JavaScript, UPDATE or REPLACE the existing script's nodeId instead. Always give inline scripts a unique id attribute.\n - Set the form action attribute (page-v2.js sets it dynamically)\n - Include these CSS rules (in the theme): #loadingOverlay position, .chat-submit:disabled, .chat-input:disabled\n\n To add chat messages: use insert with parentId of #chatMessages and position "append".\n #chatMessages is the only unlocked element inside .chat-panel.\n\nThe <html> element has class "${mode}-mode". Always add .light-mode CSS overrides for any page-specific styles so the page works in both light and dark themes, unless the user has explicitly requested a very specific color scheme.`;
75
77
  }
76
78
 
77
79
  // Build configured-connectors block
@@ -103,7 +105,26 @@ export async function transformPage(args: TransformPageArgs): Promise<AgentCompl
103
105
  }
104
106
  }
105
107
 
106
- const systemMessage = [currentPage, serverAPIs, serverScripts, connectorsBlock, themeBlock, messageFormat].filter(s => s).join('\n\n');
108
+ // Build configured-agents block (only enabled agents)
109
+ let agentsBlock = '';
110
+ const enabledAgents = (args.configuredAgents ?? []).filter(a => a.enabled);
111
+ if (enabledAgents.length > 0) {
112
+ const agentBlocks = enabledAgents.map(a => {
113
+ let block = `- ${a.name} (id: "${a.id}", provider: ${a.provider})`;
114
+ block += `\n Description: ${a.description}`;
115
+ if (a.capabilities?.streaming) {
116
+ block += `\n Supports streaming: yes`;
117
+ }
118
+ if (a.skills && a.skills.length > 0) {
119
+ const skillList = a.skills.map(s => ` - ${s.name}: ${s.description}`).join('\n');
120
+ block += `\n Skills:\n${skillList}`;
121
+ }
122
+ return block;
123
+ });
124
+ agentsBlock = `<CONFIGURED_AGENTS>\nThe user has configured these agents:\n\n${agentBlocks.join('\n\n')}\n\n${AGENT_API_REFERENCE}`;
125
+ }
126
+
127
+ const systemMessage = [currentPage, serverAPIs, serverScripts, connectorsBlock, agentsBlock, themeBlock, messageFormat].filter(s => s).join('\n\n');
107
128
  const system: SystemMessage = {
108
129
  role: 'system',
109
130
  content: systemMessage
@@ -118,7 +139,7 @@ export async function transformPage(args: TransformPageArgs): Promise<AgentCompl
118
139
  };
119
140
 
120
141
  // 3. Call model
121
- const result = await completePrompt({ prompt, system, maxTokens });
142
+ const result = await completePrompt({ prompt, system });
122
143
  if (!result.completed) {
123
144
  return { completed: false, error: result.error };
124
145
  }
@@ -153,8 +174,7 @@ export async function transformPage(args: TransformPageArgs): Promise<AgentCompl
153
174
  content: repairUSER_MESSAGE
154
175
  };
155
176
 
156
- const repairMaxTokens = Math.min(maxTokens, 4096);
157
- const repairResult = await completePrompt({ prompt: repairPrompt, system: repairSystem, maxTokens: repairMaxTokens });
177
+ const repairResult = await completePrompt({ prompt: repairPrompt, system: repairSystem });
158
178
 
159
179
  if (repairResult.completed) {
160
180
  const repairChanges = parseChangeList(repairResult.value);
@@ -650,6 +670,40 @@ Return ONLY the JSON array. Example:
650
670
  { "op": "insert", "parentId": "3", "position": "append", "html": "<div class=\\"msg\\">New message</div>" }
651
671
  ]`;
652
672
 
673
+ const AGENT_API_REFERENCE =
674
+ `## Agent API
675
+
676
+ Check availability first (required):
677
+ const agents = await synthos.agents.list({ enabled: true });
678
+
679
+ Send a message (returns full response):
680
+ const result = await synthos.agents.send(agentId, message);
681
+ // result: { kind: 'message', text: 'response text', raw: {...} }
682
+
683
+ Send with file/image attachments:
684
+ const result = await synthos.agents.send(agentId, message, [
685
+ { fileName: 'photo.jpg', mimeType: 'image/jpeg', content: '<base64-string>' }
686
+ ]);
687
+
688
+ Stream a response (token-by-token deltas):
689
+ const handle = synthos.agents.sendStream(agentId, message, function(event) {
690
+ switch (event.kind) {
691
+ case 'text': // event.data = text delta string — append to output
692
+ case 'status': // event.data = status info object
693
+ case 'done': // stream complete — stop processing
694
+ case 'error': // event.data = error message string
695
+ }
696
+ });
697
+ handle.close(); // call to abort the stream early
698
+
699
+ Stream with attachments:
700
+ synthos.agents.sendStream(agentId, message, onEvent, [
701
+ { fileName: 'doc.pdf', mimeType: 'application/pdf', content: '<base64>' }
702
+ ]);
703
+
704
+ IMPORTANT: Always check synthos.agents.list({ enabled: true }) before calling an agent.
705
+ If no agents are configured, show the user a link to Settings > Agents (/settings?tab=agents).`;
706
+
653
707
  const serverAPIs =
654
708
  `<SERVER_APIS>
655
709
  GET /api/data/:page/:table
@@ -708,6 +762,20 @@ description: Search the web using Brave Search (must be enabled in Settings > Co
708
762
  request: { query: string, count?: number, country?: string, freshness?: string }
709
763
  response: { results: [{ title: string, url: string, description: string }] }
710
764
 
765
+ GET /api/agents
766
+ description: List configured agents (A2A and OpenClaw). Supports ?enabled=true and ?provider=a2a|openclaw filters.
767
+ response: [{ id: string, name: string, description: string, url: string, enabled: boolean, provider: 'a2a'|'openclaw', capabilities?: object }]
768
+
769
+ POST /api/agents/:id/send
770
+ description: Send a text message to an agent (works for both A2A and OpenClaw protocols) and receive a normalized response
771
+ request: { message: string, attachments?: [{ fileName: string, mimeType: string, content: string }] }
772
+ response: { kind: 'message'|'task', text?: string, raw: object }
773
+
774
+ POST /api/agents/:id/stream
775
+ description: Send a message and receive a streaming SSE response (text/event-stream). Each event is JSON: { kind: 'text'|'status'|'artifact'|'done'|'error', data: any }
776
+ request: { message: string, attachments?: [{ fileName: string, mimeType: string, content: string }] }
777
+ response: SSE stream
778
+
711
779
  GET /api/connectors
712
780
  description: List available connectors (REST API proxies). Supports ?category=X and ?id=X filters.
713
781
  response: [{ id: string, name: string, category: string, configured: boolean }]
@@ -736,6 +804,11 @@ PAGE HELPERS (available globally as window.synthos):
736
804
  synthos.search.web(query, opts?) — POST /api/search/web (opts: { count?, country?, freshness? })
737
805
  synthos.connectors.call(connector, method, path, opts?) — POST /api/connectors (proxy call; opts: { headers?, body?, query? })
738
806
  synthos.connectors.list(opts?) — GET /api/connectors (opts: { category?, id? })
807
+ synthos.agents.list(opts?) — GET /api/agents (returns configured agents; opts: { enabled?, provider? }; returns [{ id, name, description, url, enabled, provider, capabilities }])
808
+ synthos.agents.send(agentId, message, attachments?) — POST /api/agents/:id/send (sends a text message to any agent, returns normalized { kind, text, raw }; attachments: [{ fileName, mimeType, content }])
809
+ synthos.agents.sendStream(agentId, message, onEvent, attachments?) — POST /api/agents/:id/stream (SSE streaming; onEvent receives { kind, data }; returns { close() } handle; attachments: [{ fileName, mimeType, content }])
810
+ synthos.agents.isEnabled(agentId) — checks if an agent is enabled (returns Promise<boolean>)
811
+ synthos.agents.getCapabilities(agentId) — returns agent capabilities object (streaming, skills, etc.)
739
812
  All methods return Promises. Prefer these helpers over raw fetch().`;
740
813
 
741
814
  const repairUSER_MESSAGE =