sparkecoder 0.1.66 → 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 (91) hide show
  1. package/dist/agent/index.d.ts +3 -3
  2. package/dist/agent/index.js +141 -13
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +206 -48
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +2 -2
  7. package/dist/{index-Db23cukG.d.ts → index-Dm6wGcYv.d.ts} +26 -25
  8. package/dist/index.d.ts +5 -5
  9. package/dist/index.js +206 -48
  10. package/dist/index.js.map +1 -1
  11. package/dist/{schema-C7Mm4Ykn.d.ts → schema-XcP0dedO.d.ts} +3 -3
  12. package/dist/{search-CVVfuBPZ.d.ts → search-CCffrVJE.d.ts} +4 -4
  13. package/dist/server/index.js +206 -48
  14. package/dist/server/index.js.map +1 -1
  15. package/dist/tools/index.d.ts +3 -3
  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/_global-error.html +2 -2
  22. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  23. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  24. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  37. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  46. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  48. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  55. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  64. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  72. package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  78. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  80. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  81. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  82. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  83. /package/web/.next/standalone/web/.next/static/{UMGGmtMDTCI6fL-AIFkiM → 6Dlxqhgk8Mki7q7L-gDbl}/_buildManifest.js +0 -0
  84. /package/web/.next/standalone/web/.next/static/{UMGGmtMDTCI6fL-AIFkiM → 6Dlxqhgk8Mki7q7L-gDbl}/_clientMiddlewareManifest.json +0 -0
  85. /package/web/.next/standalone/web/.next/static/{UMGGmtMDTCI6fL-AIFkiM → 6Dlxqhgk8Mki7q7L-gDbl}/_ssgManifest.js +0 -0
  86. /package/web/.next/standalone/web/.next/static/static/{UMGGmtMDTCI6fL-AIFkiM → 6Dlxqhgk8Mki7q7L-gDbl}/_buildManifest.js +0 -0
  87. /package/web/.next/standalone/web/.next/static/static/{UMGGmtMDTCI6fL-AIFkiM → 6Dlxqhgk8Mki7q7L-gDbl}/_clientMiddlewareManifest.json +0 -0
  88. /package/web/.next/standalone/web/.next/static/static/{UMGGmtMDTCI6fL-AIFkiM → 6Dlxqhgk8Mki7q7L-gDbl}/_ssgManifest.js +0 -0
  89. /package/web/.next/static/{UMGGmtMDTCI6fL-AIFkiM → 6Dlxqhgk8Mki7q7L-gDbl}/_buildManifest.js +0 -0
  90. /package/web/.next/static/{UMGGmtMDTCI6fL-AIFkiM → 6Dlxqhgk8Mki7q7L-gDbl}/_clientMiddlewareManifest.json +0 -0
  91. /package/web/.next/static/{UMGGmtMDTCI6fL-AIFkiM → 6Dlxqhgk8Mki7q7L-gDbl}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -6969,12 +6969,18 @@ Before calling \`complete_task\`, you MUST verify your work completely. Do not j
6969
6969
  - If the task asked for multiple things, verify EACH one individually.
6970
6970
  - If something doesn't look right, fix it \u2014 don't complete with known issues.
6971
6971
 
6972
+ **Screenshot your completed work:**
6973
+ - After completing a task, take a screenshot of the result when it makes sense (UI changes browser pages, etc.). You can use the browser skill to do this.
6974
+ - Use \`upload_file\` to upload the screenshot and include the download URL in your task result so the user can see proof of what was done.
6975
+ - This is especially valuable for UI/visual changes, successful test runs, and browser verification \u2014 show, don't just tell.
6976
+
6972
6977
  ### Use All Available Tools
6973
6978
  - **load_skill**: Load specialized skills/knowledge relevant to the task. Check what skills are available and use them.
6974
6979
  - **explore_agent**: Use for codebase exploration and understanding before making changes.
6975
6980
  - **code_graph**: Use to understand type hierarchies, references, and impact before refactoring.
6976
6981
  - **todo**: Track your progress on multi-step tasks so you don't miss steps.
6977
6982
  - **bash**: Full shell access \u2014 run builds, tests, dev servers, open browsers, curl endpoints, anything.
6983
+ - **upload_file**: Upload files (screenshots, reports, exports) to cloud storage. Use this to include screenshots of completed work in your task result \u2014 visual proof is very helpful.
6978
6984
 
6979
6985
  ### Output Schema
6980
6986
  The \`complete_task\` tool expects a \`result\` object matching this JSON Schema:
@@ -7250,6 +7256,21 @@ ${this.summary}`
7250
7256
 
