@bunny-agent/daemon 0.9.31 → 0.9.33

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/bundle.mjs CHANGED
@@ -288994,20 +288994,37 @@ var generateImageSchema = {
288994
288994
  size: {
288995
288995
  type: "string",
288996
288996
  enum: [
288997
+ "auto",
288998
+ "1024x1024",
288999
+ "1536x1024",
289000
+ "1024x1536",
288997
289001
  "256x256",
288998
289002
  "512x512",
288999
- "1024x1024",
289000
289003
  "1792x1024",
289001
- "1024x1792",
289002
- "1280x1280",
289003
- "1568x1056",
289004
- "1056x1568",
289005
- "1472x1088",
289006
- "1088x1472",
289007
- "1728x960",
289008
- "960x1728"
289004
+ "1024x1792"
289009
289005
  ],
289010
- description: "Image dimensions. Common: 1024x1024 (square), 1280x1280, 1568x1056 (landscape), 1056x1568 (portrait), 1728x960 (wide), 960x1728 (tall)."
289006
+ description: "Image dimensions. Supported values: auto, 1024x1024, 1536x1024, 1024x1536, 256x256, 512x512, 1792x1024, 1024x1792."
289007
+ },
289008
+ aspectRatio: {
289009
+ type: "string",
289010
+ enum: [
289011
+ "1:1",
289012
+ "3:2",
289013
+ "2:3",
289014
+ "3:4",
289015
+ "4:3",
289016
+ "4:5",
289017
+ "5:4",
289018
+ "9:16",
289019
+ "16:9",
289020
+ "21:9"
289021
+ ],
289022
+ description: "Image aspect ratio. Use this instead of size for models that support it when exact proportions matter. Supported values: 1:1, 3:2, 2:3, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9."
289023
+ },
289024
+ imageSize: {
289025
+ type: "string",
289026
+ enum: ["1K", "2K", "4K"],
289027
+ description: "Image resolution for models that support K-resolution output. Use this for requests like 2K or 4K."
289011
289028
  },
289012
289029
  quality: {
289013
289030
  type: "string",
@@ -289162,19 +289179,23 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
289162
289179
  name: "generate_image",
289163
289180
  label: "generate image",
289164
289181
  description: "Generate an image from a text prompt. Saves the image to disk and returns the file path.",
289165
- promptSnippet: "generate_image(prompt, filename?, size?, quality?) - generate an image from text",
289182
+ promptSnippet: "generate_image(prompt, filename?, size?, aspectRatio?, imageSize?, quality?) - generate an image from text",
289166
289183
  promptGuidelines: [
289167
289184
  "Use generate_image when the user asks to create, draw, or visualize something.",
289168
289185
  "Be descriptive in the prompt \u2014 more detail produces better results.",
289169
- "Provide a filename with extension, e.g. 'cat.png'."
289186
+ "Provide a filename with extension, e.g. 'cat.png'.",
289187
+ "Use aspectRatio (e.g. '3:4') when the requested output needs specific proportions.",
289188
+ "Use imageSize (e.g. '2K') when the user requests 1K, 2K, or 4K resolution."
289170
289189
  ],
289171
289190
  // biome-ignore lint/suspicious/noExplicitAny: plain JSON Schema compatible with TypeBox TSchema
289172
289191
  parameters: generateImageSchema,
289173
289192
  async execute(_toolCallId, params, signal, _onUpdate) {
289174
289193
  const p = params;
289175
289194
  const prompt = p.prompt;
289176
- const size = p.size ?? "1024x1024";
289195
+ const size = p.size;
289177
289196
  const quality = p.quality ?? "auto";
289197
+ const aspectRatio = p.aspectRatio;
289198
+ const imageSize = p.imageSize;
289178
289199
  const rawFilename = p.filename;
289179
289200
  const filename = rawFilename ? extname2(rawFilename) ? rawFilename : `${rawFilename}.png` : `image_${Date.now()}.png`;
289180
289201
  const filePath = join35(cwd, filename.replace(/[^a-zA-Z0-9_\-./]/g, "_"));
@@ -289190,10 +289211,12 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
289190
289211
  model: imageModelId,
289191
289212
  prompt,
289192
289213
  n: 1,
289193
- size,
289194
289214
  quality,
289195
289215
  response_format: "b64_json",
289196
- output_format: "png"
289216
+ output_format: "png",
289217
+ ...aspectRatio ? { aspect_ratio: aspectRatio } : {},
289218
+ ...imageSize ? { image_size: imageSize } : {},
289219
+ ...size ? { size } : !aspectRatio && !imageSize ? { size: "1024x1024" } : {}
289197
289220
  }),
289198
289221
  signal
289199
289222
  });
@@ -290115,8 +290138,103 @@ function buildSecretAwareTools(cwd, secrets) {
290115
290138
  return tools;
290116
290139
  }
290117
290140
 
