@flue/sdk 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -15
- package/dist/agent-BYG0nVbQ.mjs +432 -0
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +5 -2
- package/dist/cloudflare/index.d.mts +1 -1
- package/dist/cloudflare/index.mjs +2 -1
- package/dist/index.d.mts +2 -13
- package/dist/index.mjs +88 -72
- package/dist/internal.d.mts +15 -0
- package/dist/internal.mjs +6 -0
- package/dist/sandbox.d.mts +1 -1
- package/dist/sandbox.mjs +2 -1
- package/dist/{session-BD0MEuO3.mjs → session-BRLCNVG1.mjs} +38 -413
- package/dist/{types-xNvqlohs.d.mts → types-C8tsaK1j.d.mts} +18 -9
- package/package.json +5 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { createFlueContext } from "./client.mjs";
|
|
1
|
+
import { a as parseFrontmatterFile, n as createTools, t as BUILTIN_TOOL_NAMES } from "./agent-BYG0nVbQ.mjs";
|
|
3
2
|
import * as esbuild from "esbuild";
|
|
4
3
|
import * as fs from "node:fs";
|
|
5
4
|
import * as path from "node:path";
|
|
@@ -9,56 +8,57 @@ import { packageUpSync } from "package-up";
|
|
|
9
8
|
var CloudflarePlugin = class {
|
|
10
9
|
name = "cloudflare";
|
|
11
10
|
generateEntryPoint(ctx) {
|
|
12
|
-
const { agents, roles
|
|
13
|
-
const modelProvider = options.model?.provider ?? "anthropic";
|
|
14
|
-
const modelId = options.model?.modelId ?? "claude-haiku-4-5";
|
|
11
|
+
const { agents, roles } = ctx;
|
|
15
12
|
const rolesJson = JSON.stringify(roles);
|
|
16
13
|
const webhookAgents = agents.filter((a) => a.triggers.webhook);
|
|
17
|
-
const agentImports = agents.map((a) => {
|
|
18
|
-
return `import ${agentVarName$1(a.name)} from '${a.filePath.replace(/\\/g, "/")}';`;
|
|
19
|
-
}).join("\n");
|
|
20
|
-
const manifest = JSON.stringify({ agents: agents.map((a) => ({
|
|
21
|
-
name: a.name,
|
|
22
|
-
triggers: a.triggers
|
|
23
|
-
})) }, null, 2);
|
|
24
|
-
const agentClasses = webhookAgents.map((a) => {
|
|
25
|
-
const className = agentClassName(a.name);
|
|
26
|
-
const handlerVar = agentVarName$1(a.name);
|
|
27
|
-
return `export class ${className} extends Agent {
|
|
28
|
-
async onRequest(request) {
|
|
29
|
-
return handleAgentRequest(request, this, ${JSON.stringify(a.name)}, ${handlerVar});
|
|
30
|
-
}
|
|
31
|
-
}`;
|
|
32
|
-
}).join("\n\n");
|
|
33
14
|
return `
|
|
34
15
|
// Auto-generated by @flue/sdk build (cloudflare)
|
|
35
16
|
import { Agent, routeAgentRequest } from 'agents';
|
|
36
17
|
import { Bash, InMemoryFs } from 'just-bash';
|
|
37
18
|
import { getModel } from '@mariozechner/pi-ai';
|
|
38
|
-
import { createFlueContext } from '
|
|
39
|
-
import { InMemorySessionStore } from '${resolveSDKImport("session")}';
|
|
40
|
-
import { bashToSessionEnv } from '${resolveSDKImport("sandbox")}';
|
|
19
|
+
import { createFlueContext, InMemorySessionStore, bashToSessionEnv } from '@flue/sdk/internal';
|
|
41
20
|
import { setCloudflareContext, clearCloudflareContext, cfSandboxToSessionEnv } from '@flue/sdk/cloudflare';
|
|
42
21
|
|
|
43
|
-
${
|
|
22
|
+
${agents.map((a) => {
|
|
23
|
+
return `import ${agentVarName$1(a.name)} from '${a.filePath.replace(/\\/g, "/")}';`;
|
|
24
|
+
}).join("\n")}
|
|
44
25
|
|
|
45
26
|
// ─── Config ─────────────────────────────────────────────────────────────────
|
|
46
27
|
|
|
47
28
|
const roles = ${rolesJson};
|
|
48
29
|
const skills = {};
|
|
49
30
|
const systemPrompt = '';
|
|
50
|
-
const manifest = ${
|
|
31
|
+
const manifest = ${JSON.stringify({ agents: agents.map((a) => ({
|
|
32
|
+
name: a.name,
|
|
33
|
+
triggers: a.triggers
|
|
34
|
+
})) }, null, 2)};
|
|
51
35
|
|
|
52
36
|
// ─── Infrastructure ─────────────────────────────────────────────────────────
|
|
53
37
|
|
|
54
|
-
|
|
38
|
+
// No build-time model default. The user sets model at runtime via
|
|
39
|
+
// \`init({ model: "provider/model-id" })\` for a session default, or via
|
|
40
|
+
// \`{ model: "provider/model-id" }\` on any individual prompt/skill/task call.
|
|
41
|
+
const model = undefined;
|
|
55
42
|
|
|
56
43
|
function resolveModel(modelString) {
|
|
57
44
|
const slash = modelString.indexOf('/');
|
|
58
|
-
if (slash
|
|
59
|
-
|
|
45
|
+
if (slash === -1) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
'[flue] Invalid model "' + modelString + '". ' +
|
|
48
|
+
'Use the "provider/model-id" format (e.g. "anthropic/claude-haiku-4-5").'
|
|
49
|
+
);
|
|
60
50
|
}
|
|
61
|
-
|
|
51
|
+
const provider = modelString.slice(0, slash);
|
|
52
|
+
const modelId = modelString.slice(slash + 1);
|
|
53
|
+
const resolved = getModel(provider, modelId);
|
|
54
|
+
if (!resolved) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
'[flue] Unknown model "' + modelString + '". ' +
|
|
57
|
+
'Provider "' + provider + '" / model id "' + modelId + '" ' +
|
|
58
|
+
'is not registered with @mariozechner/pi-ai.'
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return resolved;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// ─── Sandbox Environments ───────────────────────────────────────────────────
|
|
@@ -265,7 +265,15 @@ async function handleAgentRequest(request, doInstance, agentName, handler) {
|
|
|
265
265
|
|
|
266
266
|
// ─── Per-Agent Durable Object Classes ──────────────────────────────────────
|
|
267
267
|
|
|
268
|
-
${
|
|
268
|
+
${webhookAgents.map((a) => {
|
|
269
|
+
const className = agentClassName(a.name);
|
|
270
|
+
const handlerVar = agentVarName$1(a.name);
|
|
271
|
+
return `export class ${className} extends Agent {
|
|
272
|
+
async onRequest(request) {
|
|
273
|
+
return handleAgentRequest(request, this, ${JSON.stringify(a.name)}, ${handlerVar});
|
|
274
|
+
}
|
|
275
|
+
}`;
|
|
276
|
+
}).join("\n\n")}
|
|
269
277
|
|
|
270
278
|
// Re-export Sandbox DO class for wrangler binding
|
|
271
279
|
export { Sandbox } from '@cloudflare/sandbox';
|
|
@@ -370,20 +378,9 @@ function agentClassName(name) {
|
|
|
370
378
|
var NodePlugin = class {
|
|
371
379
|
name = "node";
|
|
372
380
|
generateEntryPoint(ctx) {
|
|
373
|
-
const { agents, roles
|
|
374
|
-
const modelProvider = options.model?.provider ?? "anthropic";
|
|
375
|
-
const modelId = options.model?.modelId ?? "claude-haiku-4-5";
|
|
381
|
+
const { agents, roles } = ctx;
|
|
376
382
|
const rolesJson = JSON.stringify(roles);
|
|
377
383
|
const webhookAgents = agents.filter((a) => a.triggers.webhook);
|
|
378
|
-
const agentImports = agents.map((a) => {
|
|
379
|
-
return `import ${agentVarName(a.name)} from '${a.filePath.replace(/\\/g, "/")}';`;
|
|
380
|
-
}).join("\n");
|
|
381
|
-
const handlerMapEntries = agents.map((a) => ` ${JSON.stringify(a.name)}: ${agentVarName(a.name)},`).join("\n");
|
|
382
|
-
const webhookNames = JSON.stringify(webhookAgents.map((a) => a.name));
|
|
383
|
-
const manifest = JSON.stringify({ agents: agents.map((a) => ({
|
|
384
|
-
name: a.name,
|
|
385
|
-
triggers: a.triggers
|
|
386
|
-
})) }, null, 2);
|
|
387
384
|
return `
|
|
388
385
|
// Auto-generated by @flue/sdk build (node)
|
|
389
386
|
import { Hono } from 'hono';
|
|
@@ -391,12 +388,12 @@ import { streamSSE } from 'hono/streaming';
|
|
|
391
388
|
import { serve } from '@hono/node-server';
|
|
392
389
|
import { Bash, InMemoryFs, MountableFs, ReadWriteFs } from 'just-bash';
|
|
393
390
|
import { getModel } from '@mariozechner/pi-ai';
|
|
394
|
-
import { createFlueContext } from '
|
|
395
|
-
import { InMemorySessionStore } from '${resolveSDKImport("session")}';
|
|
396
|
-
import { bashToSessionEnv } from '${resolveSDKImport("sandbox")}';
|
|
391
|
+
import { createFlueContext, InMemorySessionStore, bashToSessionEnv } from '@flue/sdk/internal';
|
|
397
392
|
import { randomUUID } from 'node:crypto';
|
|
398
393
|
|
|
399
|
-
${
|
|
394
|
+
${agents.map((a) => {
|
|
395
|
+
return `import ${agentVarName(a.name)} from '${a.filePath.replace(/\\/g, "/")}';`;
|
|
396
|
+
}).join("\n")}
|
|
400
397
|
|
|
401
398
|
// ─── Config ─────────────────────────────────────────────────────────────────
|
|
402
399
|
|
|
@@ -405,23 +402,49 @@ const roles = ${rolesJson};
|
|
|
405
402
|
const systemPrompt = '';
|
|
406
403
|
|
|
407
404
|
const handlers = {
|
|
408
|
-
${
|
|
405
|
+
${agents.map((a) => ` ${JSON.stringify(a.name)}: ${agentVarName(a.name)},`).join("\n")}
|
|
409
406
|
};
|
|
410
407
|
|
|
411
|
-
const webhookAgents = new Set(${
|
|
408
|
+
const webhookAgents = new Set(${JSON.stringify(webhookAgents.map((a) => a.name))});
|
|
409
|
+
|
|
410
|
+
// When the CLI starts this server via \`flue run\`, it sets FLUE_MODE=local.
|
|
411
|
+
// In local mode the HTTP route accepts any registered agent (including
|
|
412
|
+
// trigger-less CI-only agents). In any other mode the route is restricted to
|
|
413
|
+
// agents with \`webhook: true\`, preventing accidental public exposure of
|
|
414
|
+
// agents that the user only intended to invoke from their CI pipeline.
|
|
415
|
+
const isLocalMode = process.env.FLUE_MODE === 'local';
|
|
412
416
|
|
|
413
|
-
const manifest = ${
|
|
417
|
+
const manifest = ${JSON.stringify({ agents: agents.map((a) => ({
|
|
418
|
+
name: a.name,
|
|
419
|
+
triggers: a.triggers
|
|
420
|
+
})) }, null, 2)};
|
|
414
421
|
|
|
415
422
|
// ─── Infrastructure ─────────────────────────────────────────────────────────
|
|
416
423
|
|
|
417
|
-
|
|
424
|
+
// No build-time model default. The user sets model at runtime via
|
|
425
|
+
// \`init({ model: "provider/model-id" })\` for a session default, or via
|
|
426
|
+
// \`{ model: "provider/model-id" }\` on any individual prompt/skill/task call.
|
|
427
|
+
const model = undefined;
|
|
418
428
|
|
|
419
429
|
function resolveModel(modelString) {
|
|
420
430
|
const slash = modelString.indexOf('/');
|
|
421
|
-
if (slash
|
|
422
|
-
|
|
431
|
+
if (slash === -1) {
|
|
432
|
+
throw new Error(
|
|
433
|
+
'[flue] Invalid model "' + modelString + '". ' +
|
|
434
|
+
'Use the "provider/model-id" format (e.g. "anthropic/claude-haiku-4-5").'
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
const provider = modelString.slice(0, slash);
|
|
438
|
+
const modelId = modelString.slice(slash + 1);
|
|
439
|
+
const resolved = getModel(provider, modelId);
|
|
440
|
+
if (!resolved) {
|
|
441
|
+
throw new Error(
|
|
442
|
+
'[flue] Unknown model "' + modelString + '". ' +
|
|
443
|
+
'Provider "' + provider + '" / model id "' + modelId + '" ' +
|
|
444
|
+
'is not registered with @mariozechner/pi-ai.'
|
|
445
|
+
);
|
|
423
446
|
}
|
|
424
|
-
return
|
|
447
|
+
return resolved;
|
|
425
448
|
}
|
|
426
449
|
|
|
427
450
|
// ─── Sandbox Environments ───────────────────────────────────────────────────
|
|
@@ -493,7 +516,7 @@ app.post('/agents/:name/:sessionId', async (c) => {
|
|
|
493
516
|
if (!handlers[name]) {
|
|
494
517
|
return c.json({ error: 'Agent not found' }, 404);
|
|
495
518
|
}
|
|
496
|
-
if (!webhookAgents.has(name)) {
|
|
519
|
+
if (!webhookAgents.has(name) && !isLocalMode) {
|
|
497
520
|
return c.json({ error: 'Agent "' + name + '" is not web-accessible (no webhook trigger)' }, 404);
|
|
498
521
|
}
|
|
499
522
|
|
|
@@ -572,7 +595,12 @@ const port = parseInt(process.env.PORT || '3000', 10);
|
|
|
572
595
|
|
|
573
596
|
const server = serve({ fetch: app.fetch, port });
|
|
574
597
|
console.log('[flue] Server listening on http://localhost:' + port);
|
|
575
|
-
|
|
598
|
+
if (isLocalMode) {
|
|
599
|
+
console.log('[flue] Mode: local (all agents invokable, including trigger-less)');
|
|
600
|
+
console.log('[flue] Available agents: ' + ${JSON.stringify(agents.map((a) => a.name).join(", "))});
|
|
601
|
+
} else {
|
|
602
|
+
console.log('[flue] Available agents: ' + ${JSON.stringify(webhookAgents.map((a) => a.name).join(", "))});
|
|
603
|
+
}
|
|
576
604
|
|
|
577
605
|
process.on('SIGINT', () => { server.close(); process.exit(0); });
|
|
578
606
|
process.on('SIGTERM', () => { server.close(); process.exit(0); });
|
|
@@ -603,13 +631,14 @@ async function build(options) {
|
|
|
603
631
|
const roles = discoverRoles(agentDir);
|
|
604
632
|
const agents = discoverAgents(agentDir);
|
|
605
633
|
if (agents.length === 0) throw new Error(`No agents found in ${path.join(agentDir, ".flue/agents/")}`);
|
|
606
|
-
for (const agent of agents) if (!(agent.triggers.webhook || agent.triggers.cron)) throw new Error(`[flue] Agent "${agent.name}" has no triggers configured. Add a triggers export to your agent file:\n\n export const triggers = { webhook: true };\n\nAvailable triggers: webhook (HTTP endpoint), cron (scheduled)`);
|
|
607
634
|
const webhookAgents = agents.filter((a) => a.triggers.webhook);
|
|
608
635
|
const cronAgents = agents.filter((a) => a.triggers.cron);
|
|
636
|
+
const triggerlessAgents = agents.filter((a) => !a.triggers.webhook && !a.triggers.cron);
|
|
609
637
|
console.log(`[flue] Found ${Object.keys(roles).length} role(s): ${Object.keys(roles).join(", ") || "(none)"}`);
|
|
610
638
|
console.log(`[flue] Found ${agents.length} agent(s): ${agents.map((a) => a.name).join(", ")}`);
|
|
611
639
|
if (webhookAgents.length > 0) console.log(`[flue] Webhook agents: ${webhookAgents.map((a) => a.name).join(", ")}`);
|
|
612
640
|
if (cronAgents.length > 0) console.log(`[flue] Cron agents (manifest only): ${cronAgents.map((a) => `${a.name} (${a.triggers.cron})`).join(", ")}`);
|
|
641
|
+
if (triggerlessAgents.length > 0) console.log(`[flue] CLI-only agents (no HTTP route in deployed build): ${triggerlessAgents.map((a) => a.name).join(", ")}`);
|
|
613
642
|
console.log(`[flue] AGENTS.md and .agents/skills/ will be discovered at runtime from session cwd`);
|
|
614
643
|
const distDir = path.join(agentDir, "dist");
|
|
615
644
|
fs.mkdirSync(distDir, { recursive: true });
|
|
@@ -624,8 +653,7 @@ async function build(options) {
|
|
|
624
653
|
agents,
|
|
625
654
|
roles,
|
|
626
655
|
agentDir,
|
|
627
|
-
options
|
|
628
|
-
resolveSDKImport: resolveSDKImportFn
|
|
656
|
+
options
|
|
629
657
|
};
|
|
630
658
|
const serverCode = plugin.generateEntryPoint(ctx);
|
|
631
659
|
const entryPath = path.join(distDir, "_entry_server.ts");
|
|
@@ -758,18 +786,6 @@ function getSDKDir() {
|
|
|
758
786
|
return __dirname;
|
|
759
787
|
}
|
|
760
788
|
}
|
|
761
|
-
function getSDKSrcDir() {
|
|
762
|
-
const thisDir = getSDKDir();
|
|
763
|
-
if (thisDir.endsWith("/dist") || thisDir.endsWith("\\dist")) {
|
|
764
|
-
const srcDir = path.join(path.dirname(thisDir), "src");
|
|
765
|
-
if (fs.existsSync(srcDir)) return srcDir;
|
|
766
|
-
}
|
|
767
|
-
return thisDir;
|
|
768
|
-
}
|
|
769
|
-
function resolveSDKImportFn(module) {
|
|
770
|
-
const srcDir = getSDKSrcDir();
|
|
771
|
-
return path.join(srcDir, `${module}.ts`).replace(/\\/g, "/");
|
|
772
|
-
}
|
|
773
789
|
|
|
774
790
|
//#endregion
|
|
775
|
-
export { BUILTIN_TOOL_NAMES,
|
|
791
|
+
export { BUILTIN_TOOL_NAMES, build, createTools };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { S as SessionStore, y as SessionData } from "./types-C8tsaK1j.mjs";
|
|
2
|
+
import { FlueContextConfig, FlueContextInternal, createFlueContext } from "./client.mjs";
|
|
3
|
+
import { bashToSessionEnv } from "./sandbox.mjs";
|
|
4
|
+
import "valibot";
|
|
5
|
+
|
|
6
|
+
//#region src/session.d.ts
|
|
7
|
+
/** In-memory session store. Sessions persist for the lifetime of the process. */
|
|
8
|
+
declare class InMemorySessionStore implements SessionStore {
|
|
9
|
+
private store;
|
|
10
|
+
save(id: string, data: SessionData): Promise<void>;
|
|
11
|
+
load(id: string): Promise<SessionData | null>;
|
|
12
|
+
delete(id: string): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { type FlueContextConfig, type FlueContextInternal, InMemorySessionStore, bashToSessionEnv, createFlueContext };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import "./agent-BYG0nVbQ.mjs";
|
|
2
|
+
import { t as InMemorySessionStore } from "./session-BRLCNVG1.mjs";
|
|
3
|
+
import { bashToSessionEnv } from "./sandbox.mjs";
|
|
4
|
+
import { createFlueContext } from "./client.mjs";
|
|
5
|
+
|
|
6
|
+
export { InMemorySessionStore, bashToSessionEnv, createFlueContext };
|
package/dist/sandbox.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as SessionEnv, c as CommandDef, r as BashLike, u as FileStat, v as SandboxFactory, w as ShellResult } from "./types-
|
|
1
|
+
import { b as SessionEnv, c as CommandDef, r as BashLike, u as FileStat, v as SandboxFactory, w as ShellResult } from "./types-C8tsaK1j.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/sandbox.d.ts
|
|
4
4
|
declare function bashToSessionEnv(bash: BashLike): SessionEnv;
|
package/dist/sandbox.mjs
CHANGED