7251
7257
  // src/agent/index.ts
7252
7258
  init_webhook();
7259
+ var MAX_SSE_FIELD_LENGTH = 8 * 1024;
7260
+ var SSE_PREVIEW_LENGTH = 2 * 1024;
7261
+ function truncateWriteFileInput(input) {
7262
+ const out = { ...input };
7263
+ for (const key of ["content", "old_string", "new_string"]) {
7264
+ const val = out[key];
7265
+ if (typeof val === "string" && val.length > MAX_SSE_FIELD_LENGTH) {
7266
+ out[key] = `${val.slice(0, SSE_PREVIEW_LENGTH)}
7267
+ ... (truncated)`;
7268
+ out[`${key}Truncated`] = true;
7269
+ out[`${key}Length`] = val.length;
7270
+ }
7271
+ }
7272
+ return out;
7273
+ }
7253
7274
  var approvalResolvers = /* @__PURE__ */ new Map();
7254
7275
  var Agent = class _Agent {
7255
7276
  session;
@@ -7493,8 +7514,11 @@ ${prompt}` });
7493
7514
  };
7494
7515
  let taskRecorder = null;
7495
7516
  const sessionId = this.session.id;
7517
+ const emit = options.writeSSE;
7496
7518
  const bashProgressHandler = (progress) => {
7497
7519
  options.onToolProgress?.({ toolName: "bash", data: progress });
7520
+ if (emit) emit(JSON.stringify({ type: "tool-progress", toolName: "bash", data: progress })).catch(() => {
7521
+ });
7498
7522
  const port = progress.browserStreamPort;
7499
7523
  if (port && progress.status === "started") {
7500
7524
  Promise.resolve().then(() => (init_stream_proxy(), stream_proxy_exports)).then(({ getOrCreateProxy: getOrCreateProxy2 }) => {
@@ -7503,7 +7527,17 @@ ${prompt}` });
7503
7527
  Promise.resolve().then(() => (init_recorder(), recorder_exports)).then(({ FrameRecorder: FrameRecorder2 }) => {
7504
7528
  taskRecorder = new FrameRecorder2(sessionId);
7505
7529
  taskRecorder.start();
7506
- proxy.on("frame", (frame) => taskRecorder?.addFrame(frame));
7530
+ });
7531
+ }
7532
+ if (proxy.listenerCount("frame") === 0) {
7533
+ proxy.on("frame", (frame) => {
7534
+ taskRecorder?.addFrame(frame);
7535
+ if (emit) emit(JSON.stringify({ type: "browser-frame", data: frame.data, metadata: frame.metadata })).catch(() => {
7536
+ });
7537
+ });
7538
+ proxy.on("status", (s) => {
7539
+ if (emit) emit(JSON.stringify({ type: "browser-status", ...s })).catch(() => {
7540
+ });
7507
7541
  });
7508
7542
  }
7509
7543
  });
@@ -7514,8 +7548,16 @@ ${prompt}` });
7514
7548
  workingDirectory: this.session.workingDirectory,
7515
7549
  skillsDirectories: config.resolvedSkillsDirectories,
7516
7550
  onBashProgress: bashProgressHandler,
7517
- onWriteFileProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "write_file", data: progress }) : void 0,
7518
- onSearchProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "explore_agent", data: progress }) : void 0,
7551
+ onWriteFileProgress: (progress) => {
7552
+ options.onToolProgress?.({ toolName: "write_file", data: progress });
7553
+ if (emit) emit(JSON.stringify({ type: "tool-progress", toolName: "write_file", data: progress })).catch(() => {
7554
+ });
7555
+ },
7556
+ onSearchProgress: (progress) => {
7557
+ options.onToolProgress?.({ toolName: "explore_agent", data: progress });
7558
+ if (emit) emit(JSON.stringify({ type: "tool-progress", toolName: "explore_agent", data: progress })).catch(() => {
7559
+ });
7560
+ },
7519
7561
  taskTools: {
7520
7562
  outputSchema: options.taskConfig.outputSchema,
7521
7563
  onComplete
@@ -7533,6 +7575,9 @@ ${prompt}` });
7533
7575
 
