@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/nextjs.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() {
@@ -206492,10 +206492,15 @@ async function fsStat(state, q2) {
206492
206492
  const root = resolveVolumeRoot(state, q2.volume);
206493
206493
  const target = resolveUnderRoot(root, q2.path);
206494
206494
  const stat6 = await fs2.stat(target);
206495
+ const created_at = msToIsoOrNull(stat6.birthtimeMs) ?? msToIsoOrNull(stat6.ctimeMs);
206495
206496
  return ok({
206496
206497
  path: target,
206497
206498
  is_dir: stat6.isDirectory(),
206498
- size: stat6.isFile() ? stat6.size : 0
206499
+ size: stat6.isFile() ? stat6.size : 0,
206500
+ created_at,
206501
+ modified_at: msToIsoOrNull(
206502
+ stat6.mtimeMs
206503
+ )
206499
206504
  });
206500
206505
  }
206501
206506
  async function fsExists(state, q2) {
@@ -208375,7 +208380,7 @@ function createOpenCodeRunner(options2 = {}) {
208375
208380
 
208376
208381
  // ../../packages/runner-pi/dist/pi-runner.js
208377
208382
  import { appendFileSync as appendFileSync5, existsSync as existsSync28, unlinkSync as unlinkSync6 } from "node:fs";
208378
- import { join as join35 } from "node:path";
208383
+ import { join as join36 } from "node:path";
208379
208384
 
208380
208385
  // ../../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
208381
208386
  var dist_exports = {};
@@ -263361,8 +263366,8 @@ var generateImageSchema = {
263361
263366
  },
263362
263367
  quality: {
263363
263368
  type: "string",
263364
- enum: ["standard", "hd"],
263365
- description: "Image quality (OpenAI only). Defaults to standard."
263369
+ enum: ["low", "medium", "high", "auto"],
263370
+ description: "Image quality. Defaults to auto."
263366
263371
  }
263367
263372
  },
263368
263373
  required: ["prompt"],
@@ -263524,7 +263529,7 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
263524
263529
  const p = params;
263525
263530
  const prompt = p.prompt;
263526
263531
  const size = p.size ?? "1024x1024";
263527
- const quality = p.quality ?? "standard";
263532
+ const quality = p.quality ?? "auto";
263528
263533
  const rawFilename = p.filename;
263529
263534
  const filename = rawFilename ? extname2(rawFilename) ? rawFilename : `${rawFilename}.png` : `image_${Date.now()}.png`;
263530
263535
  const filePath = join34(cwd, filename.replace(/[^a-zA-Z0-9_\-./]/g, "_"));
@@ -263562,6 +263567,7 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
263562
263567
  ],
263563
263568
  details: {
263564
263569
  filePath: savedPath,
263570
+ ...json.usage != null ? { usage: { raw: { [imageModelId]: json.usage } } } : {},
263565
263571
  response: json
263566
263572
  }
263567
263573
  };
@@ -263749,6 +263755,7 @@ function buildImageEditTool(cwd, imageModelId, baseUrl, apiKey) {
263749
263755
  ],
263750
263756
  details: {
263751
263757
  filePath: savedPath,
263758
+ ...json.usage != null ? { usage: { raw: { [imageModelId]: json.usage } } } : {},
263752
263759
  response: json
263753
263760
  }
263754
263761
  };
@@ -263765,6 +263772,309 @@ function buildImageEditTool(cwd, imageModelId, baseUrl, apiKey) {
263765
263772
  };
263766
263773
  }
263767
263774
 
