@bunny-agent/daemon 0.9.29-beta.6 → 0.9.29-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -116838,7 +116838,7 @@ var require_core3 = __commonJS({
116838
116838
  return match2 && match2.index === 0;
116839
116839
  }
116840
116840
  var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
116841
- function join38(regexps, separator = "|") {
116841
+ function join39(regexps, separator = "|") {
116842
116842
  let numCaptures = 0;
116843
116843
  return regexps.map((regex2) => {
116844
116844
  numCaptures += 1;
@@ -117142,7 +117142,7 @@ var require_core3 = __commonJS({
117142
117142
  this.exec = () => null;
117143
117143
  }
117144
117144
  const terminators = this.regexes.map((el) => el[1]);
117145
- this.matcherRe = langRe(join38(terminators), true);
117145
+ this.matcherRe = langRe(join39(terminators), true);
117146
117146
  this.lastIndex = 0;
117147
117147
  }
117148
117148
  /** @param {string} s */
@@ -168060,14 +168060,14 @@ var require_graceful_fs = __commonJS({
168060
168060
  return close;
168061
168061
  })(fs16.close);
168062
168062
  fs16.closeSync = (function(fs$closeSync) {
168063
- function closeSync2(fd) {
168063
+ function closeSync3(fd) {
168064
168064
  fs$closeSync.apply(fs16, arguments);
168065
168065
  resetQueue();
168066
168066
  }
168067
- Object.defineProperty(closeSync2, previousSymbol, {
168067
+ Object.defineProperty(closeSync3, previousSymbol, {
168068
168068
  value: fs$closeSync
168069
168069
  });
168070
- return closeSync2;
168070
+ return closeSync3;
168071
168071
  })(fs16.closeSync);
168072
168072
  if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
168073
168073
  process.on("exit", function() {
@@ -208384,7 +208384,7 @@ function createOpenCodeRunner(options2 = {}) {
208384
208384
 
208385
208385
  // ../../packages/runner-pi/dist/pi-runner.js
208386
208386
  import { appendFileSync as appendFileSync5, existsSync as existsSync28, unlinkSync as unlinkSync6 } from "node:fs";
208387
- import { join as join35 } from "node:path";
208387
+ import { join as join36 } from "node:path";
208388
208388
 
208389
208389
  // ../../node_modules/.pnpm/@mariozechner+pi-ai@0.64.0_ws@8.19.0_zod@4.3.6/node_modules/@mariozechner/pi-ai/dist/index.js
208390
208390
  var dist_exports = {};
@@ -263370,8 +263370,8 @@ var generateImageSchema = {
263370
263370
  },
263371
263371
  quality: {
263372
263372
  type: "string",
263373
- enum: ["standard", "hd"],
263374
- description: "Image quality (OpenAI only). Defaults to standard."
263373
+ enum: ["low", "medium", "high", "auto"],
263374
+ description: "Image quality. Defaults to auto."
263375
263375
  }
263376
263376
  },
263377
263377
  required: ["prompt"],
@@ -263533,7 +263533,7 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
263533
263533
  const p = params;
263534
263534
  const prompt = p.prompt;
263535
263535
  const size = p.size ?? "1024x1024";
263536
- const quality = p.quality ?? "standard";
263536
+ const quality = p.quality ?? "auto";
263537
263537
  const rawFilename = p.filename;
263538
263538
  const filename = rawFilename ? extname2(rawFilename) ? rawFilename : `${rawFilename}.png` : `image_${Date.now()}.png`;
263539
263539
  const filePath = join34(cwd, filename.replace(/[^a-zA-Z0-9_\-./]/g, "_"));
@@ -263571,6 +263571,7 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
263571
263571
  ],
263572
263572
  details: {
263573
263573
  filePath: savedPath,
263574
+ ...json.usage != null ? { usage: { raw: { [imageModelId]: json.usage } } } : {},
263574
263575
  response: json
263575
263576
  }
263576
263577
  };
@@ -263758,6 +263759,7 @@ function buildImageEditTool(cwd, imageModelId, baseUrl, apiKey) {
263758
263759
  ],
263759
263760
  details: {
263760
263761
  filePath: savedPath,
263762
+ ...json.usage != null ? { usage: { raw: { [imageModelId]: json.usage } } } : {},
263761
263763
  response: json
263762
263764
  }
263763
263765
  };
@@ -263774,6 +263776,309 @@ function buildImageEditTool(cwd, imageModelId, baseUrl, apiKey) {
263774
263776
  };
263775
263777
  }
263776
263778
 
263779
+ // ../../packages/runner-pi/dist/session-utils.js
263780
+ import { closeSync as closeSync2, fstatSync, openSync as openSync2, readdirSync as readdirSync12, readSync as readSync2, statSync as statSync13 } from "node:fs";
263781
+ import { join as join35 } from "node:path";
263782
+ var MAX_SESSION_FILE_BYTES = Number(process.env.SANDAGENT_MAX_SESSION_BYTES) || 10 * 1024 * 1024;
263783
+ function resolveSessionPathById(cwd, sessionId) {
263784
+ const tempMgr = SessionManager.create(cwd);
263785
+ const sessionsDir = tempMgr.getSessionDir();
263786
+ try {
263787
+ const suffix = `_${sessionId}.jsonl`;
263788
+ const match2 = readdirSync12(sessionsDir).find((f3) => f3.endsWith(suffix));
263789
+ return match2 ? join35(sessionsDir, match2) : void 0;
263790
+ } catch {
263791
+ return void 0;
263792
+ }
263793
+ }
263794
+ function isSessionFileTooLarge(sessionPath2) {
263795
+ try {
263796
+ return statSync13(sessionPath2).size > MAX_SESSION_FILE_BYTES;
263797
+ } catch {
263798
+ return false;
263799
+ }
263800
+ }
263801
+ function readTailEntries(sessionPath2, tailBytes = 1024 * 1024) {
263802
+ let fd;
263803
+ try {
263804
+ fd = openSync2(sessionPath2, "r");
263805
+ } catch {
263806
+ return [];
263807
+ }
263808
+ try {
263809
+ const fileSize = fstatSync(fd).size;
263810
+ const readStart = Math.max(0, fileSize - tailBytes);
263811
+ const readLen = fileSize - readStart;
263812
+ const buf = Buffer.alloc(readLen);
263813
+ readSync2(fd, buf, 0, readLen, readStart);
263814
+ const tail = buf.toString("utf8");
263815
+ const entries = [];
263816
+ for (const line of tail.split("\n")) {
263817
+ const trimmed = line.trim();
263818
+ if (!trimmed)
263819
+ continue;
263820
+ try {
263821
+ entries.push(JSON.parse(trimmed));
263822
+ } catch {
263823
+ }
263824
+ }
263825
+ return entries;
263826
+ } finally {
263827
+ closeSync2(fd);
263828
+ }
263829
+ }
263830
+ function extractSessionContext(sessionPath2) {
263831
+ const entries = readTailEntries(sessionPath2);
263832
+ if (entries.length === 0)
263833
+ return void 0;
263834
+ for (let i2 = entries.length - 1; i2 >= 0; i2--) {
263835
+ const e2 = entries[i2];
263836
+ if (e2.type === "compaction" && typeof e2.summary === "string") {
263837
+ return e2.summary;
263838
+ }
263839
+ }
263840
+ const recentMessages = [];
263841
+ const MAX_MESSAGES = 6;
263842
+ for (let i2 = entries.length - 1; i2 >= 0 && recentMessages.length < MAX_MESSAGES; i2--) {
263843
+ const e2 = entries[i2];
263844
+ if (e2.type !== "message")
263845
+ continue;
263846
+ const msg = e2.message;
263847
+ if (!msg)
263848
+ continue;
263849
+ if (msg.role !== "user" && msg.role !== "assistant")
263850
+ continue;
263851
+ let text = "";
263852
+ if (typeof msg.content === "string") {
263853
+ text = msg.content;
263854
+ } else if (Array.isArray(msg.content)) {
263855
+ text = msg.content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n");
263856
+ }
263857
+ if (text) {
263858
+ recentMessages.unshift(`[${msg.role}]: ${text}`);
263859
+ }
263860
+ }
263861
+ if (recentMessages.length === 0)
263862
+ return void 0;
263863
+ return "## Previous Session Context (auto-extracted)\n\nThe following is the tail of the previous conversation:\n\n" + recentMessages.join("\n\n");
263864
+ }
263865
+
263866
+ // ../../packages/runner-pi/dist/usage-metadata.js
263867
+ function usageToMessageMetadata(usage) {
263868
+ return {
263869
+ input_tokens: usage.input,
263870
+ output_tokens: usage.output,
263871
+ cache_read_input_tokens: usage.cacheRead,
263872
+ cache_creation_input_tokens: usage.cacheWrite
263873
+ };
263874
+ }
263875
+ function accumulateToolUsage(tally, raw) {
263876
+ for (const [key, row] of Object.entries(raw)) {
263877
+ const existing = tally[key];
263878
+ if (existing) {
263879
+ for (const [field, val] of Object.entries(row)) {
263880
+ if (typeof val === "number")
263881
+ existing[field] = (existing[field] ?? 0) + val;
263882
+ }
263883
+ } else {
263884
+ const nums = {};
263885
+ for (const [field, val] of Object.entries(row)) {
263886
+ if (typeof val === "number")
263887
+ nums[field] = val;
263888
+ }
263889
+ tally[key] = nums;
263890
+ }
263891
+ }
263892
+ }
263893
+ function getUsageFromAgentEndMessages(messages) {
263894
+ for (let i2 = messages.length - 1; i2 >= 0; i2--) {
263895
+ const m2 = messages[i2];
263896
+ if (m2.role === "assistant" && m2.usage != null)
263897
+ return m2.usage;
263898
+ }
263899
+ return void 0;
263900
+ }
263901
+
263902
+ // ../../packages/runner-pi/dist/stream-converter.js
263903
+ function emitStreamError(errorText) {
263904
+ const errorLine = "data: " + JSON.stringify({ type: "error", errorText }) + "\n\n";
263905
+ const finishLine = "data: " + JSON.stringify({ type: "finish", finishReason: "error" }) + "\n\n";
263906
+ return [errorLine, finishLine, "data: [DONE]\n\n"];
263907
+ }
263908
+ function extractToolResultText(result) {
263909
+ if (result !== null && typeof result === "object") {
263910
+ const r2 = result;
263911
+ if (Array.isArray(r2.content) && r2.content.length > 0) {
263912
+ const text = r2.content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("\n");
263913
+ if (text.length > 0)
263914
+ return text;
263915
+ }
263916
+ }
263917
+ if (typeof result === "string")
263918
+ return result;
263919
+ try {
263920
+ return JSON.stringify(result);
263921
+ } catch {
263922
+ return String(result);
263923
+ }
263924
+ }
263925
+ function sseData(obj) {
263926
+ return "data: " + JSON.stringify(obj) + "\n\n";
263927
+ }
263928
+ var PiAISDKStreamConverter = class {
263929
+ constructor(options2) {
263930
+ this.options = options2;
263931
+ this.messageId = "msg_" + Date.now() + "_" + Math.random().toString(36).slice(2);
263932
+ this.toolUsageTally = {};
263933
+ this.activeTextPartId = null;
263934
+ this.hasStarted = false;
263935
+ this.hasFinished = false;
263936
+ }
263937
+ get finished() {
263938
+ return this.hasFinished;
263939
+ }
263940
+ forceError(errorText) {
263941
+ if (this.hasFinished)
263942
+ return [];
263943
+ return [...this.ensureStart(), ...this.finishError(errorText)];
263944
+ }
263945
+ handleEvent(event, aborted) {
263946
+ if (this.hasFinished)
263947
+ return [];
263948
+ const chunks = [...this.ensureStart()];
263949
+ if (event.type === "message_start") {
263950
+ const msg = event.message;
263951
+ if (msg?.role === "assistant")
263952
+ chunks.push(...this.endTextStreamIfOpen());
263953
+ return chunks;
263954
+ }
263955
+ if (event.type === "message_end")
263956
+ return chunks;
263957
+ if (event.type === "message_update") {
263958
+ const sub = event.assistantMessageEvent;
263959
+ if (sub.type === "text_start")
263960
+ chunks.push(...this.endTextStreamIfOpen(), ...this.openTextStream());
263961
+ else if (sub.type === "text_delta")
263962
+ chunks.push(...this.emitTextDelta(sub.delta));
263963
+ else if (sub.type === "toolcall_start")
263964
+ chunks.push(...this.endTextStreamIfOpen());
263965
+ return chunks;
263966
+ }
263967
+ if (event.type === "tool_execution_start") {
263968
+ chunks.push(...this.endTextStreamIfOpen());
263969
+ chunks.push(sseData({
263970
+ type: "tool-input-start",
263971
+ toolCallId: event.toolCallId,
263972
+ toolName: event.toolName,
263973
+ dynamic: true,
263974
+ providerExecuted: true
263975
+ }), sseData({
263976
+ type: "tool-input-available",
263977
+ toolCallId: event.toolCallId,
263978
+ toolName: event.toolName,
263979
+ input: event.args,
263980
+ dynamic: true,
263981
+ providerExecuted: true
263982
+ }));
263983
+ return chunks;
263984
+ }
263985
+ if (event.type === "tool_execution_end") {
263986
+ const output = this.options.redactText(this.options.normalizeToolOutput(event.result));
263987
+ const raw = event.result?.details?.usage?.raw;
263988
+ if (raw != null)
263989
+ accumulateToolUsage(this.toolUsageTally, raw);
263990
+ chunks.push(sseData({
263991
+ type: "tool-output-available",
263992
+ toolCallId: event.toolCallId,
263993
+ output,
263994
+ isError: event.isError,
263995
+ dynamic: true,
263996
+ providerExecuted: true
263997
+ }));
263998
+ return chunks;
263999
+ }
264000
+ if (event.type === "agent_end") {
264001
+ if (aborted) {
264002
+ chunks.push(...this.finishError("Run aborted by signal."));
264003
+ } else {
264004
+ const errorMsg = this.options.getErrorFromAgentEndMessages(event.messages);
264005
+ if (errorMsg)
264006
+ chunks.push(...this.finishError(errorMsg));
264007
+ else
264008
+ chunks.push(...this.finishSuccess(this.options.getUsageFromAgentEndMessages(event.messages)));
264009
+ }
264010
+ return chunks;
264011
+ }
264012
+ return chunks;
264013
+ }
264014
+ ensureStart() {
264015
+ if (this.hasStarted)
264016
+ return [];
264017
+ this.hasStarted = true;
264018
+ return [
264019
+ sseData({ type: "start", messageId: this.messageId }),
264020
+ sseData({
264021
+ type: "message-metadata",
264022
+ messageMetadata: { sessionId: this.options.sessionId }
264023
+ })
264024
+ ];
264025
+ }
264026
+ newTextPartId() {
264027
+ return "text_" + Date.now() + "_" + Math.random().toString(36).slice(2) + "_" + Math.random().toString(36).slice(2);
264028
+ }
264029
+ openTextStream() {
264030
+ this.activeTextPartId = this.newTextPartId();
264031
+ return [sseData({ type: "text-start", id: this.activeTextPartId })];
264032
+ }
264033
+ emitTextDelta(rawDelta) {
264034
+ const delta = rawDelta ? this.options.redactText(rawDelta) : void 0;
264035
+ if (!delta)
264036
+ return [];
264037
+ const startChunk = this.activeTextPartId == null ? this.openTextStream() : [];
264038
+ return [
264039
+ ...startChunk,
264040
+ sseData({ type: "text-delta", id: this.activeTextPartId, delta })
264041
+ ];
264042
+ }
264043
+ endTextStreamIfOpen() {
264044
+ if (this.activeTextPartId == null)
264045
+ return [];
264046
+ const id = this.activeTextPartId;
264047
+ this.activeTextPartId = null;
264048
+ return [sseData({ type: "text-end", id })];
264049
+ }
264050
+ finishSuccess(usage) {
264051
+ const chunks = [...this.endTextStreamIfOpen()];
264052
+ const raw = {};
264053
+ let chatUsage;
264054
+ if (usage) {
264055
+ const { id } = this.options.model;
264056
+ chatUsage = {
264057
+ type: "chat",
264058
+ ...usageToMessageMetadata(usage)
264059
+ };
264060
+ raw[id] = chatUsage;
264061
+ }
264062
+ for (const [key, tally] of Object.entries(this.toolUsageTally)) {
264063
+ raw[key] = { ...tally };
264064
+ }
264065
+ const finishPayload = {
264066
+ type: "finish",
264067
+ finishReason: "stop"
264068
+ };
264069
+ if (usage) {
264070
+ finishPayload.messageMetadata = { usage: { ...chatUsage, raw } };
264071
+ }
264072
+ chunks.push(sseData(finishPayload), "data: [DONE]\n\n");
264073
+ this.hasFinished = true;
264074
+ return chunks;
264075
+ }
264076
+ finishError(errorText) {
264077
+ this.hasFinished = true;
264078
+ return emitStreamError(errorText);
264079
+ }
264080
+ };
264081
+
263777
264082
  // ../../packages/runner-pi/dist/web-tools.js
263778
264083
  var braveProvider = {
263779
264084
  id: "brave",
@@ -263815,7 +264120,7 @@ ${body}`);
263815
264120
  });
263816
264121
  }
263817
264122
  }
263818
- return results;
264123
+ return { results };
263819
264124
  }
263820
264125
  };
263821
264126
  var tavilyProvider = {
@@ -263850,7 +264155,7 @@ ${body}`);
263850
264155
  });
263851
264156
  }
263852
264157
  }
263853
- return results;
264158
+ return { results };
263854
264159
  }
263855
264160
  };