7534
7576
  ${taskAddendum}`;
7535
7577
  fireWebhook("task.started", { prompt: options.prompt });
7578
+ if (emit) {
7579
+ await emit(JSON.stringify({ type: "data-user-message", data: { id: `user_${Date.now()}`, content: options.prompt } }));
7580
+ }
7536
7581
  await this.context.addUserMessage(options.prompt);
7537
7582
  let iteration = 0;
7538
7583
  while (iteration < maxIterations) {
@@ -7544,7 +7589,15 @@ ${taskAddendum}`;
7544
7589
  }
7545
7590
  const messages = await this.context.getMessages();
7546
7591
  const useAnthropic = isAnthropicModel(this.session.model);
7547
- const result = await generateText3({
7592
+ if (emit) {
7593
+ await emit(JSON.stringify({ type: "start", messageId: `msg_${Date.now()}` }));
7594
+ }
7595
+ let textStarted = false;
7596
+ let textId = `text_${Date.now()}`;
7597
+ let reasoningId = `reasoning_${Date.now()}`;
7598
+ let reasoningStarted = false;
7599
+ const toolCallStarts = /* @__PURE__ */ new Set();
7600
+ const iterStream = streamText2({
7548
7601
  model: resolveModel(this.session.model),
7549
7602
  system: systemPrompt,
7550
7603
  messages,
@@ -7553,21 +7606,94 @@ ${taskAddendum}`;
7553
7606
  abortSignal: options.abortSignal,
7554
7607
  providerOptions: useAnthropic ? {
7555
7608
  anthropic: {
7609
+ toolStreaming: true,
7556
7610
  thinking: { type: "enabled", budgetTokens: 1e4 }
7557
7611
  }
7558
7612
  } : void 0,
7559
- onStepFinish: (step) => {
7613
+ onStepFinish: async (step) => {
7560
7614
  options.onStepFinish?.(step);
7561
7615
  fireWebhook("task.step_finished", { iteration, text: step.text });
7616
+ if (emit) {
7617
+ if (textStarted) {
7618
+ await emit(JSON.stringify({ type: "text-end", id: textId }));
7619
+ textStarted = false;
7620
+ textId = `text_${Date.now()}`;
7621
+ }
7622
+ await emit(JSON.stringify({ type: "finish-step" }));
7623
+ }
7562
7624
  }
7563
7625
  });
7564
- const responseMessages = result.response.messages;
7626
+ for await (const part of iterStream.fullStream) {
7627
+ if (part.type === "text-delta") {
7628
+ if (emit) {
7629
+ if (!textStarted) {
7630
+ await emit(JSON.stringify({ type: "text-start", id: textId }));
7631
+ textStarted = true;
7632
+ }
7633
+ await emit(JSON.stringify({ type: "text-delta", id: textId, delta: part.text }));
7634
+ }
7635
+ } else if (part.type === "reasoning-start") {
7636
+ if (emit) {
7637
+ await emit(JSON.stringify({ type: "reasoning-start", id: reasoningId }));
7638
+ reasoningStarted = true;
7639
+ }
7640
+ } else if (part.type === "reasoning-delta") {
7641
+ if (emit) {
7642
+ await emit(JSON.stringify({ type: "reasoning-delta", id: reasoningId, delta: part.text }));
7643
+ }
7644
+ } else if (part.type === "reasoning-end") {
7645
+ if (emit && reasoningStarted) {
7646
+ await emit(JSON.stringify({ type: "reasoning-end", id: reasoningId }));
7647
+ reasoningStarted = false;
7648
+ reasoningId = `reasoning_${Date.now()}`;
7649
+ }
7650
+ } else if (part.type === "tool-call-streaming-start") {
7651
+ if (emit) {
7652
+ const p = part;
7653
+ await emit(JSON.stringify({ type: "tool-input-start", toolCallId: p.toolCallId, toolName: p.toolName }));
7654
+ toolCallStarts.add(p.toolCallId);
7655
+ }
7656
+ } else if (part.type === "tool-call-delta") {
7657
+ if (emit) {
7658
+ const p = part;
7659
+ await emit(JSON.stringify({ type: "tool-input-delta", toolCallId: p.toolCallId, argsTextDelta: p.argsTextDelta }));
7660
+ }
7661
+ } else if (part.type === "tool-call") {
7662
+ if (emit) {
7663
+ if (!toolCallStarts.has(part.toolCallId)) {
7664
+ await emit(JSON.stringify({ type: "tool-input-start", toolCallId: part.toolCallId, toolName: part.toolName }));
7665
+ toolCallStarts.add(part.toolCallId);
7666
+ }
7667
+ const safeInput = part.toolName === "write_file" && part.input && typeof part.input === "object" ? truncateWriteFileInput(part.input) : part.input;
7668
+ await emit(JSON.stringify({ type: "tool-input-available", toolCallId: part.toolCallId, toolName: part.toolName, input: safeInput }));
7669
+ }
7670
+ } else if (part.type === "tool-result") {
7671
+ if (emit) {
7672
+ await emit(JSON.stringify({ type: "tool-output-available", toolCallId: part.toolCallId, output: part.output }));
7673
+ }
7674
+ } else if (part.type === "error") {
7675
+ console.error("Task stream error:", part.error);
7676
+ if (emit) {
7677
+ await emit(JSON.stringify({ type: "error", errorText: String(part.error) }));
7678
+ }
7679
+ }
7680
+ }
7681
+ if (emit && textStarted) {
7682
+ await emit(JSON.stringify({ type: "text-end", id: textId }));
7683
+ }
7684
+ if (emit && reasoningStarted) {
7685
+ await emit(JSON.stringify({ type: "reasoning-end", id: reasoningId }));
7686
+ }
7687
+ const iterResponse = await iterStream.response;
7688
+ const responseMessages = iterResponse.messages;
7565
7689
  await this.context.addResponseMessages(responseMessages);
7566
- if (result.text) {
7567
- options.onText?.(result.text);
7568
- fireWebhook("task.message", { iteration, text: result.text });
7690
+ const resultText = await iterStream.text;
7691
+ const resultSteps = await iterStream.steps;
7692
+ if (resultText) {
7693
+ options.onText?.(resultText);
7694
+ fireWebhook("task.message", { iteration, text: resultText });
7569
7695
  }
7570
- for (const step of result.steps) {
7696
+ for (const step of resultSteps) {
7571
7697
  if (step.toolCalls) {
7572
7698
  for (const tc of step.toolCalls) {
7573
7699
  options.onToolCall?.({ toolCallId: tc.toolCallId, toolName: tc.toolName, input: tc.args });
@@ -7620,9 +7746,11 @@ ${taskAddendum}`;
7620
7746
  iterations: iteration
7621
7747
  };
7622
7748
  }
7623
- await this.context.addUserMessage(
7624
- "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."
7625
- );
7749
+ 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.";
7750
+ if (emit) {
7751
+ await emit(JSON.stringify({ type: "data-user-message", data: { id: `user_${Date.now()}`, content: continuationPrompt } }));
7752
+ }
7753
+ await this.context.addUserMessage(continuationPrompt);
7626
7754
  }
7627
7755
  const timeoutError = `Task did not complete within ${maxIterations} iterations`;
7628
7756
  const timeoutRecordingUrls = await this.finishTaskRecording(taskRecorder);
@@ -10254,6 +10382,7 @@ init_db();
10254
10382
  import { Hono as Hono5 } from "hono";
10255
10383
  import { zValidator as zValidator5 } from "@hono/zod-validator";
10256
10384
  import { z as z19 } from "zod";
10385
+ import { nanoid as nanoid7 } from "nanoid";
10257
10386
  init_config();
10258
10387
  var tasks = new Hono5();
10259
10388
  var taskAbortControllers = /* @__PURE__ */ new Map();
@@ -10291,45 +10420,74 @@ tasks.post(
10291
10420
  const taskId = agent.sessionId;
10292
10421
  const abortController = new AbortController();
10293
10422
  taskAbortControllers.set(taskId, abortController);
10294
- (async () => {
10295
- try {
10296
- await agent.runTask({
10297
- prompt: body.prompt,
10298
- taskConfig,
10299
- abortSignal: abortController.signal
10300
- });
10301
- } catch (err) {
10302
- if (err.name === "AbortError" || abortController.signal.aborted) {
10303
- console.log(`[TASK] Task ${taskId} was cancelled`);
10304
- } else {
10305
- console.error(`[TASK] Error in task ${taskId}:`, err.message);
10306
- const errorMsg = err.message || "Unknown error";
10307
- const failedTask = {
10308
- ...taskConfig,
10309
- status: "failed",
10310
- error: errorMsg
10311
- };
10312
- await sessionQueries.update(taskId, {
10313
- config: {
10314
- toolApprovals: { bash: false, write_file: false, read_file: false },
10315
- task: failedTask
10316
- }
10423
+ const streamId = `stream_${taskId}_${nanoid7(10)}`;
10424
+ await activeStreamQueries.create(taskId, streamId);
10425
+ const taskStreamProducer = () => {
10426
+ const { readable, writable } = new TransformStream();
10427
+ const writer = writable.getWriter();
10428
+ let writerClosed = false;
10429
+ const writeSSE = async (data) => {
10430
+ if (writerClosed) return;
10431
+ try {
10432
+ await writer.write(`data: ${data}
10433
+
10434
+ `);
10435
+ } catch {
10436
+ writerClosed = true;
10437
+ }
10438
+ };
10439
+ (async () => {
10440
+ await writeSSE(JSON.stringify({ type: "data-stream-id", streamId }));
10441
+ try {
10442
+ await agent.runTask({
10443
+ prompt: body.prompt,
10444
+ taskConfig,
10445
+ abortSignal: abortController.signal,
10446
+ writeSSE
10317
10447
  });
10318
- if (taskConfig.webhookUrl) {
10319
- const { sendWebhook: sendWebhook2 } = await Promise.resolve().then(() => (init_webhook(), webhook_exports));
10320
- sendWebhook2(taskConfig.webhookUrl, {
10321
- type: "task.failed",
10322
- taskId,
10323
- sessionId: taskId,
10324
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10325
- data: { status: "failed", error: errorMsg }
10448
+ await writeSSE(JSON.stringify({ type: "finish" }));
10449
+ } catch (err) {
10450
+ if (err.name === "AbortError" || abortController.signal.aborted) {
10451
+ console.log(`[TASK] Task ${taskId} was cancelled`);
10452
+ await writeSSE(JSON.stringify({ type: "abort" }));
10453
+ } else {
10454
+ console.error(`[TASK] Error in task ${taskId}:`, err.message);
10455
+ const errorMsg = err.message || "Unknown error";
10456
+ await writeSSE(JSON.stringify({ type: "error", errorText: errorMsg }));
10457
+ const failedTask = {
10458
+ ...taskConfig,
10459
+ status: "failed",
10460
+ error: errorMsg
10461
+ };
10462
+ await sessionQueries.update(taskId, {
10463
+ config: {
10464
+ toolApprovals: { bash: false, write_file: false, read_file: false },
10465
+ task: failedTask
10466
+ }
10326
10467
  });
10468
+ if (taskConfig.webhookUrl) {
10469
+ const { sendWebhook: sendWebhook2 } = await Promise.resolve().then(() => (init_webhook(), webhook_exports));
10470
+ sendWebhook2(taskConfig.webhookUrl, {
10471
+ type: "task.failed",
10472
+ taskId,
10473
+ sessionId: taskId,
10474
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10475
+ data: { status: "failed", error: errorMsg }
10476
+ });
10477
+ }
10327
10478
  }
10479
+ } finally {
10480
+ await writeSSE("[DONE]");
10481
+ writer.close().catch(() => {
10482
+ });
10483
+ await activeStreamQueries.finish(streamId).catch(() => {
10484
+ });
10485
+ taskAbortControllers.delete(taskId);
10328
10486
  }
10329
- } finally {
10330
- taskAbortControllers.delete(taskId);
10331
- }
10332
- })();
10487
+ })();
10488
+ return readable;
10489
+ };
10490
+ await streamContext.resumableStream(streamId, taskStreamProducer);
10333
10491
  return c.json({ taskId, status: "running" }, 201);
10334
10492
  }
10335
10493
  );