sparkecoder 0.1.67 → 0.1.69

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.
Files changed (108) hide show
  1. package/dist/agent/index.d.ts +3 -3
  2. package/dist/agent/index.js +173 -19
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +307 -64
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +2 -2
  7. package/dist/{index-DHyVVhJY.d.ts → index-DqaHLgSC.d.ts} +20 -19
  8. package/dist/index.d.ts +5 -5
  9. package/dist/index.js +307 -64
  10. package/dist/index.js.map +1 -1
  11. package/dist/{schema-XcP0dedO.d.ts → schema-Bq4tID-f.d.ts} +3 -3
  12. package/dist/{search-CCffrVJE.d.ts → search-BRnGaIl-.d.ts} +7 -7
  13. package/dist/server/index.js +307 -64
  14. package/dist/server/index.js.map +1 -1
  15. package/dist/tools/index.d.ts +2 -2
  16. package/package.json +1 -1
  17. package/web/.next/BUILD_ID +1 -1
  18. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  19. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  20. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  21. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  22. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  23. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  24. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  39. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  48. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  57. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  66. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/embed/[id]/page_client-reference-manifest.js +1 -1
  74. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  75. package/web/.next/standalone/web/.next/server/app/index.rsc +3 -3
  76. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
  77. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
  78. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +3 -3
  79. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  82. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__c71f29f9._.js +3 -3
  83. package/web/.next/standalone/web/.next/server/chunks/ssr/web_2b3a5919._.js +1 -1
  84. package/web/.next/standalone/web/.next/server/chunks/ssr/web_38156da8._.js +1 -1
  85. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  86. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  87. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  88. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  89. package/web/.next/standalone/web/.next/static/chunks/{4e673433173ad456.js → 2cafc7cb79454d33.js} +3 -3
  90. package/web/.next/standalone/web/.next/static/chunks/{515f0c0bd6087843.js → b6ec74cad9ffd3ee.js} +3 -3
  91. package/web/.next/{static/chunks/31208ade542a0fcb.js → standalone/web/.next/static/chunks/fc39a194539da104.js} +3 -3
  92. package/web/.next/{static/chunks/4e673433173ad456.js → standalone/web/.next/static/static/chunks/2cafc7cb79454d33.js} +3 -3
  93. package/web/.next/standalone/web/.next/static/static/chunks/{515f0c0bd6087843.js → b6ec74cad9ffd3ee.js} +3 -3
  94. package/web/.next/standalone/web/.next/static/static/chunks/{31208ade542a0fcb.js → fc39a194539da104.js} +3 -3
  95. package/web/.next/standalone/web/src/components/chat-interface.tsx +14 -0
  96. package/web/.next/standalone/web/src/lib/api.ts +89 -16
  97. package/web/.next/{standalone/web/.next/static/static/chunks/4e673433173ad456.js → static/chunks/2cafc7cb79454d33.js} +3 -3
  98. package/web/.next/static/chunks/{515f0c0bd6087843.js → b6ec74cad9ffd3ee.js} +3 -3
  99. package/web/.next/{standalone/web/.next/static/chunks/31208ade542a0fcb.js → static/chunks/fc39a194539da104.js} +3 -3
  100. /package/web/.next/standalone/web/.next/static/{static/tZkod5afiOX7T9AkN1yPO → XB638PEDChQhwk6wSMrSh}/_buildManifest.js +0 -0
  101. /package/web/.next/standalone/web/.next/static/{static/tZkod5afiOX7T9AkN1yPO → XB638PEDChQhwk6wSMrSh}/_clientMiddlewareManifest.json +0 -0
  102. /package/web/.next/standalone/web/.next/static/{static/tZkod5afiOX7T9AkN1yPO → XB638PEDChQhwk6wSMrSh}/_ssgManifest.js +0 -0
  103. /package/web/.next/standalone/web/.next/static/{tZkod5afiOX7T9AkN1yPO → static/XB638PEDChQhwk6wSMrSh}/_buildManifest.js +0 -0
  104. /package/web/.next/standalone/web/.next/static/{tZkod5afiOX7T9AkN1yPO → static/XB638PEDChQhwk6wSMrSh}/_clientMiddlewareManifest.json +0 -0
  105. /package/web/.next/standalone/web/.next/static/{tZkod5afiOX7T9AkN1yPO → static/XB638PEDChQhwk6wSMrSh}/_ssgManifest.js +0 -0
  106. /package/web/.next/static/{tZkod5afiOX7T9AkN1yPO → XB638PEDChQhwk6wSMrSh}/_buildManifest.js +0 -0
  107. /package/web/.next/static/{tZkod5afiOX7T9AkN1yPO → XB638PEDChQhwk6wSMrSh}/_clientMiddlewareManifest.json +0 -0
  108. /package/web/.next/static/{tZkod5afiOX7T9AkN1yPO → XB638PEDChQhwk6wSMrSh}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -2556,10 +2556,15 @@ import WebSocket from "ws";
2556
2556
  import { EventEmitter } from "events";
