sparkecoder 0.1.67 → 0.1.68

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 (87) hide show
  1. package/dist/agent/index.d.ts +1 -1
  2. package/dist/agent/index.js +135 -13
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +200 -48
  5. package/dist/cli.js.map +1 -1
  6. package/dist/{index-DHyVVhJY.d.ts → index-Dm6wGcYv.d.ts} +1 -0
  7. package/dist/index.d.ts +2 -2
  8. package/dist/index.js +200 -48
  9. package/dist/index.js.map +1 -1
  10. package/dist/server/index.js +200 -48
  11. package/dist/server/index.js.map +1 -1
  12. package/package.json +1 -1
  13. package/web/.next/BUILD_ID +1 -1
  14. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  15. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  16. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  17. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  18. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  19. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  20. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  21. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  22. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  23. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  24. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  33. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  42. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  48. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  51. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  60. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  68. package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  76. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  77. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  78. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  79. /package/web/.next/standalone/web/.next/static/{static/tZkod5afiOX7T9AkN1yPO → 6Dlxqhgk8Mki7q7L-gDbl}/_buildManifest.js +0 -0
  80. /package/web/.next/standalone/web/.next/static/{static/tZkod5afiOX7T9AkN1yPO → 6Dlxqhgk8Mki7q7L-gDbl}/_clientMiddlewareManifest.json +0 -0
  81. /package/web/.next/standalone/web/.next/static/{static/tZkod5afiOX7T9AkN1yPO → 6Dlxqhgk8Mki7q7L-gDbl}/_ssgManifest.js +0 -0
  82. /package/web/.next/standalone/web/.next/static/{tZkod5afiOX7T9AkN1yPO → static/6Dlxqhgk8Mki7q7L-gDbl}/_buildManifest.js +0 -0
  83. /package/web/.next/standalone/web/.next/static/{tZkod5afiOX7T9AkN1yPO → static/6Dlxqhgk8Mki7q7L-gDbl}/_clientMiddlewareManifest.json +0 -0
  84. /package/web/.next/standalone/web/.next/static/{tZkod5afiOX7T9AkN1yPO → static/6Dlxqhgk8Mki7q7L-gDbl}/_ssgManifest.js +0 -0
  85. /package/web/.next/static/{tZkod5afiOX7T9AkN1yPO → 6Dlxqhgk8Mki7q7L-gDbl}/_buildManifest.js +0 -0
  86. /package/web/.next/static/{tZkod5afiOX7T9AkN1yPO → 6Dlxqhgk8Mki7q7L-gDbl}/_clientMiddlewareManifest.json +0 -0
  87. /package/web/.next/static/{tZkod5afiOX7T9AkN1yPO → 6Dlxqhgk8Mki7q7L-gDbl}/_ssgManifest.js +0 -0
@@ -480,6 +480,7 @@ declare class Agent {
480
480
  prompt: string;
481
481
  taskConfig: TaskConfig;
482
482
  abortSignal?: AbortSignal;
483
+ writeSSE?: (data: string) => Promise<void>;
483
484
  onText?: (text: string) => void;
484
485
  onToolCall?: (toolCall: {
485
486
  toolCallId: string;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as ResolvedConfig } from './index-DHyVVhJY.js';
2
- export { A as Agent, a as AgentOptions, b as AgentRunOptions, c as AgentStreamResult, S as SparkcoderConfig, T as ToolApprovalConfig } from './index-DHyVVhJY.js';
1
+ import { R as ResolvedConfig } from './index-Dm6wGcYv.js';
2
+ export { A as Agent, a as AgentOptions, b as AgentRunOptions, c as AgentStreamResult, S as SparkcoderConfig, T as ToolApprovalConfig } from './index-Dm6wGcYv.js';
3
3
  export { ServerOptions, createApp, startServer, stopServer } from './server/index.js';
4
4
  export { checkpointQueries, closeDatabase, fileBackupQueries, getDb, initDatabase, messageQueries, sessionQueries, skillQueries, todoQueries, toolExecutionQueries } from './db/index.js';
5
5
  import { F as FileBackup, C as Checkpoint } from './schema-XcP0dedO.js';
package/dist/index.js CHANGED
@@ -6473,6 +6473,21 @@ ${this.summary}`
6473
6473
 
6474
6474
  // src/agent/index.ts
6475
6475
  init_webhook();
6476
+ var MAX_SSE_FIELD_LENGTH = 8 * 1024;
6477
+ var SSE_PREVIEW_LENGTH = 2 * 1024;
6478
+ function truncateWriteFileInput(input) {
6479
+ const out = { ...input };
6480
+ for (const key of ["content", "old_string", "new_string"]) {
6481
+ const val = out[key];
6482
+ if (typeof val === "string" && val.length > MAX_SSE_FIELD_LENGTH) {
6483
+ out[key] = `${val.slice(0, SSE_PREVIEW_LENGTH)}
6484
+ ... (truncated)`;
6485
+ out[`${key}Truncated`] = true;
6486
+ out[`${key}Length`] = val.length;
6487
+ }
6488
+ }
6489
+ return out;
6490
+ }
6476
6491
  var approvalResolvers = /* @__PURE__ */ new Map();
6477
6492
  var Agent = class _Agent {
6478
6493
  session;
@@ -6716,8 +6731,11 @@ ${prompt}` });
6716
6731
  };
