@flue/sdk 0.1.0 → 0.1.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/README.md CHANGED
@@ -1,8 +1,14 @@
1
- # flue
2
-
3
1
  > **Experimental** — Flue is under active development. APIs may change.
2
+ >
3
+ > Looking for `v0.0.x`? [See here.](https://github.com/withastro/flue/tree/v0.0.x)
4
+
5
+ # Flue
6
+
7
+ Flue is **The Sandbox Agent Framework.** If you know how to use Claude Code (or OpenCode, Codex, Gemini, etc)... then you already know the basics of how to build agents with Flue.
4
8
 
5
- Agent framework where agents are directories compiled into deployable server artifacts.
9
+ A [Sandbox Agent](https://developers.openai.com/api/docs/guides/agents/sandboxes) pairs an **agent harness** (like Claude Code) with a secure, isolated container workspace. Sandbox Agents can edit files, write and execute code, spin up subagents, run terminal commands, and drive themselves autonomously to solve any given task. This pattern unlocks more powerful, intelligent agents that traditional AI frameworks wouldn't otherwise let you build.
10
+
11
+ Our take is that 1) any agent can be represented as a Sandbox Agent, and 2) any agent is _best_ represented as a Sandbox Agent. So we designed Flue to deliver on this vision.
6
12
 
7
13
  ## Packages
8
14
 
@@ -18,6 +24,8 @@ Agent framework where agents are directories compiled into deployable server art
18
24
 
19
25
  The simplest agent — no container, no tools, just a prompt and a typed result.
20
26
 