263775
+ // ../../packages/runner-pi/dist/session-utils.js
263776
+ import { closeSync as closeSync2, fstatSync, openSync as openSync2, readdirSync as readdirSync12, readSync as readSync2, statSync as statSync13 } from "node:fs";
263777
+ import { join as join35 } from "node:path";
263778
+ var MAX_SESSION_FILE_BYTES = Number(process.env.SANDAGENT_MAX_SESSION_BYTES) || 10 * 1024 * 1024;
263779
+ function resolveSessionPathById(cwd, sessionId) {
263780
+ const tempMgr = SessionManager.create(cwd);
263781
+ const sessionsDir = tempMgr.getSessionDir();
263782
+ try {
263783
+ const suffix = `_${sessionId}.jsonl`;
263784
+ const match2 = readdirSync12(sessionsDir).find((f3) => f3.endsWith(suffix));
263785
+ return match2 ? join35(sessionsDir, match2) : void 0;
263786
+ } catch {
263787
+ return void 0;
263788
+ }
263789
+ }
263790
+ function isSessionFileTooLarge(sessionPath2) {
263791
+ try {
263792
+ return statSync13(sessionPath2).size > MAX_SESSION_FILE_BYTES;
263793
+ } catch {
263794
+ return false;
263795
+ }
263796
+ }
263797
+ function readTailEntries(sessionPath2, tailBytes = 1024 * 1024) {
263798
+ let fd;
263799
+ try {
263800
+ fd = openSync2(sessionPath2, "r");
263801
+ } catch {
263802
+ return [];
263803
+ }
263804
+ try {
263805
+ const fileSize = fstatSync(fd).size;
263806
+ const readStart = Math.max(0, fileSize - tailBytes);
263807
+ const readLen = fileSize - readStart;
263808
+ const buf = Buffer.alloc(readLen);
263809
+ readSync2(fd, buf, 0, readLen, readStart);
263810
+ const tail = buf.toString("utf8");
263811
+ const entries = [];
263812
+ for (const line of tail.split("\n")) {
263813
+ const trimmed = line.trim();
263814
+ if (!trimmed)
263815
+ continue;
263816
+ try {
263817
+ entries.push(JSON.parse(trimmed));
263818
+ } catch {
263819
+ }
263820
+ }
263821
+ return entries;
263822
+ } finally {
263823
+ closeSync2(fd);
263824
+ }
263825
+ }
263826
+ function extractSessionContext(sessionPath2) {
263827
+ const entries = readTailEntries(sessionPath2);
263828
+ if (entries.length === 0)
263829
+ return void 0;
263830
+ for (let i2 = entries.length - 1; i2 >= 0; i2--) {
263831
+ const e2 = entries[i2];
263832
+ if (e2.type === "compaction" && typeof e2.summary === "string") {
263833
+ return e2.summary;
263834
+ }
263835
+ }
263836
+ const recentMessages = [];
263837
+ const MAX_MESSAGES = 6;
263838
+ for (let i2 = entries.length - 1; i2 >= 0 && recentMessages.length < MAX_MESSAGES; i2--) {
263839
+ const e2 = entries[i2];
263840
+ if (e2.type !== "message")
263841
+ continue;
263842
+ const msg = e2.message;
263843
+ if (!msg)
263844
+ continue;
263845
+ if (msg.role !== "user" && msg.role !== "assistant")
263846
+ continue;
263847
+ let text = "";
263848
+ if (typeof msg.content === "string") {
263849
+ text = msg.content;
263850
+ } else if (Array.isArray(msg.content)) {
263851
+ text = msg.content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n");
263852
+ }
263853
+ if (text) {
263854
+ recentMessages.unshift(`[${msg.role}]: ${text}`);
263855
+ }
263856
+ }
263857
+ if (recentMessages.length === 0)
263858
+ return void 0;
263859
+ return "## Previous Session Context (auto-extracted)\n\nThe following is the tail of the previous conversation:\n\n" + recentMessages.join("\n\n");
263860
+ }
263861
+
263862
+ // ../../packages/runner-pi/dist/usage-metadata.js
263863
+ function usageToMessageMetadata(usage) {
263864
+ return {
263865
+ input_tokens: usage.input,
263866
+ output_tokens: usage.output,
263867
+ cache_read_input_tokens: usage.cacheRead,
263868
+ cache_creation_input_tokens: usage.cacheWrite
263869
+ };
263870
+ }
263871
+ function accumulateToolUsage(tally, raw) {
263872
+ for (const [key, row] of Object.entries(raw)) {
263873
+ const existing = tally[key];
263874
+ if (existing) {
263875
+ for (const [field, val] of Object.entries(row)) {
263876
+ if (typeof val === "number")
263877
+ existing[field] = (existing[field] ?? 0) + val;
263878
+ }
263879
+ } else {
263880
+ const nums = {};
263881
+ for (const [field, val] of Object.entries(row)) {
263882
+ if (typeof val === "number")
263883
+ nums[field] = val;
263884
+ }
263885
+ tally[key] = nums;
263886
+ }
263887
+ }
263888
+ }
263889
+ function getUsageFromAgentEndMessages(messages) {
263890
+ for (let i2 = messages.length - 1; i2 >= 0; i2--) {
263891
+ const m2 = messages[i2];
263892
+ if (m2.role === "assistant" && m2.usage != null)
263893
+ return m2.usage;
263894
+ }
263895
+ return void 0;
263896
+ }
263897
+
263898
+ // ../../packages/runner-pi/dist/stream-converter.js
263899
+ function emitStreamError(errorText) {
263900
+ const errorLine = "data: " + JSON.stringify({ type: "error", errorText }) + "\n\n";
263901
+ const finishLine = "data: " + JSON.stringify({ type: "finish", finishReason: "error" }) + "\n\n";
263902
+ return [errorLine, finishLine, "data: [DONE]\n\n"];
263903
+ }
263904
+ function extractToolResultText(result) {
263905
+ if (result !== null && typeof result === "object") {
263906
+ const r2 = result;
263907
+ if (Array.isArray(r2.content) && r2.content.length > 0) {
263908
+ const text = r2.content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("\n");
263909
+ if (text.length > 0)
263910
+ return text;
263911
+ }
263912
+ }
263913
+ if (typeof result === "string")
263914
+ return result;
263915
+ try {
263916
+ return JSON.stringify(result);
263917
+ } catch {
263918
+ return String(result);
263919
+ }
263920
+ }
263921
+ function sseData(obj) {
263922
+ return "data: " + JSON.stringify(obj) + "\n\n";
263923
+ }
263924
+ var PiAISDKStreamConverter = class {
263925
+ constructor(options2) {
263926
+ this.options = options2;
263927
+ this.messageId = "msg_" + Date.now() + "_" + Math.random().toString(36).slice(2);
263928
+ this.toolUsageTally = {};
263929
+ this.activeTextPartId = null;
263930
+ this.hasStarted = false;
263931
+ this.hasFinished = false;
263932
+ }
263933
+ get finished() {
263934
+ return this.hasFinished;
263935
+ }
263936
+ forceError(errorText) {
263937
+ if (this.hasFinished)
263938
+ return [];
263939
+ return [...this.ensureStart(), ...this.finishError(errorText)];
263940
+ }
263941
+ handleEvent(event, aborted) {
263942
+ if (this.hasFinished)
263943
+ return [];
263944
+ const chunks = [...this.ensureStart()];
263945
+ if (event.type === "message_start") {
263946
+ const msg = event.message;
263947
+ if (msg?.role === "assistant")
263948
+ chunks.push(...this.endTextStreamIfOpen());
263949
+ return chunks;
263950
+ }
263951
+ if (event.type === "message_end")
263952
+ return chunks;
263953
+ if (event.type === "message_update") {
263954
+ const sub = event.assistantMessageEvent;
263955
+ if (sub.type === "text_start")
263956
+ chunks.push(...this.endTextStreamIfOpen(), ...this.openTextStream());
263957
+ else if (sub.type === "text_delta")
263958
+ chunks.push(...this.emitTextDelta(sub.delta));
263959
+ else if (sub.type === "toolcall_start")
263960
+ chunks.push(...this.endTextStreamIfOpen());
263961
+ return chunks;
263962
+ }
263963
+ if (event.type === "tool_execution_start") {
263964
+ chunks.push(...this.endTextStreamIfOpen());
263965
+ chunks.push(sseData({
263966
+ type: "tool-input-start",
263967
+ toolCallId: event.toolCallId,
263968
+ toolName: event.toolName,
263969
+ dynamic: true,
263970
+ providerExecuted: true
263971
+ }), sseData({
263972
+ type: "tool-input-available",
263973
+ toolCallId: event.toolCallId,
263974
+ toolName: event.toolName,
263975
+ input: event.args,
263976
+ dynamic: true,
263977
+ providerExecuted: true
263978
+ }));
263979
+ return chunks;
263980
+ }
263981
+ if (event.type === "tool_execution_end") {
263982
+ const output = this.options.redactText(this.options.normalizeToolOutput(event.result));
263983
+ const raw = event.result?.details?.usage?.raw;
263984
+ if (raw != null)
263985
+ accumulateToolUsage(this.toolUsageTally, raw);
263986
+ chunks.push(sseData({
263987
+ type: "tool-output-available",
263988
+ toolCallId: event.toolCallId,
263989
+ output,
263990
+ isError: event.isError,
263991
+ dynamic: true,
263992
+ providerExecuted: true
263993
+ }));
263994
+ return chunks;
263995
+ }
263996
+ if (event.type === "agent_end") {
263997
+ if (aborted) {
263998
+ chunks.push(...this.finishError("Run aborted by signal."));
263999
+ } else {
264000
+ const errorMsg = this.options.getErrorFromAgentEndMessages(event.messages);
264001
+ if (errorMsg)
264002
+ chunks.push(...this.finishError(errorMsg));
264003
+ else
264004
+ chunks.push(...this.finishSuccess(this.options.getUsageFromAgentEndMessages(event.messages)));
264005
+ }
264006
+ return chunks;
264007
+ }
264008
+ return chunks;
264009
+ }
264010
+ ensureStart() {
264011
+ if (this.hasStarted)
264012
+ return [];
264013
+ this.hasStarted = true;
264014
+ return [
264015
+ sseData({ type: "start", messageId: this.messageId }),
264016
+ sseData({
264017
+ type: "message-metadata",
264018
+ messageMetadata: { sessionId: this.options.sessionId }
264019
+ })
264020
+ ];
264021
+ }
264022
+ newTextPartId() {
264023
+ return "text_" + Date.now() + "_" + Math.random().toString(36).slice(2) + "_" + Math.random().toString(36).slice(2);
264024
+ }
264025
+ openTextStream() {
264026
+ this.activeTextPartId = this.newTextPartId();
264027
+ return [sseData({ type: "text-start", id: this.activeTextPartId })];
264028
+ }
264029
+ emitTextDelta(rawDelta) {
264030
+ const delta = rawDelta ? this.options.redactText(rawDelta) : void 0;
264031
+ if (!delta)
264032
+ return [];
264033
+ const startChunk = this.activeTextPartId == null ? this.openTextStream() : [];
264034
+ return [
264035
+ ...startChunk,
264036
+ sseData({ type: "text-delta", id: this.activeTextPartId, delta })
264037
+ ];
264038
+ }
264039
+ endTextStreamIfOpen() {
264040
+ if (this.activeTextPartId == null)
264041
+ return [];
264042
+ const id = this.activeTextPartId;
264043
+ this.activeTextPartId = null;
264044
+ return [sseData({ type: "text-end", id })];
264045
+ }
264046
+ finishSuccess(usage) {
264047
+ const chunks = [...this.endTextStreamIfOpen()];
264048
+ const raw = {};
264049
+ let chatUsage;
264050
+ if (usage) {
264051
+ const { id } = this.options.model;
264052
+ chatUsage = {
264053
+ type: "chat",
264054
+ ...usageToMessageMetadata(usage)
264055
+ };
264056
+ raw[id] = chatUsage;
264057
+ }
264058
+ for (const [key, tally] of Object.entries(this.toolUsageTally)) {
264059
+ raw[key] = { ...tally };
264060
+ }
264061
+ const finishPayload = {
264062
+ type: "finish",
264063
+ finishReason: "stop"
264064
+ };
264065
+ if (usage) {
264066
+ finishPayload.messageMetadata = { usage: { ...chatUsage, raw } };
264067
+ }
264068
+ chunks.push(sseData(finishPayload), "data: [DONE]\n\n");
264069
+ this.hasFinished = true;
264070
+ return chunks;
264071
+ }
264072
+ finishError(errorText) {
264073
+ this.hasFinished = true;
264074
+ return emitStreamError(errorText);
264075
+ }
264076
+ };
264077
+
263768
264078
  // ../../packages/runner-pi/dist/web-tools.js