263856
264161
  var AUTO_DETECT_ORDER = [braveProvider, tavilyProvider];
@@ -263997,7 +264302,7 @@ function buildWebSearchTool(env2) {
263997
264302
  let lastError;
263998
264303
  for (const { provider, apiKey } of providers) {
263999
264304
  try {
264000
- const results = await provider.search({
264305
+ const { results } = await provider.search({
264001
264306
  apiKey,
264002
264307
  query,
264003
264308
  count,
@@ -264005,11 +264310,21 @@ function buildWebSearchTool(env2) {
264005
264310
  freshness,
264006
264311
  signal
264007
264312
  });
264313
+ let fetchedPages = 0;
264008
264314
  if (shouldFetchContent) {
264009
264315
  for (const r2 of results) {
264010
264316
  r2.content = await fetchPageContent(r2.link, signal);
264317
+ fetchedPages += 1;
264011
264318
  }
264012
264319
  }
264320
+ const usage = {
264321
+ raw: {
264322
+ [provider.id]: {
264323
+ requests: 1,
264324
+ fetchedPages
264325
+ }
264326
+ }
264327
+ };
264013
264328
  return {
264014
264329
  content: [
264015
264330
  {
@@ -264017,7 +264332,9 @@ function buildWebSearchTool(env2) {
264017
264332
  text: formatSearchResults(results, provider.label)
264018
264333
  }
264019
264334
  ],
264020
- details: void 0
264335
+ details: {
264336
+ usage
264337
+ }
264021
264338
  };
264022
264339
  } catch (e2) {
264023
264340
  lastError = e2;
@@ -264200,52 +264517,6 @@ function applyModelOverrides(model, provider, optionsEnv) {
264200
264517
  model.baseUrl = anthropicBaseUrl;
264201
264518
  }
264202
264519
  }
264203
- function emitStreamError(errorText) {
264204
- return [
264205
- `data: ${JSON.stringify({ type: "error", errorText })}
264206
-
264207
- `,
264208
- `data: ${JSON.stringify({ type: "finish", finishReason: "error" })}
264209
-
264210
- `,
264211
- "data: [DONE]\n\n"
264212
- ];
264213
- }
264214
- function extractToolResultText(result) {
264215
- if (result !== null && typeof result === "object") {
264216
- const r2 = result;
264217
- if (Array.isArray(r2.content) && r2.content.length > 0) {
264218
- const text = r2.content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("\n");
264219
- if (text.length > 0) {
264220
- return text;
264221
- }
264222
- }
264223
- }
264224
- if (typeof result === "string")
264225
- return result;
264226
- try {
264227
- return JSON.stringify(result);
264228
- } catch {
264229
- return String(result);
264230
- }
264231
- }
264232
- function usageToMessageMetadata(usage) {
264233
- return {
264234
- input_tokens: usage.input,
264235
- output_tokens: usage.output,
264236
- cache_read_input_tokens: usage.cacheRead,
264237
- cache_creation_input_tokens: usage.cacheWrite
264238
- };
264239
- }
264240
- function getUsageFromAgentEndMessages(messages) {
264241
- for (let i2 = messages.length - 1; i2 >= 0; i2--) {
264242
- const m2 = messages[i2];
264243
- if (m2.role === "assistant" && m2.usage != null) {
264244
- return m2.usage;
264245
- }
264246
- }
264247
- return void 0;
264248
- }
264249
264520
  function getErrorFromAgentEndMessages(messages) {
264250
264521
  for (let i2 = messages.length - 1; i2 >= 0; i2--) {
264251
264522
  const m2 = messages[i2];
@@ -264261,7 +264532,7 @@ function traceRawMessage(debugCwd, data, reset = false, optionsEnv) {
264261
264532
  if (!enabled)
264262
264533
  return;
264263
264534
  try {
264264
- const file = join35(debugCwd, "pi-message-stream-debug.json");
264535
+ const file = join36(debugCwd, "pi-message-stream-debug.json");
264265
264536
  if (reset && existsSync28(file))
264266
264537
  unlinkSync6(file);
264267
264538
  const type = data !== null && typeof data === "object" ? data.type : void 0;
@@ -264330,9 +264601,22 @@ function createPiRunner(options2 = {}) {
264330
264601
  if (resume.includes("/")) {
264331
264602
  return SessionManager.open(resume);
264332
264603
  }
264333
- const sessions = await SessionManager.list(cwd);
264334
- const found = sessions.find((s2) => s2.id === resume);
264335
- return found ? SessionManager.open(found.path) : SessionManager.create(cwd);
264604
+ const sessionPath2 = resolveSessionPathById(cwd, resume);
264605
+ console.error(`${LOG_PREFIX2} resume: id=${resume} path=${sessionPath2 ?? "(not found)"}`);
264606
+ if (sessionPath2) {
264607
+ if (isSessionFileTooLarge(sessionPath2)) {
264608
+ const context = extractSessionContext(sessionPath2);
264609
+ console.error(`${LOG_PREFIX2} session file too large, starting fresh${context ? " (with context)" : ""}`);
264610
+ const newMgr = SessionManager.create(cwd);
264611
+ if (context) {
264612
+ const firstId = newMgr.getEntries()[0]?.id ?? "";
264613
+ newMgr.appendCompaction(context, firstId, 0);
264614
+ }
264615
+ return newMgr;
264616
+ }
264617
+ return SessionManager.open(sessionPath2);
264618
+ }
264619
+ return SessionManager.create(cwd);
264336
264620
  }
264337
264621
  return SessionManager.create(cwd);
264338
264622
  })();
@@ -264390,165 +264674,34 @@ function createPiRunner(options2 = {}) {
264390
264674
  }
264391
264675
  try {
264392
264676
  traceRawMessage(cwd, null, true, options2.env);
264393
- let promptText = userInput;
264394
- let images;
264395
- try {
264396
- if (userInput.startsWith("[") && userInput.endsWith("]")) {
264397
- const parsed = JSON.parse(userInput);
264398
- if (Array.isArray(parsed)) {
264399
- promptText = parsed.filter((p) => p.type === "text").map((p) => p.text).join("\n");
264400
- const imageParts = parsed.filter((p) => p.type === "image");
264401
- if (imageParts.length > 0) {
264402
- images = imageParts.map((p) => ({
264403
- type: "image",
264404
- data: p.data,
264405
- mimeType: p.mimeType
264406
- }));
264407
- }
264677
+ const promptText = userInput;
264678
+ const promptPromise = session.prompt(promptText);
264679
+ const streamConverter = new PiAISDKStreamConverter({
264680
+ sessionId: session.sessionId,
264681
+ model,
264682
+ redactText: (value2) => {
264683
+ if (options2.env && Object.keys(options2.env).length > 0) {
264684
+ return redactSecrets(value2, options2.env);
264408
264685
  }
264409
- }
264410
- } catch (_e2) {
264411
- }
264412
- const promptPromise = session.prompt(promptText, images ? { images } : void 0);
264413
- const messageId = `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`;
264414
- let hasStarted = false;
264415
- let hasFinished = false;
264416
- const imageToolUsage = { input_tokens: 0, output_tokens: 0 };
264417
- const newTextPartId = () => `text_${Date.now()}_${Math.random().toString(36).slice(2)}_${Math.random().toString(36).slice(2)}`;
264418
- let activeTextPartId = null;
264419
- let textStreamOpen = false;
264420
- const endTextStreamIfOpen = function* () {
264421
- if (textStreamOpen && activeTextPartId != null) {
264422
- yield `data: ${JSON.stringify({ type: "text-end", id: activeTextPartId })}
264423
-
264424
- `;
264425
- textStreamOpen = false;
264426
- activeTextPartId = null;
264427
- }
264428
- };
264429
- const beginTextStream = function* () {
264430
- activeTextPartId = newTextPartId();
264431
- yield `data: ${JSON.stringify({ type: "text-start", id: activeTextPartId })}
264432
-
264433
- `;
264434
- textStreamOpen = true;
264435
- };
264436
- const ensureStartEvent = async function* () {
264437
- if (!hasStarted) {
264438
- yield `data: ${JSON.stringify({ type: "start", messageId })}
264439
-
264440
- `;
264441
- yield `data: ${JSON.stringify({
264442
- type: "message-metadata",
264443
- messageMetadata: { sessionId: session.sessionId }
264444
- })}
264445
-
264446
- `;
264447
- hasStarted = true;
264448
- }
264449
- };
264450
- const finishSuccess = async function* (usage) {
264451
- yield* endTextStreamIfOpen();
264452
- const finishPayload = { type: "finish", finishReason: "stop" };
264453
- const hasImageUsage = imageToolUsage.input_tokens > 0 || imageToolUsage.output_tokens > 0;
264454
- if (usage != null || hasImageUsage) {
264455
- const base = usage != null ? usageToMessageMetadata(usage) : {};
264456
- finishPayload.messageMetadata = {
264457
- usage: {
264458
- ...base,
264459
- input_tokens: (base.input_tokens ?? 0) + imageToolUsage.input_tokens,
264460
- output_tokens: (base.output_tokens ?? 0) + imageToolUsage.output_tokens
264461
- }
264462
- };
264463
- }
264464
- yield `data: ${JSON.stringify(finishPayload)}
264465
-
264466
- `;
264467
- yield "data: [DONE]\n\n";
264468
- hasFinished = true;
264469
- };
264470
- const finishError = async function* (errorText) {
264471
- for (const chunk of emitStreamError(errorText)) {
264472
- yield chunk;
264473
- }
264474
- hasFinished = true;
264475
- };
264686
+ return value2;
264687
+ },
264688
+ normalizeToolOutput: extractToolResultText,
264689
+ getUsageFromAgentEndMessages,
264690
+ getErrorFromAgentEndMessages
264691
+ });
264476
264692
  while (!isComplete || eventQueue.length > 0) {
264477
264693
  while (eventQueue.length > 0) {
264478
264694
  const event = eventQueue.shift();
264479
264695
  traceRawMessage(cwd, event, false, options2.env);
264480
- yield* ensureStartEvent();
264481
- if (event.type === "message_start") {
264482
- const msg = event.message;
264483
- if (msg?.role === "assistant") {
264484
- yield* endTextStreamIfOpen();
264485
- }
264486
- } else if (event.type === "message_update") {
264487
- const sub = event.assistantMessageEvent;
264488
- if (sub.type === "text_start") {
264489
- yield* endTextStreamIfOpen();
264490
- yield* beginTextStream();
264491
- } else if (sub.type === "text_delta") {
264492
- let delta = sub.delta;
264493
- if (delta) {
264494
- if (options2.env && Object.keys(options2.env).length > 0) {
264495
- delta = redactSecrets(delta, options2.env);
264496
- }
264497
- if (!textStreamOpen) {
264498
- yield* beginTextStream();
264499
- }
264500
- yield `data: ${JSON.stringify({
264501
- type: "text-delta",
264502
- id: activeTextPartId,
264503
- delta
264504
- })}
264505
-
264506
- `;
264507
- }
264508
- } else if (sub.type === "toolcall_start") {
264509
- yield* endTextStreamIfOpen();
264510
- }
264511
- } else if (event.type === "tool_execution_start") {
264512
- yield* endTextStreamIfOpen();
264513
- yield `data: ${JSON.stringify({ type: "tool-input-start", toolCallId: event.toolCallId, toolName: event.toolName, dynamic: true, providerExecuted: true })}
264514
-
264515
- `;
264516
- yield `data: ${JSON.stringify({ type: "tool-input-available", toolCallId: event.toolCallId, toolName: event.toolName, input: event.args, dynamic: true, providerExecuted: true })}
264517
-
264518
- `;
264519
- } else if (event.type === "tool_execution_end") {
264520
- let output = extractToolResultText(event.result);
264521
- if (options2.env && Object.keys(options2.env).length > 0) {
264522
- output = redactSecrets(output, options2.env);
264523
- }
264524
- if ((event.toolName === "generate_image" || event.toolName === "edit_image") && event.result !== null && typeof event.result === "object") {
264525
- const details = event.result.details;
264526
- const u = details?.response?.usage;
264527
- if (u) {
264528
- imageToolUsage.input_tokens += u.input_tokens ?? 0;
264529
- imageToolUsage.output_tokens += u.output_tokens ?? 0;
264530
- }
264531
- }
264532
- yield `data: ${JSON.stringify({ type: "tool-output-available", toolCallId: event.toolCallId, output, isError: event.isError, dynamic: true, providerExecuted: true })}
264533
-
264534
- `;
264535
- } else if (event.type === "agent_end") {
264536
- if (aborted) {
264537
- yield* finishError("Run aborted by signal.");
264538
- } else {
264539
- const errorMsg = getErrorFromAgentEndMessages(event.messages);
264540
- if (errorMsg) {
264541
- yield* finishError(errorMsg);
264542
- } else {
264543
- const usage = getUsageFromAgentEndMessages(event.messages);
264544
- yield* finishSuccess(usage);
264545
- }
264546
- }
264696
+ const chunks = streamConverter.handleEvent(event, aborted);
264697
+ for (const chunk of chunks) {
264698
+ yield chunk;
264547
264699
  }
264548
264700
  }
264549
- if (aborted && !hasFinished) {
264550
- yield* ensureStartEvent();
264551
- yield* finishError("Run aborted by signal.");
264701
+ if (aborted && !streamConverter.finished) {
264702
+ for (const chunk of streamConverter.forceError("Run aborted by signal.")) {
264703
+ yield chunk;
264704
+ }
264552
264705
  break;
264553
264706
  }
264554
264707
  if (!isComplete && eventQueue.length === 0) {
@@ -264557,22 +264710,24 @@ function createPiRunner(options2 = {}) {
264557
264710
  });
264558
264711
  }
264559
264712
  }
264560
- if (hasFinished) {
264713
+ if (streamConverter.finished) {
264561
264714
  return;
264562
264715
  }
264563
264716
  try {
264564
264717
  await promptPromise;
264565
264718
  } catch (error) {
264566
- if (!hasFinished) {
264567
- yield* ensureStartEvent();
264719
+ if (!streamConverter.finished) {
264568
264720
  const message = error instanceof Error ? error.message : "Pi agent run failed.";
264569
- yield* finishError(message);
264721
+ for (const chunk of streamConverter.forceError(message)) {
264722
+ yield chunk;
264723
+ }
264570
264724
  }
264571
264725
  return;
264572
264726
  }
264573
- if (!hasFinished && session.agent.state.error) {
264574
- yield* ensureStartEvent();
264575
- yield* finishError(session.agent.state.error);
264727
+ if (!streamConverter.finished && session.agent.state.error) {
264728
+ for (const chunk of streamConverter.forceError(session.agent.state.error)) {
264729
+ yield chunk;
264730
+ }
264576
264731
  }
264577
264732
  } finally {
264578
264733
  if (abortSignal) {
@@ -264592,11 +264747,11 @@ function createPiRunner(options2 = {}) {
264592
264747
 
264593
264748
  // ../../packages/runner-harness/dist/session.js
264594
264749
  import { existsSync as existsSync29, mkdirSync as mkdirSync11, readFileSync as readFileSync23, writeFileSync as writeFileSync14 } from "node:fs";
264595
- import { join as join36 } from "node:path";
264750
+ import { join as join37 } from "node:path";
264596
264751
  var DIR = ".bunny-agent";
264597
264752
  var FILE = "session-id";
264598
264753
  function sessionPath(cwd) {
264599
- return join36(cwd, DIR, FILE);
264754
+ return join37(cwd, DIR, FILE);
264600
264755
  }
264601
264756
  function readSessionId(cwd) {
264602
264757
  try {
@@ -264610,28 +264765,28 @@ function readSessionId(cwd) {
264610
264765
  }
264611
264766
  function writeSessionId(cwd, id) {
264612
264767
  try {
264613
- mkdirSync11(join36(cwd, DIR), { recursive: true });
264768
+ mkdirSync11(join37(cwd, DIR), { recursive: true });
264614
264769
  writeFileSync14(sessionPath(cwd), id, "utf8");
264615
264770
  } catch {
264616
264771
  }
264617
264772
  }
264618
264773
 
264619
264774
  // ../../packages/runner-harness/dist/skills.js
264620
- import { existsSync as existsSync30, readdirSync as readdirSync12, statSync as statSync13 } from "node:fs";
264775
+ import { existsSync as existsSync30, readdirSync as readdirSync13, statSync as statSync14 } from "node:fs";
264621
264776
  import { homedir as homedir14 } from "node:os";
264622
- import { join as join37 } from "node:path";
264777
+ import { join as join38 } from "node:path";
264623
264778
  function discoverSkillPaths(cwd) {
264624
264779
  const paths = [];
264625
264780
  for (const base of [
264626
- join37(cwd, "skills"),
264627
- join37(homedir14(), ".bunny-agent", "skills")
264781
+ join38(cwd, "skills"),
264782
+ join38(homedir14(), ".bunny-agent", "skills")
264628
264783
  ]) {
264629
264784
  if (!existsSync30(base))
264630
264785
  continue;
264631
264786
  try {
264632
- for (const entry of readdirSync12(base)) {
264633
- const full = join37(base, entry);
264634
- if (statSync13(full).isDirectory() && existsSync30(join37(full, "SKILL.md"))) {
264787
+ for (const entry of readdirSync13(base)) {
264788
+ const full = join38(base, entry);
264789
+ if (statSync14(full).isDirectory() && existsSync30(join38(full, "SKILL.md"))) {
264635
264790
  paths.push(full);
264636
264791
  }
264637
264792
  }