27
+ Unless you opt-in to initializing a full container sandbox, Flue will default to a virtual sandbox for every agent, powered by [just-bash](https://github.com/vercel-labs/just-bash). A virtual sandbox is going to be dramatically faster, cheaper, and more scalable than running a full container for every agent, which makes it perfect for building high-traffic/high-scale agents.
28
+
21
29
  ```ts
22
30
  // .flue/agents/hello-world.ts
23
31
  import type { FlueContext } from '@flue/sdk/client';
@@ -34,8 +42,8 @@ export default async function ({ init, payload, sessionId }: FlueContext) {
34
42
  const session = await init();
35
43
 
36
44
  // prompt() sends a message in the session, triggering action.
37
- // You can pass a schema to `result` to get typed, validated JSON back.
38
45
  const result = await session.prompt(`Translate this to ${payload.language}: "${payload.text}"`, {
46
+ // Pass a result schema to get typed, schema-validated data back from your agent.
39
47
  result: v.object({
40
48
  translation: v.string(),
41
49
  confidence: v.picklist(['low', 'medium', 'high']),
@@ -48,9 +56,9 @@ export default async function ({ init, payload, sessionId }: FlueContext) {
48
56
 
49
57
  ### Support Agent
50
58
 
51
- A support agent, also running in a virtual sandbox but now with an R2 bucket mounted as its file-system. The knowledge base is stored in R2 and mounted directly into the agent's filesystem — the agent searches it with its built-in tools (grep, glob, read).
59
+ A support agent can also run in a virtual sandbox, but we now add a file-system using an R2 bucket. The knowledge base is stored in R2 and mounted directly into the agent's filesystem — the agent searches it with its built-in tools (grep, glob, read). Skills are also defined in the bucket that help the agent perform its task.
52
60
 
53
- Session message history and file-system state are automatically persisted using Durable Objects (Cloudflare only). So you can revisit this session days, weeks, or years later and pick up where you left off automatically.
61
+ Because this agent is deployed to Cloudflare, message history and session state are automatically persisted for you. So you (or your customer) can revisit this support session days, weeks, or years later and pick up exactly where you left off.
54
62
 
55
63
  ```ts
56
64
  // .flue/agents/support.ts
@@ -72,18 +80,17 @@ export default async function ({ init, payload, env }: FlueContext) {
72
80
  relevant to this request, then write a helpful response.
73
81
 
74
82
  Customer: ${payload.message}`,
83
+ {
84
+ // Provide roles (aka subagents) to guide your agent. Defined in .flue/roles/
85
+ role: 'triager',
86
+ },
75
87
  );
76
88
  }
77
89
  ```
78
90
 
79
91
  ### Issue Triage (CI)
80
92
 
81
- A triage agent that runs whenever a new issue is opened (or commented on) on GitHub, running on GitHub Actions.
82
-
83
- Flue was designed to power CI workflows since day one. The `"local"` filesystem sandbox enables two things:
84
-
85
- 1. Mount the current directory to your virtual file system.
86
- 2. Connect privileged CLIs to your agent (`gh`, `glab`, `git`) without leaking sensitive keys and secrets.
93
+ A triage agent that runs in CI whenever an issue is opened on GitHub. The `"local"` sandbox mounts the host filesystem and lets you connect privileged CLIs (`gh`, `npm`, `git`) to the agent without leaking secrets.
87
94
 
88
95
  ```ts
89
96
  // .flue/agents/triage.ts
@@ -92,6 +99,8 @@ import { execFile } from 'node:child_process';
92
99
  import { promisify } from 'node:util';
93
100
  import * as v from 'valibot';
94
101
 
102
+ // Because we are running this in CI, we don't need to expose this as an HTTP endpoint.
103
+ // The CLI can run any agent from the command line, `flue run triage ...`
95
104
  export const triggers = {};
96
105
 
97
106
  // Connect privileged CLIs to your agent without leaking sensitive keys and secrets.
@@ -108,15 +117,23 @@ export default async function ({ init, payload }: FlueContext) {
108
117
  // 'local' mounts the host filesystem at /workspace — ideal for CI
109
118
  // where the repo is already checked out. Skills and AGENTS.md are
110
119
  // discovered automatically from the workspace directory.
111
- const session = await init({ sandbox: 'local' });
120
+ //
121
+ // `model` sets the default model for every prompt/skill call in this
122
+ // session. Override per-call with `{ model: '...' }` on prompt()/skill().
123
+ const session = await init({
124
+ sandbox: 'local',
125
+ model: 'anthropic/claude-opus-4-20250514',
126
+ });
112
127
 
128
+ // Skills can be referenced either by their frontmatter `name:` (shown below)
129
+ // or by a relative path under `.agents/skills/` — e.g.
130
+ // `session.skill('triage/reproduce.md', ...)`. Path references are handy for
131
+ // skill packs that group multiple stages under one directory.
113
132
  const result = await session.skill('triage', {
114
133
  // Pass arguments to any prompt or skill.
115
134
  args: { issueNumber: payload.issueNumber },
116
135
  // Grant access to `gh` and `npm` for the life of this skill.
117
136
  commands: [gh, npm],
118
- // Provide roles (aka subagents) to guide your agent. Defined in .flue/roles/
119
- role: 'triager',
120
137
  // Result schemas are great for being able to act/orchestrate
121
138
  // based on the result of your prompt or skill call.
122
139
  result: v.object({
package/dist/client.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as ShellOptions, D as TaskOptions, E as SkillOptions, O as ToolDef, S as SessionStore, b as SessionEnv, d as FlueContext, f as FlueEvent, g as PromptResponse, h as PromptOptions, l as CommandSupport, m as FlueSession, p as FlueEventCallback, r as BashLike, s as Command, t as AgentConfig, u as FileStat, v as SandboxFactory, w as ShellResult, x as SessionInit, y as SessionData } from "./types-xNvqlohs.mjs";
1
+ import { C as ShellOptions, D as TaskOptions, E as SkillOptions, O as ToolDef, S as SessionStore, b as SessionEnv, d as FlueContext, f as FlueEvent, g as PromptResponse, h as PromptOptions, l as CommandSupport, m as FlueSession, p as FlueEventCallback, r as BashLike, s as Command, t as AgentConfig, u as FileStat, v as SandboxFactory, w as ShellResult, x as SessionInit, y as SessionData } from "./types-C97_qJ21.mjs";
2
2
  import { Type } from "@mariozechner/pi-ai";
3
3
 
4
4
  //#region src/client.d.ts
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as Session, o as discoverSessionContext } from "./session-BD0MEuO3.mjs";
1
+ import { n as Session, o as discoverSessionContext } from "./session-0gnaB_aY.mjs";
2
2
  import { bashToSessionEnv } from "./sandbox.mjs";
3
3
  import { Type } from "@mariozechner/pi-ai";
4
4
 
@@ -24,10 +24,12 @@ function createFlueContext(config) {
24
24
  const store = options?.persist ?? config.defaultStore;
25
25
  const savedData = await store.load(config.sessionId);
26
26
  const localContext = await discoverSessionContext(env);
27
+ const sessionModel = options?.model && config.agentConfig.resolveModel ? config.agentConfig.resolveModel(options.model) : config.agentConfig.model;
27
28
  const sessionConfig = {
28
29
  ...config.agentConfig,
29
30
  systemPrompt: localContext.systemPrompt,
30
- skills: localContext.skills
31
+ skills: localContext.skills,
32
+ model: sessionModel
31
33
  };
32
34
  return new Session(config.sessionId, sessionConfig, env, store, savedData, currentEventCallback);
33
35
  },
@@ -1,4 +1,4 @@
1
- import { S as SessionStore, b as SessionEnv } from "../types-xNvqlohs.mjs";
1
+ import { S as SessionStore, b as SessionEnv } from "../types-C97_qJ21.mjs";
2
2
 
3
3
  //#region src/cloudflare/virtual-sandbox.d.ts
4
4
  interface VirtualSandboxOptions {
@@ -1,4 +1,4 @@
1
- import "../session-BD0MEuO3.mjs";
1
+ import "../session-0gnaB_aY.mjs";
2
2
  import { createSandboxSessionEnv } from "../sandbox.mjs";
3
3
  import { Workspace, WorkspaceFileSystem } from "@cloudflare/shell";
4
4
 
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as ShellOptions, D as TaskOptions, E as SkillOptions, O as ToolDef, S as SessionStore, T as Skill, _ as Role, a as BuildOptions, b as SessionEnv, c as CommandDef, d as FlueContext, f as FlueEvent, g as PromptResponse, h as PromptOptions, i as BuildContext, l as CommandSupport, m as FlueSession, n as AgentInfo, o as BuildPlugin, p as FlueEventCallback, r as BashLike, s as Command, t as AgentConfig, u as FileStat, v as SandboxFactory, w as ShellResult, x as SessionInit, y as SessionData } from "./types-xNvqlohs.mjs";
1
+ import { C as ShellOptions, D as TaskOptions, E as SkillOptions, O as ToolDef, S as SessionStore, T as Skill, _ as Role, a as BuildOptions, b as SessionEnv, c as CommandDef, d as FlueContext, f as FlueEvent, g as PromptResponse, h as PromptOptions, i as BuildContext, l as CommandSupport, m as FlueSession, n as AgentInfo, o as BuildPlugin, p as FlueEventCallback, r as BashLike, s as Command, t as AgentConfig, u as FileStat, v as SandboxFactory, w as ShellResult, x as SessionInit, y as SessionData } from "./types-C97_qJ21.mjs";
2
2
  import { FlueContextConfig, FlueContextInternal, createFlueContext } from "./client.mjs";
3
3
  import { AgentTool } from "@mariozechner/pi-agent-core";
4
4
  import "valibot";
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as createTools, i as BUILTIN_TOOL_NAMES, s as parseFrontmatterFile, t as InMemorySessionStore } from "./session-BD0MEuO3.mjs";
1
+ import { a as createTools, i as BUILTIN_TOOL_NAMES, s as parseFrontmatterFile, t as InMemorySessionStore } from "./session-0gnaB_aY.mjs";
2
2
  import { createFlueContext } from "./client.mjs";
3
3
  import * as esbuild from "esbuild";
4
4
  import * as fs from "node:fs";
@@ -9,9 +9,7 @@ import { packageUpSync } from "package-up";
9
9
  var CloudflarePlugin = class {
10
10
  name = "cloudflare";
11
11
  generateEntryPoint(ctx) {
12
- const { agents, roles, options, resolveSDKImport } = ctx;
13
- const modelProvider = options.model?.provider ?? "anthropic";
14
- const modelId = options.model?.modelId ?? "claude-haiku-4-5";
12
+ const { agents, roles, resolveSDKImport } = ctx;
15
13
  const rolesJson = JSON.stringify(roles);
16
14
  const webhookAgents = agents.filter((a) => a.triggers.webhook);
17
15
  const agentImports = agents.map((a) => {
@@ -51,14 +49,30 @@ const manifest = ${manifest};
51
49
 
52
50
  // ─── Infrastructure ─────────────────────────────────────────────────────────
53
51
 
54
- const model = getModel(${JSON.stringify(modelProvider)}, ${JSON.stringify(modelId)});
52
+ // No build-time model default. The user sets model at runtime via
53
+ // \`init({ model: "provider/model-id" })\` for a session default, or via
54
+ // \`{ model: "provider/model-id" }\` on any individual prompt/skill/task call.
55
+ const model = undefined;
55
56
 
56
57
  function resolveModel(modelString) {
57
58
  const slash = modelString.indexOf('/');
58
- if (slash !== -1) {
59
- return getModel(modelString.slice(0, slash), modelString.slice(slash + 1));
59
+ if (slash === -1) {
60
+ throw new Error(
61
+ '[flue] Invalid model "' + modelString + '". ' +
62
+ 'Use the "provider/model-id" format (e.g. "anthropic/claude-haiku-4-5").'
63
+ );
64
+ }
65
+ const provider = modelString.slice(0, slash);
66
+ const modelId = modelString.slice(slash + 1);
67
+ const resolved = getModel(provider, modelId);
68
+ if (!resolved) {
69
+ throw new Error(
70
+ '[flue] Unknown model "' + modelString + '". ' +
71
+ 'Provider "' + provider + '" / model id "' + modelId + '" ' +
72
+ 'is not registered with @mariozechner/pi-ai.'
73
+ );
60
74
  }
61
- return getModel(${JSON.stringify(modelProvider)}, modelString);
75
+ return resolved;
62
76
  }
63
77
 
64
78
  // ─── Sandbox Environments ───────────────────────────────────────────────────
@@ -370,9 +384,7 @@ function agentClassName(name) {
370
384
  var NodePlugin = class {
371
385
  name = "node";
372
386
  generateEntryPoint(ctx) {
373
- const { agents, roles, options, resolveSDKImport } = ctx;
374
- const modelProvider = options.model?.provider ?? "anthropic";
375
- const modelId = options.model?.modelId ?? "claude-haiku-4-5";
387
+ const { agents, roles, resolveSDKImport } = ctx;
376
388
  const rolesJson = JSON.stringify(roles);
377
389
  const webhookAgents = agents.filter((a) => a.triggers.webhook);
378
390
  const agentImports = agents.map((a) => {
@@ -414,14 +426,30 @@ const manifest = ${manifest};
414
426
 
415
427
  // ─── Infrastructure ─────────────────────────────────────────────────────────
416
428
 
417
- const model = getModel(${JSON.stringify(modelProvider)}, ${JSON.stringify(modelId)});
429
+ // No build-time model default. The user sets model at runtime via
430
+ // \`init({ model: "provider/model-id" })\` for a session default, or via
431
+ // \`{ model: "provider/model-id" }\` on any individual prompt/skill/task call.
432
+ const model = undefined;
418
433
 
419
434
  function resolveModel(modelString) {
420
435
  const slash = modelString.indexOf('/');
421
- if (slash !== -1) {
422
- return getModel(modelString.slice(0, slash), modelString.slice(slash + 1));
436
+ if (slash === -1) {
437
+ throw new Error(
438
+ '[flue] Invalid model "' + modelString + '". ' +
439
+ 'Use the "provider/model-id" format (e.g. "anthropic/claude-haiku-4-5").'
440
+ );
441
+ }
442
+ const provider = modelString.slice(0, slash);
443
+ const modelId = modelString.slice(slash + 1);
444
+ const resolved = getModel(provider, modelId);
445
+ if (!resolved) {
446
+ throw new Error(
447
+ '[flue] Unknown model "' + modelString + '". ' +
448
+ 'Provider "' + provider + '" / model id "' + modelId + '" ' +
449
+ 'is not registered with @mariozechner/pi-ai.'
450
+ );
423
451
  }
424
- return getModel(${JSON.stringify(modelProvider)}, modelString);
452
+ return resolved;
425
453
  }
426
454
 
427
455
  // ─── Sandbox Environments ───────────────────────────────────────────────────
@@ -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-xNvqlohs.mjs";
1
+ import { b as SessionEnv, c as CommandDef, r as BashLike, u as FileStat, v as SandboxFactory, w as ShellResult } from "./types-C97_qJ21.mjs";
2
2
 
3
3
  //#region src/sandbox.d.ts
4
4
  declare function bashToSessionEnv(bash: BashLike): SessionEnv;
package/dist/sandbox.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { r as normalizePath } from "./session-BD0MEuO3.mjs";
1
+ import { r as normalizePath } from "./session-0gnaB_aY.mjs";
2
2
 
3
3
  //#region src/sandbox.ts
4
4
  function bashToSessionEnv(bash) {
@@ -39,6 +39,28 @@ async function readAgentsMd(env, basePath) {
39
39
  }
40
40
  return parts.join("\n\n");
41
41
  }
42
+ /**
43
+ * Load a skill directly by relative path under `.agents/skills/`.
44
+ *
45
+ * The path is taken as-is — no extension is auto-appended. Callers reference
46
+ * the full filename, e.g. `'triage/reproduce.md'`. Returns `null` if the file
47
+ * doesn't exist.
48
+ *
49
+ * Used as a fallback by `session.skill()` when the requested name doesn't match
50
+ * a discovered skill's frontmatter `name:` field. Lets users organise skills as
51
+ * a pack of sibling markdown files under one directory (orchestration SKILL.md
52
+ * + stage files) without forcing each stage into its own `SKILL.md` subdirectory.
53
+ */
54
+ async function loadSkillByPath(env, basePath, relPath) {
55
+ const filePath = `${basePath.endsWith("/") ? `${basePath}.agents/skills` : `${basePath}/.agents/skills`}/${relPath}`;
56
+ if (!await env.exists(filePath)) return null;
57
+ const parsed = parseFrontmatterFile(await env.readFile(filePath), relPath.replace(/\.(md|markdown)$/i, ""));
58
+ return {
59
+ name: parsed.name,
60
+ description: parsed.description,
61
+ instructions: parsed.body
62
+ };
63
+ }
42
64
  /** Discover skills from .agents/skills/<name>/SKILL.md under basePath. */
43
65
  async function discoverLocalSkills(env, basePath) {
44
66
  const skillsDir = basePath.endsWith("/") ? `${basePath}.agents/skills` : `${basePath}/.agents/skills`;
@@ -987,6 +1009,7 @@ var Session = class Session {
987
1009
  });
988
1010
  }
989
1011
  async prompt(text, options) {
1012
+ this.assertRoleExists(options?.role);
990
1013
  this.resolveModelForCall(options?.model, options?.role);
991
1014
  const promptWithRole = this.injectRoleInstructions(text, options?.role);
992
1015
  const schema = options?.result;
@@ -1007,8 +1030,16 @@ var Session = class Session {
1007
1030
  }
1008
1031
  }
1009
1032
  async skill(name, options) {
1010
- const registeredSkill = this.config.skills[name];
1011
- if (!registeredSkill) throw new Error(`Skill "${name}" not registered. Available: ${Object.keys(this.config.skills).join(", ") || "(none)"}`);
1033
+ this.assertRoleExists(options?.role);
1034
+ let registeredSkill = this.config.skills[name];
1035
+ if (!registeredSkill && (name.includes("/") || /\.(md|markdown)$/i.test(name))) {
1036
+ const loaded = await loadSkillByPath(this.env, this.env.cwd, name);
1037
+ if (loaded) registeredSkill = loaded;
1038
+ }
1039
+ if (!registeredSkill) {
1040
+ const available = Object.keys(this.config.skills).join(", ") || "(none)";
1041
+ throw new Error(`Skill "${name}" not registered. Available: ${available}. Skills can also be referenced by relative path under .agents/skills/ (e.g. "triage/reproduce.md").`);
1042
+ }
1012
1043
  this.resolveModelForCall(options?.model, options?.role);
1013
1044
  const schema = options?.result;
1014
1045
  const skillPrompt = buildSkillPrompt(registeredSkill.instructions, options?.args, schema);
@@ -1046,6 +1077,7 @@ var Session = class Session {
1046
1077
  }
1047
1078
  }
1048
1079
  async task(prompt, options) {
1080
+ this.assertRoleExists(options?.role);
1049
1081
  if (!options?.workspace) throw new Error("[flue] task() requires a workspace option.");
1050
1082
  const taskCwd = options.workspace.startsWith("/") ? options.workspace : normalizePath(this.env.cwd + "/" + options.workspace);
1051
1083
  function taskResolvePath(p) {
@@ -1081,7 +1113,7 @@ var Session = class Session {
1081
1113
  systemPrompt: localContext.systemPrompt,
1082
1114
  skills: localContext.skills,
1083
1115
  roles: this.config.roles,
1084
- model: taskModel,
1116
+ model: this.requireModel(taskModel, "this task() call"),
1085
1117
  resolveModel: this.config.resolveModel,
1086
1118
  compaction: this.config.compaction
1087
1119
  };
@@ -1113,7 +1145,28 @@ var Session = class Session {
1113
1145
  let model = this.config.model;
1114
1146
  if (roleName && this.config.roles[roleName]?.model && this.config.resolveModel) model = this.config.resolveModel(this.config.roles[roleName].model);
1115
1147
  if (promptModel && this.config.resolveModel) model = this.config.resolveModel(promptModel);
1116
- this.agent.state.model = model;
1148
+ this.agent.state.model = this.requireModel(model, "this prompt()/skill()/task() call");
1149
+ }
1150
+ /**
1151
+ * Throws a clear, actionable error when no model is configured for a call.
1152
+ * Use with the resolved model (post-precedence) to guarantee we never hand
1153
+ * `undefined` to the underlying agent.
1154
+ */
1155
+ requireModel(model, callSite) {
1156
+ if (model) return model;
1157
+ throw new Error(`[flue] No model configured for ${callSite}. Pass \`{ model: "provider/model-id" }\` to \`init()\` for a session-wide default, or to this prompt()/skill()/task() call for a one-off override.`);
1158
+ }
1159
+ /**
1160
+ * Throws a clear error when a caller references a role that isn't registered.
1161
+ * Roles are loaded from `.flue/roles/` at build time. Called eagerly at the top
1162
+ * of prompt()/skill()/task() so typos surface before any LLM work begins.
1163
+ */
1164
+ assertRoleExists(roleName) {
1165
+ if (!roleName) return;
1166
+ if (this.config.roles[roleName]) return;
1167
+ const available = Object.keys(this.config.roles);
1168
+ const list = available.length > 0 ? available.join(", ") : "(none defined)";
1169
+ throw new Error(`[flue] Role "${roleName}" not registered. Available roles: ${list}. Define roles as markdown files under \`.flue/roles/\`.`);
1117
1170
  }