6717
6732
  let taskRecorder = null;
6718
6733
  const sessionId = this.session.id;
6734
+ const emit = options.writeSSE;
6719
6735
  const bashProgressHandler = (progress) => {
6720
6736
  options.onToolProgress?.({ toolName: "bash", data: progress });
6737
+ if (emit) emit(JSON.stringify({ type: "tool-progress", toolName: "bash", data: progress })).catch(() => {
6738
+ });
6721
6739
  const port = progress.browserStreamPort;
6722
6740
  if (port && progress.status === "started") {
6723
6741
  Promise.resolve().then(() => (init_stream_proxy(), stream_proxy_exports)).then(({ getOrCreateProxy: getOrCreateProxy2 }) => {
@@ -6726,7 +6744,17 @@ ${prompt}` });
6726
6744
  Promise.resolve().then(() => (init_recorder(), recorder_exports)).then(({ FrameRecorder: FrameRecorder2 }) => {
6727
6745
  taskRecorder = new FrameRecorder2(sessionId);
6728
6746
  taskRecorder.start();
6729
- proxy.on("frame", (frame) => taskRecorder?.addFrame(frame));
6747
+ });
6748
+ }
6749
+ if (proxy.listenerCount("frame") === 0) {
6750
+ proxy.on("frame", (frame) => {
6751
+ taskRecorder?.addFrame(frame);
6752
+ if (emit) emit(JSON.stringify({ type: "browser-frame", data: frame.data, metadata: frame.metadata })).catch(() => {
6753
+ });
6754
+ });
6755
+ proxy.on("status", (s) => {
6756
+ if (emit) emit(JSON.stringify({ type: "browser-status", ...s })).catch(() => {
6757
+ });
6730
6758
  });
6731
6759
  }
6732
6760
  });
@@ -6737,8 +6765,16 @@ ${prompt}` });
6737
6765
  workingDirectory: this.session.workingDirectory,
6738
6766
  skillsDirectories: config.resolvedSkillsDirectories,
6739
6767
  onBashProgress: bashProgressHandler,
6740
- onWriteFileProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "write_file", data: progress }) : void 0,
6741
- onSearchProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "explore_agent", data: progress }) : void 0,
6768
+ onWriteFileProgress: (progress) => {
6769
+ options.onToolProgress?.({ toolName: "write_file", data: progress });
6770
+ if (emit) emit(JSON.stringify({ type: "tool-progress", toolName: "write_file", data: progress })).catch(() => {
6771
+ });
6772
+ },
6773
+ onSearchProgress: (progress) => {
6774
+ options.onToolProgress?.({ toolName: "explore_agent", data: progress });
6775
+ if (emit) emit(JSON.stringify({ type: "tool-progress", toolName: "explore_agent", data: progress })).catch(() => {
6776
+ });
6777
+ },
6742
6778
  taskTools: {
6743
6779
  outputSchema: options.taskConfig.outputSchema,
6744
6780
  onComplete
@@ -6756,6 +6792,9 @@ ${prompt}` });
6756
6792
 
6757
6793
  ${taskAddendum}`;
6758
6794
  fireWebhook("task.started", { prompt: options.prompt });
6795
+ if (emit) {
6796
+ await emit(JSON.stringify({ type: "data-user-message", data: { id: `user_${Date.now()}`, content: options.prompt } }));
6797
+ }
6759
6798
  await this.context.addUserMessage(options.prompt);
6760
6799
  let iteration = 0;
6761
6800
  while (iteration < maxIterations) {
@@ -6767,7 +6806,15 @@ ${taskAddendum}`;
6767
6806
  }
6768
6807
  const messages = await this.context.getMessages();
6769
6808
  const useAnthropic = isAnthropicModel(this.session.model);
6770
- const result = await generateText3({
6809
+ if (emit) {
6810
+ await emit(JSON.stringify({ type: "start", messageId: `msg_${Date.now()}` }));
6811
+ }
6812
+ let textStarted = false;
6813
+ let textId = `text_${Date.now()}`;
6814
+ let reasoningId = `reasoning_${Date.now()}`;
6815
+ let reasoningStarted = false;
6816
+ const toolCallStarts = /* @__PURE__ */ new Set();
6817
+ const iterStream = streamText2({
6771
6818
  model: resolveModel(this.session.model),
6772
6819
  system: systemPrompt,
6773
6820
  messages,
@@ -6776,21 +6823,94 @@ ${taskAddendum}`;
6776
6823
  abortSignal: options.abortSignal,
6777
6824
  providerOptions: useAnthropic ? {
6778
6825
  anthropic: {
6826
+ toolStreaming: true,
6779
6827
  thinking: { type: "enabled", budgetTokens: 1e4 }
6780
6828
  }
6781
6829
  } : void 0,
6782
- onStepFinish: (step) => {
6830
+ onStepFinish: async (step) => {
6783
6831
  options.onStepFinish?.(step);
6784
6832
  fireWebhook("task.step_finished", { iteration, text: step.text });
6833
+ if (emit) {
6834
+ if (textStarted) {
6835
+ await emit(JSON.stringify({ type: "text-end", id: textId }));
6836
+ textStarted = false;
6837
+ textId = `text_${Date.now()}`;
6838
+ }
6839
+ await emit(JSON.stringify({ type: "finish-step" }));
6840
+ }
6785
6841
  }
6786
6842
  });
6787
- const responseMessages = result.response.messages;
6843
+ for await (const part of iterStream.fullStream) {
6844
+ if (part.type === "text-delta") {
6845
+ if (emit) {
6846
+ if (!textStarted) {
6847
+ await emit(JSON.stringify({ type: "text-start", id: textId }));
6848
+ textStarted = true;
6849
+ }
6850
+ await emit(JSON.stringify({ type: "text-delta", id: textId, delta: part.text }));
6851
+ }
6852
+ } else if (part.type === "reasoning-start") {
6853
+ if (emit) {
6854
+ await emit(JSON.stringify({ type: "reasoning-start", id: reasoningId }));
6855
+ reasoningStarted = true;
6856
+ }
6857
+ } else if (part.type === "reasoning-delta") {
6858
+ if (emit) {
6859
+ await emit(JSON.stringify({ type: "reasoning-delta", id: reasoningId, delta: part.text }));
6860
+ }
6861
+ } else if (part.type === "reasoning-end") {
6862
+ if (emit && reasoningStarted) {
6863
+ await emit(JSON.stringify({ type: "reasoning-end", id: reasoningId }));
6864
+ reasoningStarted = false;
6865
+ reasoningId = `reasoning_${Date.now()}`;
6866
+ }
6867
+ } else if (part.type === "tool-call-streaming-start") {
6868
+ if (emit) {
6869
+ const p = part;
6870
+ await emit(JSON.stringify({ type: "tool-input-start", toolCallId: p.toolCallId, toolName: p.toolName }));
6871
+ toolCallStarts.add(p.toolCallId);
6872
+ }
6873
+ } else if (part.type === "tool-call-delta") {
6874
+ if (emit) {
6875
+ const p = part;
6876
+ await emit(JSON.stringify({ type: "tool-input-delta", toolCallId: p.toolCallId, argsTextDelta: p.argsTextDelta }));
6877
+ }
6878
+ } else if (part.type === "tool-call") {
6879
+ if (emit) {
6880
+ if (!toolCallStarts.has(part.toolCallId)) {
6881
+ await emit(JSON.stringify({ type: "tool-input-start", toolCallId: part.toolCallId, toolName: part.toolName }));
6882
+ toolCallStarts.add(part.toolCallId);
6883
+ }
6884
+ const safeInput = part.toolName === "write_file" && part.input && typeof part.input === "object" ? truncateWriteFileInput(part.input) : part.input;
6885
+ await emit(JSON.stringify({ type: "tool-input-available", toolCallId: part.toolCallId, toolName: part.toolName, input: safeInput }));
6886
+ }
6887
+ } else if (part.type === "tool-result") {
6888
+ if (emit) {
6889
+ await emit(JSON.stringify({ type: "tool-output-available", toolCallId: part.toolCallId, output: part.output }));
6890
+ }
6891
+ } else if (part.type === "error") {
6892
+ console.error("Task stream error:", part.error);
6893
+ if (emit) {
6894
+ await emit(JSON.stringify({ type: "error", errorText: String(part.error) }));
6895
+ }
6896
+ }
6897
+ }
6898
+ if (emit && textStarted) {
6899
+ await emit(JSON.stringify({ type: "text-end", id: textId }));
6900
+ }
6901
+ if (emit && reasoningStarted) {
6902
+ await emit(JSON.stringify({ type: "reasoning-end", id: reasoningId }));
6903
+ }
6904
+ const iterResponse = await iterStream.response;
6905
+ const responseMessages = iterResponse.messages;
6788
6906
  await this.context.addResponseMessages(responseMessages);
6789
- if (result.text) {
6790
- options.onText?.(result.text);
6791
- fireWebhook("task.message", { iteration, text: result.text });
6907
+ const resultText = await iterStream.text;
6908
+ const resultSteps = await iterStream.steps;
6909
+ if (resultText) {
6910
+ options.onText?.(resultText);
6911
+ fireWebhook("task.message", { iteration, text: resultText });
6792
6912
  }
6793
- for (const step of result.steps) {
6913
+ for (const step of resultSteps) {
6794
6914
  if (step.toolCalls) {
6795
6915
  for (const tc of step.toolCalls) {
6796
6916
  options.onToolCall?.({ toolCallId: tc.toolCallId, toolName: tc.toolName, input: tc.args });
@@ -6843,9 +6963,11 @@ ${taskAddendum}`;
6843
6963
  iterations: iteration
6844
6964
  };
6845
6965
  }
6846
- await this.context.addUserMessage(
6847
- "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."
6848
- );
6966
+ 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.";
6967
+ if (emit) {
6968
+ await emit(JSON.stringify({ type: "data-user-message", data: { id: `user_${Date.now()}`, content: continuationPrompt } }));
6969
+ }
6970
+ await this.context.addUserMessage(continuationPrompt);
6849
6971
  }
6850
6972
  const timeoutError = `Task did not complete within ${maxIterations} iterations`;
6851
6973
  const timeoutRecordingUrls = await this.finishTaskRecording(taskRecorder);
@@ -9497,6 +9619,7 @@ init_db();
9497
9619
  import { Hono as Hono5 } from "hono";
9498
9620
  import { zValidator as zValidator5 } from "@hono/zod-validator";
9499
9621
  import { z as z19 } from "zod";
9622
+ import { nanoid as nanoid7 } from "nanoid";
9500
9623
  init_config();
9501
9624
  var tasks = new Hono5();
9502
9625
  var taskAbortControllers = /* @__PURE__ */ new Map();
@@ -9534,45 +9657,74 @@ tasks.post(
9534
9657
  const taskId = agent.sessionId;
9535
9658
  const abortController = new AbortController();
9536
9659
  taskAbortControllers.set(taskId, abortController);
9537
- (async () => {
9538
- try {
9539
- await agent.runTask({
9540
- prompt: body.prompt,
9541
- taskConfig,
9542
- abortSignal: abortController.signal
9543
- });
9544
- } catch (err) {
9545
- if (err.name === "AbortError" || abortController.signal.aborted) {
9546
- console.log(`[TASK] Task ${taskId} was cancelled`);
9547
- } else {
9548
- console.error(`[TASK] Error in task ${taskId}:`, err.message);
9549
- const errorMsg = err.message || "Unknown error";
9550
- const failedTask = {
9551
- ...taskConfig,
9552
- status: "failed",
9553
- error: errorMsg
9554
- };
9555
- await sessionQueries.update(taskId, {
9556
- config: {
9557
- toolApprovals: { bash: false, write_file: false, read_file: false },
9558
- task: failedTask
9559
- }
9660
+ const streamId = `stream_${taskId}_${nanoid7(10)}`;
9661
+ await activeStreamQueries.create(taskId, streamId);
9662
+ const taskStreamProducer = () => {
9663
+ const { readable, writable } = new TransformStream();
9664
+ const writer = writable.getWriter();
9665
+ let writerClosed = false;
9666
+ const writeSSE = async (data) => {
9667
+ if (writerClosed) return;
9668
+ try {
9669
+ await writer.write(`data: ${data}
9670
+
9671
+ `);
9672
+ } catch {
9673
+ writerClosed = true;
9674
+ }
9675
+ };
9676
+ (async () => {
9677
+ await writeSSE(JSON.stringify({ type: "data-stream-id", streamId }));
9678
+ try {
9679
+ await agent.runTask({
9680
+ prompt: body.prompt,
9681
+ taskConfig,
9682
+ abortSignal: abortController.signal,
9683
+ writeSSE
9560
9684
  });
9561
- if (taskConfig.webhookUrl) {
9562
- const { sendWebhook: sendWebhook2 } = await Promise.resolve().then(() => (init_webhook(), webhook_exports));
9563
- sendWebhook2(taskConfig.webhookUrl, {
9564
- type: "task.failed",
9565
- taskId,
9566
- sessionId: taskId,
9567
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
9568
- data: { status: "failed", error: errorMsg }
9685
+ await writeSSE(JSON.stringify({ type: "finish" }));
9686
+ } catch (err) {
9687
+ if (err.name === "AbortError" || abortController.signal.aborted) {
9688
+ console.log(`[TASK] Task ${taskId} was cancelled`);
9689
+ await writeSSE(JSON.stringify({ type: "abort" }));
9690
+ } else {
9691
+ console.error(`[TASK] Error in task ${taskId}:`, err.message);
9692
+ const errorMsg = err.message || "Unknown error";
9693
+ await writeSSE(JSON.stringify({ type: "error", errorText: errorMsg }));
9694
+ const failedTask = {
9695
+ ...taskConfig,
9696
+ status: "failed",
9697
+ error: errorMsg
9698
+ };
9699
+ await sessionQueries.update(taskId, {
9700
+ config: {
9701
+ toolApprovals: { bash: false, write_file: false, read_file: false },
9702
+ task: failedTask
9703
+ }
9569
9704
  });
9705
+ if (taskConfig.webhookUrl) {
9706
+ const { sendWebhook: sendWebhook2 } = await Promise.resolve().then(() => (init_webhook(), webhook_exports));
9707
+ sendWebhook2(taskConfig.webhookUrl, {
9708
+ type: "task.failed",
9709
+ taskId,
9710
+ sessionId: taskId,
9711
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
9712
+ data: { status: "failed", error: errorMsg }
9713
+ });
9714
+ }
9570
9715
  }
9716
+ } finally {
9717
+ await writeSSE("[DONE]");
9718
+ writer.close().catch(() => {
9719
+ });
9720
+ await activeStreamQueries.finish(streamId).catch(() => {
9721
+ });
9722
+ taskAbortControllers.delete(taskId);
9571
9723
  }
9572
- } finally {
9573
- taskAbortControllers.delete(taskId);
9574
- }
9575
- })();
9724
+ })();
9725
+ return readable;
9726
+ };
9727
+ await streamContext.resumableStream(streamId, taskStreamProducer);
9576
9728
  return c.json({ taskId, status: "running" }, 201);
9577
9729
  }
9578
9730
  );