@bunny-agent/daemon 0.9.29-beta.5 → 0.9.29-beta.7

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