1118
1171
  injectRoleInstructions(text, roleName) {
1119
1172
  if (!roleName) return text;
@@ -107,8 +107,13 @@ interface AgentConfig {
107
107
  /** Discovered at runtime from .agents/skills/ in the session's cwd. */
108
108
  skills: Record<string, Skill>;
109
109
  roles: Record<string, Role>;
110
- model: Model<any>;
111
- /** Resolve a "provider/modelId" string to a Model instance. */
110
+ /**
111
+ * Session-wide default model. Undefined by default the user must set it via
112
+ * `init({ model: "provider/model-id" })` or pass `{ model }` at each prompt/
113
+ * skill/task call site. Calls with no model resolved throw clearly at runtime.
114
+ */
115
+ model: Model<any> | undefined;
116
+ /** Resolve a "provider/modelId" string to a Model instance. Throws on invalid input. */
112
117
  resolveModel?: (modelString: string) => Model<any>;
113
118
  compaction?: CompactionConfig;
114
119
  }
@@ -121,7 +126,7 @@ interface FlueContext {
121
126
  /** Create a session with sandbox + persistence. Can only be called once per request. */
122
127
  init(options?: SessionInit): Promise<FlueSession>;
123
128
  }
124
- /** Both fields are optional — omitting gives platform defaults (empty sandbox, platform store). */
129
+ /** All fields are optional — omitting gives platform defaults (empty sandbox, platform store, build-time model). */
125
130
  interface SessionInit {
126
131
  /**
127
132
  * - `'empty'` (default): In-memory sandbox, no files, no host access.
@@ -132,6 +137,15 @@ interface SessionInit {
132
137
  sandbox?: 'empty' | 'local' | SandboxFactory | BashLike;
133
138
  /** Defaults to platform store (in-memory on Node, DO SQLite on Cloudflare). */
134
139
  persist?: SessionStore;
140
+ /**
141
+ * Override the default model for this session. Applies to all prompt(), skill(),
142
+ * and task() calls unless overridden at the call site.
143
+ *
144
+ * Format: `'provider/modelId'` (e.g. `'anthropic/claude-opus-4-20250514'`).
145
+ *
146
+ * Precedence (highest wins): per-call `model` > role `model` > session `model` > build-time default.
147
+ */
148
+ model?: string;
135
149
  }
136
150
  interface FlueSession {
137
151
  prompt<S extends v.GenericSchema>(text: string, options: PromptOptions<S> & {
@@ -318,10 +332,6 @@ interface BuildOptions {
318
332
  target?: 'node' | 'cloudflare';
319
333
  /** Overrides `target` when provided. */
320
334
  plugin?: BuildPlugin;
321
- model?: {
322
- provider: string;
323
- modelId: string;
324
- };
325
335
  }
326
336
  //#endregion
327
337
  export { ShellOptions as C, TaskOptions as D, SkillOptions as E, ToolDef as O, SessionStore as S, Skill as T, Role as _, BuildOptions as a, SessionEnv as b, CommandDef as c, FlueContext as d, FlueEvent as f, PromptResponse as g, PromptOptions as h, BuildContext as i, CommandSupport as l, FlueSession as m, AgentInfo as n, BuildPlugin as o, FlueEventCallback as p, BashLike as r, Command as s, AgentConfig as t, FileStat as u, SandboxFactory as v, ShellResult as w, SessionInit as x, SessionData as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flue/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "exports": {