@flue/sdk 0.3.11 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/internal.mjs CHANGED
@@ -1,426 +1,12 @@
1
- import "./agent-Cahthgu3.mjs";
2
- import { t as InMemorySessionStore } from "./session-DlwIt7wq.mjs";
1
+ import "./result-K1IRhWKM.mjs";
2
+ import { i as handleAgentRequest, n as createDefaultFlueApp, t as configureFlueRuntime } from "./flue-app-DeTOZjPs.mjs";
3
+ import { r as getProviderConfiguration, s as resolveRegisteredModel } from "./providers-DeFRIwp0.mjs";
4
+ import { t as InMemorySessionStore } from "./session-CO_uGVOk.mjs";
3
5
  import { bashFactoryToSessionEnv } from "./sandbox.mjs";
4
- import "./mcp-DmDTeVXW.mjs";
6
+ import "./mcp-2SW_tpox.mjs";
5
7
  import { createFlueContext } from "./client.mjs";
6
8
  import { getModel } from "@mariozechner/pi-ai";
7
9
 
8
- //#region src/errors.ts
9
- /**
10
- * Concrete error classes thrown by Flue.
11
- *
12
- * This file is the *vocabulary* of errors in Flue. Every error the framework
13
- * throws has a class here. The framework scaffolding (base class, renderers,
14
- * type guards, request-parsing helpers) lives in `error-utils.ts`.
15
- *
16
- * ──── Why this file exists ────────────────────────────────────────────────
17
- *
18
- * Concentrating every error in one file is deliberate. When all errors are
19
- * visible together, it's easy to:
20
- *
21
- * - Keep message tone and detail level consistent across the codebase.
22
- * - Notice duplicates ("oh, we already have an error for this case").
23
- * - Establish norms by example — when adding a new error, look at the
24
- * neighbors above and copy the pattern.
25
- *
26
- * Application code throughout the codebase should reach for one of these
27
- * classes rather than constructing a `FlueError` ad hoc. If no existing class
28
- * fits, add one here. That's the entire convention.
29
- *
30
- * ──── Two audiences: caller vs. developer ─────────────────────────────────
31
- *
32
- * The reader of an error message is one of two distinct audiences:
33
- *
34
- * - The *caller*: an HTTP client. Possibly third-party, possibly hostile,
35
- * possibly an end user who shouldn't even know we're built on Flue.
36
- * Sees `message` and `details` always.
37
- *
38
- * - The *developer*: the human running the service (`flue dev`, `flue run`,
39
- * local debugging). Sees `dev` in addition, but only when the server is
40
- * running in local/dev mode (gated by `FLUE_MODE=local`).
41
- *
42
- * Every error class must classify its prose by audience. The required-but-
43
- * possibly-empty shape of both `details` and `dev` is the discipline:
44
- * forgetting either field is a TypeScript error, and writing `''` is a
45
- * deliberate "I have nothing for that audience" decision.
46
- *
47
- * Concretely:
48
- *
49
- * - `message` One sentence. Caller-safe. Always rendered.
50
- * - `details` Longer caller-safe prose. About the request itself, the
51
- * contract, what the caller can do to fix it. Always
52
- * rendered. NEVER includes:
53
- * - sibling/neighbor enumeration (leaks namespace)
54
- * - filesystem paths or "agents/" / "skills/" / etc.
55
- * (leaks framework internals)
56
- * - source-code-level fix instructions ("add ... to your
57
- * agent definition") (caller can't act on these)
58
- * - build-time or runtime mechanics
59
- * - `dev` Longer dev-audience prose. Available alternatives,
60
- * filesystem layout, framework guidance, source-code-level
61
- * fix instructions. Rendered ONLY when FLUE_MODE=local.
62
- *
63
- * When in doubt, put information in `dev`. The default is conservative.
64
- *
65
- * ──── Conventions for new error classes ───────────────────────────────────
66
- *
67
- * - Class name: PascalCase, suffixed with `Error`. E.g. `AgentNotFoundError`.
68
- * - The class owns its `type` constant (snake_case). Set once in the
69
- * subclass constructor, never passed by callers. Renaming the wire type
70
- * is then a one-line change.
71
- * - Constructor takes ONLY structured input data (the values used to build
72
- * the message). The constructor assembles `message`, `details`, and
73
- * `dev` from that data, so call sites never reinvent phrasing.
74
- * - `details` and `dev` are both required strings. Pass `''` only when
75
- * there's genuinely nothing more to say for that audience.
76
- * - For HTTP errors, the class sets its own `status` (and `headers` where
77
- * relevant). Callers do not pick HTTP status codes ad-hoc.
78
- *
79
- * Worked example (matches `AgentNotFoundError` below):
80
- *
81
- * new AgentNotFoundError({ name, available });
82
- * // builds:
83
- * // message: `Agent "foo" is not registered.`
84
- * // details: `Verify the agent name is correct.`
85
- * // dev: `Available agents: "echo", "greeter". Agents are
86
- * // loaded from the workspace's "agents/" directory at
87
- * // build time. ...`
88
- *
89
- * The wire response in production omits `dev`; in `flue dev` / `flue run`
90
- * it includes `dev`. That separation is what lets the dev field be richly
91
- * helpful without leaking namespace state to public callers.
92
- *
93
- * Counter-example to avoid:
94
- *
95
- * class AgentNotFoundError extends FlueHttpError {
96
- * constructor(message: string) { // ✗ free-form
97
- * super({ // ✗ wrong type
98
- * type: 'agent_error',
99
- * message,
100
- * details: 'Available: "x", "y", "z"', // ✗ leaks names
101
- * dev: '', // ✗ wasted channel
102
- * status: 500, // ✗ wrong status
103
- * });
104
- * }
105
- * }
106
- *
107
- * The structured-constructor pattern below is what prevents that drift.
108
- */
109
- /**
110
- * Format a list of items for inclusion in error details. Empty lists render
111
- * as the supplied fallback (default `(none)`), so messages read naturally
112
- * regardless of whether anything is registered.
113
- *
114
- * Module-private: only used by the concrete error subclasses below. Promote
115
- * to `export` if/when a real cross-file caller appears.
116
- */
117
- function formatList(items, fallback = "(none)") {
118
- if (items.length === 0) return fallback;
119
- return items.map((item) => `"${String(item)}"`).join(", ");
120
- }
121
- /**
122
- * Base class for every error Flue throws. Do not instantiate directly in
123
- * application code — extend it via a subclass below. If a use case isn't
124
- * covered, add a new subclass here rather than throwing a raw `FlueError`.
125
- */
126
- var FlueError = class extends Error {
127
- type;
128
- details;
129
- dev;
130
- meta;
131
- cause;
132
- constructor(options) {
133
- super(options.message);
134
- this.name = "FlueError";
135
- this.type = options.type;
136
- this.details = options.details;
137
- this.dev = options.dev;
138
- this.meta = options.meta;
139
- this.cause = options.cause;
140
- }
141
- };
142
- /**
143
- * Base class for HTTP-layer errors. Adds `status` and optional `headers`.
144
- * Subclasses set these in the `super({...})` call so the call site doesn't
145
- * have to think about HTTP semantics.
146
- */
147
- var FlueHttpError = class extends FlueError {
148
- status;
149
- headers;
150
- constructor(options) {
151
- super(options);
152
- this.name = "FlueHttpError";
153
- this.status = options.status;
154
- this.headers = options.headers;
155
- }
156
- };
157
- var MethodNotAllowedError = class extends FlueHttpError {
158
- constructor({ method, allowed }) {
159
- super({
160
- type: "method_not_allowed",
161
- message: `HTTP method ${method} is not allowed on this endpoint.`,
162
- details: `This endpoint accepts ${formatList(allowed)} only.`,
163
- dev: "",
164
- status: 405,
165
- headers: { Allow: allowed.join(", ") }
166
- });
167
- }
168
- };
169
- var UnsupportedMediaTypeError = class extends FlueHttpError {
170
- constructor({ received }) {
171
- const detailLines = [];
172
- if (received) detailLines.push(`Received Content-Type: "${received}".`);
173
- else detailLines.push(`No Content-Type header was sent.`);
174
- detailLines.push("Send the request body as JSON with the header \"Content-Type: application/json\", or omit the body entirely (and the Content-Type header) if the request doesn't have a payload.");
175
- super({
176
- type: "unsupported_media_type",
177
- message: `Request body must be sent as application/json.`,
178
- details: detailLines.join("\n"),
179
- dev: "",
180
- status: 415
181
- });
182
- }
183
- };
184
- var InvalidJsonError = class extends FlueHttpError {
185
- constructor({ parseError }) {
186
- super({
187
- type: "invalid_json",
188
- message: `Request body is not valid JSON.`,
189
- details: `The JSON parser reported: ${parseError}\nVerify the body is well-formed JSON, or omit the body entirely if the request doesn't have a payload.`,
190
- dev: "",
191
- status: 400
192
- });
193
- }
194
- };
195
- var AgentNotFoundError = class extends FlueHttpError {
196
- constructor({ name, available }) {
197
- super({
198
- type: "agent_not_found",
199
- message: `Agent "${name}" is not registered.`,
200
- details: `Verify the agent name is correct.`,
201
- dev: `Available agents: ${formatList(available)}.\nAgents are loaded from the workspace's "agents/" directory at build time. Verify the agent file is present in the workspace being served.`,
202
- status: 404
203
- });
204
- }
205
- };
206
- var AgentNotWebhookError = class extends FlueHttpError {
207
- constructor({ name }) {
208
- super({
209
- type: "agent_not_webhook",
210
- message: `Agent "${name}" is not web-accessible.`,
211
- details: `This endpoint is not exposed over HTTP.`,
212
- dev: "This agent has no webhook trigger configured. To expose it, add a webhook trigger to its definition (`triggers: { webhook: true }`). Trigger-less agents remain invokable via \"flue run\" in local mode.",
213
- status: 404
214
- });
215
- }
216
- };
217
- var RouteNotFoundError = class extends FlueHttpError {
218
- constructor({ method, path }) {
219
- super({
220
- type: "route_not_found",
221
- message: `No route matches ${method} ${path}.`,
222
- details: `Webhook agents are served at POST /agents/<name>/<id>.`,
223
- dev: "",
224
- status: 404
225
- });
226
- }
227
- };
228
- var InvalidRequestError = class extends FlueHttpError {
229
- constructor({ reason }) {
230
- super({
231
- type: "invalid_request",
232
- message: `Request is malformed.`,
233
- details: reason,
234
- dev: "",
235
- status: 400
236
- });
237
- }
238
- };
239
-
240
- //#endregion
241
- //#region src/error-utils.ts
242
- /**
243
- * Error framework for Flue.
244
- *
245
- * This file holds the abstract scaffolding (renderers, helpers, request-
246
- * parsing utilities, type guard, logger) that supports the concrete error
247
- * subclasses defined in `errors.ts`. The two-file split is deliberate:
248
- *
249
- * - `errors.ts` is the *vocabulary*: the `FlueError` base class plus every
250
- * concrete subclass Flue can throw. That's the file new contributors
251
- * touch when they need to add a new error.
252
- *
253
- * - `error-utils.ts` (this file) is the *framework*: the renderers that
254
- * turn errors into HTTP responses and SSE event data, the type guard,
255
- * the logger, and the request-parsing utilities. This file rarely
256
- * changes.
257
- *
258
- * Application code should NOT instantiate `FlueError` directly. Always reach
259
- * for a subclass from `errors.ts`. If no existing subclass fits, add one
260
- * there. This is what keeps message tone, detail level, and field naming
261
- * consistent across the codebase.
262
- *
263
- * Wire envelope (HTTP body + SSE `data:` payload for error events):
264
- *
265
- * {
266
- * "error": {
267
- * "type": "...",
268
- * "message": "...",
269
- * "details": "...",
270
- * "dev": "..." // present only in local/dev mode AND when non-empty
271
- * }
272
- * }
273
- *
274
- * Field rules:
275
- * - `type`, `message`, `details` are always present on the wire.
276
- * - `dev` is gated by `FLUE_MODE === 'local'` (set by `flue run` and
277
- * `flue dev --target node`). Even in dev mode, `dev` is omitted when
278
- * the error class set it to `''` — so its presence is not a reliable
279
- * signal of mode by itself; clients should not depend on it that way.
280
- * See `errors.ts` for the two-audience rationale.
281
- * - `meta` is included on the wire only when an error subclass sets it
282
- * (rare).
283
- * - `cause` is never included on the wire (it's logged server-side only).
284
- */
285
- function isFlueError(value) {
286
- return value instanceof FlueError;
287
- }
288
- /**
289
- * Structured error logger. Used by the HTTP and SSE renderers below to log
290
- * unknown/wrapped errors before rendering a generic envelope.
291
- *
292
- * Module-private for now: when an external call site appears we can promote
293
- * to `export` and decide the right shape for `warn`/`info` (FlueError
294
- * subclasses with severity? plain strings? structured data?) — rather than
295
- * committing to a shape now without any usage to validate it.
296
- */
297
- function formatForLog(prefix, err) {
298
- if (isFlueError(err)) {
299
- const lines = [`${prefix} [${err.type}] ${err.message}`];
300
- if (err.details) for (const line of err.details.split("\n")) lines.push(` ${line}`);
301
- if (err.dev) for (const line of err.dev.split("\n")) lines.push(` ${line}`);
302
- if (err.cause !== void 0) lines.push(` cause: ${err.cause instanceof Error ? err.cause.stack ?? err.cause.message : String(err.cause)}`);
303
- return lines.join("\n");
304
- }
305
- if (err instanceof Error) return `${prefix} ${err.stack ?? err.message}`;
306
- return `${prefix} ${String(err)}`;
307
- }
308
- const flueLog = { error(err) {
309
- console.error(formatForLog("[flue]", err));
310
- } };
311
- /**
312
- * Detect whether the server is running in local/dev mode. Gates whether the
313
- * `dev` field is included on the wire — see the convention doc in `errors.ts`.
314
- *
315
- * Currently keyed off the `FLUE_MODE=local` env var, which is set by
316
- * `flue run` and `flue dev --target node`. On Cloudflare workers there is
317
- * no global `process` and no current "local mode" plumbing for the worker —
318
- * so deployed CF and `flue dev --target cloudflare` both currently render
319
- * the prod envelope. Threading a dev-mode signal through to the worker
320
- * fetch handler is left as a follow-up.
321
- */
322
- function isDevMode() {
323
- return typeof process !== "undefined" && process.env?.FLUE_MODE === "local";
324
- }
325
- function envelope(err) {
326
- const out = { error: {
327
- type: err.type,
328
- message: err.message,
329
- details: err.details
330
- } };
331
- if (isDevMode() && err.dev) out.error.dev = err.dev;
332
- if (err.meta) out.error.meta = err.meta;
333
- return out;
334
- }
335
- const GENERIC_INTERNAL = { error: {
336
- type: "internal_error",
337
- message: "An internal error occurred.",
338
- details: "The server encountered an unexpected error while handling this request."
339
- } };
340
- /**
341
- * Render any thrown value into a `Response` with the canonical Flue error
342
- * envelope. Unknown / non-Flue errors are logged in full and rendered as a
343
- * generic 500 with no message leaked.
344
- */
345
- function toHttpResponse(err) {
346
- if (isFlueError(err)) {
347
- const isHttp = err instanceof FlueHttpError;
348
- const status = isHttp ? err.status : 500;
349
- const headers = { "content-type": "application/json" };
350
- if (isHttp && err.headers) Object.assign(headers, err.headers);
351
- if (!isHttp) flueLog.error(err);
352
- return new Response(JSON.stringify(envelope(err)), {
353
- status,
354
- headers
355
- });
356
- }
357
- flueLog.error(err);
358
- return new Response(JSON.stringify(GENERIC_INTERNAL), {
359
- status: 500,
360
- headers: { "content-type": "application/json" }
361
- });
362
- }
363
- /**
364
- * Render any thrown value into a JSON string suitable for the `data:` line of
365
- * an SSE `error` event. Same envelope as `toHttpResponse`. Unknown / non-Flue
366
- * errors are logged and replaced with a generic envelope.
367
- */
368
- function toSseData(err) {
369
- if (isFlueError(err)) {
370
- if (!(err instanceof FlueHttpError)) flueLog.error(err);
371
- return JSON.stringify({
372
- type: "error",
373
- ...envelope(err)
374
- });
375
- }
376
- flueLog.error(err);
377
- return JSON.stringify({
378
- type: "error",
379
- ...GENERIC_INTERNAL
380
- });
381
- }
382
- /**
383
- * Parse a request body as JSON. Returns `{}` for genuinely empty bodies
384
- * (Content-Length: 0 or missing) so that webhook agents which don't accept
385
- * a payload can be invoked without one.
386
- *
387
- * Throws `UnsupportedMediaTypeError` if a body is present without
388
- * `application/json` content-type, and `InvalidJsonError` if the body is
389
- * present but unparseable.
390
- */
391
- async function parseJsonBody(request) {
392
- const contentLengthHeader = request.headers.get("content-length");
393
- const contentLength = contentLengthHeader === null ? null : Number(contentLengthHeader);
394
- const contentType = request.headers.get("content-type");
395
- if (contentLength === 0 || contentLengthHeader === null && contentType === null) return {};
396
- if (!contentType || !contentType.toLowerCase().includes("application/json")) throw new UnsupportedMediaTypeError({ received: contentType });
397
- let text;
398
- try {
399
- text = await request.text();
400
- } catch (err) {
401
- throw new InvalidJsonError({ parseError: err instanceof Error ? err.message : String(err) });
402
- }
403
- if (text.trim() === "") return {};
404
- try {
405
- return JSON.parse(text);
406
- } catch (err) {
407
- throw new InvalidJsonError({ parseError: err instanceof Error ? err.message : String(err) });
408
- }
409
- }
410
- function validateAgentRequest(opts) {
411
- if (opts.method !== "POST") throw new MethodNotAllowedError({
412
- method: opts.method,
413
- allowed: ["POST"]
414
- });
415
- if (opts.name.trim() === "" || opts.id.trim() === "") throw new InvalidRequestError({ reason: "Webhook URLs must have the shape /agents/<name>/<id> with non-empty segments." });
416
- if (!opts.registeredAgents.includes(opts.name)) throw new AgentNotFoundError({
417
- name: opts.name,
418
- available: opts.registeredAgents
419
- });
420
- if (!opts.allowNonWebhook && !opts.webhookAgents.includes(opts.name)) throw new AgentNotWebhookError({ name: opts.name });
421
- }
422
-
423
- //#endregion
424
10
  //#region src/internal.ts
