@runtypelabs/cli 2.14.0 → 2.15.1
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/index.js +806 -62
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -26255,7 +26255,8 @@ var BuiltInToolCategory = {
|
|
|
26255
26255
|
DATA_MANAGEMENT: "data_management",
|
|
26256
26256
|
COMMERCE: "commerce",
|
|
26257
26257
|
BROWSER: "browser",
|
|
26258
|
-
SANDBOX: "sandbox"
|
|
26258
|
+
SANDBOX: "sandbox",
|
|
26259
|
+
MESSAGING: "messaging"
|
|
26259
26260
|
};
|
|
26260
26261
|
var BuiltInToolIdPrefix = {
|
|
26261
26262
|
BUILTIN: "builtin",
|
|
@@ -26651,7 +26652,15 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
|
|
|
26651
26652
|
modelCompatibility: [
|
|
26652
26653
|
{
|
|
26653
26654
|
provider: BuiltInToolProvider.ANTHROPIC,
|
|
26654
|
-
models: [
|
|
26655
|
+
models: [
|
|
26656
|
+
"claude-opus-4",
|
|
26657
|
+
"claude-sonnet-4",
|
|
26658
|
+
"claude-opus-4-5",
|
|
26659
|
+
"claude-sonnet-4-5",
|
|
26660
|
+
"claude-opus-4-6",
|
|
26661
|
+
"claude-sonnet-4-6",
|
|
26662
|
+
"claude-haiku-4-5"
|
|
26663
|
+
]
|
|
26655
26664
|
}
|
|
26656
26665
|
],
|
|
26657
26666
|
documentationUrl: "https://sdk.vercel.ai/providers/ai-sdk-providers/anthropic#web-search",
|
|
@@ -26742,7 +26751,10 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
|
|
|
26742
26751
|
type: "string",
|
|
26743
26752
|
enum: ["web", "x", "news", "rss"]
|
|
26744
26753
|
},
|
|
26745
|
-
country: {
|
|
26754
|
+
country: {
|
|
26755
|
+
type: "string",
|
|
26756
|
+
description: "ISO 3166-1 alpha-2 country code (web/news)."
|
|
26757
|
+
},
|
|
26746
26758
|
allowedWebsites: {
|
|
26747
26759
|
type: "array",
|
|
26748
26760
|
description: "Up to 5 domains to restrict search to (web only).",
|
|
@@ -28231,7 +28243,10 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
|
|
|
28231
28243
|
city: { type: "string", description: "City" },
|
|
28232
28244
|
province_code: { type: "string", description: "State/province code" },
|
|
28233
28245
|
postal_code: { type: "string", description: "Postal/ZIP code" },
|
|
28234
|
-
country_code: {
|
|
28246
|
+
country_code: {
|
|
28247
|
+
type: "string",
|
|
28248
|
+
description: "ISO 3166-1 alpha-2 country code"
|
|
28249
|
+
}
|
|
28235
28250
|
}
|
|
28236
28251
|
},
|
|
28237
28252
|
phone_number: { type: "string", description: "Recipient phone number" }
|
|
@@ -28349,7 +28364,10 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
|
|
|
28349
28364
|
city: { type: "string", description: "City" },
|
|
28350
28365
|
province_code: { type: "string", description: "State/province code" },
|
|
28351
28366
|
postal_code: { type: "string", description: "Postal/ZIP code" },
|
|
28352
|
-
country_code: {
|
|
28367
|
+
country_code: {
|
|
28368
|
+
type: "string",
|
|
28369
|
+
description: "ISO 3166-1 alpha-2 country code"
|
|
28370
|
+
}
|
|
28353
28371
|
}
|
|
28354
28372
|
},
|
|
28355
28373
|
phone_number: { type: "string", description: "Recipient phone number" }
|
|
@@ -28556,7 +28574,10 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
|
|
|
28556
28574
|
intent: { type: "string", description: "Buyer intent description" }
|
|
28557
28575
|
}
|
|
28558
28576
|
},
|
|
28559
|
-
bearerToken: {
|
|
28577
|
+
bearerToken: {
|
|
28578
|
+
type: "string",
|
|
28579
|
+
description: "Bearer token for authenticated session (optional)"
|
|
28580
|
+
}
|
|
28560
28581
|
},
|
|
28561
28582
|
required: ["domain", "items"]
|
|
28562
28583
|
},
|
|
@@ -29180,6 +29201,81 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
|
|
|
29180
29201
|
executionHint: "platform",
|
|
29181
29202
|
requiresApiKey: false,
|
|
29182
29203
|
platformKeySupport: true
|
|
29204
|
+
},
|
|
29205
|
+
// Send email via Resend. Mirrors the send-email context step so agents can
|
|
29206
|
+
// dispatch transactional email without wrapping it in a flow.
|
|
29207
|
+
{
|
|
29208
|
+
id: "send_email",
|
|
29209
|
+
name: "Send Email",
|
|
29210
|
+
description: 'Send a transactional email via Resend. Leave "from" blank to use the platform-managed sender; set it to send from your own verified domain (requires a custom Resend key configured in Settings > Integrations).',
|
|
29211
|
+
category: BuiltInToolCategory.MESSAGING,
|
|
29212
|
+
providers: [BuiltInToolProvider.MULTI],
|
|
29213
|
+
parametersSchema: {
|
|
29214
|
+
type: "object",
|
|
29215
|
+
properties: {
|
|
29216
|
+
to: {
|
|
29217
|
+
type: "string",
|
|
29218
|
+
description: "Recipient email address. Multiple addresses can be provided comma-separated.",
|
|
29219
|
+
minLength: 1
|
|
29220
|
+
},
|
|
29221
|
+
subject: {
|
|
29222
|
+
type: "string",
|
|
29223
|
+
description: "Email subject line.",
|
|
29224
|
+
minLength: 1
|
|
29225
|
+
},
|
|
29226
|
+
html: {
|
|
29227
|
+
type: "string",
|
|
29228
|
+
description: "HTML body of the email. Provide either html or text (or both); at least one is required."
|
|
29229
|
+
},
|
|
29230
|
+
text: {
|
|
29231
|
+
type: "string",
|
|
29232
|
+
description: "Plain-text body of the email. Provide either html or text (or both); at least one is required."
|
|
29233
|
+
},
|
|
29234
|
+
from: {
|
|
29235
|
+
type: "string",
|
|
29236
|
+
description: "Optional sender address. Leave blank to use the platform-managed sender (e.g. agent_id@<platform-domain>). Custom values require your own Resend API key and a verified domain."
|
|
29237
|
+
},
|
|
29238
|
+
cc: {
|
|
29239
|
+
type: "string",
|
|
29240
|
+
description: "Optional CC recipients, comma-separated."
|
|
29241
|
+
},
|
|
29242
|
+
bcc: {
|
|
29243
|
+
type: "string",
|
|
29244
|
+
description: "Optional BCC recipients, comma-separated."
|
|
29245
|
+
},
|
|
29246
|
+
replyTo: {
|
|
29247
|
+
type: "string",
|
|
29248
|
+
description: "Optional Reply-To address."
|
|
29249
|
+
},
|
|
29250
|
+
attachments: {
|
|
29251
|
+
type: "array",
|
|
29252
|
+
description: "Optional file attachments. Each item must include a filename and base64-encoded content.",
|
|
29253
|
+
items: {
|
|
29254
|
+
type: "object",
|
|
29255
|
+
properties: {
|
|
29256
|
+
filename: {
|
|
29257
|
+
type: "string",
|
|
29258
|
+
description: "Attachment filename, including extension."
|
|
29259
|
+
},
|
|
29260
|
+
content: {
|
|
29261
|
+
type: "string",
|
|
29262
|
+
description: "Base64-encoded file contents."
|
|
29263
|
+
},
|
|
29264
|
+
contentType: {
|
|
29265
|
+
type: "string",
|
|
29266
|
+
description: "Optional MIME type (e.g. application/pdf)."
|
|
29267
|
+
}
|
|
29268
|
+
},
|
|
29269
|
+
required: ["filename", "content"]
|
|
29270
|
+
}
|
|
29271
|
+
}
|
|
29272
|
+
},
|
|
29273
|
+
required: ["to", "subject"]
|
|
29274
|
+
},
|
|
29275
|
+
documentationUrl: "https://resend.com/docs/api-reference/emails/send-email",
|
|
29276
|
+
requiresApiKey: false,
|
|
29277
|
+
executionHint: "platform",
|
|
29278
|
+
platformKeySupport: true
|
|
29183
29279
|
}
|
|
29184
29280
|
];
|
|
29185
29281
|
var BUILTIN_TOOLS_REGISTRY = [
|
|
@@ -34687,7 +34783,8 @@ var CATEGORY_DISPLAY_NAMES = {
|
|
|
34687
34783
|
[BuiltInToolCategory.THIRD_PARTY_API]: "Third-Party API",
|
|
34688
34784
|
[BuiltInToolCategory.ARTIFACT]: "Artifact",
|
|
34689
34785
|
[BuiltInToolCategory.DATA_MANAGEMENT]: "Data Management",
|
|
34690
|
-
[BuiltInToolCategory.COMMERCE]: "Commerce"
|
|
34786
|
+
[BuiltInToolCategory.COMMERCE]: "Commerce",
|
|
34787
|
+
[BuiltInToolCategory.MESSAGING]: "Messaging"
|
|
34691
34788
|
};
|
|
34692
34789
|
var TOOL_CATALOG_FOR_FLOW_GENERATION = (() => {
|
|
34693
34790
|
const providerNativeSearchIds = /* @__PURE__ */ new Set([
|
|
@@ -35408,15 +35505,17 @@ var FlowInputSchema = external_exports.object({
|
|
|
35408
35505
|
id: external_exports.string().min(1).optional(),
|
|
35409
35506
|
name: external_exports.string().min(1).optional(),
|
|
35410
35507
|
description: external_exports.string().optional(),
|
|
35411
|
-
steps: external_exports.array(external_exports.any()).optional()
|
|
35508
|
+
steps: external_exports.array(external_exports.any()).optional(),
|
|
35509
|
+
contentHash: external_exports.string().length(64).optional()
|
|
35412
35510
|
}).refine(
|
|
35413
35511
|
(data) => {
|
|
35414
35512
|
const hasFlowId = !!data.id;
|
|
35415
35513
|
const hasSteps = !!(data.name && data.steps && data.steps.length > 0);
|
|
35416
|
-
|
|
35514
|
+
const hasPersistedFlow = !!(data.name && data.contentHash);
|
|
35515
|
+
return hasFlowId || hasSteps || hasPersistedFlow;
|
|
35417
35516
|
},
|
|
35418
35517
|
{
|
|
35419
|
-
message: "Either 'id'
|
|
35518
|
+
message: "Either 'id', flow definition with 'name' and 'steps', or persisted flow with 'name' and 'contentHash' must be provided."
|
|
35420
35519
|
}
|
|
35421
35520
|
);
|
|
35422
35521
|
var AgentLoopConfigSchema = external_exports.object({
|
|
@@ -53970,6 +54069,612 @@ gcloud run deploy runtype-deploy \\
|
|
|
53970
54069
|
\`GET /health\` returns \`{"status":"ok","agents":[...]}\`.
|
|
53971
54070
|
`;
|
|
53972
54071
|
}
|
|
54072
|
+
function workerIndexTs(agentSlugs) {
|
|
54073
|
+
const imports = agentSlugs.map((slug, i) => `import agent${i}Json from '../agents/${slug}.json'`).join("\n");
|
|
54074
|
+
const agentFiles = agentSlugs.map((slug, i) => ` ['${slug}.json', agent${i}Json],`).join("\n");
|
|
54075
|
+
return `/**
|
|
54076
|
+
* Generated by \`runtype deploy --target cloudflare\`.
|
|
54077
|
+
*
|
|
54078
|
+
* Routes:
|
|
54079
|
+
* GET /health \u2014 liveness probe (lists registered agent names)
|
|
54080
|
+
* POST /agent/:name \u2014 SSE stream of the agent event schema
|
|
54081
|
+
*
|
|
54082
|
+
* Agent definitions are statically imported so Wrangler bundles them.
|
|
54083
|
+
* To add a new agent:
|
|
54084
|
+
* 1. Export it with \`runtype deploy --agent <id> --target cloudflare\`
|
|
54085
|
+
* 2. Or drop a JSON file under agents/ and add an import + entry below
|
|
54086
|
+
* 3. Run \`wrangler deploy\`
|
|
54087
|
+
*/
|
|
54088
|
+
import {
|
|
54089
|
+
CloudflareAdapter,
|
|
54090
|
+
createRuntime,
|
|
54091
|
+
exportedAgentSchema,
|
|
54092
|
+
type ExportedAgent,
|
|
54093
|
+
} from '@runtypelabs/runtime'
|
|
54094
|
+
|
|
54095
|
+
// ---------------------------------------------------------------------------
|
|
54096
|
+
// Agent registry \u2014 static imports bundled by Wrangler at deploy time
|
|
54097
|
+
// ---------------------------------------------------------------------------
|
|
54098
|
+
|
|
54099
|
+
${imports}
|
|
54100
|
+
|
|
54101
|
+
function parseAgent(json: unknown, filename: string): ExportedAgent {
|
|
54102
|
+
try {
|
|
54103
|
+
return exportedAgentSchema.parse(json)
|
|
54104
|
+
} catch (err) {
|
|
54105
|
+
throw new Error(
|
|
54106
|
+
\`[runtype] invalid agent JSON in \${filename}: \${
|
|
54107
|
+
err instanceof Error ? err.message : String(err)
|
|
54108
|
+
}\`
|
|
54109
|
+
)
|
|
54110
|
+
}
|
|
54111
|
+
}
|
|
54112
|
+
|
|
54113
|
+
const agentFiles: Array<[string, unknown]> = [
|
|
54114
|
+
${agentFiles}
|
|
54115
|
+
]
|
|
54116
|
+
|
|
54117
|
+
const agentRegistry: Record<string, ExportedAgent> = {}
|
|
54118
|
+
for (const [filename, json] of agentFiles) {
|
|
54119
|
+
const agent = parseAgent(json, filename)
|
|
54120
|
+
if (agentRegistry[agent.name]) {
|
|
54121
|
+
throw new Error(\`[runtype] duplicate agent name "\${agent.name}" in \${filename}\`)
|
|
54122
|
+
}
|
|
54123
|
+
agentRegistry[agent.name] = agent
|
|
54124
|
+
}
|
|
54125
|
+
|
|
54126
|
+
// ---------------------------------------------------------------------------
|
|
54127
|
+
// Env \u2014 Wrangler injects secrets + bindings here
|
|
54128
|
+
// ---------------------------------------------------------------------------
|
|
54129
|
+
|
|
54130
|
+
export interface Env {
|
|
54131
|
+
// Secrets \u2014 set via \`wrangler secret put <NAME>\`
|
|
54132
|
+
ANTHROPIC_API_KEY?: string
|
|
54133
|
+
OPENAI_API_KEY?: string
|
|
54134
|
+
GOOGLE_API_KEY?: string
|
|
54135
|
+
MIXLAYER_API_KEY?: string
|
|
54136
|
+
// Optional: narrow CORS from * to specific origins (comma-separated)
|
|
54137
|
+
ALLOWED_ORIGINS?: string
|
|
54138
|
+
// Optional: KV namespace binding for durable cross-request caching
|
|
54139
|
+
CACHE_KV?: KVNamespace
|
|
54140
|
+
}
|
|
54141
|
+
|
|
54142
|
+
// ---------------------------------------------------------------------------
|
|
54143
|
+
// Worker
|
|
54144
|
+
// ---------------------------------------------------------------------------
|
|
54145
|
+
|
|
54146
|
+
export default {
|
|
54147
|
+
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
54148
|
+
const url = new URL(request.url)
|
|
54149
|
+
const cors = corsHeaders(request, env.ALLOWED_ORIGINS)
|
|
54150
|
+
|
|
54151
|
+
if (request.method === 'OPTIONS') {
|
|
54152
|
+
return new Response(null, { status: 204, headers: cors })
|
|
54153
|
+
}
|
|
54154
|
+
|
|
54155
|
+
if (request.method === 'GET' && url.pathname === '/health') {
|
|
54156
|
+
return json({ status: 'ok', agents: Object.keys(agentRegistry) }, 200, cors)
|
|
54157
|
+
}
|
|
54158
|
+
|
|
54159
|
+
const agentMatch = url.pathname.match(/^\\/agent\\/([^/]+)$/)
|
|
54160
|
+
if (request.method === 'POST' && agentMatch) {
|
|
54161
|
+
const name = decodeURIComponent(agentMatch[1])
|
|
54162
|
+
if (!agentRegistry[name]) {
|
|
54163
|
+
return json({ error: \`unknown agent: \${name}\` }, 404, cors)
|
|
54164
|
+
}
|
|
54165
|
+
|
|
54166
|
+
const runtime = createRuntime({
|
|
54167
|
+
agents: agentRegistry,
|
|
54168
|
+
keys: { mode: 'own' },
|
|
54169
|
+
adapter: new CloudflareAdapter(env, {
|
|
54170
|
+
kvNamespace: env.CACHE_KV,
|
|
54171
|
+
waitUntil: ctx.waitUntil.bind(ctx),
|
|
54172
|
+
}),
|
|
54173
|
+
})
|
|
54174
|
+
|
|
54175
|
+
let body: { messages?: Array<{ role: string; content: string }> } = {}
|
|
54176
|
+
try {
|
|
54177
|
+
body = (await request.json()) as typeof body
|
|
54178
|
+
} catch {
|
|
54179
|
+
return json({ error: 'request body must be JSON' }, 400, cors)
|
|
54180
|
+
}
|
|
54181
|
+
const messages = Array.isArray(body.messages) ? body.messages : []
|
|
54182
|
+
|
|
54183
|
+
try {
|
|
54184
|
+
const response = await runtime.executeAgent(name, {
|
|
54185
|
+
messages: messages as Array<{
|
|
54186
|
+
role: 'system' | 'user' | 'assistant'
|
|
54187
|
+
content: string
|
|
54188
|
+
}>,
|
|
54189
|
+
signal: request.signal,
|
|
54190
|
+
})
|
|
54191
|
+
const headers = new Headers(response.headers)
|
|
54192
|
+
for (const [k, v] of Object.entries(cors)) headers.set(k, v)
|
|
54193
|
+
return new Response(response.body, { status: response.status, headers })
|
|
54194
|
+
} catch (err) {
|
|
54195
|
+
return json({ error: err instanceof Error ? err.message : 'unknown error' }, 500, cors)
|
|
54196
|
+
}
|
|
54197
|
+
}
|
|
54198
|
+
|
|
54199
|
+
return json({ error: 'not found' }, 404, cors)
|
|
54200
|
+
},
|
|
54201
|
+
}
|
|
54202
|
+
|
|
54203
|
+
// ---------------------------------------------------------------------------
|
|
54204
|
+
// Helpers
|
|
54205
|
+
// ---------------------------------------------------------------------------
|
|
54206
|
+
|
|
54207
|
+
function json(body: unknown, status: number, extra: Record<string, string>): Response {
|
|
54208
|
+
return new Response(JSON.stringify(body), {
|
|
54209
|
+
status,
|
|
54210
|
+
headers: { 'Content-Type': 'application/json', ...extra },
|
|
54211
|
+
})
|
|
54212
|
+
}
|
|
54213
|
+
|
|
54214
|
+
function corsHeaders(request: Request, allowedOriginsEnv?: string): Record<string, string> {
|
|
54215
|
+
const origin = request.headers.get('Origin') ?? ''
|
|
54216
|
+
let allow = '*'
|
|
54217
|
+
if (allowedOriginsEnv) {
|
|
54218
|
+
const list = allowedOriginsEnv.split(',').map((o) => o.trim()).filter(Boolean)
|
|
54219
|
+
allow = list.includes(origin) ? origin : (list[0] ?? '*')
|
|
54220
|
+
}
|
|
54221
|
+
const headers: Record<string, string> = {
|
|
54222
|
+
'Access-Control-Allow-Origin': allow,
|
|
54223
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
54224
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
54225
|
+
'Access-Control-Max-Age': '86400',
|
|
54226
|
+
}
|
|
54227
|
+
if (allow !== '*') headers['Vary'] = 'Origin'
|
|
54228
|
+
return headers
|
|
54229
|
+
}
|
|
54230
|
+
`;
|
|
54231
|
+
}
|
|
54232
|
+
function wranglerToml(projectName) {
|
|
54233
|
+
return `name = "${projectName}"
|
|
54234
|
+
main = "src/index.ts"
|
|
54235
|
+
compatibility_date = "2025-01-01"
|
|
54236
|
+
|
|
54237
|
+
# Secrets \u2014 set via \`wrangler secret put <NAME>\`
|
|
54238
|
+
# Run this for each API key your agents need:
|
|
54239
|
+
# wrangler secret put ANTHROPIC_API_KEY
|
|
54240
|
+
# wrangler secret put OPENAI_API_KEY
|
|
54241
|
+
# wrangler secret put GOOGLE_API_KEY
|
|
54242
|
+
# wrangler secret put MIXLAYER_API_KEY
|
|
54243
|
+
|
|
54244
|
+
# Optional: KV namespace for durable cross-request caching.
|
|
54245
|
+
# Without this the adapter uses a per-isolate in-memory Map (ephemeral).
|
|
54246
|
+
# To enable:
|
|
54247
|
+
# 1. wrangler kv namespace create CACHE_KV
|
|
54248
|
+
# 2. Uncomment the block below and paste the generated id.
|
|
54249
|
+
# [[kv_namespaces]]
|
|
54250
|
+
# binding = "CACHE_KV"
|
|
54251
|
+
# id = "<paste your KV namespace id here>"
|
|
54252
|
+
|
|
54253
|
+
# Optional: Workers AI binding (for @cf/* and workers-ai/* model ids).
|
|
54254
|
+
# [ai]
|
|
54255
|
+
# binding = "AI"
|
|
54256
|
+
|
|
54257
|
+
# CORS: narrow from * to specific origins via ALLOWED_ORIGINS env var.
|
|
54258
|
+
# [vars]
|
|
54259
|
+
# ALLOWED_ORIGINS = "https://yourapp.com,https://persona-chat.dev"
|
|
54260
|
+
`;
|
|
54261
|
+
}
|
|
54262
|
+
function workerPackageJson(name, runtimeDep) {
|
|
54263
|
+
return JSON.stringify(
|
|
54264
|
+
{
|
|
54265
|
+
name,
|
|
54266
|
+
version: "0.0.0",
|
|
54267
|
+
private: true,
|
|
54268
|
+
scripts: {
|
|
54269
|
+
dev: "wrangler dev",
|
|
54270
|
+
deploy: "wrangler deploy",
|
|
54271
|
+
typecheck: "tsc --noEmit"
|
|
54272
|
+
},
|
|
54273
|
+
dependencies: {
|
|
54274
|
+
"@runtypelabs/runtime": runtimeDep
|
|
54275
|
+
},
|
|
54276
|
+
devDependencies: {
|
|
54277
|
+
"@cloudflare/workers-types": "^4.0.0",
|
|
54278
|
+
typescript: "^5.3.3",
|
|
54279
|
+
wrangler: "^4.0.0"
|
|
54280
|
+
}
|
|
54281
|
+
},
|
|
54282
|
+
null,
|
|
54283
|
+
2
|
|
54284
|
+
);
|
|
54285
|
+
}
|
|
54286
|
+
function workerTsconfigJson() {
|
|
54287
|
+
return JSON.stringify(
|
|
54288
|
+
{
|
|
54289
|
+
compilerOptions: {
|
|
54290
|
+
target: "ES2022",
|
|
54291
|
+
module: "ES2022",
|
|
54292
|
+
moduleResolution: "bundler",
|
|
54293
|
+
strict: true,
|
|
54294
|
+
resolveJsonModule: true,
|
|
54295
|
+
types: ["@cloudflare/workers-types"]
|
|
54296
|
+
},
|
|
54297
|
+
include: ["src"]
|
|
54298
|
+
},
|
|
54299
|
+
null,
|
|
54300
|
+
2
|
|
54301
|
+
);
|
|
54302
|
+
}
|
|
54303
|
+
function workerSetupSh(monorepoRoot) {
|
|
54304
|
+
return `#!/usr/bin/env bash
|
|
54305
|
+
# Generated by \`runtype deploy --target cloudflare\`.
|
|
54306
|
+
#
|
|
54307
|
+
# Builds and packs @runtypelabs/runtime from your local monorepo, then
|
|
54308
|
+
# installs all dependencies so you can run \`wrangler dev\` or deploy with
|
|
54309
|
+
# \`wrangler deploy\`.
|
|
54310
|
+
#
|
|
54311
|
+
# Usage (from this directory):
|
|
54312
|
+
# ./setup.sh
|
|
54313
|
+
|
|
54314
|
+
set -euo pipefail
|
|
54315
|
+
|
|
54316
|
+
DEPLOY_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
|
|
54317
|
+
MONOREPO_ROOT=${bashSingleQuote(monorepoRoot)}
|
|
54318
|
+
TARBALL_DIR="\${DEPLOY_DIR}/packages"
|
|
54319
|
+
|
|
54320
|
+
echo "[setup] building @runtypelabs/runtime..."
|
|
54321
|
+
pnpm --dir "\${MONOREPO_ROOT}" --filter @runtypelabs/runtime build
|
|
54322
|
+
|
|
54323
|
+
mkdir -p "\${TARBALL_DIR}"
|
|
54324
|
+
|
|
54325
|
+
echo "[setup] packing @runtypelabs/runtime tarball..."
|
|
54326
|
+
pnpm --dir "\${MONOREPO_ROOT}/packages/runtime" pack \\
|
|
54327
|
+
--pack-destination "\${TARBALL_DIR}"
|
|
54328
|
+
|
|
54329
|
+
RUNTIME_TGZ="$(ls "\${TARBALL_DIR}"/runtypelabs-runtime-*.tgz | head -n 1)"
|
|
54330
|
+
if [ -z "\${RUNTIME_TGZ}" ]; then
|
|
54331
|
+
echo "[setup] error: no tarball produced by pnpm pack" >&2
|
|
54332
|
+
exit 1
|
|
54333
|
+
fi
|
|
54334
|
+
RUNTIME_TGZ_NAME="$(basename "\${RUNTIME_TGZ}")"
|
|
54335
|
+
|
|
54336
|
+
echo "[setup] updating package.json with file: dependency..."
|
|
54337
|
+
node -e "
|
|
54338
|
+
const fs = require('fs');
|
|
54339
|
+
const pkg = JSON.parse(fs.readFileSync('\${DEPLOY_DIR}/package.json', 'utf8'));
|
|
54340
|
+
pkg.dependencies['@runtypelabs/runtime'] = 'file:./packages/\${RUNTIME_TGZ_NAME}';
|
|
54341
|
+
fs.writeFileSync('\${DEPLOY_DIR}/package.json', JSON.stringify(pkg, null, 2) + '\\\\n');
|
|
54342
|
+
"
|
|
54343
|
+
|
|
54344
|
+
echo "[setup] installing dependencies..."
|
|
54345
|
+
npm install --no-audit --no-fund
|
|
54346
|
+
|
|
54347
|
+
echo ""
|
|
54348
|
+
echo "[setup] Done! Next steps:"
|
|
54349
|
+
echo " wrangler dev \u2014 preview locally"
|
|
54350
|
+
echo " wrangler deploy \u2014 deploy to Cloudflare Workers"
|
|
54351
|
+
`;
|
|
54352
|
+
}
|
|
54353
|
+
function workerReadme(agentNames, secretNames) {
|
|
54354
|
+
const agentList = agentNames.map((n) => ` - ${n}`).join("\n");
|
|
54355
|
+
const secretList = secretNames.length > 0 ? secretNames.map((s) => ` wrangler secret put ${s}`).join("\n") : " (none detected)";
|
|
54356
|
+
return `# Runtype Cloudflare Workers Deployment
|
|
54357
|
+
|
|
54358
|
+
Generated by \`runtype deploy --target cloudflare\`. Contains the following agents:
|
|
54359
|
+
|
|
54360
|
+
${agentList}
|
|
54361
|
+
|
|
54362
|
+
## Setup
|
|
54363
|
+
|
|
54364
|
+
\`\`\`bash
|
|
54365
|
+
chmod +x setup.sh && ./setup.sh # build runtime + install deps
|
|
54366
|
+
\`\`\`
|
|
54367
|
+
|
|
54368
|
+
## Secrets
|
|
54369
|
+
|
|
54370
|
+
Set each API key your agents use:
|
|
54371
|
+
|
|
54372
|
+
\`\`\`bash
|
|
54373
|
+
${secretList}
|
|
54374
|
+
\`\`\`
|
|
54375
|
+
|
|
54376
|
+
## Run locally
|
|
54377
|
+
|
|
54378
|
+
\`\`\`bash
|
|
54379
|
+
wrangler dev
|
|
54380
|
+
\`\`\`
|
|
54381
|
+
|
|
54382
|
+
## Deploy
|
|
54383
|
+
|
|
54384
|
+
\`\`\`bash
|
|
54385
|
+
wrangler deploy
|
|
54386
|
+
\`\`\`
|
|
54387
|
+
|
|
54388
|
+
## Health check
|
|
54389
|
+
|
|
54390
|
+
\`GET /health\` returns \`{"status":"ok","agents":[...]}\`.
|
|
54391
|
+
|
|
54392
|
+
## Call an agent
|
|
54393
|
+
|
|
54394
|
+
\`\`\`bash
|
|
54395
|
+
curl https://<worker-subdomain>.workers.dev/agent/<name> \\
|
|
54396
|
+
-H 'Content-Type: application/json' \\
|
|
54397
|
+
-d '{"messages":[{"role":"user","content":"Hello"}]}'
|
|
54398
|
+
\`\`\`
|
|
54399
|
+
`;
|
|
54400
|
+
}
|
|
54401
|
+
function vercelRouteTs(agentSlugs) {
|
|
54402
|
+
const imports = agentSlugs.map((slug, i) => `import agent${i}Json from '../agents/${slug}.json'`).join("\n");
|
|
54403
|
+
const agentFiles = agentSlugs.map((slug, i) => ` ['${slug}.json', agent${i}Json],`).join("\n");
|
|
54404
|
+
return `/**
|
|
54405
|
+
* Generated by \`runtype deploy --target vercel\`.
|
|
54406
|
+
*
|
|
54407
|
+
* Catch-all Vercel Function. All traffic is rewritten here by vercel.json.
|
|
54408
|
+
* Routes:
|
|
54409
|
+
* GET /health \u2014 liveness probe (lists registered agent names)
|
|
54410
|
+
* POST /agent/:name \u2014 SSE stream of the agent event schema
|
|
54411
|
+
*
|
|
54412
|
+
* Agent definitions are statically imported and bundled by Vercel.
|
|
54413
|
+
* To add a new agent:
|
|
54414
|
+
* 1. Export it with \`runtype deploy --agent <id> --target vercel\`
|
|
54415
|
+
* 2. Or drop a JSON file under agents/ and add an import + entry below
|
|
54416
|
+
* 3. Run \`vercel deploy\`
|
|
54417
|
+
*/
|
|
54418
|
+
import { Hono } from 'hono'
|
|
54419
|
+
import { handle } from 'hono/vercel'
|
|
54420
|
+
import { cors } from 'hono/cors'
|
|
54421
|
+
import {
|
|
54422
|
+
VercelAdapter,
|
|
54423
|
+
createRuntime,
|
|
54424
|
+
exportedAgentSchema,
|
|
54425
|
+
type ExportedAgent,
|
|
54426
|
+
} from '@runtypelabs/runtime'
|
|
54427
|
+
|
|
54428
|
+
// ---------------------------------------------------------------------------
|
|
54429
|
+
// Agent registry \u2014 built at module load, cached across warm invocations
|
|
54430
|
+
// ---------------------------------------------------------------------------
|
|
54431
|
+
|
|
54432
|
+
${imports}
|
|
54433
|
+
|
|
54434
|
+
function parseAgent(json: unknown, filename: string): ExportedAgent {
|
|
54435
|
+
try {
|
|
54436
|
+
return exportedAgentSchema.parse(json)
|
|
54437
|
+
} catch (err) {
|
|
54438
|
+
throw new Error(
|
|
54439
|
+
\`[runtype] invalid agent JSON in \${filename}: \${
|
|
54440
|
+
err instanceof Error ? err.message : String(err)
|
|
54441
|
+
}\`
|
|
54442
|
+
)
|
|
54443
|
+
}
|
|
54444
|
+
}
|
|
54445
|
+
|
|
54446
|
+
const agentFiles: Array<[string, unknown]> = [
|
|
54447
|
+
${agentFiles}
|
|
54448
|
+
]
|
|
54449
|
+
|
|
54450
|
+
const agentRegistry: Record<string, ExportedAgent> = {}
|
|
54451
|
+
for (const [filename, json] of agentFiles) {
|
|
54452
|
+
const agent = parseAgent(json, filename)
|
|
54453
|
+
if (agentRegistry[agent.name]) {
|
|
54454
|
+
throw new Error(\`[runtype] duplicate agent name "\${agent.name}" in \${filename}\`)
|
|
54455
|
+
}
|
|
54456
|
+
agentRegistry[agent.name] = agent
|
|
54457
|
+
}
|
|
54458
|
+
|
|
54459
|
+
// ---------------------------------------------------------------------------
|
|
54460
|
+
// Runtime \u2014 constructed at module scope (warm across invocations)
|
|
54461
|
+
// ---------------------------------------------------------------------------
|
|
54462
|
+
|
|
54463
|
+
const runtime = createRuntime({
|
|
54464
|
+
agents: agentRegistry,
|
|
54465
|
+
keys: { mode: 'own' },
|
|
54466
|
+
adapter: new VercelAdapter(),
|
|
54467
|
+
})
|
|
54468
|
+
|
|
54469
|
+
// ---------------------------------------------------------------------------
|
|
54470
|
+
// Hono app
|
|
54471
|
+
// ---------------------------------------------------------------------------
|
|
54472
|
+
|
|
54473
|
+
const app = new Hono()
|
|
54474
|
+
|
|
54475
|
+
const allowedOriginsEnv = process.env.ALLOWED_ORIGINS?.trim()
|
|
54476
|
+
const allowedOrigins = allowedOriginsEnv
|
|
54477
|
+
? allowedOriginsEnv.split(',').map((o) => o.trim()).filter(Boolean)
|
|
54478
|
+
: '*'
|
|
54479
|
+
|
|
54480
|
+
app.use(
|
|
54481
|
+
'*',
|
|
54482
|
+
cors({
|
|
54483
|
+
origin: allowedOrigins,
|
|
54484
|
+
allowMethods: ['GET', 'POST', 'OPTIONS'],
|
|
54485
|
+
allowHeaders: ['Content-Type', 'Authorization'],
|
|
54486
|
+
maxAge: 86400,
|
|
54487
|
+
})
|
|
54488
|
+
)
|
|
54489
|
+
|
|
54490
|
+
app.get('/health', (c) => c.json({ status: 'ok', agents: Object.keys(agentRegistry) }))
|
|
54491
|
+
|
|
54492
|
+
app.post('/agent/:name', async (c) => {
|
|
54493
|
+
const name = c.req.param('name')
|
|
54494
|
+
if (!runtime.getAgent(name)) {
|
|
54495
|
+
return c.json({ error: \`unknown agent: \${name}\` }, 404)
|
|
54496
|
+
}
|
|
54497
|
+
|
|
54498
|
+
let body: { messages?: Array<{ role: string; content: string }> } = {}
|
|
54499
|
+
try {
|
|
54500
|
+
body = (await c.req.json()) as typeof body
|
|
54501
|
+
} catch {
|
|
54502
|
+
return c.json({ error: 'request body must be JSON' }, 400)
|
|
54503
|
+
}
|
|
54504
|
+
const messages = Array.isArray(body.messages) ? body.messages : []
|
|
54505
|
+
|
|
54506
|
+
try {
|
|
54507
|
+
const response = await runtime.executeAgent(name, {
|
|
54508
|
+
messages: messages as Array<{
|
|
54509
|
+
role: 'system' | 'user' | 'assistant'
|
|
54510
|
+
content: string
|
|
54511
|
+
}>,
|
|
54512
|
+
signal: c.req.raw.signal,
|
|
54513
|
+
})
|
|
54514
|
+
return response
|
|
54515
|
+
} catch (err) {
|
|
54516
|
+
return c.json({ error: err instanceof Error ? err.message : 'unknown error' }, 500)
|
|
54517
|
+
}
|
|
54518
|
+
})
|
|
54519
|
+
|
|
54520
|
+
export const GET = handle(app)
|
|
54521
|
+
export const POST = handle(app)
|
|
54522
|
+
`;
|
|
54523
|
+
}
|
|
54524
|
+
function vercelJson() {
|
|
54525
|
+
return JSON.stringify(
|
|
54526
|
+
{
|
|
54527
|
+
rewrites: [{ source: "/(.*)", destination: "/api/[[...route]]" }],
|
|
54528
|
+
functions: {
|
|
54529
|
+
"api/[[...route]].ts": { maxDuration: 60 }
|
|
54530
|
+
}
|
|
54531
|
+
},
|
|
54532
|
+
null,
|
|
54533
|
+
2
|
|
54534
|
+
);
|
|
54535
|
+
}
|
|
54536
|
+
function vercelPackageJson(name, runtimeDep) {
|
|
54537
|
+
return JSON.stringify(
|
|
54538
|
+
{
|
|
54539
|
+
name,
|
|
54540
|
+
version: "0.0.0",
|
|
54541
|
+
private: true,
|
|
54542
|
+
scripts: {
|
|
54543
|
+
dev: "vercel dev",
|
|
54544
|
+
deploy: "vercel deploy",
|
|
54545
|
+
typecheck: "tsc --noEmit"
|
|
54546
|
+
},
|
|
54547
|
+
dependencies: {
|
|
54548
|
+
"@runtypelabs/runtime": runtimeDep,
|
|
54549
|
+
hono: "^4.12.16"
|
|
54550
|
+
},
|
|
54551
|
+
devDependencies: {
|
|
54552
|
+
"@types/node": "^22.0.0",
|
|
54553
|
+
"@vercel/node": "^5.0.0",
|
|
54554
|
+
typescript: "^5.3.3",
|
|
54555
|
+
vercel: "^44.0.0"
|
|
54556
|
+
}
|
|
54557
|
+
},
|
|
54558
|
+
null,
|
|
54559
|
+
2
|
|
54560
|
+
);
|
|
54561
|
+
}
|
|
54562
|
+
function vercelTsconfigJson() {
|
|
54563
|
+
return JSON.stringify(
|
|
54564
|
+
{
|
|
54565
|
+
compilerOptions: {
|
|
54566
|
+
target: "ES2022",
|
|
54567
|
+
module: "ESNext",
|
|
54568
|
+
moduleResolution: "bundler",
|
|
54569
|
+
strict: true,
|
|
54570
|
+
resolveJsonModule: true,
|
|
54571
|
+
esModuleInterop: true,
|
|
54572
|
+
skipLibCheck: true
|
|
54573
|
+
},
|
|
54574
|
+
include: ["api"]
|
|
54575
|
+
},
|
|
54576
|
+
null,
|
|
54577
|
+
2
|
|
54578
|
+
);
|
|
54579
|
+
}
|
|
54580
|
+
function vercelSetupSh(monorepoRoot) {
|
|
54581
|
+
return `#!/usr/bin/env bash
|
|
54582
|
+
# Generated by \`runtype deploy --target vercel\`.
|
|
54583
|
+
#
|
|
54584
|
+
# Builds and packs @runtypelabs/runtime from your local monorepo, then
|
|
54585
|
+
# installs all dependencies so you can run \`vercel dev\` or deploy with
|
|
54586
|
+
# \`vercel deploy\`.
|
|
54587
|
+
#
|
|
54588
|
+
# Usage (from this directory):
|
|
54589
|
+
# ./setup.sh
|
|
54590
|
+
|
|
54591
|
+
set -euo pipefail
|
|
54592
|
+
|
|
54593
|
+
DEPLOY_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
|
|
54594
|
+
MONOREPO_ROOT=${bashSingleQuote(monorepoRoot)}
|
|
54595
|
+
TARBALL_DIR="\${DEPLOY_DIR}/packages"
|
|
54596
|
+
|
|
54597
|
+
echo "[setup] building @runtypelabs/runtime..."
|
|
54598
|
+
pnpm --dir "\${MONOREPO_ROOT}" --filter @runtypelabs/runtime build
|
|
54599
|
+
|
|
54600
|
+
mkdir -p "\${TARBALL_DIR}"
|
|
54601
|
+
|
|
54602
|
+
echo "[setup] packing @runtypelabs/runtime tarball..."
|
|
54603
|
+
pnpm --dir "\${MONOREPO_ROOT}/packages/runtime" pack \\
|
|
54604
|
+
--pack-destination "\${TARBALL_DIR}"
|
|
54605
|
+
|
|
54606
|
+
RUNTIME_TGZ="$(ls "\${TARBALL_DIR}"/runtypelabs-runtime-*.tgz | head -n 1)"
|
|
54607
|
+
if [ -z "\${RUNTIME_TGZ}" ]; then
|
|
54608
|
+
echo "[setup] error: no tarball produced by pnpm pack" >&2
|
|
54609
|
+
exit 1
|
|
54610
|
+
fi
|
|
54611
|
+
RUNTIME_TGZ_NAME="$(basename "\${RUNTIME_TGZ}")"
|
|
54612
|
+
|
|
54613
|
+
echo "[setup] updating package.json with file: dependency..."
|
|
54614
|
+
node -e "
|
|
54615
|
+
const fs = require('fs');
|
|
54616
|
+
const pkg = JSON.parse(fs.readFileSync('\${DEPLOY_DIR}/package.json', 'utf8'));
|
|
54617
|
+
pkg.dependencies['@runtypelabs/runtime'] = 'file:./packages/\${RUNTIME_TGZ_NAME}';
|
|
54618
|
+
fs.writeFileSync('\${DEPLOY_DIR}/package.json', JSON.stringify(pkg, null, 2) + '\\\\n');
|
|
54619
|
+
"
|
|
54620
|
+
|
|
54621
|
+
echo "[setup] installing dependencies..."
|
|
54622
|
+
npm install --no-audit --no-fund
|
|
54623
|
+
|
|
54624
|
+
echo ""
|
|
54625
|
+
echo "[setup] Done! Next steps:"
|
|
54626
|
+
echo " vercel dev \u2014 preview locally"
|
|
54627
|
+
echo " vercel deploy \u2014 deploy to Vercel Functions"
|
|
54628
|
+
`;
|
|
54629
|
+
}
|
|
54630
|
+
function vercelReadme(agentNames, secretNames) {
|
|
54631
|
+
const agentList = agentNames.map((n) => ` - ${n}`).join("\n");
|
|
54632
|
+
const secretList = secretNames.length > 0 ? secretNames.map((s) => ` vercel env add ${s}`).join("\n") : " (none detected)";
|
|
54633
|
+
return `# Runtype Vercel Functions Deployment
|
|
54634
|
+
|
|
54635
|
+
Generated by \`runtype deploy --target vercel\`. Contains the following agents:
|
|
54636
|
+
|
|
54637
|
+
${agentList}
|
|
54638
|
+
|
|
54639
|
+
## Setup
|
|
54640
|
+
|
|
54641
|
+
\`\`\`bash
|
|
54642
|
+
chmod +x setup.sh && ./setup.sh # build runtime + install deps
|
|
54643
|
+
\`\`\`
|
|
54644
|
+
|
|
54645
|
+
## Secrets
|
|
54646
|
+
|
|
54647
|
+
Set each API key your agents use via the Vercel dashboard or CLI:
|
|
54648
|
+
|
|
54649
|
+
\`\`\`bash
|
|
54650
|
+
${secretList}
|
|
54651
|
+
\`\`\`
|
|
54652
|
+
|
|
54653
|
+
## Run locally
|
|
54654
|
+
|
|
54655
|
+
\`\`\`bash
|
|
54656
|
+
vercel dev
|
|
54657
|
+
\`\`\`
|
|
54658
|
+
|
|
54659
|
+
## Deploy
|
|
54660
|
+
|
|
54661
|
+
\`\`\`bash
|
|
54662
|
+
vercel deploy
|
|
54663
|
+
\`\`\`
|
|
54664
|
+
|
|
54665
|
+
## Health check
|
|
54666
|
+
|
|
54667
|
+
\`GET /health\` returns \`{"status":"ok","agents":[...]}\`.
|
|
54668
|
+
|
|
54669
|
+
## Call an agent
|
|
54670
|
+
|
|
54671
|
+
\`\`\`bash
|
|
54672
|
+
curl https://<your-project>.vercel.app/agent/<name> \\
|
|
54673
|
+
-H 'Content-Type: application/json' \\
|
|
54674
|
+
-d '{"messages":[{"role":"user","content":"Hello"}]}'
|
|
54675
|
+
\`\`\`
|
|
54676
|
+
`;
|
|
54677
|
+
}
|
|
53973
54678
|
function collectSecretNames(agentDef) {
|
|
53974
54679
|
const names = /* @__PURE__ */ new Set();
|
|
53975
54680
|
const model = agentDef.config?.model?.toLowerCase();
|
|
@@ -53992,13 +54697,13 @@ function collectSecretNames(agentDef) {
|
|
|
53992
54697
|
function slugify2(s) {
|
|
53993
54698
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63);
|
|
53994
54699
|
}
|
|
53995
|
-
var deployCommand = new Command24("deploy").description("Export an agent or flow and scaffold a
|
|
54700
|
+
var deployCommand = new Command24("deploy").description("Export an agent or flow and scaffold a deployment (cloud-run, cloudflare, or vercel)").option("--agent <id>", "Agent ID to export (may be repeated)", (v, acc) => {
|
|
53996
54701
|
acc.push(v);
|
|
53997
54702
|
return acc;
|
|
53998
54703
|
}, []).option("--flow <id>", "Flow ID to export (may be repeated)", (v, acc) => {
|
|
53999
54704
|
acc.push(v);
|
|
54000
54705
|
return acc;
|
|
54001
|
-
}, []).option("--output <dir>", "Output directory for the scaffold (default: ./runtype-deploy)", "./runtype-deploy").option("--name <name>", "Project name used in package.json (default: derived from output dir)").action(
|
|
54706
|
+
}, []).option("--output <dir>", "Output directory for the scaffold (default: ./runtype-deploy)", "./runtype-deploy").option("--name <name>", "Project name used in package.json (default: derived from output dir)").option("--target <target>", "Deployment target: cloud-run, cloudflare, or vercel (default: cloud-run)", "cloud-run").action(
|
|
54002
54707
|
async (options) => {
|
|
54003
54708
|
const agentIds = options.agent;
|
|
54004
54709
|
const flowIds = options.flow;
|
|
@@ -54006,13 +54711,18 @@ var deployCommand = new Command24("deploy").description("Export an agent or flow
|
|
|
54006
54711
|
console.error(chalk30.red("Error: provide at least one --agent <id> or --flow <id>"));
|
|
54007
54712
|
process.exit(1);
|
|
54008
54713
|
}
|
|
54714
|
+
const target = options.target;
|
|
54715
|
+
if (target !== "cloud-run" && target !== "cloudflare" && target !== "vercel") {
|
|
54716
|
+
console.error(chalk30.red(`Error: unknown --target "${target}". Must be one of: cloud-run, cloudflare, vercel`));
|
|
54717
|
+
process.exit(1);
|
|
54718
|
+
}
|
|
54009
54719
|
const apiKey = await ensureAuth();
|
|
54010
54720
|
if (!apiKey) return;
|
|
54011
54721
|
const client = new ApiClient(apiKey);
|
|
54012
54722
|
const outDir = path14.resolve(options.output);
|
|
54013
54723
|
const projectName = options.name ?? slugify2(path14.basename(outDir));
|
|
54014
54724
|
console.log(chalk30.cyan(`
|
|
54015
|
-
Scaffolding deployment to ${outDir}
|
|
54725
|
+
Scaffolding ${target} deployment to ${outDir}
|
|
54016
54726
|
`));
|
|
54017
54727
|
const agentDefs = [];
|
|
54018
54728
|
for (const id of agentIds) {
|
|
@@ -54063,36 +54773,26 @@ Scaffolding deployment to ${outDir}
|
|
|
54063
54773
|
process.exit(1);
|
|
54064
54774
|
}
|
|
54065
54775
|
}
|
|
54776
|
+
const agentSlugs = agentDefs.map(({ name }) => slugify2(name));
|
|
54777
|
+
const slugSet = /* @__PURE__ */ new Set();
|
|
54778
|
+
for (let i = 0; i < agentSlugs.length; i++) {
|
|
54779
|
+
const slug = agentSlugs[i];
|
|
54780
|
+
if (slugSet.has(slug)) {
|
|
54781
|
+
const colliders = agentDefs.filter(({ name }) => slugify2(name) === slug).map(({ name }) => `"${name}"`).join(" and ");
|
|
54782
|
+
console.error(chalk30.red(`Error: agents ${colliders} produce the same slug "${slug}".`));
|
|
54783
|
+
console.error(chalk30.yellow(" Rename one of them in the Runtype dashboard to make slugs unique."));
|
|
54784
|
+
process.exit(1);
|
|
54785
|
+
}
|
|
54786
|
+
slugSet.add(slug);
|
|
54787
|
+
}
|
|
54066
54788
|
fs14.mkdirSync(path14.join(outDir, "agents"), { recursive: true });
|
|
54067
54789
|
fs14.mkdirSync(path14.join(outDir, "packages"), { recursive: true });
|
|
54068
54790
|
for (const { name, def } of agentDefs) {
|
|
54069
54791
|
const filename = `${slugify2(name)}.json`;
|
|
54070
|
-
fs14.writeFileSync(
|
|
54071
|
-
path14.join(outDir, "agents", filename),
|
|
54072
|
-
JSON.stringify(def, null, 2)
|
|
54073
|
-
);
|
|
54792
|
+
fs14.writeFileSync(path14.join(outDir, "agents", filename), JSON.stringify(def, null, 2));
|
|
54074
54793
|
console.log(` Wrote agents/${filename}`);
|
|
54075
54794
|
}
|
|
54076
|
-
|
|
54077
|
-
path14.join(outDir, "server.ts"),
|
|
54078
|
-
serverTs()
|
|
54079
|
-
);
|
|
54080
|
-
fs14.writeFileSync(
|
|
54081
|
-
path14.join(outDir, "Dockerfile"),
|
|
54082
|
-
dockerfile()
|
|
54083
|
-
);
|
|
54084
|
-
fs14.writeFileSync(
|
|
54085
|
-
path14.join(outDir, ".dockerignore"),
|
|
54086
|
-
dockerignore()
|
|
54087
|
-
);
|
|
54088
|
-
fs14.writeFileSync(
|
|
54089
|
-
path14.join(outDir, "tsconfig.json"),
|
|
54090
|
-
tsconfigJson()
|
|
54091
|
-
);
|
|
54092
|
-
fs14.writeFileSync(
|
|
54093
|
-
path14.join(outDir, "package.json"),
|
|
54094
|
-
packageJson(projectName, "workspace:*")
|
|
54095
|
-
);
|
|
54795
|
+
const agentNames = agentDefs.map((a) => a.name);
|
|
54096
54796
|
let monorepoRoot = process.cwd();
|
|
54097
54797
|
for (let i = 0; i < 8; i++) {
|
|
54098
54798
|
if (fs14.existsSync(path14.join(monorepoRoot, "pnpm-workspace.yaml"))) break;
|
|
@@ -54100,46 +54800,90 @@ Scaffolding deployment to ${outDir}
|
|
|
54100
54800
|
if (parent === monorepoRoot) break;
|
|
54101
54801
|
monorepoRoot = parent;
|
|
54102
54802
|
}
|
|
54103
|
-
const setupScript = setupSh(monorepoRoot);
|
|
54104
|
-
const setupPath = path14.join(outDir, "setup.sh");
|
|
54105
|
-
fs14.writeFileSync(setupPath, setupScript);
|
|
54106
|
-
fs14.chmodSync(setupPath, 493);
|
|
54107
54803
|
const allSecrets = /* @__PURE__ */ new Set();
|
|
54108
54804
|
for (const { def } of agentDefs) {
|
|
54109
54805
|
for (const s of collectSecretNames(def)) allSecrets.add(s);
|
|
54110
54806
|
}
|
|
54111
54807
|
const secretNames = Array.from(allSecrets);
|
|
54112
|
-
|
|
54113
|
-
path14.join(outDir, "
|
|
54114
|
-
|
|
54115
|
-
|
|
54116
|
-
|
|
54117
|
-
)
|
|
54118
|
-
|
|
54808
|
+
if (target === "cloudflare") {
|
|
54809
|
+
fs14.mkdirSync(path14.join(outDir, "src"), { recursive: true });
|
|
54810
|
+
fs14.writeFileSync(path14.join(outDir, "src", "index.ts"), workerIndexTs(agentSlugs));
|
|
54811
|
+
fs14.writeFileSync(path14.join(outDir, "wrangler.toml"), wranglerToml(projectName));
|
|
54812
|
+
fs14.writeFileSync(path14.join(outDir, "package.json"), workerPackageJson(projectName, "workspace:*"));
|
|
54813
|
+
fs14.writeFileSync(path14.join(outDir, "tsconfig.json"), workerTsconfigJson());
|
|
54814
|
+
const setupPath = path14.join(outDir, "setup.sh");
|
|
54815
|
+
fs14.writeFileSync(setupPath, workerSetupSh(monorepoRoot));
|
|
54816
|
+
fs14.chmodSync(setupPath, 493);
|
|
54817
|
+
fs14.writeFileSync(path14.join(outDir, "README.md"), workerReadme(agentNames, secretNames));
|
|
54818
|
+
} else if (target === "vercel") {
|
|
54819
|
+
fs14.mkdirSync(path14.join(outDir, "api"), { recursive: true });
|
|
54820
|
+
fs14.writeFileSync(path14.join(outDir, "api", "[[...route]].ts"), vercelRouteTs(agentSlugs));
|
|
54821
|
+
fs14.writeFileSync(path14.join(outDir, "vercel.json"), vercelJson());
|
|
54822
|
+
fs14.writeFileSync(path14.join(outDir, "package.json"), vercelPackageJson(projectName, "workspace:*"));
|
|
54823
|
+
fs14.writeFileSync(path14.join(outDir, "tsconfig.json"), vercelTsconfigJson());
|
|
54824
|
+
const setupPath = path14.join(outDir, "setup.sh");
|
|
54825
|
+
fs14.writeFileSync(setupPath, vercelSetupSh(monorepoRoot));
|
|
54826
|
+
fs14.chmodSync(setupPath, 493);
|
|
54827
|
+
fs14.writeFileSync(path14.join(outDir, "README.md"), vercelReadme(agentNames, secretNames));
|
|
54828
|
+
} else {
|
|
54829
|
+
fs14.writeFileSync(path14.join(outDir, "server.ts"), serverTs());
|
|
54830
|
+
fs14.writeFileSync(path14.join(outDir, "Dockerfile"), dockerfile());
|
|
54831
|
+
fs14.writeFileSync(path14.join(outDir, ".dockerignore"), dockerignore());
|
|
54832
|
+
fs14.writeFileSync(path14.join(outDir, "tsconfig.json"), tsconfigJson());
|
|
54833
|
+
fs14.writeFileSync(path14.join(outDir, "package.json"), packageJson(projectName, "workspace:*"));
|
|
54834
|
+
const setupPath = path14.join(outDir, "setup.sh");
|
|
54835
|
+
fs14.writeFileSync(setupPath, setupSh(monorepoRoot));
|
|
54836
|
+
fs14.chmodSync(setupPath, 493);
|
|
54837
|
+
fs14.writeFileSync(path14.join(outDir, "README.md"), readme(agentNames, secretNames));
|
|
54838
|
+
}
|
|
54119
54839
|
console.log("");
|
|
54120
54840
|
console.log(chalk30.green(`\u2713 Scaffold written to ${outDir}`));
|
|
54121
54841
|
console.log("");
|
|
54122
54842
|
console.log(chalk30.bold("Next steps:"));
|
|
54123
54843
|
console.log(` cd ${options.output}`);
|
|
54124
54844
|
console.log(" chmod +x setup.sh && ./setup.sh # pack runtime + install deps");
|
|
54125
|
-
|
|
54126
|
-
|
|
54127
|
-
|
|
54128
|
-
|
|
54129
|
-
|
|
54130
|
-
|
|
54845
|
+
if (target === "cloudflare") {
|
|
54846
|
+
console.log(" wrangler dev # test locally");
|
|
54847
|
+
console.log("");
|
|
54848
|
+
if (secretNames.length > 0) {
|
|
54849
|
+
console.log(chalk30.yellow("Required secrets (set via wrangler):"));
|
|
54850
|
+
for (const s of secretNames) {
|
|
54851
|
+
console.log(` wrangler secret put ${chalk30.cyan(s)}`);
|
|
54852
|
+
}
|
|
54853
|
+
console.log("");
|
|
54131
54854
|
}
|
|
54855
|
+
console.log("Deploy to Cloudflare Workers:");
|
|
54856
|
+
console.log(" wrangler deploy");
|
|
54857
|
+
} else if (target === "vercel") {
|
|
54858
|
+
console.log(" vercel dev # test locally");
|
|
54132
54859
|
console.log("");
|
|
54133
|
-
|
|
54134
|
-
|
|
54860
|
+
if (secretNames.length > 0) {
|
|
54861
|
+
console.log(chalk30.yellow("Required secrets (set via Vercel):"));
|
|
54862
|
+
for (const s of secretNames) {
|
|
54863
|
+
console.log(` vercel env add ${chalk30.cyan(s)}`);
|
|
54864
|
+
}
|
|
54865
|
+
console.log("");
|
|
54866
|
+
}
|
|
54867
|
+
console.log("Deploy to Vercel Functions:");
|
|
54868
|
+
console.log(" vercel deploy");
|
|
54869
|
+
} else {
|
|
54870
|
+
console.log(" npm run dev # test locally");
|
|
54135
54871
|
console.log("");
|
|
54872
|
+
if (secretNames.length > 0) {
|
|
54873
|
+
console.log(chalk30.yellow("Required secrets (set before deploying):"));
|
|
54874
|
+
for (const s of secretNames) {
|
|
54875
|
+
console.log(` ${chalk30.cyan(s)}`);
|
|
54876
|
+
}
|
|
54877
|
+
console.log("");
|
|
54878
|
+
console.log(" Set via Cloud Run: gcloud run deploy \u2026 --set-secrets KEY=NAME:latest");
|
|
54879
|
+
console.log(" Or export locally: export KEY=<value>");
|
|
54880
|
+
console.log("");
|
|
54881
|
+
}
|
|
54882
|
+
console.log("Deploy to Cloud Run:");
|
|
54883
|
+
console.log(` gcloud run deploy ${projectName} --source ${options.output} \\`);
|
|
54884
|
+
console.log(" --region us-central1 --platform managed \\");
|
|
54885
|
+
console.log(" --allow-unauthenticated --port 8080");
|
|
54136
54886
|
}
|
|
54137
|
-
console.log("Deploy to Cloud Run:");
|
|
54138
|
-
console.log(
|
|
54139
|
-
` gcloud run deploy ${projectName} --source ${options.output} \\`
|
|
54140
|
-
);
|
|
54141
|
-
console.log(" --region us-central1 --platform managed \\");
|
|
54142
|
-
console.log(" --allow-unauthenticated --port 8080");
|
|
54143
54887
|
}
|
|
54144
54888
|
);
|
|
54145
54889
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runtypelabs/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.1",
|
|
4
4
|
"description": "Command-line interface for Runtype AI platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"micromatch": "^4.0.8",
|
|
22
22
|
"yaml": "^2.8.3",
|
|
23
23
|
"@runtypelabs/ink-components": "0.3.1",
|
|
24
|
-
"@runtypelabs/sdk": "1.
|
|
24
|
+
"@runtypelabs/sdk": "1.24.1",
|
|
25
25
|
"@runtypelabs/terminal-animations": "0.2.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|