290141
+ // ../../packages/runner-pi/dist/tool-refs.js
290142
+ var LOG_PREFIX2 = "[bunny-agent:pi-tool-ref]";
290143
+ function buildToolDefinitionsFromRefs(tools) {
290144
+ return tools.map((spec) => buildOne(spec));
290145
+ }
290146
+ function buildOne(spec) {
290147
+ const parameters = Type.Unsafe(spec.inputSchema);
290148
+ return {
290149
+ name: spec.name,
290150
+ label: spec.name,
290151
+ description: spec.description,
290152
+ parameters,
290153
+ async execute(_toolCallId, params, signal) {
290154
+ let response;
290155
+ try {
290156
+ response = await executeToolRef(spec, params, signal);
290157
+ } catch (error) {
290158
+ const message = error instanceof Error ? error.message : String(error);
290159
+ return transportErrorResult(spec.name, message);
290160
+ }
290161
+ if (response.status < 200 || response.status >= 300) {
290162
+ return statusErrorResult(spec.name, response.status, response.body);
290163
+ }
290164
+ return okResult(response.body);
290165
+ }
290166
+ };
290167
+ }
290168
+ async function executeToolRef(spec, params, signal) {
290169
+ switch (spec.runtime.type) {
290170
+ case "http":
290171
+ return sendDirectHttpRequest(spec.runtime, params, signal);
290172
+ case "module":
290173
+ return executeModuleTool(spec.runtime, params, signal);
290174
+ }
290175
+ }
290176
+ async function sendDirectHttpRequest(runtime, params, signal) {
290177
+ const response = await fetch(runtime.url, {
290178
+ method: "POST",
290179
+ signal,
290180
+ headers: {
290181
+ "Content-Type": "application/json",
290182
+ ...runtime.headers ?? {}
290183
+ },
290184
+ body: JSON.stringify(params)
290185
+ });
290186
+ const body = await response.text();
290187
+ return { status: response.status, body };
290188
+ }
290189
+ async function executeModuleTool(runtime, params, signal) {
290190
+ const mod = await import(runtime.module);
290191
+ const exportName = runtime.exportName ?? "execute";
290192
+ const fn = mod[exportName];
290193
+ if (typeof fn !== "function") {
290194
+ return {
290195
+ status: 500,
290196
+ body: `module tool export "${exportName}" is not a function`
290197
+ };
290198
+ }
290199
+ const result = await fn(params, { signal });
290200
+ return { status: 200, body: serializeResult(result) };
290201
+ }
290202
+ function okResult(text) {
290203
+ return {
290204
+ content: [{ type: "text", text }],
290205
+ details: void 0
290206
+ };
290207
+ }
290208
+ function statusErrorResult(toolName, status2, body) {
290209
+ return {
290210
+ content: [
290211
+ {
290212
+ type: "text",
290213
+ text: `${LOG_PREFIX2} tool "${toolName}" failed (status ${status2}): ${body}`
290214
+ }
290215
+ ],
290216
+ details: void 0
290217
+ };
290218
+ }
290219
+ function transportErrorResult(toolName, message) {
290220
+ return {
290221
+ content: [
290222
+ {
290223
+ type: "text",
290224
+ text: `${LOG_PREFIX2} tool "${toolName}" transport error: ${message}`
290225
+ }
290226
+ ],
290227
+ details: void 0
290228
+ };
290229
+ }
290230
+ function serializeResult(result) {
290231
+ if (typeof result === "string")
290232
+ return result;
290233
+ return JSON.stringify(result);
290234
+ }
290235
+
290118
290236
  // ../../packages/runner-pi/dist/pi-runner.js