425
11
  /**
426
12
  * Internal runtime helpers consumed by the generated server entry point.
@@ -433,24 +19,24 @@ function validateAgentRequest(opts) {
433
19
  * User agent code should never import from here.
434
20
  */
435
21
  /**
436
- * Resolve a `provider/model-id` string into a pi-ai `Model` object.
437
- * Lives here (rather than in the generated entry point) so that user
438
- * projects don't have to declare `@mariozechner/pi-ai` as a direct
439
- * dependency — wrangler's bundler resolves bare specifiers from the entry
440
- * file's location, which on pnpm-isolated installs doesn't see Flue's
441
- * transitive deps. Centralizing the resolver here keeps `_entry.ts`
442
- * dependency-free apart from `@flue/sdk/*`.
22
+ * Resolve `provider/model-id` to a pi-ai Model. Registered URL prefixes win
23
+ * over pi-ai's catalog; configureProvider settings patch the resolved Model.
443
24
  */
444
- function resolveModel(model, providers) {
25
+ function resolveModel(model) {
445
26
  if (model === false || model === void 0) return void 0;
446
27
  const modelString = model;
447
28
  const slash = modelString.indexOf("/");
448
29
  if (slash === -1) throw new Error(`[flue] Invalid model "${modelString}". Use the "provider/model-id" format (e.g. "anthropic/claude-haiku-4-5").`);
449
30
  const provider = modelString.slice(0, slash);
450
31
  const modelId = modelString.slice(slash + 1);
32
+ const built = resolveRegisteredModel(provider, modelId);
33
+ if (built) {
34
+ if (modelId === "") throw new Error(`[flue] Invalid model "${modelString}". The "${provider}/" prefix is registered via registerProvider(), but no model id was given. Use "${provider}/<model-id>".`);
35
+ return applyProviderSettings(built, getProviderConfiguration(built.provider));
36
+ }
451
37
  const resolved = getModel(provider, modelId);
452
- if (!resolved) throw new Error(`[flue] Unknown model "${modelString}". Provider "${provider}" / model id "${modelId}" is not registered with @mariozechner/pi-ai.`);
453
- return applyProviderSettings(resolved, providers?.[provider]);
38
+ if (!resolved) throw new Error(`[flue] Unknown model "${modelString}". Provider "${provider}" / model id "${modelId}" is not registered with @mariozechner/pi-ai or via registerProvider().`);
39
+ return applyProviderSettings(resolved, getProviderConfiguration(provider));
454
40
  }
455
41
  function applyProviderSettings(model, providerSettings) {
456
42
  if (!providerSettings) return model;
@@ -468,4 +54,4 @@ function applyProviderSettings(model, providerSettings) {
468
54
  }
469
55
 
470
56
  //#endregion
471
- export { AgentNotFoundError, InMemorySessionStore, InvalidRequestError, MethodNotAllowedError, RouteNotFoundError, bashFactoryToSessionEnv, createFlueContext, parseJsonBody, resolveModel, toHttpResponse, toSseData, validateAgentRequest };
57
+ export { InMemorySessionStore, bashFactoryToSessionEnv, configureFlueRuntime, createDefaultFlueApp, createFlueContext, handleAgentRequest, resolveModel };
@@ -1,6 +1,7 @@
1
- import { r as discoverSessionContext } from "./agent-Cahthgu3.mjs";
2
- import { a as assertRoleExists, n as Session, o as createScopedEnv, r as deleteSessionTree, s as mergeCommands } from "./session-DlwIt7wq.mjs";
3
- import { createCwdSessionEnv } from "./sandbox.mjs";
1
+ import { u as discoverSessionContext } from "./result-K1IRhWKM.mjs";
2
+ import { n as createCallHandle } from "./abort-Bg3qsAkU.mjs";
3
+ import { a as assertRoleExists, n as Session, r as deleteSessionTree } from "./session-CO_uGVOk.mjs";
4
+ import { createCwdSessionEnv, createFlueFs } from "./sandbox.mjs";
4
5
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
5
6
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
6
7
 
@@ -12,43 +13,35 @@ var AgentClient = class {
12
13
  create: (id, options) => this.openSession(id, "create", options),
13
14
  delete: (id) => this.deleteSession(id)
14
15
  };
16
+ fs;
15
17
  openSessions = /* @__PURE__ */ new Map();
16
- destroyed = false;
17
- constructor(id, config, env, store, eventCallback, agentCommands = [], agentTools = []) {
18
+ constructor(id, config, env, store, eventCallback, agentTools = []) {
18
19
  this.id = id;
19
20
  this.config = config;
20
21
  this.env = env;
21
22
  this.store = store;
22
23
  this.eventCallback = eventCallback;
23
- this.agentCommands = agentCommands;
24
24
  this.agentTools = agentTools;
25
+ this.fs = createFlueFs(env);
25
26
  }
26
27
  async session(id, options) {
27
28
  return this.openSession(id, "get-or-create", options);
28
29
  }
29
- async shell(command, options) {
30
- this.assertActive();
31
- const effectiveCommands = mergeCommands(this.agentCommands, options?.commands);
32
- const result = await (await createScopedEnv(this.env, effectiveCommands)).exec(command, {
33
- env: options?.env,
34
- cwd: options?.cwd,
35
- timeout: options?.timeout
30
+ shell(command, options) {
31
+ return createCallHandle(options?.signal, async (signal) => {
32
+ const result = await this.env.exec(command, {
33
+ env: options?.env,
34
+ cwd: options?.cwd,
35
+ signal
36
+ });
37
+ return {
38
+ stdout: result.stdout,
39
+ stderr: result.stderr,
40
+ exitCode: result.exitCode
41
+ };
36
42
  });
37
- return {
38
- stdout: result.stdout,
39
- stderr: result.stderr,
40
- exitCode: result.exitCode
41
- };
42
- }
43
- async destroy() {
44
- if (this.destroyed) return;
45
- this.destroyed = true;
46
- for (const session of Array.from(this.openSessions.values())) session.close();
47
- this.openSessions.clear();
48
- await this.env.cleanup();
49
43
  }
50
44
  async openSession(id, mode, options) {
51
- this.assertActive();
52
45
  assertRoleExists(this.config.roles, options?.role);
53
46
  const sessionId = normalizeSessionId(id);
54
47
  const open = this.openSessions.get(sessionId);
@@ -74,7 +67,6 @@ var AgentClient = class {
74
67
  store: this.store,
75
68
  existingData: data,
76
69
  onAgentEvent: this.eventCallback,
77
- agentCommands: this.agentCommands,
78
70
  agentTools: this.agentTools,
79
71
  sessionRole: options?.role,
80
72
  taskDepth: 0,
@@ -85,7 +77,6 @@ var AgentClient = class {
85
77
  return session;
86
78
  }
87
79
  async deleteSession(id) {
88
- this.assertActive();
89
80
  const sessionId = normalizeSessionId(id);
90
81
  const open = this.openSessions.get(sessionId);
91
82
  if (open) {
@@ -95,7 +86,6 @@ var AgentClient = class {
95
86
  await deleteSessionTree(this.store, createSessionStorageKey(this.id, sessionId));
96
87
  }
97
88
  async createTaskSession(options) {
98
- this.assertActive();
99
89
  assertRoleExists(this.config.roles, options.role);
100
90
  const sessionId = `task:${options.parentSessionId}:${options.taskId}`;
101
91
  const taskEnv = options.cwd ? createCwdSessionEnv(options.parentEnv, options.parentEnv.resolvePath(options.cwd)) : options.parentEnv;
@@ -130,16 +120,12 @@ var AgentClient = class {
130
120
  store: this.store,
131
121
  existingData: data,
132
122
  onAgentEvent: eventCallback,
133
- agentCommands: options.commands,
134
123
  agentTools: this.agentTools,
135
124
  sessionRole: options.role,
136
125
  taskDepth: options.depth,
137
126
  createTaskSession: (childOptions) => this.createTaskSession(childOptions)
138
127
  });
139
128
  }
140
- assertActive() {
141
- if (this.destroyed) throw new Error(`[flue] Agent "${this.id}" has been destroyed.`);
142
- }
143
129
  };
144
130
  function normalizeSessionId(id) {
145
131
  return id ?? DEFAULT_SESSION_ID;
@@ -1,4 +1,4 @@
1
- import { P as ToolDef } from "./types-DGpyKMFm.mjs";
1
+ import { L as ToolDef } from "./types-BAmV4f3Q.mjs";
2
2
 
3
3
  //#region src/mcp.d.ts
4
4
  type McpTransport = 'streamable-http' | 'sse';
@@ -1,14 +1,10 @@
1
- import { l as Command } from "../types-DGpyKMFm.mjs";
2
- import { t as CommandExecutor } from "../command-helpers-eVG1-Iru.mjs";
3
- import { execFile } from "node:child_process";
1
+ import { O as SessionEnv } from "../types-BAmV4f3Q.mjs";
4
2
 
5
- //#region src/node/define-command.d.ts
6
- /**
7
- * Options forwarded directly to Node's `child_process.execFile`. Full pass-through.
8
- */
9
- type CommandOptions = NonNullable<Parameters<typeof execFile>[2]>;
10
- declare function defineCommand(name: string): Command;
11
- declare function defineCommand(name: string, options: CommandOptions): Command;
12
- declare function defineCommand(name: string, execute: CommandExecutor): Command;
3
+ //#region src/node/local-env.d.ts
4
+ interface LocalSessionEnvOptions {
5
+ /** Working directory. Defaults to `process.cwd()`. */
6
+ cwd?: string;
7
+ }
8
+ declare function createLocalSessionEnv(options?: LocalSessionEnvOptions): SessionEnv;
13
9
  //#endregion
14
- export { type CommandOptions, defineCommand };
10
+ export { type LocalSessionEnvOptions, createLocalSessionEnv };