263769
264079
  var braveProvider = {
263770
264080
  id: "brave",
@@ -263806,7 +264116,7 @@ ${body}`);
263806
264116
  });
263807
264117
  }
263808
264118
  }
263809
- return results;
264119
+ return { results };
263810
264120
  }
263811
264121
  };
263812
264122
  var tavilyProvider = {
@@ -263841,7 +264151,7 @@ ${body}`);
263841
264151
  });
263842
264152
  }
263843
264153
  }
263844
- return results;
264154
+ return { results };
263845
264155
  }
263846
264156
  };
263847
264157
  var AUTO_DETECT_ORDER = [braveProvider, tavilyProvider];
@@ -263988,7 +264298,7 @@ function buildWebSearchTool(env2) {
263988
264298
  let lastError;
263989
264299
  for (const { provider, apiKey } of providers) {
263990
264300
  try {
263991
- const results = await provider.search({
264301
+ const { results } = await provider.search({
263992
264302
  apiKey,
263993
264303
  query,
263994
264304
  count,
@@ -263996,11 +264306,21 @@ function buildWebSearchTool(env2) {
263996
264306
  freshness,
263997
264307
  signal
263998
264308
  });
264309
+ let fetchedPages = 0;
263999
264310
  if (shouldFetchContent) {
264000
264311
  for (const r2 of results) {
264001
264312
  r2.content = await fetchPageContent(r2.link, signal);
264313
+ fetchedPages += 1;
264002
264314
  }
264003
264315
  }
264316
+ const usage = {
264317
+ raw: {
264318
+ [provider.id]: {
264319
+ requests: 1,
264320
+ fetchedPages
264321
+ }
264322
+ }
264323
+ };
264004
264324
  return {
264005
264325
  content: [
264006
264326
  {
@@ -264008,7 +264328,9 @@ function buildWebSearchTool(env2) {
264008
264328
  text: formatSearchResults(results, provider.label)
264009
264329
  }
264010
264330
  ],
264011
- details: void 0
264331
+ details: {
264332
+ usage
264333
+ }
264012
264334
  };
264013
264335
  } catch (e2) {
264014
264336
  lastError = e2;
@@ -264191,52 +264513,6 @@ function applyModelOverrides(model, provider, optionsEnv) {
264191
264513
  model.baseUrl = anthropicBaseUrl;
264192
264514
  }
264193
264515
  }
264194
- function emitStreamError(errorText) {
264195
- return [
264196
- `data: ${JSON.stringify({ type: "error", errorText })}
264197
-
264198
- `,
264199
- `data: ${JSON.stringify({ type: "finish", finishReason: "error" })}
264200
-
264201
- `,
264202
- "data: [DONE]\n\n"
264203
- ];
264204
- }
264205
- function extractToolResultText(result) {
264206
- if (result !== null && typeof result === "object") {
264207
- const r2 = result;
264208
- if (Array.isArray(r2.content) && r2.content.length > 0) {
264209
- const text = r2.content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("\n");
264210
- if (text.length > 0) {
264211
- return text;
264212
- }
264213
- }
264214
- }
264215
- if (typeof result === "string")
264216
- return result;
264217
- try {
264218
- return JSON.stringify(result);
264219
- } catch {
264220
- return String(result);
264221
- }
264222
- }
264223
- function usageToMessageMetadata(usage) {
264224
- return {
264225
- input_tokens: usage.input,
264226
- output_tokens: usage.output,
264227
- cache_read_input_tokens: usage.cacheRead,
264228
- cache_creation_input_tokens: usage.cacheWrite
264229
- };
264230
- }
264231
- function getUsageFromAgentEndMessages(messages) {
264232
- for (let i2 = messages.length - 1; i2 >= 0; i2--) {
264233
- const m2 = messages[i2];
264234
- if (m2.role === "assistant" && m2.usage != null) {
264235
- return m2.usage;
264236
- }
264237
- }
264238
- return void 0;
264239
- }
264240
264516
  function getErrorFromAgentEndMessages(messages) {
264241
264517
  for (let i2 = messages.length - 1; i2 >= 0; i2--) {
264242
264518
  const m2 = messages[i2];
@@ -264252,7 +264528,7 @@ function traceRawMessage(debugCwd, data, reset = false, optionsEnv) {
264252
264528
  if (!enabled)
264253
264529
  return;
264254
264530
  try {
264255
- const file = join35(debugCwd, "pi-message-stream-debug.json");
264531
+ const file = join36(debugCwd, "pi-message-stream-debug.json");
264256
264532
  if (reset && existsSync28(file))
264257
264533
  unlinkSync6(file);
264258
264534
  const type = data !== null && typeof data === "object" ? data.type : void 0;
@@ -264321,9 +264597,22 @@ function createPiRunner(options2 = {}) {
264321
264597
  if (resume.includes("/")) {
264322
264598
  return SessionManager.open(resume);
264323
264599
  }
264324
- const sessions = await SessionManager.list(cwd);
264325
- const found = sessions.find((s2) => s2.id === resume);
264326
- return found ? SessionManager.open(found.path) : SessionManager.create(cwd);
264600
+ const sessionPath2 = resolveSessionPathById(cwd, resume);
264601
+ console.error(`${LOG_PREFIX2} resume: id=${resume} path=${sessionPath2 ?? "(not found)"}`);
264602
+ if (sessionPath2) {
264603
+ if (isSessionFileTooLarge(sessionPath2)) {
264604
+ const context = extractSessionContext(sessionPath2);
264605
+ console.error(`${LOG_PREFIX2} session file too large, starting fresh${context ? " (with context)" : ""}`);
264606
+ const newMgr = SessionManager.create(cwd);
264607
+ if (context) {
264608
+ const firstId = newMgr.getEntries()[0]?.id ?? "";
264609
+ newMgr.appendCompaction(context, firstId, 0);
264610
+ }
264611
+ return newMgr;
264612
+ }
264613
+ return SessionManager.open(sessionPath2);
264614
+ }
264615
+ return SessionManager.create(cwd);
264327
264616
  }
264328
264617
  return SessionManager.create(cwd);
264329
264618
  })();
@@ -264381,165 +264670,34 @@ function createPiRunner(options2 = {}) {
264381
264670
  }
264382
264671
  try {
264383
264672
  traceRawMessage(cwd, null, true, options2.env);
264384
- let promptText = userInput;
264385
- let images;
264386
- try {
264387
- if (userInput.startsWith("[") && userInput.endsWith("]")) {
264388
- const parsed = JSON.parse(userInput);
264389
- if (Array.isArray(parsed)) {
264390
- promptText = parsed.filter((p) => p.type === "text").map((p) => p.text).join("\n");
264391
- const imageParts = parsed.filter((p) => p.type === "image");
264392
- if (imageParts.length > 0) {
264393
- images = imageParts.map((p) => ({
264394
- type: "image",
264395
- data: p.data,
264396
- mimeType: p.mimeType
264397
- }));
264398
- }
264673
+ const promptText = userInput;
264674
+ const promptPromise = session.prompt(promptText);
264675
+ const streamConverter = new PiAISDKStreamConverter({
264676
+ sessionId: session.sessionId,
264677
+ model,
264678
+ redactText: (value2) => {
264679
+ if (options2.env && Object.keys(options2.env).length > 0) {
264680
+ return redactSecrets(value2, options2.env);
264399
264681
  }
264400
- }
264401
- } catch (_e2) {
264402
- }
264403
- const promptPromise = session.prompt(promptText, images ? { images } : void 0);
264404
- const messageId = `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`;
264405
- let hasStarted = false;
264406
- let hasFinished = false;
264407
- const imageToolUsage = { input_tokens: 0, output_tokens: 0 };
264408
- const newTextPartId = () => `text_${Date.now()}_${Math.random().toString(36).slice(2)}_${Math.random().toString(36).slice(2)}`;
264409
- let activeTextPartId = null;
264410
- let textStreamOpen = false;
264411
- const endTextStreamIfOpen = function* () {
264412
- if (textStreamOpen && activeTextPartId != null) {
264413
- yield `data: ${JSON.stringify({ type: "text-end", id: activeTextPartId })}
264414
-
264415
- `;
264416
- textStreamOpen = false;
264417
- activeTextPartId = null;
264418
- }
264419
- };
264420
- const beginTextStream = function* () {
264421
- activeTextPartId = newTextPartId();
264422
- yield `data: ${JSON.stringify({ type: "text-start", id: activeTextPartId })}
264423
-
264424
- `;
264425
- textStreamOpen = true;
264426
- };
264427
- const ensureStartEvent = async function* () {
264428
- if (!hasStarted) {
264429
- yield `data: ${JSON.stringify({ type: "start", messageId })}
264430
-
264431
- `;
264432
- yield `data: ${JSON.stringify({
264433
- type: "message-metadata",
264434
- messageMetadata: { sessionId: session.sessionId }
264435
- })}
264436
-
264437
- `;
264438
- hasStarted = true;
264439
- }
264440
- };
264441
- const finishSuccess = async function* (usage) {
264442
- yield* endTextStreamIfOpen();
264443
- const finishPayload = { type: "finish", finishReason: "stop" };
264444
- const hasImageUsage = imageToolUsage.input_tokens > 0 || imageToolUsage.output_tokens > 0;
264445
- if (usage != null || hasImageUsage) {
264446
- const base = usage != null ? usageToMessageMetadata(usage) : {};
264447
- finishPayload.messageMetadata = {
264448
- usage: {
264449
- ...base,
264450
- input_tokens: (base.input_tokens ?? 0) + imageToolUsage.input_tokens,
264451
- output_tokens: (base.output_tokens ?? 0) + imageToolUsage.output_tokens
264452
- }
264453
- };
264454
- }
264455
- yield `data: ${JSON.stringify(finishPayload)}
264456
-
264457
- `;
264458
- yield "data: [DONE]\n\n";
264459
- hasFinished = true;
264460
- };
264461
- const finishError = async function* (errorText) {
264462
- for (const chunk of emitStreamError(errorText)) {
264463
- yield chunk;
264464
- }
264465
- hasFinished = true;
264466
- };
264682
+ return value2;
264683
+ },
264684
+ normalizeToolOutput: extractToolResultText,
264685
+ getUsageFromAgentEndMessages,
264686
+ getErrorFromAgentEndMessages
264687
+ });
264467
264688
  while (!isComplete || eventQueue.length > 0) {
264468
264689
  while (eventQueue.length > 0) {
264469
264690
  const event = eventQueue.shift();
264470
264691
  traceRawMessage(cwd, event, false, options2.env);
264471
- yield* ensureStartEvent();
264472
- if (event.type === "message_start") {
264473
- const msg = event.message;
264474
- if (msg?.role === "assistant") {
264475
- yield* endTextStreamIfOpen();
264476
- }
264477
- } else if (event.type === "message_update") {
264478
- const sub = event.assistantMessageEvent;
264479
- if (sub.type === "text_start") {
264480
- yield* endTextStreamIfOpen();
264481
- yield* beginTextStream();
264482
- } else if (sub.type === "text_delta") {
264483
- let delta = sub.delta;
264484
- if (delta) {
264485
- if (options2.env && Object.keys(options2.env).length > 0) {
264486
- delta = redactSecrets(delta, options2.env);
264487
- }
264488
- if (!textStreamOpen) {
264489
- yield* beginTextStream();
264490
- }
264491
- yield `data: ${JSON.stringify({
264492
- type: "text-delta",
264493
- id: activeTextPartId,
264494
- delta
264495
- })}
264496
-
264497
- `;
264498
- }
264499
- } else if (sub.type === "toolcall_start") {
264500
- yield* endTextStreamIfOpen();
264501
- }
264502
- } else if (event.type === "tool_execution_start") {
264503
- yield* endTextStreamIfOpen();
264504
- yield `data: ${JSON.stringify({ type: "tool-input-start", toolCallId: event.toolCallId, toolName: event.toolName, dynamic: true, providerExecuted: true })}
264505
-
264506
- `;
264507
- yield `data: ${JSON.stringify({ type: "tool-input-available", toolCallId: event.toolCallId, toolName: event.toolName, input: event.args, dynamic: true, providerExecuted: true })}
264508
-
264509
- `;
264510
- } else if (event.type === "tool_execution_end") {
264511
- let output = extractToolResultText(event.result);
264512
- if (options2.env && Object.keys(options2.env).length > 0) {
264513
- output = redactSecrets(output, options2.env);
264514
- }
264515
- if ((event.toolName === "generate_image" || event.toolName === "edit_image") && event.result !== null && typeof event.result === "object") {
264516
- const details = event.result.details;
264517
- const u = details?.response?.usage;
264518
- if (u) {
264519
- imageToolUsage.input_tokens += u.input_tokens ?? 0;
264520
- imageToolUsage.output_tokens += u.output_tokens ?? 0;
264521
- }
264522
- }
264523
- yield `data: ${JSON.stringify({ type: "tool-output-available", toolCallId: event.toolCallId, output, isError: event.isError, dynamic: true, providerExecuted: true })}
264524
-
264525
- `;
264526
- } else if (event.type === "agent_end") {
264527
- if (aborted) {
264528
- yield* finishError("Run aborted by signal.");
264529
- } else {
264530
- const errorMsg = getErrorFromAgentEndMessages(event.messages);
264531
- if (errorMsg) {
264532
- yield* finishError(errorMsg);
264533
- } else {
264534
- const usage = getUsageFromAgentEndMessages(event.messages);
264535
- yield* finishSuccess(usage);
264536
- }
264537
- }
264692
+ const chunks = streamConverter.handleEvent(event, aborted);
264693
+ for (const chunk of chunks) {
264694
+ yield chunk;
264538
264695
  }
264539
264696
  }
264540
- if (aborted && !hasFinished) {
264541
- yield* ensureStartEvent();
264542
- yield* finishError("Run aborted by signal.");
264697
+ if (aborted && !streamConverter.finished) {
264698
+ for (const chunk of streamConverter.forceError("Run aborted by signal.")) {
264699
+ yield chunk;
264700
+ }
264543
264701
  break;
264544
264702
  }
264545
264703
  if (!isComplete && eventQueue.length === 0) {
@@ -264548,22 +264706,24 @@ function createPiRunner(options2 = {}) {
264548
264706
  });
264549
264707
  }
264550
264708
  }
264551
- if (hasFinished) {
264709
+ if (streamConverter.finished) {
264552
264710
  return;
264553
264711
  }
264554
264712
  try {
264555
264713
  await promptPromise;
264556
264714
  } catch (error) {
264557
- if (!hasFinished) {
264558
- yield* ensureStartEvent();
264715
+ if (!streamConverter.finished) {
264559
264716
  const message = error instanceof Error ? error.message : "Pi agent run failed.";
264560
- yield* finishError(message);
264717
+ for (const chunk of streamConverter.forceError(message)) {
264718
+ yield chunk;
264719
+ }
264561
264720
  }
264562
264721
  return;
264563
264722
  }
264564
- if (!hasFinished && session.agent.state.error) {
264565
- yield* ensureStartEvent();
264566
- yield* finishError(session.agent.state.error);
264723
+ if (!streamConverter.finished && session.agent.state.error) {
264724
+ for (const chunk of streamConverter.forceError(session.agent.state.error)) {
264725
+ yield chunk;
264726
+ }
264567
264727
  }
264568
264728
  } finally {
264569
264729
  if (abortSignal) {
@@ -264583,11 +264743,11 @@ function createPiRunner(options2 = {}) {
264583
264743
 
264584
264744
  // ../../packages/runner-harness/dist/session.js
264585
264745
  import { existsSync as existsSync29, mkdirSync as mkdirSync11, readFileSync as readFileSync23, writeFileSync as writeFileSync14 } from "node:fs";
264586
- import { join as join36 } from "node:path";
264746
+ import { join as join37 } from "node:path";
264587
264747
  var DIR = ".bunny-agent";
264588
264748
  var FILE = "session-id";
264589
264749
  function sessionPath(cwd) {
264590
- return join36(cwd, DIR, FILE);
264750
+ return join37(cwd, DIR, FILE);
264591
264751
  }
264592
264752
  function readSessionId(cwd) {
264593
264753
  try {
@@ -264601,28 +264761,28 @@ function readSessionId(cwd) {
264601
264761
  }
264602
264762
  function writeSessionId(cwd, id) {
264603
264763
  try {
264604
- mkdirSync11(join36(cwd, DIR), { recursive: true });
264764
+ mkdirSync11(join37(cwd, DIR), { recursive: true });
264605
264765
  writeFileSync14(sessionPath(cwd), id, "utf8");
264606
264766
  } catch {
264607
264767
  }
264608
264768
  }
264609
264769
 
264610
264770
  // ../../packages/runner-harness/dist/skills.js
264611
- import { existsSync as existsSync30, readdirSync as readdirSync12, statSync as statSync13 } from "node:fs";
264771
+ import { existsSync as existsSync30, readdirSync as readdirSync13, statSync as statSync14 } from "node:fs";
264612
264772
  import { homedir as homedir14 } from "node:os";
264613
- import { join as join37 } from "node:path";
264773
+ import { join as join38 } from "node:path";
264614
264774
  function discoverSkillPaths(cwd) {
264615
264775
  const paths = [];
264616
264776
  for (const base of [
264617
- join37(cwd, "skills"),
264618
- join37(homedir14(), ".bunny-agent", "skills")
264777
+ join38(cwd, "skills"),
264778
+ join38(homedir14(), ".bunny-agent", "skills")
264619
264779
  ]) {
264620
264780
  if (!existsSync30(base))
264621
264781
  continue;
264622
264782
  try {
264623
- for (const entry of readdirSync12(base)) {
264624
- const full = join37(base, entry);
264625
- if (statSync13(full).isDirectory() && existsSync30(join37(full, "SKILL.md"))) {
264783
+ for (const entry of readdirSync13(base)) {
264784
+ const full = join38(base, entry);
264785
+ if (statSync14(full).isDirectory() && existsSync30(join38(full, "SKILL.md"))) {
264626
264786
  paths.push(full);
264627
264787
  }
264628
264788
  }