2557
2557
  function getOrCreateProxy(sessionId, port) {
2558
2558
  const existing = activeProxies.get(sessionId);
2559
- if (existing) return existing;
2559
+ if (existing) {
2560
+ console.log(`[BROWSER-WS] Reusing existing proxy for session ${sessionId} (connected=${existing.connected})`);
2561
+ return existing;
2562
+ }
2563
+ console.log(`[BROWSER-WS] Creating new proxy for session ${sessionId} on port ${port} (active proxies: ${activeProxies.size})`);
2560
2564
  const proxy = new BrowserStreamProxy(port);
2561
2565
  activeProxies.set(sessionId, proxy);
2562
2566
  proxy.on("close", () => {
2567
+ console.log(`[BROWSER-WS] Proxy closed for session ${sessionId}, removing from registry`);
2563
2568
  activeProxies.delete(sessionId);
2564
2569
  });
2565
2570
  proxy.connect();
@@ -2571,8 +2576,11 @@ function getProxy(sessionId) {
2571
2576
  function destroyProxy(sessionId) {
2572
2577
  const proxy = activeProxies.get(sessionId);
2573
2578
  if (proxy) {
2579
+ console.log(`[BROWSER-WS] destroyProxy() called for session ${sessionId}`);
2574
2580
  proxy.destroy();
2575
2581
  activeProxies.delete(sessionId);
2582
+ } else {
2583
+ console.log(`[BROWSER-WS] destroyProxy() called but no proxy exists for session ${sessionId}`);
2576
2584
  }
2577
2585
  }
2578
2586
  var RECONNECT_DELAY_MS, MAX_RECONNECT_ATTEMPTS, FRAME_THROTTLE_MS, BrowserStreamProxy, activeProxies;
@@ -2603,18 +2611,22 @@ var init_stream_proxy = __esm({
2603
2611
  }
2604
2612
  connect() {
2605
2613
  if (this.destroyed) return;
2614
+ console.log(`[BROWSER-WS] connect() called for port ${this.port}`);
2606
2615
  this.doConnect();
2607
2616
  }
2608
2617
  doConnect() {
2609
2618
  if (this.destroyed) return;
2610
2619
  const url = `ws://localhost:${this.port}`;
2620
+ console.log(`[BROWSER-WS] Attempting WebSocket connection to ${url} (attempt ${this.reconnectAttempts + 1}/${MAX_RECONNECT_ATTEMPTS})`);
2611
2621
  try {
2612
2622
  this.ws = new WebSocket(url);
2613
- } catch {
2623
+ } catch (err) {
2624
+ console.warn(`[BROWSER-WS] WebSocket constructor threw for ${url}:`, err);
2614
2625
  this.scheduleReconnect();
2615
2626
  return;
2616
2627
  }
2617
2628
  this.ws.on("open", () => {
2629
+ console.log(`[BROWSER-WS] Connected to ${url} (after ${this.reconnectAttempts} retries)`);
2618
2630
  this.reconnectAttempts = 0;
2619
2631
  this._connected = true;
2620
2632
  this.emit("status", {
@@ -2626,12 +2638,14 @@ var init_stream_proxy = __esm({
2626
2638
  try {
2627
2639
  const msg = JSON.parse(typeof raw === "string" ? raw : raw.toString("utf8"));
2628
2640
  this.handleMessage(msg);
2629
- } catch {
2641
+ } catch (err) {
2642
+ console.warn(`[BROWSER-WS] Malformed message from ${url}:`, err);
2630
2643
  }
2631
2644
  });
2632
- this.ws.on("close", () => {
2645
+ this.ws.on("close", (code, reason) => {
2633
2646
  const wasConnected = this._connected;
2634
2647
  this._connected = false;
2648
+ console.log(`[BROWSER-WS] Connection closed: code=${code} reason="${reason?.toString() || ""}" wasConnected=${wasConnected} destroyed=${this.destroyed}`);
2635
2649
  if (wasConnected) {
2636
2650
  this.emit("status", { connected: false, screencasting: false });
2637
2651
  }
@@ -2639,14 +2653,26 @@ var init_stream_proxy = __esm({
2639
2653
  this.scheduleReconnect();
2640
2654
  }
2641
2655
  });
2642
- this.ws.on("error", () => {
2656
+ this.ws.on("error", (err) => {
2657
+ console.warn(`[BROWSER-WS] WebSocket error on port ${this.port}:`, err.message);
2643
2658
  });
2644
2659
  }
2660
+ frameCount = 0;
2661
+ throttledCount = 0;
2662
+ lastFrameLogTime = 0;
2645
2663
  handleMessage(msg) {
2646
2664
  if (msg.type === "frame") {
2647
2665
  const now = Date.now();
2648
- if (now - this.lastFrameTime < FRAME_THROTTLE_MS) return;
2666
+ if (now - this.lastFrameTime < FRAME_THROTTLE_MS) {
2667
+ this.throttledCount++;
2668
+ return;
2669
+ }
2649
2670
  this.lastFrameTime = now;
2671
+ this.frameCount++;
2672
+ if (now - this.lastFrameLogTime > 5e3) {
2673
+ console.log(`[BROWSER-WS] Frame stats: emitted=${this.frameCount} throttled=${this.throttledCount} listeners=${this.listenerCount("frame")} dataSize=${msg.data?.length ?? 0}`);
2674
+ this.lastFrameLogTime = now;
2675
+ }
2650
2676
  const frame = {
2651
2677
  data: msg.data,
2652
2678
  metadata: msg.metadata ?? {
@@ -2662,21 +2688,26 @@ var init_stream_proxy = __esm({
2662
2688
  this._latestFrame = frame;
2663
2689
  this.emit("frame", frame);
2664
2690
  } else if (msg.type === "status") {
2691
+ console.log(`[BROWSER-WS] Status message received:`, JSON.stringify(msg));
2665
2692
  this.emit("status", {
2666
2693
  connected: msg.connected ?? true,
2667
2694
  screencasting: msg.screencasting ?? true,
2668
2695
  viewportWidth: msg.viewportWidth,
2669
2696
  viewportHeight: msg.viewportHeight
2670
2697
  });
2698
+ } else {
2699
+ console.log(`[BROWSER-WS] Unknown message type: ${msg.type}`);
2671
2700
  }
2672
2701
  }
2673
2702
  scheduleReconnect() {
2674
2703
  if (this.destroyed || this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
2704
+ console.log(`[BROWSER-WS] Giving up reconnection: destroyed=${this.destroyed} attempts=${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS}`);
2675
2705
  this.emit("close");
2676
2706
  return;
2677
2707
  }
2678
2708
  this.reconnectAttempts++;
2679
2709
  const delay = this.reconnectAttempts <= 5 ? RECONNECT_DELAY_MS : RECONNECT_DELAY_MS * (this.reconnectAttempts - 4);
2710
+ console.log(`[BROWSER-WS] Scheduling reconnect in ${delay}ms (attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`);
2680
2711
  this.reconnectTimer = setTimeout(() => this.doConnect(), delay);
2681
2712
  }
2682
2713
  /**
@@ -2688,6 +2719,7 @@ var init_stream_proxy = __esm({
2688
2719
  }
2689
2720
  }
2690
2721
  destroy() {
2722
+ console.log(`[BROWSER-WS] Destroying proxy for port ${this.port} (emitted ${this.frameCount} frames, throttled ${this.throttledCount})`);
2691
2723
  this.destroyed = true;
2692
2724
  if (this.reconnectTimer) {
2693
2725
  clearTimeout(this.reconnectTimer);
@@ -7256,6 +7288,21 @@ ${this.summary}`
7256
7288
 
7257
7289
  // src/agent/index.ts
7258
7290
  init_webhook();
7291
+ var MAX_SSE_FIELD_LENGTH = 8 * 1024;
7292
+ var SSE_PREVIEW_LENGTH = 2 * 1024;
7293
+ function truncateWriteFileInput(input) {
7294
+ const out = { ...input };
7295
+ for (const key of ["content", "old_string", "new_string"]) {
7296
+ const val = out[key];
7297
+ if (typeof val === "string" && val.length > MAX_SSE_FIELD_LENGTH) {
7298
+ out[key] = `${val.slice(0, SSE_PREVIEW_LENGTH)}
7299
+ ... (truncated)`;
7300
+ out[`${key}Truncated`] = true;
7301
+ out[`${key}Length`] = val.length;
7302
+ }
7303
+ }
7304
+ return out;
7305
+ }
7259
7306
  var approvalResolvers = /* @__PURE__ */ new Map();
7260
7307
  var Agent = class _Agent {
7261
7308
  session;
@@ -7499,8 +7546,11 @@ ${prompt}` });
7499
7546
  };
7500
7547
  let taskRecorder = null;
7501
7548
  const sessionId = this.session.id;
7549
+ const emit = options.writeSSE;
7502
7550
  const bashProgressHandler = (progress) => {
7503
7551
  options.onToolProgress?.({ toolName: "bash", data: progress });
7552
+ if (emit) emit(JSON.stringify({ type: "tool-progress", toolName: "bash", data: progress })).catch(() => {
7553
+ });
7504
7554
  const port = progress.browserStreamPort;
7505
7555
  if (port && progress.status === "started") {
7506
7556
  Promise.resolve().then(() => (init_stream_proxy(), stream_proxy_exports)).then(({ getOrCreateProxy: getOrCreateProxy2 }) => {
@@ -7509,7 +7559,17 @@ ${prompt}` });
7509
7559
  Promise.resolve().then(() => (init_recorder(), recorder_exports)).then(({ FrameRecorder: FrameRecorder2 }) => {
7510
7560
  taskRecorder = new FrameRecorder2(sessionId);
7511
7561
  taskRecorder.start();
7512
- proxy.on("frame", (frame) => taskRecorder?.addFrame(frame));
7562
+ });
7563
+ }
7564
+ if (proxy.listenerCount("frame") === 0) {
7565
+ proxy.on("frame", (frame) => {
7566
+ taskRecorder?.addFrame(frame);
7567
+ if (emit) emit(JSON.stringify({ type: "browser-frame", data: frame.data, metadata: frame.metadata })).catch(() => {
7568
+ });
7569
+ });
7570
+ proxy.on("status", (s) => {
7571
+ if (emit) emit(JSON.stringify({ type: "browser-status", ...s })).catch(() => {
7572
+ });
7513
7573
  });
7514
7574
  }
7515
7575
  });
@@ -7520,8 +7580,16 @@ ${prompt}` });
7520
7580
  workingDirectory: this.session.workingDirectory,
7521
7581
  skillsDirectories: config.resolvedSkillsDirectories,
7522
7582
  onBashProgress: bashProgressHandler,
7523
- onWriteFileProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "write_file", data: progress }) : void 0,
7524
- onSearchProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "explore_agent", data: progress }) : void 0,
7583
+ onWriteFileProgress: (progress) => {
7584
+ options.onToolProgress?.({ toolName: "write_file", data: progress });
7585
+ if (emit) emit(JSON.stringify({ type: "tool-progress", toolName: "write_file", data: progress })).catch(() => {
7586
+ });
7587
+ },
7588
+ onSearchProgress: (progress) => {
7589
+ options.onToolProgress?.({ toolName: "explore_agent", data: progress });
7590
+ if (emit) emit(JSON.stringify({ type: "tool-progress", toolName: "explore_agent", data: progress })).catch(() => {
7591
+ });
7592
+ },
7525
7593
  taskTools: {
7526
7594
  outputSchema: options.taskConfig.outputSchema,
7527
7595
  onComplete
@@ -7539,6 +7607,9 @@ ${prompt}` });
7539
7607
 
7540
7608
  ${taskAddendum}`;
7541
7609
  fireWebhook("task.started", { prompt: options.prompt });
7610
+ if (emit) {
7611
+ await emit(JSON.stringify({ type: "data-user-message", data: { id: `user_${Date.now()}`, content: options.prompt } }));
7612
+ }
7542
7613
  await this.context.addUserMessage(options.prompt);
7543
7614
  let iteration = 0;
7544
7615
  while (iteration < maxIterations) {
@@ -7550,7 +7621,15 @@ ${taskAddendum}`;
7550
7621
  }
7551
7622
  const messages = await this.context.getMessages();
7552
7623
  const useAnthropic = isAnthropicModel(this.session.model);
7553
- const result = await generateText3({
7624
+ if (emit) {
7625
+ await emit(JSON.stringify({ type: "start", messageId: `msg_${Date.now()}` }));
7626
+ }
7627
+ let textStarted = false;
7628
+ let textId = `text_${Date.now()}`;
7629
+ let reasoningId = `reasoning_${Date.now()}`;
7630
+ let reasoningStarted = false;
7631
+ const toolCallStarts = /* @__PURE__ */ new Set();
7632
+ const iterStream = streamText2({
7554
7633
  model: resolveModel(this.session.model),
7555
7634
  system: systemPrompt,
7556
7635
  messages,
@@ -7559,21 +7638,94 @@ ${taskAddendum}`;
7559
7638
  abortSignal: options.abortSignal,
7560
7639
  providerOptions: useAnthropic ? {
7561
7640
  anthropic: {
7641
+ toolStreaming: true,
7562
7642
  thinking: { type: "enabled", budgetTokens: 1e4 }
7563
7643
  }
7564
7644
  } : void 0,
7565
- onStepFinish: (step) => {
7645
+ onStepFinish: async (step) => {
7566
7646
  options.onStepFinish?.(step);
7567
7647
  fireWebhook("task.step_finished", { iteration, text: step.text });
7648
+ if (emit) {
7649
+ if (textStarted) {
7650
+ await emit(JSON.stringify({ type: "text-end", id: textId }));
7651
+ textStarted = false;
7652
+ textId = `text_${Date.now()}`;
7653
+ }
7654
+ await emit(JSON.stringify({ type: "finish-step" }));
7655
+ }
7568
7656
  }
7569
7657
  });
7570
- const responseMessages = result.response.messages;
7658
+ for await (const part of iterStream.fullStream) {
7659
+ if (part.type === "text-delta") {
7660
+ if (emit) {
7661
+ if (!textStarted) {
7662
+ await emit(JSON.stringify({ type: "text-start", id: textId }));
7663
+ textStarted = true;
7664
+ }
7665
+ await emit(JSON.stringify({ type: "text-delta", id: textId, delta: part.text }));
7666
+ }
7667
+ } else if (part.type === "reasoning-start") {
7668
+ if (emit) {
7669
+ await emit(JSON.stringify({ type: "reasoning-start", id: reasoningId }));
7670
+ reasoningStarted = true;
7671
+ }
7672
+ } else if (part.type === "reasoning-delta") {
7673
+ if (emit) {
7674
+ await emit(JSON.stringify({ type: "reasoning-delta", id: reasoningId, delta: part.text }));
7675
+ }
7676
+ } else if (part.type === "reasoning-end") {
7677
+ if (emit && reasoningStarted) {
7678
+ await emit(JSON.stringify({ type: "reasoning-end", id: reasoningId }));
7679
+ reasoningStarted = false;
7680
+ reasoningId = `reasoning_${Date.now()}`;
7681
+ }
7682
+ } else if (part.type === "tool-call-streaming-start") {
7683
+ if (emit) {
7684
+ const p = part;
7685
+ await emit(JSON.stringify({ type: "tool-input-start", toolCallId: p.toolCallId, toolName: p.toolName }));
7686
+ toolCallStarts.add(p.toolCallId);
7687
+ }
7688
+ } else if (part.type === "tool-call-delta") {
7689
+ if (emit) {
7690
+ const p = part;
7691
+ await emit(JSON.stringify({ type: "tool-input-delta", toolCallId: p.toolCallId, argsTextDelta: p.argsTextDelta }));
7692
+ }
7693
+ } else if (part.type === "tool-call") {
7694
+ if (emit) {
7695
+ if (!toolCallStarts.has(part.toolCallId)) {
7696
+ await emit(JSON.stringify({ type: "tool-input-start", toolCallId: part.toolCallId, toolName: part.toolName }));
7697
+ toolCallStarts.add(part.toolCallId);
7698
+ }
7699
+ const safeInput = part.toolName === "write_file" && part.input && typeof part.input === "object" ? truncateWriteFileInput(part.input) : part.input;
7700
+ await emit(JSON.stringify({ type: "tool-input-available", toolCallId: part.toolCallId, toolName: part.toolName, input: safeInput }));
7701
+ }
7702
+ } else if (part.type === "tool-result") {
7703
+ if (emit) {
7704
+ await emit(JSON.stringify({ type: "tool-output-available", toolCallId: part.toolCallId, output: part.output }));
7705
+ }
7706
+ } else if (part.type === "error") {
7707
+ console.error("Task stream error:", part.error);
7708
+ if (emit) {
7709
+ await emit(JSON.stringify({ type: "error", errorText: String(part.error) }));
7710
+ }
7711
+ }
7712
+ }
7713
+ if (emit && textStarted) {
7714
+ await emit(JSON.stringify({ type: "text-end", id: textId }));
7715
+ }
7716
+ if (emit && reasoningStarted) {
7717
+ await emit(JSON.stringify({ type: "reasoning-end", id: reasoningId }));
7718
+ }
7719
+ const iterResponse = await iterStream.response;
7720
+ const responseMessages = iterResponse.messages;
7571
7721
  await this.context.addResponseMessages(responseMessages);
7572
- if (result.text) {
7573
- options.onText?.(result.text);
7574
- fireWebhook("task.message", { iteration, text: result.text });
7722
+ const resultText = await iterStream.text;
7723
+ const resultSteps = await iterStream.steps;
7724
+ if (resultText) {
7725
+ options.onText?.(resultText);
7726
+ fireWebhook("task.message", { iteration, text: resultText });
7575
7727
  }
7576
- for (const step of result.steps) {
7728
+ for (const step of resultSteps) {
7577
7729
  if (step.toolCalls) {
7578
7730
  for (const tc of step.toolCalls) {
7579
7731
  options.onToolCall?.({ toolCallId: tc.toolCallId, toolName: tc.toolName, input: tc.args });
@@ -7626,9 +7778,11 @@ ${taskAddendum}`;
7626
7778
  iterations: iteration
7627
7779
  };
7628
7780
  }
7629
- await this.context.addUserMessage(
7630
- "Continue working on the task. Before calling `complete_task`, VERIFY your work is correct \u2014 re-read edited files, run the linter, run tests if applicable, and check the browser/server if you made UI or API changes. Make sure you searched the right directories and found everything relevant. When fully verified, call `complete_task` with the result. If you cannot complete it, call `task_failed` with a reason."
7631
- );
7781
+ const continuationPrompt = "Continue working on the task. Before calling `complete_task`, VERIFY your work is correct \u2014 re-read edited files, run the linter, run tests if applicable, and check the browser/server if you made UI or API changes. Make sure you searched the right directories and found everything relevant. When fully verified, call `complete_task` with the result. If you cannot complete it, call `task_failed` with a reason.";
7782
+ if (emit) {
7783
+ await emit(JSON.stringify({ type: "data-user-message", data: { id: `user_${Date.now()}`, content: continuationPrompt } }));
7784
+ }
7785
+ await this.context.addUserMessage(continuationPrompt);
7632
7786
  }
7633
7787
  const timeoutError = `Task did not complete within ${maxIterations} iterations`;
7634
7788
  const timeoutRecordingUrls = await this.finishTaskRecording(taskRecorder);
@@ -8719,11 +8873,19 @@ var cleanupInterval = setInterval(() => {
8719
8873
  }
8720
8874
  }, 6e4);
8721
8875
  cleanupInterval.unref();
8876
+ var publishCount = 0;
8877
+ var lastPublishLog = 0;
8722
8878
  var publisher = {
8723
8879
  connect: async () => {
8724
8880
  },
8725
8881
  publish: async (channel, message) => {
8726
8882
  const subscribers = channels.get(channel);
8883
+ publishCount++;
8884
+ const now = Date.now();
8885
+ if (now - lastPublishLog > 1e4) {
8886
+ console.log(`[ResumableStream] Publish stats: total=${publishCount}, channels=${channels.size}, store=${store.size}`);
8887
+ lastPublishLog = now;
8888
+ }
8727
8889
  if (subscribers) {
8728
8890
  for (const callback of subscribers) {
8729
8891
  setImmediate(() => callback(message));
@@ -8762,9 +8924,12 @@ var subscriber = {
8762
8924
  channels.set(channel, /* @__PURE__ */ new Set());
8763
8925
  }
8764
8926
  channels.get(channel).add(callback);
8927
+ console.log(`[ResumableStream] Subscribe to channel "${channel}" (total subscribers: ${channels.get(channel).size})`);
8765
8928
  },
8766
8929
  unsubscribe: async (channel) => {
8930
+ const count = channels.get(channel)?.size ?? 0;
8767
8931
  channels.delete(channel);
8932
+ console.log(`[ResumableStream] Unsubscribe from channel "${channel}" (removed ${count} subscribers)`);
8768
8933
  }
8769
8934
  };
8770
8935
  var streamContext = createResumableStreamContext({
@@ -8950,19 +9115,28 @@ function createAgentStreamProducer(sessionId, prompt, streamId, attachments) {
8950
9115
  const toolCallStarts = /* @__PURE__ */ new Set();
8951
9116
  const abortController = new AbortController();
8952
9117
  streamAbortControllers.set(streamId, abortController);
9118
+ let sseEventCount = 0;
9119
+ let sseBrowserFrameCount = 0;
9120
+ let sseWriteErrors = 0;
8953
9121
  const writeSSE = async (data) => {
8954
9122
  if (writerClosed) return;
8955
9123
  try {
9124
+ sseEventCount++;
8956
9125
  await writer.write(`data: ${data}
8957
9126
 
8958
9127
  `);
8959
9128
  } catch (err) {
9129
+ sseWriteErrors++;
9130
+ if (sseWriteErrors === 1) {
9131
+ console.log(`[SSE:${streamId}] Writer closed (client disconnected). Total events sent: ${sseEventCount}, browser frames: ${sseBrowserFrameCount}`);
9132
+ }
8960
9133
  writerClosed = true;
8961
9134
  }
8962
9135
  };
8963
9136
  const safeClose = async () => {
8964
9137
  if (writerClosed) return;
8965
9138
  try {
9139
+ console.log(`[SSE:${streamId}] Stream closing. Total events: ${sseEventCount}, browser frames: ${sseBrowserFrameCount}, write errors: ${sseWriteErrors}`);
8966
9140
  writerClosed = true;
8967
9141
  await writer.close();
8968
9142
  } catch {
@@ -9085,35 +9259,47 @@ ${prompt}` });
9085
9259
  const browserPort = progress.data?.browserStreamPort;
9086
9260
  const browserClosed = progress.data?.browserClosed;
9087
9261
  if (progress.toolName === "bash" && browserClosed) {
9088
- console.log(`[BROWSER-STREAM] agent-browser close detected, destroying proxy`);
9262
+ console.log(`[BROWSER-STREAM:${streamId}] agent-browser close detected, destroying proxy for session ${sessionId}`);
9089
9263
  destroyProxy(sessionId);
9090
9264
  } else if (progress.toolName === "bash" && browserPort) {
9091
- console.log(`[BROWSER-STREAM] agent-browser command detected, ensuring proxy on port ${browserPort}`);
9265
+ console.log(`[BROWSER-STREAM:${streamId}] agent-browser command detected, ensuring proxy on port ${browserPort} for session ${sessionId}`);
9092
9266
  const proxy = getOrCreateProxy(sessionId, browserPort);
9267
+ console.log(`[BROWSER-STREAM:${streamId}] Proxy state: connected=${proxy.connected}, frameListeners=${proxy.listenerCount("frame")}, statusListeners=${proxy.listenerCount("status")}`);
9093
9268
  if (!sessionRecorders.has(sessionId)) {
9094
9269
  const recorder = new FrameRecorder(sessionId);
9095
9270
  recorder.start();
9096
9271
  sessionRecorders.set(sessionId, recorder);
9097
9272
  }
9098
9273
  if (proxy.listenerCount("frame") === 0) {
9274
+ console.log(`[BROWSER-STREAM:${streamId}] Attaching frame+status listeners to proxy`);
9099
9275
  proxy.on("frame", (frame) => {
9276
+ sseBrowserFrameCount++;
9277
+ if (sseBrowserFrameCount === 1) {
9278
+ console.log(`[BROWSER-STREAM:${streamId}] First browser frame received! dataSize=${frame.data?.length ?? 0} writerClosed=${writerClosed}`);
9279
+ } else if (sseBrowserFrameCount % 50 === 0) {
9280
+ console.log(`[BROWSER-STREAM:${streamId}] Browser frame #${sseBrowserFrameCount} (writerClosed=${writerClosed})`);
9281
+ }
9100
9282
  const rec = sessionRecorders.get(sessionId);
9101
9283
  rec?.addFrame(frame);
9102
9284
  writeSSE(JSON.stringify({
9103
9285
  type: "browser-frame",
9104
9286
  data: frame.data,
9105
9287
  metadata: frame.metadata
9106
- })).catch(() => {
9288
+ })).catch((err) => {
9289
+ console.warn(`[BROWSER-STREAM:${streamId}] Failed to send browser-frame via SSE:`, err);
9107
9290
  });
9108
9291
  });
9109
9292
  proxy.on("status", (s) => {
9110
- console.log(`[BROWSER-STREAM] Status:`, s);
9293
+ console.log(`[BROWSER-STREAM:${streamId}] Browser status event: connected=${s.connected} screencasting=${s.screencasting} viewport=${s.viewportWidth}x${s.viewportHeight}`);
9111
9294
  writeSSE(JSON.stringify({
9112
9295
  type: "browser-status",
9113
9296
  ...s
9114
- })).catch(() => {
9297
+ })).catch((err) => {
9298
+ console.warn(`[BROWSER-STREAM:${streamId}] Failed to send browser-status via SSE:`, err);
9115
9299
  });
9116
9300
  });
9301
+ } else {
9302
+ console.log(`[BROWSER-STREAM:${streamId}] Frame listeners already attached (count=${proxy.listenerCount("frame")}), skipping`);
9117
9303
  }
9118
9304
  }
9119
9305
  },
@@ -9303,14 +9489,17 @@ ${prompt}` });
9303
9489
  }
9304
9490
  await messageQueries.create(id, { role: "user", content: userMessageContent });
9305
9491
  const streamId = `stream_${id}_${nanoid6(10)}`;
9492
+ console.log(`[STREAM] Creating stream ${streamId} for session ${id}`);
9306
9493
  await activeStreamQueries.create(id, streamId);
9307
9494
  const stream = await streamContext.resumableStream(
9308
9495
  streamId,
9309
9496
  createAgentStreamProducer(id, prompt, streamId, streamAttachments)
9310
9497
  );
9311
9498
  if (!stream) {
9499
+ console.error(`[STREAM] Failed to create resumable stream ${streamId}`);
9312
9500
  return c.json({ error: "Failed to create stream" }, 500);
9313
9501
  }
9502
+ console.log(`[STREAM] Stream ${streamId} created successfully`);
9314
9503
  const encodedStream = stream.pipeThrough(new TextEncoderStream());
9315
9504
  return new Response(encodedStream, {
9316
9505
  headers: {
@@ -9339,17 +9528,20 @@ agents.get("/:id/watch", async (c) => {
9339
9528
  }
9340
9529
  streamId = activeStream.streamId;
9341
9530
  }
9531
+ console.log(`[STREAM] Watch request for session ${sessionId}, streamId=${streamId}, resumeAt=${resumeAt || "none"}`);
9342
9532
  const stream = await streamContext.resumeExistingStream(
9343
9533
  streamId,
9344
9534
  resumeAt ? parseInt(resumeAt, 10) : void 0
9345
9535
  );
9346
9536
  if (!stream) {
9537
+ console.log(`[STREAM] Watch failed \u2014 stream ${streamId} is no longer active`);
9347
9538
  return c.json({
9348
9539
  error: "Stream is no longer active",
9349
9540
  streamId,
9350
9541
  hint: "The stream may have finished. Check /agents/:id/approvals or start a new run."
9351
9542
  }, 422);
9352
9543
  }
9544
+ console.log(`[STREAM] Client watching stream ${streamId}`);
9353
9545
  const encodedStream = stream.pipeThrough(new TextEncoderStream());
9354
9546
  return new Response(encodedStream, {
9355
9547
  headers: {
@@ -9511,19 +9703,28 @@ agents.post(
9511
9703
  const toolCallStarts = /* @__PURE__ */ new Set();
9512
9704
  const abortController = new AbortController();
9513
9705
  streamAbortControllers.set(streamId, abortController);
9706
+ let sseEventCount = 0;
9707
+ let sseBrowserFrameCount = 0;
9708
+ let sseWriteErrors = 0;
9514
9709
  const writeSSE = async (data) => {
9515
9710
  if (writerClosed) return;
9516
9711
  try {
9712
+ sseEventCount++;
9517
9713
  await writer.write(`data: ${data}
9518
9714
 
9519
9715
  `);
9520
9716
  } catch (err) {
9717
+ sseWriteErrors++;
9718
+ if (sseWriteErrors === 1) {
9719
+ console.log(`[SSE:${streamId}] Writer closed (client disconnected). Total events sent: ${sseEventCount}, browser frames: ${sseBrowserFrameCount}`);
9720
+ }
9521
9721
  writerClosed = true;
9522
9722
  }
9523
9723
  };
9524
9724
  const safeClose = async () => {
9525
9725
  if (writerClosed) return;
9526
9726
  try {
9727
+ console.log(`[SSE:${streamId}] Stream closing. Total events: ${sseEventCount}, browser frames: ${sseBrowserFrameCount}, write errors: ${sseWriteErrors}`);
9527
9728
  writerClosed = true;
9528
9729
  await writer.close();
9529
9730
  } catch {
@@ -9583,35 +9784,47 @@ agents.post(
9583
9784
  const browserPort = progress.data?.browserStreamPort;
9584
9785
  const browserClosed = progress.data?.browserClosed;
9585
9786
  if (progress.toolName === "bash" && browserClosed) {
9586
- console.log(`[BROWSER-STREAM] agent-browser close detected`);
9787
+ console.log(`[BROWSER-STREAM:${streamId}] agent-browser close detected, destroying proxy for session ${session.id}`);
9587
9788
  destroyProxy(session.id);
9588
9789
  } else if (progress.toolName === "bash" && browserPort) {
9589
- console.log(`[BROWSER-STREAM] agent-browser command detected, port ${browserPort}`);
9790
+ console.log(`[BROWSER-STREAM:${streamId}] agent-browser command detected, port ${browserPort} for session ${session.id}`);
9590
9791
  const proxy = getOrCreateProxy(session.id, browserPort);
9792
+ console.log(`[BROWSER-STREAM:${streamId}] Proxy state: connected=${proxy.connected}, frameListeners=${proxy.listenerCount("frame")}, statusListeners=${proxy.listenerCount("status")}`);
9591
9793
  if (!sessionRecorders.has(session.id)) {
9592
9794
  const recorder = new FrameRecorder(session.id);
9593
9795
  recorder.start();
9594
9796
  sessionRecorders.set(session.id, recorder);
9595
9797
  }
9596
9798
  if (proxy.listenerCount("frame") === 0) {
9799
+ console.log(`[BROWSER-STREAM:${streamId}] Attaching frame+status listeners to proxy`);
9597
9800
  proxy.on("frame", (frame) => {
9801
+ sseBrowserFrameCount++;
9802
+ if (sseBrowserFrameCount === 1) {
9803
+ console.log(`[BROWSER-STREAM:${streamId}] First browser frame received! dataSize=${frame.data?.length ?? 0} writerClosed=${writerClosed}`);
9804
+ } else if (sseBrowserFrameCount % 50 === 0) {
9805
+ console.log(`[BROWSER-STREAM:${streamId}] Browser frame #${sseBrowserFrameCount} (writerClosed=${writerClosed})`);
9806
+ }
9598
9807
  const rec = sessionRecorders.get(session.id);
9599
9808
  rec?.addFrame(frame);
9600
9809
  writeSSE(JSON.stringify({
9601
9810
  type: "browser-frame",
9602
9811
  data: frame.data,
9603
9812
  metadata: frame.metadata
9604
- })).catch(() => {
9813
+ })).catch((err) => {
9814
+ console.warn(`[BROWSER-STREAM:${streamId}] Failed to send browser-frame via SSE:`, err);
9605
9815
  });
9606
9816
  });
9607
9817
  proxy.on("status", (s) => {
9608
- console.log(`[BROWSER-STREAM] Status:`, s);
9818
+ console.log(`[BROWSER-STREAM:${streamId}] Browser status event: connected=${s.connected} screencasting=${s.screencasting} viewport=${s.viewportWidth}x${s.viewportHeight}`);
9609
9819
  writeSSE(JSON.stringify({
9610
9820
  type: "browser-status",
9611
9821
  ...s
9612
- })).catch(() => {
9822
+ })).catch((err) => {
9823
+ console.warn(`[BROWSER-STREAM:${streamId}] Failed to send browser-status via SSE:`, err);
9613
9824
  });
9614
9825
  });
9826
+ } else {
9827
+ console.log(`[BROWSER-STREAM:${streamId}] Frame listeners already attached (count=${proxy.listenerCount("frame")}), skipping`);
9615
9828
  }
9616
9829
  }
9617
9830
  },
