@standardagents/builder 0.11.0-next.41deba4 → 0.11.0-next.56def20
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/dist/built-in-routes.js +21823 -317
- package/dist/built-in-routes.js.map +1 -1
- package/dist/client/assets/index.css +1 -1
- package/dist/client/index.js +26 -23
- package/dist/client/vendor.js +1 -1
- package/dist/client/vue.js +1 -1
- package/dist/index.d.ts +239 -26
- package/dist/index.js +3184 -1230
- package/dist/index.js.map +1 -1
- package/dist/plugin.d.ts +6 -0
- package/dist/plugin.js +281 -61
- package/dist/plugin.js.map +1 -1
- package/dist/sip.wasm +0 -0
- package/package.json +8 -6
- package/dist/client/assets/img/meta.svg +0 -19
- package/dist/client/assets/img/moonshotai.svg +0 -4
- package/dist/client/assets/img/zai.svg +0 -219
package/dist/plugin.d.ts
CHANGED
|
@@ -9,6 +9,12 @@ interface AgentPluginOptions {
|
|
|
9
9
|
promptsDir?: string;
|
|
10
10
|
agentsDir?: string;
|
|
11
11
|
effectsDir?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Additional provider packages to expose in the UI.
|
|
14
|
+
* First-party providers (@standardagents/openai, @standardagents/openrouter) are always included.
|
|
15
|
+
* @example ['my-custom-provider', '@company/custom-openai']
|
|
16
|
+
*/
|
|
17
|
+
providers?: string[];
|
|
12
18
|
}
|
|
13
19
|
declare function agentbuilder(options?: AgentPluginOptions): Plugin;
|
|
14
20
|
|
package/dist/plugin.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import fs2 from 'fs';
|
|
2
2
|
import path3 from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
-
import { createRequire } from 'module';
|
|
5
4
|
|
|
6
5
|
// src/plugin.ts
|
|
7
6
|
var TSCONFIG_CONTENT = `{
|
|
@@ -398,6 +397,9 @@ declare module 'virtual:@standardagents/builder' {
|
|
|
398
397
|
listThreads(params?: {
|
|
399
398
|
agent_name?: string;
|
|
400
399
|
user_id?: string;
|
|
400
|
+
search?: string;
|
|
401
|
+
startDate?: number;
|
|
402
|
+
endDate?: number;
|
|
401
403
|
limit?: number;
|
|
402
404
|
offset?: number;
|
|
403
405
|
}): Promise<{ threads: ThreadRegistryEntry[]; total: number }>;
|
|
@@ -579,14 +581,91 @@ function needsRegeneration(config) {
|
|
|
579
581
|
return false;
|
|
580
582
|
}
|
|
581
583
|
|
|
584
|
+
// src/utils/model-parser.ts
|
|
585
|
+
function getName(content) {
|
|
586
|
+
return content.match(/name:\s*['"]([^'"]+)['"]/)?.[1];
|
|
587
|
+
}
|
|
588
|
+
function getProvider(content) {
|
|
589
|
+
const stringMatch = content.match(/provider:\s*['"]([^'"]+)['"]/)?.[1];
|
|
590
|
+
if (stringMatch) return stringMatch;
|
|
591
|
+
const refMatch = content.match(/provider:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*[,\n}]/)?.[1];
|
|
592
|
+
return refMatch || void 0;
|
|
593
|
+
}
|
|
594
|
+
function getModel(content) {
|
|
595
|
+
return content.match(/model:\s*['"]([^'"]+)['"]/)?.[1];
|
|
596
|
+
}
|
|
597
|
+
function getInputPrice(content) {
|
|
598
|
+
const match = content.match(/inputPrice:\s*([\d.]+)/);
|
|
599
|
+
return match ? parseFloat(match[1]) : void 0;
|
|
600
|
+
}
|
|
601
|
+
function getOutputPrice(content) {
|
|
602
|
+
const match = content.match(/outputPrice:\s*([\d.]+)/);
|
|
603
|
+
return match ? parseFloat(match[1]) : void 0;
|
|
604
|
+
}
|
|
605
|
+
function getCachedPrice(content) {
|
|
606
|
+
const match = content.match(/cachedPrice:\s*([\d.]+)/);
|
|
607
|
+
return match ? parseFloat(match[1]) : void 0;
|
|
608
|
+
}
|
|
609
|
+
function getIncludedProviders(content) {
|
|
610
|
+
const match = content.match(/includedProviders:\s*\[([^\]]*)\]/);
|
|
611
|
+
if (!match) return void 0;
|
|
612
|
+
const items = match[1].match(/['"]([^'"]+)['"]/g);
|
|
613
|
+
return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
|
|
614
|
+
}
|
|
615
|
+
function getFallbacks(content) {
|
|
616
|
+
const match = content.match(/fallbacks:\s*\[([^\]]*)\]/);
|
|
617
|
+
if (!match) return [];
|
|
618
|
+
const items = match[1].match(/['"]([^'"]+)['"]/g);
|
|
619
|
+
return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
|
|
620
|
+
}
|
|
621
|
+
function getProviderTools(content) {
|
|
622
|
+
const match = content.match(/providerTools:\s*\[([^\]]*)\]/);
|
|
623
|
+
if (!match) return [];
|
|
624
|
+
const items = match[1].match(/['"]([^'"]+)['"]/g);
|
|
625
|
+
return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
|
|
626
|
+
}
|
|
627
|
+
function getCapabilities(content) {
|
|
628
|
+
const match = content.match(/capabilities:\s*\{([^}]*)\}/s);
|
|
629
|
+
if (!match) return void 0;
|
|
630
|
+
const inner = match[1];
|
|
631
|
+
const caps = {};
|
|
632
|
+
const boolMatches = inner.matchAll(/(\w+):\s*(true|false)/g);
|
|
633
|
+
for (const m of boolMatches) {
|
|
634
|
+
caps[m[1]] = m[2] === "true";
|
|
635
|
+
}
|
|
636
|
+
const numMatches = inner.matchAll(/(\w+):\s*(\d+)/g);
|
|
637
|
+
for (const m of numMatches) {
|
|
638
|
+
caps[m[1]] = parseInt(m[2], 10);
|
|
639
|
+
}
|
|
640
|
+
return Object.keys(caps).length > 0 ? caps : void 0;
|
|
641
|
+
}
|
|
642
|
+
function parseModelFile(content) {
|
|
643
|
+
const name = getName(content);
|
|
644
|
+
if (!name) return null;
|
|
645
|
+
return {
|
|
646
|
+
name,
|
|
647
|
+
provider: getProvider(content),
|
|
648
|
+
model: getModel(content),
|
|
649
|
+
inputPrice: getInputPrice(content),
|
|
650
|
+
outputPrice: getOutputPrice(content),
|
|
651
|
+
cachedPrice: getCachedPrice(content),
|
|
652
|
+
includedProviders: getIncludedProviders(content),
|
|
653
|
+
fallbacks: getFallbacks(content),
|
|
654
|
+
providerTools: getProviderTools(content),
|
|
655
|
+
capabilities: getCapabilities(content)
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
|
|
582
659
|
// src/sdk/generators/generateModelFile.ts
|
|
583
|
-
function generateModelFile(data) {
|
|
660
|
+
function generateModelFile(data, options) {
|
|
661
|
+
const { providerName, providerPackage } = options;
|
|
584
662
|
const lines = [
|
|
585
663
|
`import { defineModel } from '@standardagents/builder';`,
|
|
664
|
+
`import { ${providerName} } from '${providerPackage}';`,
|
|
586
665
|
"",
|
|
587
666
|
`export default defineModel({`,
|
|
588
667
|
` name: '${escapeString(data.name)}',`,
|
|
589
|
-
` provider:
|
|
668
|
+
` provider: ${providerName},`,
|
|
590
669
|
` model: '${escapeString(data.model)}',`
|
|
591
670
|
];
|
|
592
671
|
if (data.includedProviders && data.includedProviders.length > 0) {
|
|
@@ -595,6 +674,9 @@ function generateModelFile(data) {
|
|
|
595
674
|
if (data.fallbacks && data.fallbacks.length > 0) {
|
|
596
675
|
lines.push(` fallbacks: ${JSON.stringify(data.fallbacks)},`);
|
|
597
676
|
}
|
|
677
|
+
if (data.providerTools && data.providerTools.length > 0) {
|
|
678
|
+
lines.push(` providerTools: ${JSON.stringify(data.providerTools)},`);
|
|
679
|
+
}
|
|
598
680
|
if (data.inputPrice !== void 0) {
|
|
599
681
|
lines.push(` inputPrice: ${data.inputPrice},`);
|
|
600
682
|
}
|
|
@@ -604,6 +686,36 @@ function generateModelFile(data) {
|
|
|
604
686
|
if (data.cachedPrice !== void 0) {
|
|
605
687
|
lines.push(` cachedPrice: ${data.cachedPrice},`);
|
|
606
688
|
}
|
|
689
|
+
if (data.capabilities && Object.keys(data.capabilities).length > 0) {
|
|
690
|
+
const caps = data.capabilities;
|
|
691
|
+
const capLines = [];
|
|
692
|
+
if (caps.supportsImages !== void 0) {
|
|
693
|
+
capLines.push(` supportsImages: ${caps.supportsImages},`);
|
|
694
|
+
}
|
|
695
|
+
if (caps.supportsToolCalls !== void 0) {
|
|
696
|
+
capLines.push(` supportsToolCalls: ${caps.supportsToolCalls},`);
|
|
697
|
+
}
|
|
698
|
+
if (caps.supportsStreaming !== void 0) {
|
|
699
|
+
capLines.push(` supportsStreaming: ${caps.supportsStreaming},`);
|
|
700
|
+
}
|
|
701
|
+
if (caps.supportsJsonMode !== void 0) {
|
|
702
|
+
capLines.push(` supportsJsonMode: ${caps.supportsJsonMode},`);
|
|
703
|
+
}
|
|
704
|
+
if (caps.maxContextTokens !== void 0) {
|
|
705
|
+
capLines.push(` maxContextTokens: ${caps.maxContextTokens},`);
|
|
706
|
+
}
|
|
707
|
+
if (caps.maxOutputTokens !== void 0) {
|
|
708
|
+
capLines.push(` maxOutputTokens: ${caps.maxOutputTokens},`);
|
|
709
|
+
}
|
|
710
|
+
if (caps.reasoningLevels !== void 0) {
|
|
711
|
+
capLines.push(` reasoningLevels: ${JSON.stringify(caps.reasoningLevels)},`);
|
|
712
|
+
}
|
|
713
|
+
if (capLines.length > 0) {
|
|
714
|
+
lines.push(` capabilities: {`);
|
|
715
|
+
lines.push(...capLines);
|
|
716
|
+
lines.push(` },`);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
607
719
|
lines.push(`});`);
|
|
608
720
|
lines.push("");
|
|
609
721
|
return lines.join("\n");
|
|
@@ -858,6 +970,12 @@ function formatToolConfig(config) {
|
|
|
858
970
|
if (config.init_user_message_property !== void 0 && config.init_user_message_property !== null) {
|
|
859
971
|
parts.push(`initUserMessageProperty: '${escapeString2(config.init_user_message_property)}'`);
|
|
860
972
|
}
|
|
973
|
+
if (config.init_attachments_property !== void 0 && config.init_attachments_property !== null) {
|
|
974
|
+
parts.push(`initAttachmentsProperty: '${escapeString2(config.init_attachments_property)}'`);
|
|
975
|
+
}
|
|
976
|
+
if (config.tenvs && Object.keys(config.tenvs).length > 0) {
|
|
977
|
+
parts.push(`tenvs: ${JSON.stringify(config.tenvs)}`);
|
|
978
|
+
}
|
|
861
979
|
return `{ ${parts.join(", ")} }`;
|
|
862
980
|
}
|
|
863
981
|
function formatReasoningConfig(reasoning) {
|
|
@@ -990,6 +1108,9 @@ function generateAgentFile(data) {
|
|
|
990
1108
|
if (data.toolDescription) {
|
|
991
1109
|
lines.push(` toolDescription: '${escapeString3(data.toolDescription)}',`);
|
|
992
1110
|
}
|
|
1111
|
+
if (data.tenvs && Object.keys(data.tenvs).length > 0) {
|
|
1112
|
+
lines.push(` tenvs: ${JSON.stringify(data.tenvs)},`);
|
|
1113
|
+
}
|
|
993
1114
|
lines.push(`});`);
|
|
994
1115
|
lines.push("");
|
|
995
1116
|
return lines.join("\n");
|
|
@@ -1026,8 +1147,15 @@ function escapeString3(str) {
|
|
|
1026
1147
|
}
|
|
1027
1148
|
|
|
1028
1149
|
// src/sdk/persistence/index.ts
|
|
1150
|
+
var PROVIDER_PACKAGE_MAP = {
|
|
1151
|
+
openai: { name: "openai", package: "@standardagents/openai" },
|
|
1152
|
+
openrouter: { name: "openrouter", package: "@standardagents/openrouter" },
|
|
1153
|
+
anthropic: { name: "anthropic", package: "@standardagents/anthropic" },
|
|
1154
|
+
google: { name: "google", package: "@standardagents/google" },
|
|
1155
|
+
test: { name: "test", package: "@standardagents/builder/test" }
|
|
1156
|
+
};
|
|
1029
1157
|
function nameToFilename(name) {
|
|
1030
|
-
return name.replace(/[/\\]/g, "__").replace(/[:*?"
|
|
1158
|
+
return name.replace(/[/\\]/g, "__").replace(/[:*?"<>|.]/g, "_").replace(/-/g, "_");
|
|
1031
1159
|
}
|
|
1032
1160
|
function getModelFilePath(modelsDir, name) {
|
|
1033
1161
|
const filename = nameToFilename(name);
|
|
@@ -1049,7 +1177,17 @@ async function saveModel(modelsDir, data, overwrite = false) {
|
|
|
1049
1177
|
error: `Model file already exists: ${filePath}. Use update to modify existing models.`
|
|
1050
1178
|
};
|
|
1051
1179
|
}
|
|
1052
|
-
const
|
|
1180
|
+
const providerInfo = PROVIDER_PACKAGE_MAP[data.provider];
|
|
1181
|
+
if (!providerInfo) {
|
|
1182
|
+
return {
|
|
1183
|
+
success: false,
|
|
1184
|
+
error: `Unknown provider '${data.provider}'. Must be one of: ${Object.keys(PROVIDER_PACKAGE_MAP).join(", ")}`
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
const content = generateModelFile(data, {
|
|
1188
|
+
providerName: providerInfo.name,
|
|
1189
|
+
providerPackage: providerInfo.package
|
|
1190
|
+
});
|
|
1053
1191
|
await fs2.promises.writeFile(filePath, content, "utf-8");
|
|
1054
1192
|
return {
|
|
1055
1193
|
success: true,
|
|
@@ -1113,7 +1251,7 @@ function validateModelData(data) {
|
|
|
1113
1251
|
if (!data.provider || typeof data.provider !== "string") {
|
|
1114
1252
|
return "Model provider is required and must be a string";
|
|
1115
1253
|
}
|
|
1116
|
-
const validProviders =
|
|
1254
|
+
const validProviders = Object.keys(PROVIDER_PACKAGE_MAP);
|
|
1117
1255
|
if (!validProviders.includes(data.provider)) {
|
|
1118
1256
|
return `Invalid provider '${data.provider}'. Must be one of: ${validProviders.join(", ")}`;
|
|
1119
1257
|
}
|
|
@@ -1617,7 +1755,6 @@ function validateAgentData(data) {
|
|
|
1617
1755
|
}
|
|
1618
1756
|
|
|
1619
1757
|
// src/plugin.ts
|
|
1620
|
-
createRequire(import.meta.url);
|
|
1621
1758
|
var VIRTUAL_TOOLS_ID = "virtual:@standardagents-tools";
|
|
1622
1759
|
var RESOLVED_VIRTUAL_TOOLS_ID = "\0" + VIRTUAL_TOOLS_ID;
|
|
1623
1760
|
var VIRTUAL_ROUTES_ID = "virtual:@standardagents-routes";
|
|
@@ -1638,6 +1775,8 @@ var VIRTUAL_AGENTS_ID = "virtual:@standardagents-agents";
|
|
|
1638
1775
|
var RESOLVED_VIRTUAL_AGENTS_ID = "\0" + VIRTUAL_AGENTS_ID;
|
|
1639
1776
|
var VIRTUAL_EFFECTS_ID = "virtual:@standardagents-effects";
|
|
1640
1777
|
var RESOLVED_VIRTUAL_EFFECTS_ID = "\0" + VIRTUAL_EFFECTS_ID;
|
|
1778
|
+
var VIRTUAL_PROVIDERS_ID = "virtual:@standardagents-providers";
|
|
1779
|
+
var RESOLVED_VIRTUAL_PROVIDERS_ID = "\0" + VIRTUAL_PROVIDERS_ID;
|
|
1641
1780
|
var VIRTUAL_BUILDER_ID = "virtual:@standardagents/builder";
|
|
1642
1781
|
var RESOLVED_VIRTUAL_BUILDER_ID = "\0" + VIRTUAL_BUILDER_ID;
|
|
1643
1782
|
function scanApiDirectory(dir, baseRoute = "") {
|
|
@@ -2070,7 +2209,15 @@ function agentbuilder(options = {}) {
|
|
|
2070
2209
|
"zod",
|
|
2071
2210
|
"openai"
|
|
2072
2211
|
];
|
|
2212
|
+
const currentDir = path3.dirname(fileURLToPath(import.meta.url));
|
|
2213
|
+
const isInDist = currentDir.endsWith("dist");
|
|
2214
|
+
const builderClientDir = path3.resolve(
|
|
2215
|
+
currentDir,
|
|
2216
|
+
isInDist ? "./client" : "../dist/client"
|
|
2217
|
+
);
|
|
2073
2218
|
return {
|
|
2219
|
+
// Set publicDir to builder's client assets so Cloudflare plugin preserves assets config
|
|
2220
|
+
publicDir: fs2.existsSync(builderClientDir) ? builderClientDir : void 0,
|
|
2074
2221
|
optimizeDeps: {
|
|
2075
2222
|
// Exclude our packages from pre-bundling - they contain cloudflare:workers imports
|
|
2076
2223
|
// that cannot be resolved during dependency optimization
|
|
@@ -2106,6 +2253,9 @@ function agentbuilder(options = {}) {
|
|
|
2106
2253
|
];
|
|
2107
2254
|
const depsToInclude = [
|
|
2108
2255
|
"zod",
|
|
2256
|
+
"zod/v3",
|
|
2257
|
+
"zod/v4",
|
|
2258
|
+
"zod/v4/core",
|
|
2109
2259
|
"openai"
|
|
2110
2260
|
];
|
|
2111
2261
|
config.optimizeDeps = config.optimizeDeps || {};
|
|
@@ -2146,6 +2296,9 @@ function agentbuilder(options = {}) {
|
|
|
2146
2296
|
if (id === VIRTUAL_EFFECTS_ID) {
|
|
2147
2297
|
return RESOLVED_VIRTUAL_EFFECTS_ID;
|
|
2148
2298
|
}
|
|
2299
|
+
if (id === VIRTUAL_PROVIDERS_ID) {
|
|
2300
|
+
return RESOLVED_VIRTUAL_PROVIDERS_ID;
|
|
2301
|
+
}
|
|
2149
2302
|
if (id === VIRTUAL_BUILDER_ID) {
|
|
2150
2303
|
return RESOLVED_VIRTUAL_BUILDER_ID;
|
|
2151
2304
|
}
|
|
@@ -2221,9 +2374,56 @@ function isPublicRoute(routePath) {
|
|
|
2221
2374
|
return true;
|
|
2222
2375
|
}
|
|
2223
2376
|
|
|
2377
|
+
// Provider icon routes are public (used by <img src>)
|
|
2378
|
+
if (routePath.startsWith('/api/providers/') && routePath.includes('/icon')) {
|
|
2379
|
+
return true;
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2224
2382
|
return false;
|
|
2225
2383
|
}
|
|
2226
2384
|
|
|
2385
|
+
// CORS headers for API responses
|
|
2386
|
+
const CORS_HEADERS = {
|
|
2387
|
+
"Access-Control-Allow-Origin": "*",
|
|
2388
|
+
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
|
2389
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With",
|
|
2390
|
+
"Access-Control-Max-Age": "86400",
|
|
2391
|
+
};
|
|
2392
|
+
|
|
2393
|
+
// Helper to create headers with CORS
|
|
2394
|
+
function corsHeaders(contentType) {
|
|
2395
|
+
return {
|
|
2396
|
+
"Content-Type": contentType,
|
|
2397
|
+
...CORS_HEADERS,
|
|
2398
|
+
};
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
// Helper to add CORS headers to any Response without touching the body
|
|
2402
|
+
function addCorsHeaders(response) {
|
|
2403
|
+
// Skip WebSocket upgrade responses - they can't be wrapped
|
|
2404
|
+
if (response.status === 101) {
|
|
2405
|
+
return response;
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
// Skip if already has CORS headers
|
|
2409
|
+
if (response.headers.has("Access-Control-Allow-Origin")) {
|
|
2410
|
+
return response;
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
// Create new headers with CORS added
|
|
2414
|
+
const newHeaders = new Headers(response.headers);
|
|
2415
|
+
for (const [key, value] of Object.entries(CORS_HEADERS)) {
|
|
2416
|
+
newHeaders.set(key, value);
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
// Return new Response with same body stream (not cloned, just transferred)
|
|
2420
|
+
return new Response(response.body, {
|
|
2421
|
+
status: response.status,
|
|
2422
|
+
statusText: response.statusText,
|
|
2423
|
+
headers: newHeaders,
|
|
2424
|
+
});
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2227
2427
|
export async function router(request, env) {
|
|
2228
2428
|
const url = new URL(request.url);
|
|
2229
2429
|
const pathname = url.pathname;
|
|
@@ -2233,6 +2433,14 @@ export async function router(request, env) {
|
|
|
2233
2433
|
return null;
|
|
2234
2434
|
}
|
|
2235
2435
|
|
|
2436
|
+
// Handle CORS preflight requests
|
|
2437
|
+
if (request.method === "OPTIONS") {
|
|
2438
|
+
return new Response(null, {
|
|
2439
|
+
status: 204,
|
|
2440
|
+
headers: CORS_HEADERS,
|
|
2441
|
+
});
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2236
2444
|
// Strip mount point prefix for route matching, ensuring we keep the leading slash
|
|
2237
2445
|
let routePath = pathname.slice(MOUNT_POINT.length) || "/";
|
|
2238
2446
|
if (!routePath.startsWith('/')) {
|
|
@@ -2267,7 +2475,7 @@ ${threadRouteCode}
|
|
|
2267
2475
|
|
|
2268
2476
|
// If requireAuth returns a Response, it's an error (401)
|
|
2269
2477
|
if (authResult instanceof Response) {
|
|
2270
|
-
return authResult;
|
|
2478
|
+
return addCorsHeaders(authResult);
|
|
2271
2479
|
}
|
|
2272
2480
|
|
|
2273
2481
|
authContext = authResult;
|
|
@@ -2286,16 +2494,17 @@ ${threadRouteCode}
|
|
|
2286
2494
|
const result = await controller(context);
|
|
2287
2495
|
|
|
2288
2496
|
if (result instanceof Response) {
|
|
2289
|
-
return result;
|
|
2497
|
+
return addCorsHeaders(result);
|
|
2290
2498
|
}
|
|
2291
2499
|
if (typeof result === "string") {
|
|
2292
2500
|
return new Response(result, {
|
|
2293
|
-
headers:
|
|
2294
|
-
"Content-Type": "text/plain",
|
|
2295
|
-
},
|
|
2501
|
+
headers: corsHeaders("text/plain"),
|
|
2296
2502
|
});
|
|
2297
2503
|
}
|
|
2298
|
-
|
|
2504
|
+
// JSON responses get CORS headers
|
|
2505
|
+
return new Response(JSON.stringify(result), {
|
|
2506
|
+
headers: corsHeaders("application/json"),
|
|
2507
|
+
});
|
|
2299
2508
|
}
|
|
2300
2509
|
|
|
2301
2510
|
// Serve UI for all other routes (SPA fallback)
|
|
@@ -2310,13 +2519,15 @@ async function serveUI(pathname, env) {
|
|
|
2310
2519
|
// Create a proper request for the asset path
|
|
2311
2520
|
// Use a dummy origin since we only care about the path
|
|
2312
2521
|
// Re-add mount point since pathname was stripped by router
|
|
2313
|
-
|
|
2522
|
+
// Handle root mountPoint "/" specially to avoid double slashes
|
|
2523
|
+
const mountPrefix = MOUNT_POINT === "/" ? "" : MOUNT_POINT;
|
|
2524
|
+
const assetUrl = \`http://localhost\${mountPrefix}\${pathname}\`;
|
|
2314
2525
|
let response = await env.ASSETS.fetch(assetUrl);
|
|
2315
2526
|
|
|
2316
2527
|
// If not found, fall back to index.html for SPA routing
|
|
2317
2528
|
const isIndexHtml = response.status === 404 || pathname === "/" || !pathname.includes(".");
|
|
2318
2529
|
if (isIndexHtml) {
|
|
2319
|
-
response = await env.ASSETS.fetch(\`http://localhost\${
|
|
2530
|
+
response = await env.ASSETS.fetch(\`http://localhost\${mountPrefix}/index.html\`);
|
|
2320
2531
|
|
|
2321
2532
|
// Transform HTML to use configured mount point
|
|
2322
2533
|
if (response.status === 200) {
|
|
@@ -2488,6 +2699,30 @@ ${effectsCode}
|
|
|
2488
2699
|
};
|
|
2489
2700
|
|
|
2490
2701
|
export const effectNames = ${JSON.stringify(effects.filter((e) => !e.error).map((e) => e.name))};
|
|
2702
|
+
`;
|
|
2703
|
+
}
|
|
2704
|
+
if (id === RESOLVED_VIRTUAL_PROVIDERS_ID) {
|
|
2705
|
+
const firstPartyProviders = [
|
|
2706
|
+
{ name: "openai", package: "@standardagents/openai", label: "OpenAI", envKey: "OPENAI_API_KEY" },
|
|
2707
|
+
{ name: "openrouter", package: "@standardagents/openrouter", label: "OpenRouter", envKey: "OPENROUTER_API_KEY" }
|
|
2708
|
+
];
|
|
2709
|
+
const customProviders = (options.providers || []).map((pkg) => ({
|
|
2710
|
+
name: pkg.split("/").pop() || pkg,
|
|
2711
|
+
package: pkg,
|
|
2712
|
+
label: pkg.split("/").pop() || pkg,
|
|
2713
|
+
envKey: `${(pkg.split("/").pop() || pkg).toUpperCase().replace(/-/g, "_")}_API_KEY`,
|
|
2714
|
+
isCustom: true
|
|
2715
|
+
}));
|
|
2716
|
+
const allProviders = [...firstPartyProviders, ...customProviders];
|
|
2717
|
+
return `// Virtual providers module - lists available LLM provider packages
|
|
2718
|
+
export const providers = ${JSON.stringify(allProviders, null, 2)};
|
|
2719
|
+
|
|
2720
|
+
export const providerNames = ${JSON.stringify(allProviders.map((p) => p.name))};
|
|
2721
|
+
|
|
2722
|
+
// Provider factories - dynamic imports for code splitting
|
|
2723
|
+
export const providerFactories = {
|
|
2724
|
+
${allProviders.map((p) => ` "${p.name}": async () => (await import("${p.package}")).${p.name},`).join("\n")}
|
|
2725
|
+
};
|
|
2491
2726
|
`;
|
|
2492
2727
|
}
|
|
2493
2728
|
if (id === RESOLVED_VIRTUAL_BUILDER_ID) {
|
|
@@ -2601,7 +2836,8 @@ import { DurableAgentBuilder as _BaseDurableAgentBuilder } from '@standardagents
|
|
|
2601
2836
|
|
|
2602
2837
|
// Import sip WASM module and initializer
|
|
2603
2838
|
// Static import allows workerd to pre-compile the WASM at bundle time
|
|
2604
|
-
|
|
2839
|
+
// WASM is bundled in builder's dist to avoid transitive dependency resolution issues
|
|
2840
|
+
import _sipWasm from '@standardagents/builder/dist/sip.wasm';
|
|
2605
2841
|
import { initWithWasmModule as _initSipWasm } from '@standardagents/sip';
|
|
2606
2842
|
|
|
2607
2843
|
// Re-export router from virtual:@standardagents-routes
|
|
@@ -2740,51 +2976,26 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
|
|
|
2740
2976
|
try {
|
|
2741
2977
|
const filePath = path3.join(modelsDir, file);
|
|
2742
2978
|
const content = fs4.readFileSync(filePath, "utf-8");
|
|
2743
|
-
const
|
|
2744
|
-
|
|
2745
|
-
const
|
|
2746
|
-
const getInputPrice = (c) => {
|
|
2747
|
-
const match = c.match(/inputPrice:\s*([\d.]+)/);
|
|
2748
|
-
return match ? parseFloat(match[1]) : void 0;
|
|
2749
|
-
};
|
|
2750
|
-
const getOutputPrice = (c) => {
|
|
2751
|
-
const match = c.match(/outputPrice:\s*([\d.]+)/);
|
|
2752
|
-
return match ? parseFloat(match[1]) : void 0;
|
|
2753
|
-
};
|
|
2754
|
-
const getCachedPrice = (c) => {
|
|
2755
|
-
const match = c.match(/cachedPrice:\s*([\d.]+)/);
|
|
2756
|
-
return match ? parseFloat(match[1]) : void 0;
|
|
2757
|
-
};
|
|
2758
|
-
const getIncludedProviders = (c) => {
|
|
2759
|
-
const match = c.match(/includedProviders:\s*\[([^\]]*)\]/);
|
|
2760
|
-
if (!match) return void 0;
|
|
2761
|
-
const items = match[1].match(/['"]([^'"]+)['"]/g);
|
|
2762
|
-
return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
|
|
2763
|
-
};
|
|
2764
|
-
const getFallbacks = (c) => {
|
|
2765
|
-
const match = c.match(/fallbacks:\s*\[([^\]]*)\]/);
|
|
2766
|
-
if (!match) return [];
|
|
2767
|
-
const items = match[1].match(/['"]([^'"]+)['"]/g);
|
|
2768
|
-
return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
|
|
2769
|
-
};
|
|
2770
|
-
const name = getName(content);
|
|
2771
|
-
if (!name) return null;
|
|
2772
|
-
const fallbacks = getFallbacks(content);
|
|
2773
|
-
const fallbackObjects = fallbacks.map((fallbackName, index) => ({
|
|
2979
|
+
const parsed = parseModelFile(content);
|
|
2980
|
+
if (!parsed || !parsed.name) return null;
|
|
2981
|
+
const fallbackObjects = parsed.fallbacks.map((fallbackName, index) => ({
|
|
2774
2982
|
id: fallbackName,
|
|
2775
2983
|
name: fallbackName,
|
|
2776
2984
|
order: index
|
|
2777
2985
|
}));
|
|
2778
2986
|
return {
|
|
2779
|
-
id: name,
|
|
2780
|
-
name,
|
|
2781
|
-
provider:
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2987
|
+
id: parsed.name,
|
|
2988
|
+
name: parsed.name,
|
|
2989
|
+
provider: parsed.provider,
|
|
2990
|
+
provider_id: parsed.provider,
|
|
2991
|
+
model: parsed.model,
|
|
2992
|
+
input_price: parsed.inputPrice,
|
|
2993
|
+
output_price: parsed.outputPrice,
|
|
2994
|
+
cached_price: parsed.cachedPrice,
|
|
2995
|
+
included_providers: parsed.includedProviders,
|
|
2787
2996
|
fallbacks: fallbackObjects,
|
|
2997
|
+
providerTools: parsed.providerTools,
|
|
2998
|
+
capabilities: parsed.capabilities,
|
|
2788
2999
|
created_at: Math.floor(Date.now() / 1e3)
|
|
2789
3000
|
};
|
|
2790
3001
|
} catch (error) {
|
|
@@ -2950,9 +3161,9 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
|
|
|
2950
3161
|
try {
|
|
2951
3162
|
const filePath = path3.join(promptsDir, file);
|
|
2952
3163
|
const content = fs4.readFileSync(filePath, "utf-8");
|
|
2953
|
-
const
|
|
3164
|
+
const getName2 = (c) => c.match(/name:\s*['"]([^'"]+)['"]/)?.[1];
|
|
2954
3165
|
const getToolDescription = (c) => c.match(/toolDescription:\s*['"]([^'"]+)['"]/)?.[1];
|
|
2955
|
-
const
|
|
3166
|
+
const getModel2 = (c) => c.match(/model:\s*['"]([^'"]+)['"]/)?.[1];
|
|
2956
3167
|
const getIncludeChat = (c) => c.match(/includeChat:\s*(true|false)/)?.[1] === "true";
|
|
2957
3168
|
const getIncludePastTools = (c) => c.match(/includePastTools:\s*(true|false)/)?.[1] === "true";
|
|
2958
3169
|
const getParallelToolCalls = (c) => c.match(/parallelToolCalls:\s*(true|false)/)?.[1] === "true";
|
|
@@ -2972,9 +3183,9 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
|
|
|
2972
3183
|
if (arrayMatch) return arrayMatch[1];
|
|
2973
3184
|
return "";
|
|
2974
3185
|
};
|
|
2975
|
-
const name =
|
|
3186
|
+
const name = getName2(content);
|
|
2976
3187
|
if (!name) return null;
|
|
2977
|
-
const modelId =
|
|
3188
|
+
const modelId = getModel2(content);
|
|
2978
3189
|
const modelDef = modelId ? modelMap[modelId] : null;
|
|
2979
3190
|
return {
|
|
2980
3191
|
id: name,
|
|
@@ -3145,7 +3356,7 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
|
|
|
3145
3356
|
try {
|
|
3146
3357
|
const filePath = path3.join(agentsDir, file);
|
|
3147
3358
|
const content = fs4.readFileSync(filePath, "utf-8");
|
|
3148
|
-
const
|
|
3359
|
+
const getName2 = (c) => c.match(/name:\s*['"]([^'"]+)['"]/)?.[1];
|
|
3149
3360
|
const getTitle = (c) => c.match(/title:\s*['"]([^'"]+)['"]/)?.[1];
|
|
3150
3361
|
const getType = (c) => c.match(/type:\s*['"]([^'"]+)['"]/)?.[1];
|
|
3151
3362
|
const getDefaultPrompt = (c) => c.match(/defaultPrompt:\s*['"]([^'"]+)['"]/)?.[1];
|
|
@@ -3156,7 +3367,14 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
|
|
|
3156
3367
|
const items = match[1].match(/['"]([^'"]+)['"]/g);
|
|
3157
3368
|
return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
|
|
3158
3369
|
};
|
|
3159
|
-
const
|
|
3370
|
+
const getSidePrompt = (c, side) => {
|
|
3371
|
+
const sideRegex = new RegExp(`${side}:\\s*\\{([^}]+)\\}`, "s");
|
|
3372
|
+
const sideMatch = c.match(sideRegex);
|
|
3373
|
+
if (!sideMatch) return null;
|
|
3374
|
+
const promptMatch = sideMatch[1].match(/prompt:\s*['"]([^'"]+)['"]/);
|
|
3375
|
+
return promptMatch ? promptMatch[1] : null;
|
|
3376
|
+
};
|
|
3377
|
+
const name = getName2(content);
|
|
3160
3378
|
if (!name) return null;
|
|
3161
3379
|
return {
|
|
3162
3380
|
id: name,
|
|
@@ -3166,6 +3384,8 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
|
|
|
3166
3384
|
default_prompt: getDefaultPrompt(content) || "",
|
|
3167
3385
|
default_model: getDefaultModel(content) || "",
|
|
3168
3386
|
tools: getTools(content),
|
|
3387
|
+
side_a_agent_prompt: getSidePrompt(content, "sideA"),
|
|
3388
|
+
side_b_agent_prompt: getSidePrompt(content, "sideB"),
|
|
3169
3389
|
created_at: Math.floor(Date.now() / 1e3)
|
|
3170
3390
|
};
|
|
3171
3391
|
} catch (error) {
|