290119
- var LOG_PREFIX2 = "[bunny-agent:pi]";
290237
+ var LOG_PREFIX3 = "[bunny-agent:pi]";
290120
290238
  function parseModelSpec(model) {
290121
290239
  const trimmed = model.trim();
290122
290240
  const separator = trimmed.indexOf(":");
@@ -290241,11 +290359,11 @@ function createPiRunner(options2 = {}) {
290241
290359
  return SessionManager.open(resume);
290242
290360
  }
290243
290361
  const sessionPath2 = resolveSessionPathById(cwd, resume);
290244
- console.error(`${LOG_PREFIX2} resume: id=${resume} path=${sessionPath2 ?? "(not found)"}`);
290362
+ console.error(`${LOG_PREFIX3} resume: id=${resume} path=${sessionPath2 ?? "(not found)"}`);
290245
290363
  if (sessionPath2) {
290246
290364
  if (isSessionFileTooLarge(sessionPath2)) {
290247
290365
  const context = extractSessionContext(sessionPath2);
290248
- console.error(`${LOG_PREFIX2} session file too large, starting fresh${context ? " (with context)" : ""}`);
290366
+ console.error(`${LOG_PREFIX3} session file too large, starting fresh${context ? " (with context)" : ""}`);
290249
290367
  const newMgr = SessionManager.create(cwd);
290250
290368
  if (context) {
290251
290369
  const firstId = newMgr.getEntries()[0]?.id ?? "";
@@ -290265,7 +290383,7 @@ function createPiRunner(options2 = {}) {
290265
290383
  appendSystemPrompt: options2.systemPrompt
290266
290384
  }) : void 0;
290267
290385
  if (options2.skillPaths && options2.skillPaths.length > 0) {
290268
- console.error(`${LOG_PREFIX2} runner: cwd=${cwd} skillPaths=${JSON.stringify(options2.skillPaths)}`);
290386
+ console.error(`${LOG_PREFIX3} runner: cwd=${cwd} skillPaths=${JSON.stringify(options2.skillPaths)}`);
290269
290387
  }
290270
290388
  if (resourceLoader) {
290271
290389
  await resourceLoader.reload();
@@ -290275,6 +290393,12 @@ function createPiRunner(options2 = {}) {
290275
290393
  const apiKey = await modelRegistry2.authStorage.getApiKey(provider) ?? "";
290276
290394
  customTools.push(buildImageGenerateTool(cwd, imageModelName, model.baseUrl, apiKey), buildImageEditTool(cwd, imageModelName, model.baseUrl, apiKey));
290277
290395
  }
290396
+ if (options2.customTools && options2.customTools.length > 0) {
290397
+ customTools.push(...options2.customTools);
290398
+ }
290399
+ if (options2.toolRefs && options2.toolRefs.length > 0) {
290400
+ customTools.push(...buildToolDefinitionsFromRefs(options2.toolRefs));
290401
+ }
290278
290402
  const { session } = await createAgentSession({
290279
290403
  cwd,
290280
290404
  model,
@@ -290472,13 +290596,15 @@ function dispatchRunner(runner, base, cwd, options2) {
290472
290596
  env: base.env,
290473
290597
  abortController: base.abortController
290474
290598
  }).run(options2.userInput);
290475
- case "pi":
290599
+ case "pi": {
290476
290600
  return createPiRunner({
290477
290601
  ...base,
290478
290602
  cwd,
290479
290603
  sessionId: base.resume,
290480
- skillPaths: options2.skillPaths ?? discoverSkillPaths(cwd)
290604
+ skillPaths: options2.skillPaths ?? discoverSkillPaths(cwd),
290605
+ toolRefs: options2.toolRefs
290481
290606
  }).run(options2.userInput);
290607
+ }
290482
290608
  case "opencode":
290483
290609
  return createOpenCodeRunner({
290484
290610
  model: options2.model,
@@ -290549,6 +290675,7 @@ async function bunnyAgentRun(req, res, env2) {
290549
290675
  yolo: req.yolo,
290550
290676
  env: env2,
290551
290677
  abortController,
290678
+ toolRefs: req.toolRefs,
290552
290679
  // API: caller owns resume/session; do not read/write cwd/.bunny-agent or auto-load CLAUDE.md.
290553
290680
  autoInject: false
290554
290681
  });
package/dist/index.js CHANGED
@@ -288990,20 +288990,37 @@ var generateImageSchema = {
288990
288990
  size: {
288991
288991
  type: "string",
288992
288992
  enum: [
288993
+ "auto",
288994
+ "1024x1024",
288995
+ "1536x1024",
288996
+ "1024x1536",
288993
288997
  "256x256",
288994
288998
  "512x512",
288995
- "1024x1024",
288996
288999
  "1792x1024",
288997
- "1024x1792",
288998
- "1280x1280",
288999
- "1568x1056",
289000
- "1056x1568",
289001
- "1472x1088",
289002
- "1088x1472",
289003
- "1728x960",
289004
- "960x1728"
289000
+ "1024x1792"
289005
289001
  ],
289006
- description: "Image dimensions. Common: 1024x1024 (square), 1280x1280, 1568x1056 (landscape), 1056x1568 (portrait), 1728x960 (wide), 960x1728 (tall)."
289002
+ description: "Image dimensions. Supported values: auto, 1024x1024, 1536x1024, 1024x1536, 256x256, 512x512, 1792x1024, 1024x1792."
289003
+ },
289004
+ aspectRatio: {
289005
+ type: "string",
289006
+ enum: [
289007
+ "1:1",
289008
+ "3:2",
289009
+ "2:3",
289010
+ "3:4",
289011
+ "4:3",
289012
+ "4:5",
289013
+ "5:4",
289014
+ "9:16",
289015
+ "16:9",
289016
+ "21:9"
289017
+ ],
289018
+ description: "Image aspect ratio. Use this instead of size for models that support it when exact proportions matter. Supported values: 1:1, 3:2, 2:3, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9."
289019
+ },
289020
+ imageSize: {
289021
+ type: "string",
289022
+ enum: ["1K", "2K", "4K"],
289023
+ description: "Image resolution for models that support K-resolution output. Use this for requests like 2K or 4K."
289007
289024
  },
289008
289025
  quality: {
289009
289026
  type: "string",
@@ -289158,19 +289175,23 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
289158
289175
  name: "generate_image",
289159
289176
  label: "generate image",
289160
289177
  description: "Generate an image from a text prompt. Saves the image to disk and returns the file path.",
289161
- promptSnippet: "generate_image(prompt, filename?, size?, quality?) - generate an image from text",
289178
+ promptSnippet: "generate_image(prompt, filename?, size?, aspectRatio?, imageSize?, quality?) - generate an image from text",
289162
289179
  promptGuidelines: [
289163
289180
  "Use generate_image when the user asks to create, draw, or visualize something.",
289164
289181
  "Be descriptive in the prompt \u2014 more detail produces better results.",
289165
- "Provide a filename with extension, e.g. 'cat.png'."
289182
+ "Provide a filename with extension, e.g. 'cat.png'.",
289183
+ "Use aspectRatio (e.g. '3:4') when the requested output needs specific proportions.",
289184
+ "Use imageSize (e.g. '2K') when the user requests 1K, 2K, or 4K resolution."
289166
289185
  ],
289167
289186
  // biome-ignore lint/suspicious/noExplicitAny: plain JSON Schema compatible with TypeBox TSchema
289168
289187
  parameters: generateImageSchema,
289169
289188
  async execute(_toolCallId, params, signal, _onUpdate) {
289170
289189
  const p = params;
289171
289190
  const prompt = p.prompt;
289172
- const size = p.size ?? "1024x1024";
289191
+ const size = p.size;
289173
289192
  const quality = p.quality ?? "auto";
289193
+ const aspectRatio = p.aspectRatio;
289194
+ const imageSize = p.imageSize;
289174
289195
  const rawFilename = p.filename;
289175
289196
  const filename = rawFilename ? extname2(rawFilename) ? rawFilename : `${rawFilename}.png` : `image_${Date.now()}.png`;
289176
289197
  const filePath = join35(cwd, filename.replace(/[^a-zA-Z0-9_\-./]/g, "_"));
@@ -289186,10 +289207,12 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
289186
289207
  model: imageModelId,
289187
289208
  prompt,
289188
289209
  n: 1,
289189
- size,
289190
289210
  quality,
289191
289211
  response_format: "b64_json",
289192
- output_format: "png"
289212
+ output_format: "png",
289213
+ ...aspectRatio ? { aspect_ratio: aspectRatio } : {},
289214
+ ...imageSize ? { image_size: imageSize } : {},
289215
+ ...size ? { size } : !aspectRatio && !imageSize ? { size: "1024x1024" } : {}
289193
289216
  }),
289194
289217
  signal
289195
289218
  });
@@ -290111,8 +290134,103 @@ function buildSecretAwareTools(cwd, secrets) {
290111
290134
  return tools;
290112
290135
  }
290113
290136
 
290137
+ // ../../packages/runner-pi/dist/tool-refs.js
290138
+ var LOG_PREFIX2 = "[bunny-agent:pi-tool-ref]";
290139
+ function buildToolDefinitionsFromRefs(tools) {
290140
+ return tools.map((spec) => buildOne(spec));
290141
+ }
290142
+ function buildOne(spec) {
290143
+ const parameters = Type.Unsafe(spec.inputSchema);
290144
+ return {
290145
+ name: spec.name,
290146
+ label: spec.name,
290147
+ description: spec.description,
290148
+ parameters,
290149
+ async execute(_toolCallId, params, signal) {
290150
+ let response;
290151
+ try {
290152
+ response = await executeToolRef(spec, params, signal);
290153
+ } catch (error) {
290154
+ const message = error instanceof Error ? error.message : String(error);
290155
+ return transportErrorResult(spec.name, message);
290156
+ }
290157
+ if (response.status < 200 || response.status >= 300) {
290158
+ return statusErrorResult(spec.name, response.status, response.body);
290159
+ }
290160
+ return okResult(response.body);
290161
+ }
290162
+ };
290163
+ }
290164
+ async function executeToolRef(spec, params, signal) {
290165
+ switch (spec.runtime.type) {
290166
+ case "http":
290167
+ return sendDirectHttpRequest(spec.runtime, params, signal);
290168
+ case "module":
290169
+ return executeModuleTool(spec.runtime, params, signal);
290170
+ }
290171
+ }
290172
+ async function sendDirectHttpRequest(runtime, params, signal) {
290173
+ const response = await fetch(runtime.url, {
290174
+ method: "POST",
290175
+ signal,
290176
+ headers: {
290177
+ "Content-Type": "application/json",
290178
+ ...runtime.headers ?? {}
290179
+ },
290180
+ body: JSON.stringify(params)
290181
+ });
290182
+ const body = await response.text();
290183
+ return { status: response.status, body };
290184
+ }
290185
+ async function executeModuleTool(runtime, params, signal) {
290186
+ const mod = await import(runtime.module);
290187
+ const exportName = runtime.exportName ?? "execute";
290188
+ const fn = mod[exportName];
290189
+ if (typeof fn !== "function") {
290190
+ return {
290191
+ status: 500,
290192
+ body: `module tool export "${exportName}" is not a function`
290193
+ };
290194
+ }
290195
+ const result = await fn(params, { signal });
290196
+ return { status: 200, body: serializeResult(result) };
290197
+ }
290198
+ function okResult(text) {
290199
+ return {
290200
+ content: [{ type: "text", text }],
290201
+ details: void 0
290202
+ };
290203
+ }
290204
+ function statusErrorResult(toolName, status2, body) {
290205
+ return {
290206
+ content: [
290207
+ {
290208
+ type: "text",
290209
+ text: `${LOG_PREFIX2} tool "${toolName}" failed (status ${status2}): ${body}`
290210
+ }
290211
+ ],
290212
+ details: void 0
290213
+ };
290214
+ }
290215
+ function transportErrorResult(toolName, message) {
290216
+ return {
290217
+ content: [
290218
+ {
290219
+ type: "text",
290220
+ text: `${LOG_PREFIX2} tool "${toolName}" transport error: ${message}`
290221
+ }
290222
+ ],
290223
+ details: void 0
290224
+ };
290225
+ }
290226
+ function serializeResult(result) {
290227
+ if (typeof result === "string")
290228
+ return result;
290229
+ return JSON.stringify(result);
290230
+ }
290231
+
290114
290232
  // ../../packages/runner-pi/dist/pi-runner.js
290115
- var LOG_PREFIX2 = "[bunny-agent:pi]";
290233
+ var LOG_PREFIX3 = "[bunny-agent:pi]";
290116
290234
  function parseModelSpec(model) {
290117
290235
  const trimmed = model.trim();
290118
290236
  const separator = trimmed.indexOf(":");
@@ -290237,11 +290355,11 @@ function createPiRunner(options2 = {}) {
290237
290355
  return SessionManager.open(resume);
290238
290356
  }
290239
290357
  const sessionPath2 = resolveSessionPathById(cwd, resume);
290240
- console.error(`${LOG_PREFIX2} resume: id=${resume} path=${sessionPath2 ?? "(not found)"}`);
290358
+ console.error(`${LOG_PREFIX3} resume: id=${resume} path=${sessionPath2 ?? "(not found)"}`);
290241
290359
  if (sessionPath2) {
290242
290360
  if (isSessionFileTooLarge(sessionPath2)) {
290243
290361
  const context = extractSessionContext(sessionPath2);
290244
- console.error(`${LOG_PREFIX2} session file too large, starting fresh${context ? " (with context)" : ""}`);
290362
+ console.error(`${LOG_PREFIX3} session file too large, starting fresh${context ? " (with context)" : ""}`);
290245
290363
  const newMgr = SessionManager.create(cwd);
290246
290364
  if (context) {
290247
290365
  const firstId = newMgr.getEntries()[0]?.id ?? "";
@@ -290261,7 +290379,7 @@ function createPiRunner(options2 = {}) {
290261
290379
  appendSystemPrompt: options2.systemPrompt
290262
290380
  }) : void 0;
290263
290381
  if (options2.skillPaths && options2.skillPaths.length > 0) {
290264
- console.error(`${LOG_PREFIX2} runner: cwd=${cwd} skillPaths=${JSON.stringify(options2.skillPaths)}`);
290382
+ console.error(`${LOG_PREFIX3} runner: cwd=${cwd} skillPaths=${JSON.stringify(options2.skillPaths)}`);
290265
290383
  }
290266
290384
  if (resourceLoader) {
290267
290385
  await resourceLoader.reload();
@@ -290271,6 +290389,12 @@ function createPiRunner(options2 = {}) {
290271
290389
  const apiKey = await modelRegistry2.authStorage.getApiKey(provider) ?? "";
290272
290390
  customTools.push(buildImageGenerateTool(cwd, imageModelName, model.baseUrl, apiKey), buildImageEditTool(cwd, imageModelName, model.baseUrl, apiKey));
290273
290391
  }
290392
+ if (options2.customTools && options2.customTools.length > 0) {
290393
+ customTools.push(...options2.customTools);
290394
+ }
290395
+ if (options2.toolRefs && options2.toolRefs.length > 0) {
290396
+ customTools.push(...buildToolDefinitionsFromRefs(options2.toolRefs));
290397
+ }
290274
290398
  const { session } = await createAgentSession({
290275
290399
  cwd,
290276
290400
  model,
@@ -290468,13 +290592,15 @@ function dispatchRunner(runner, base, cwd, options2) {
290468
290592
  env: base.env,
290469
290593
  abortController: base.abortController
290470
290594
  }).run(options2.userInput);
290471
- case "pi":
290595
+ case "pi": {
290472
290596
  return createPiRunner({
290473
290597
  ...base,
290474
290598
  cwd,
290475
290599
  sessionId: base.resume,
290476
- skillPaths: options2.skillPaths ?? discoverSkillPaths(cwd)
290600
+ skillPaths: options2.skillPaths ?? discoverSkillPaths(cwd),
290601
+ toolRefs: options2.toolRefs
290477
290602
  }).run(options2.userInput);
290603
+ }
290478
290604
  case "opencode":
290479
290605
  return createOpenCodeRunner({
290480
290606
  model: options2.model,
@@ -290545,6 +290671,7 @@ async function bunnyAgentRun(req, res, env2) {
290545
290671
  yolo: req.yolo,
290546
290672
  env: env2,
290547
290673
  abortController,
290674
+ toolRefs: req.toolRefs,
290548
290675
  // API: caller owns resume/session; do not read/write cwd/.bunny-agent or auto-load CLAUDE.md.
290549
290676
  autoInject: false
290550
290677
  });
package/dist/nextjs.js CHANGED
@@ -288986,20 +288986,37 @@ var generateImageSchema = {
288986
288986
  size: {
288987
288987
  type: "string",
288988
288988
  enum: [
288989
+ "auto",
288990
+ "1024x1024",
288991
+ "1536x1024",
288992
+ "1024x1536",
288989
288993
  "256x256",
288990
288994
  "512x512",
288991
- "1024x1024",
288992
288995
  "1792x1024",
288993
- "1024x1792",
288994
- "1280x1280",
288995
- "1568x1056",
288996
- "1056x1568",
288997
- "1472x1088",
288998
- "1088x1472",
288999
- "1728x960",
289000
- "960x1728"
288996
+ "1024x1792"
289001
288997
  ],
289002
- description: "Image dimensions. Common: 1024x1024 (square), 1280x1280, 1568x1056 (landscape), 1056x1568 (portrait), 1728x960 (wide), 960x1728 (tall)."
288998
+ description: "Image dimensions. Supported values: auto, 1024x1024, 1536x1024, 1024x1536, 256x256, 512x512, 1792x1024, 1024x1792."
288999
+ },
289000
+ aspectRatio: {
289001
+ type: "string",
289002
+ enum: [
289003
+ "1:1",
289004
+ "3:2",
289005
+ "2:3",
289006
+ "3:4",
289007
+ "4:3",
289008
+ "4:5",
289009
+ "5:4",
289010
+ "9:16",
289011
+ "16:9",
289012
+ "21:9"
289013
+ ],
289014
+ description: "Image aspect ratio. Use this instead of size for models that support it when exact proportions matter. Supported values: 1:1, 3:2, 2:3, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9."
289015
+ },
289016
+ imageSize: {
289017
+ type: "string",
289018
+ enum: ["1K", "2K", "4K"],
289019
+ description: "Image resolution for models that support K-resolution output. Use this for requests like 2K or 4K."
289003
289020
  },
289004
289021
  quality: {
289005
289022
  type: "string",
@@ -289154,19 +289171,23 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
289154
289171
  name: "generate_image",
289155
289172
  label: "generate image",
289156
289173
  description: "Generate an image from a text prompt. Saves the image to disk and returns the file path.",
289157
- promptSnippet: "generate_image(prompt, filename?, size?, quality?) - generate an image from text",
289174
+ promptSnippet: "generate_image(prompt, filename?, size?, aspectRatio?, imageSize?, quality?) - generate an image from text",
289158
289175
  promptGuidelines: [
289159
289176
  "Use generate_image when the user asks to create, draw, or visualize something.",
289160
289177
  "Be descriptive in the prompt \u2014 more detail produces better results.",
289161
- "Provide a filename with extension, e.g. 'cat.png'."
289178
+ "Provide a filename with extension, e.g. 'cat.png'.",
289179
+ "Use aspectRatio (e.g. '3:4') when the requested output needs specific proportions.",
289180
+ "Use imageSize (e.g. '2K') when the user requests 1K, 2K, or 4K resolution."
289162
289181
  ],
289163
289182
  // biome-ignore lint/suspicious/noExplicitAny: plain JSON Schema compatible with TypeBox TSchema
289164
289183
  parameters: generateImageSchema,
289165
289184
  async execute(_toolCallId, params, signal, _onUpdate) {
289166
289185
  const p = params;
289167
289186
  const prompt = p.prompt;
289168
- const size = p.size ?? "1024x1024";
289187
+ const size = p.size;
289169
289188
  const quality = p.quality ?? "auto";
289189
+ const aspectRatio = p.aspectRatio;
289190
+ const imageSize = p.imageSize;
289170
289191
  const rawFilename = p.filename;
289171
289192
  const filename = rawFilename ? extname2(rawFilename) ? rawFilename : `${rawFilename}.png` : `image_${Date.now()}.png`;
289172
289193
  const filePath = join35(cwd, filename.replace(/[^a-zA-Z0-9_\-./]/g, "_"));
@@ -289182,10 +289203,12 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
289182
289203
  model: imageModelId,
289183
289204
  prompt,
289184
289205
  n: 1,
289185
- size,
289186
289206
  quality,
289187
289207
  response_format: "b64_json",
289188
- output_format: "png"
289208
+ output_format: "png",
289209
+ ...aspectRatio ? { aspect_ratio: aspectRatio } : {},
289210
+ ...imageSize ? { image_size: imageSize } : {},
289211
+ ...size ? { size } : !aspectRatio && !imageSize ? { size: "1024x1024" } : {}
289189
289212
  }),
289190
289213
  signal
289191
289214
  });
@@ -290107,8 +290130,103 @@ function buildSecretAwareTools(cwd, secrets) {
290107
290130
  return tools;
290108
290131
  }
290109
290132
 
290133
+ // ../../packages/runner-pi/dist/tool-refs.js
290134
+ var LOG_PREFIX2 = "[bunny-agent:pi-tool-ref]";
290135
+ function buildToolDefinitionsFromRefs(tools) {
290136
+ return tools.map((spec) => buildOne(spec));
290137
+ }
290138
+ function buildOne(spec) {
290139
+ const parameters = Type.Unsafe(spec.inputSchema);
290140
+ return {
290141
+ name: spec.name,
290142
+ label: spec.name,
290143
+ description: spec.description,
290144
+ parameters,
290145
+ async execute(_toolCallId, params, signal) {
290146
+ let response;
290147
+ try {
290148
+ response = await executeToolRef(spec, params, signal);
290149
+ } catch (error) {
290150
+ const message = error instanceof Error ? error.message : String(error);
290151
+ return transportErrorResult(spec.name, message);
290152
+ }
290153
+ if (response.status < 200 || response.status >= 300) {
290154
+ return statusErrorResult(spec.name, response.status, response.body);
290155
+ }
290156
+ return okResult(response.body);
290157
+ }
290158
+ };
290159
+ }
290160
+ async function executeToolRef(spec, params, signal) {
290161
+ switch (spec.runtime.type) {
290162
+ case "http":
290163
+ return sendDirectHttpRequest(spec.runtime, params, signal);
290164
+ case "module":
290165
+ return executeModuleTool(spec.runtime, params, signal);
290166
+ }
290167
+ }
290168
+ async function sendDirectHttpRequest(runtime, params, signal) {
290169
+ const response = await fetch(runtime.url, {
290170
+ method: "POST",
290171
+ signal,
290172
+ headers: {
290173
+ "Content-Type": "application/json",
290174
+ ...runtime.headers ?? {}
290175
+ },
290176
+ body: JSON.stringify(params)
290177
+ });
290178
+ const body = await response.text();
290179
+ return { status: response.status, body };
290180
+ }
290181
+ async function executeModuleTool(runtime, params, signal) {
290182
+ const mod = await import(runtime.module);
290183
+ const exportName = runtime.exportName ?? "execute";
290184
+ const fn = mod[exportName];
290185
+ if (typeof fn !== "function") {
290186
+ return {
290187
+ status: 500,
290188
+ body: `module tool export "${exportName}" is not a function`
290189
+ };
290190
+ }
290191
+ const result = await fn(params, { signal });
290192
+ return { status: 200, body: serializeResult(result) };
290193
+ }
290194
+ function okResult(text) {
290195
+ return {
290196
+ content: [{ type: "text", text }],
290197
+ details: void 0
290198
+ };
290199
+ }
290200
+ function statusErrorResult(toolName, status2, body) {
290201
+ return {
290202
+ content: [
290203
+ {
290204
+ type: "text",
290205
+ text: `${LOG_PREFIX2} tool "${toolName}" failed (status ${status2}): ${body}`
290206
+ }
290207
+ ],
290208
+ details: void 0
290209
+ };
290210
+ }
290211
+ function transportErrorResult(toolName, message) {
290212
+ return {
290213
+ content: [
290214
+ {
290215
+ type: "text",
290216
+ text: `${LOG_PREFIX2} tool "${toolName}" transport error: ${message}`
290217
+ }
290218
+ ],
290219
+ details: void 0
290220
+ };
290221
+ }
290222
+ function serializeResult(result) {
290223
+ if (typeof result === "string")
290224
+ return result;
290225
+ return JSON.stringify(result);
290226
+ }
290227
+
290110
290228
  // ../../packages/runner-pi/dist/pi-runner.js
290111
- var LOG_PREFIX2 = "[bunny-agent:pi]";
290229
+ var LOG_PREFIX3 = "[bunny-agent:pi]";
290112
290230
  function parseModelSpec(model) {
290113
290231
  const trimmed = model.trim();
290114
290232
  const separator = trimmed.indexOf(":");
@@ -290233,11 +290351,11 @@ function createPiRunner(options2 = {}) {
290233
290351
  return SessionManager.open(resume);
290234
290352
  }
290235
290353
  const sessionPath2 = resolveSessionPathById(cwd, resume);
290236
- console.error(`${LOG_PREFIX2} resume: id=${resume} path=${sessionPath2 ?? "(not found)"}`);
290354
+ console.error(`${LOG_PREFIX3} resume: id=${resume} path=${sessionPath2 ?? "(not found)"}`);
290237
290355
  if (sessionPath2) {
290238
290356
  if (isSessionFileTooLarge(sessionPath2)) {
290239
290357
  const context = extractSessionContext(sessionPath2);
290240
- console.error(`${LOG_PREFIX2} session file too large, starting fresh${context ? " (with context)" : ""}`);
290358
+ console.error(`${LOG_PREFIX3} session file too large, starting fresh${context ? " (with context)" : ""}`);
290241
290359
  const newMgr = SessionManager.create(cwd);
290242
290360
  if (context) {
290243
290361
  const firstId = newMgr.getEntries()[0]?.id ?? "";
@@ -290257,7 +290375,7 @@ function createPiRunner(options2 = {}) {
290257
290375
  appendSystemPrompt: options2.systemPrompt
290258
290376
  }) : void 0;
290259
290377
  if (options2.skillPaths && options2.skillPaths.length > 0) {
290260
- console.error(`${LOG_PREFIX2} runner: cwd=${cwd} skillPaths=${JSON.stringify(options2.skillPaths)}`);
290378
+ console.error(`${LOG_PREFIX3} runner: cwd=${cwd} skillPaths=${JSON.stringify(options2.skillPaths)}`);
290261
290379
  }
290262
290380
  if (resourceLoader) {
290263
290381
  await resourceLoader.reload();
@@ -290267,6 +290385,12 @@ function createPiRunner(options2 = {}) {
290267
290385
  const apiKey = await modelRegistry2.authStorage.getApiKey(provider) ?? "";
290268
290386
  customTools.push(buildImageGenerateTool(cwd, imageModelName, model.baseUrl, apiKey), buildImageEditTool(cwd, imageModelName, model.baseUrl, apiKey));
290269
290387
  }
290388
+ if (options2.customTools && options2.customTools.length > 0) {
290389
+ customTools.push(...options2.customTools);
290390
+ }
290391
+ if (options2.toolRefs && options2.toolRefs.length > 0) {
290392
+ customTools.push(...buildToolDefinitionsFromRefs(options2.toolRefs));
290393
+ }
290270
290394
  const { session } = await createAgentSession({
290271
290395
  cwd,
290272
290396
  model,
@@ -290464,13 +290588,15 @@ function dispatchRunner(runner, base, cwd, options2) {
290464
290588
  env: base.env,
290465
290589
  abortController: base.abortController
290466
290590
  }).run(options2.userInput);
290467
- case "pi":
290591
+ case "pi": {
290468
290592
  return createPiRunner({
290469
290593
  ...base,
290470
290594
  cwd,
290471
290595
  sessionId: base.resume,
290472
- skillPaths: options2.skillPaths ?? discoverSkillPaths(cwd)
290596
+ skillPaths: options2.skillPaths ?? discoverSkillPaths(cwd),
290597
+ toolRefs: options2.toolRefs
290473
290598
  }).run(options2.userInput);
290599
+ }
290474
290600
  case "opencode":
290475
290601
  return createOpenCodeRunner({
290476
290602
  model: options2.model,
@@ -290539,6 +290665,7 @@ function codingRunStream(req, env2) {
290539
290665
  yolo: req.yolo,
290540
290666
  env: env2,
290541
290667
  abortController,
290668
+ toolRefs: req.toolRefs,
290542
290669
  autoInject: false
290543
290670
  });
290544
290671
  for await (const chunk of stream2) {
@@ -1,4 +1,6 @@
1
1
  import type * as http from "node:http";
2
+ import { type RunnerCoreOptions } from "@bunny-agent/runner-harness";
3
+ type RunToolRefs = RunnerCoreOptions["toolRefs"];
2
4
  export interface RunRequest {
3
5
  runner?: string;
4
6
  model?: string;
@@ -13,6 +15,8 @@ export interface RunRequest {
13
15
  yolo?: boolean;
14
16
  /** Inline runner env (string map); same keys override. */
15
17
  env?: Record<string, string>;
18
+ /** Tool refs the runner should expose to the LLM. */
19
+ toolRefs?: RunToolRefs;
16
20
  }
17
21
  export declare const HEARTBEAT_COMMENT = ": heartbeat\n\n";
18
22
  /** Get current heartbeat interval. */
@@ -28,4 +32,5 @@ export declare function bunnyAgentRun(req: RunRequest, res: http.ServerResponse,
28
32
  * Returns a streaming Response with NDJSON body.
29
33
  */
30
34
  export declare function codingRunStream(req: RunRequest, env: Record<string, string>): Response;
35
+ export {};
31
36
  //# sourceMappingURL=coding.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coding.d.ts","sourceRoot":"","sources":["../../src/routes/coding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAC;AAGvC,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAKD,eAAO,MAAM,iBAAiB,oBAAoB,CAAC;AAEnD,sCAAsC;AACtC,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,8DAA8D;AAC9D,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CAoDf;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,QAAQ,CA6DV"}
1
+ {"version":3,"file":"coding.d.ts","sourceRoot":"","sources":["../../src/routes/coding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAC;AACvC,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,6BAA6B,CAAC;AAErC,KAAK,WAAW,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAKD,eAAO,MAAM,iBAAiB,oBAAoB,CAAC;AAEnD,sCAAsC;AACtC,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,8DAA8D;AAC9D,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CAqDf;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,QAAQ,CA8DV"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bunny-agent/daemon",
3
- "version": "0.9.31",
3
+ "version": "0.9.33",
4
4
  "description": "BunnyAgent Daemon - Unified API gateway for sandbox services (file, git, volumes)",
5
5
  "type": "module",
6
6
  "bin": {