@@ -10260,6 +10473,7 @@ init_db();
10260
10473
  import { Hono as Hono5 } from "hono";
10261
10474
  import { zValidator as zValidator5 } from "@hono/zod-validator";
10262
10475
  import { z as z19 } from "zod";
10476
+ import { nanoid as nanoid7 } from "nanoid";
10263
10477
  init_config();
10264
10478
  var tasks = new Hono5();
10265
10479
  var taskAbortControllers = /* @__PURE__ */ new Map();
@@ -10297,45 +10511,74 @@ tasks.post(
10297
10511
  const taskId = agent.sessionId;
10298
10512
  const abortController = new AbortController();
10299
10513
  taskAbortControllers.set(taskId, abortController);
10300
- (async () => {
10301
- try {
10302
- await agent.runTask({
10303
- prompt: body.prompt,
10304
- taskConfig,
10305
- abortSignal: abortController.signal
10306
- });
10307
- } catch (err) {
10308
- if (err.name === "AbortError" || abortController.signal.aborted) {
10309
- console.log(`[TASK] Task ${taskId} was cancelled`);
10310
- } else {
10311
- console.error(`[TASK] Error in task ${taskId}:`, err.message);
10312
- const errorMsg = err.message || "Unknown error";
10313
- const failedTask = {
10314
- ...taskConfig,
10315
- status: "failed",
10316
- error: errorMsg
10317
- };
10318
- await sessionQueries.update(taskId, {
10319
- config: {
10320
- toolApprovals: { bash: false, write_file: false, read_file: false },
10321
- task: failedTask
10322
- }
10514
+ const streamId = `stream_${taskId}_${nanoid7(10)}`;
10515
+ await activeStreamQueries.create(taskId, streamId);
10516
+ const taskStreamProducer = () => {
10517
+ const { readable, writable } = new TransformStream();
10518
+ const writer = writable.getWriter();
10519
+ let writerClosed = false;
10520
+ const writeSSE = async (data) => {
10521
+ if (writerClosed) return;
10522
+ try {
10523
+ await writer.write(`data: ${data}
10524
+
10525
+ `);
10526
+ } catch {
10527
+ writerClosed = true;
10528
+ }
10529
+ };
10530
+ (async () => {
10531
+ await writeSSE(JSON.stringify({ type: "data-stream-id", streamId }));
10532
+ try {
10533
+ await agent.runTask({
10534
+ prompt: body.prompt,
10535
+ taskConfig,
10536
+ abortSignal: abortController.signal,
10537
+ writeSSE
10323
10538
  });
10324
- if (taskConfig.webhookUrl) {
10325
- const { sendWebhook: sendWebhook2 } = await Promise.resolve().then(() => (init_webhook(), webhook_exports));
10326
- sendWebhook2(taskConfig.webhookUrl, {
10327
- type: "task.failed",
10328
- taskId,
10329
- sessionId: taskId,
10330
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10331
- data: { status: "failed", error: errorMsg }
10539
+ await writeSSE(JSON.stringify({ type: "finish" }));
10540
+ } catch (err) {
10541
+ if (err.name === "AbortError" || abortController.signal.aborted) {
10542
+ console.log(`[TASK] Task ${taskId} was cancelled`);
10543
+ await writeSSE(JSON.stringify({ type: "abort" }));
10544
+ } else {
10545
+ console.error(`[TASK] Error in task ${taskId}:`, err.message);
10546
+ const errorMsg = err.message || "Unknown error";
10547
+ await writeSSE(JSON.stringify({ type: "error", errorText: errorMsg }));
10548
+ const failedTask = {
10549
+ ...taskConfig,
10550
+ status: "failed",
10551
+ error: errorMsg
10552
+ };
10553
+ await sessionQueries.update(taskId, {
10554
+ config: {
10555
+ toolApprovals: { bash: false, write_file: false, read_file: false },
10556
+ task: failedTask
10557
+ }
10332
10558
  });
10559
+ if (taskConfig.webhookUrl) {
10560
+ const { sendWebhook: sendWebhook2 } = await Promise.resolve().then(() => (init_webhook(), webhook_exports));
10561
+ sendWebhook2(taskConfig.webhookUrl, {
10562
+ type: "task.failed",
10563
+ taskId,
10564
+ sessionId: taskId,
10565
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10566
+ data: { status: "failed", error: errorMsg }
10567
+ });
10568
+ }
10333
10569
  }
10570
+ } finally {
10571
+ await writeSSE("[DONE]");
10572
+ writer.close().catch(() => {
10573
+ });
10574
+ await activeStreamQueries.finish(streamId).catch(() => {
10575
+ });
10576
+ taskAbortControllers.delete(taskId);
10334
10577
  }
10335
- } finally {
10336
- taskAbortControllers.delete(taskId);
10337
- }
10338
- })();
10578
+ })();
10579
+ return readable;
10580
+ };
10581
+ await streamContext.resumableStream(streamId, taskStreamProducer);
10339
10582
  return c.json({ taskId, status: "running" }, 201);
10340
10583
  }
10341
10584
  );