@deepagents/context 2.1.0 → 2.2.0

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 (42) hide show
  1. package/README.md +18 -14
  2. package/dist/browser.js +37 -2
  3. package/dist/browser.js.map +3 -3
  4. package/dist/index.js +828 -106
  5. package/dist/index.js.map +4 -4
  6. package/dist/lib/guardrail.d.ts +2 -6
  7. package/dist/lib/guardrail.d.ts.map +1 -1
  8. package/dist/lib/sandbox/abort.d.ts.map +1 -1
  9. package/dist/lib/sandbox/agent-os-sandbox.d.ts +5 -1
  10. package/dist/lib/sandbox/agent-os-sandbox.d.ts.map +1 -1
  11. package/dist/lib/sandbox/daytona-sandbox.d.ts +63 -0
  12. package/dist/lib/sandbox/daytona-sandbox.d.ts.map +1 -0
  13. package/dist/lib/sandbox/docker-sandbox-errors.d.ts +9 -4
  14. package/dist/lib/sandbox/docker-sandbox-errors.d.ts.map +1 -1
  15. package/dist/lib/sandbox/docker-sandbox.d.ts +1 -1
  16. package/dist/lib/sandbox/docker-sandbox.d.ts.map +1 -1
  17. package/dist/lib/sandbox/file-events.d.ts +10 -1
  18. package/dist/lib/sandbox/file-events.d.ts.map +1 -1
  19. package/dist/lib/sandbox/index.d.ts +1 -1
  20. package/dist/lib/sandbox/index.d.ts.map +1 -1
  21. package/dist/lib/sandbox/installers/bin.d.ts +40 -0
  22. package/dist/lib/sandbox/installers/bin.d.ts.map +1 -0
  23. package/dist/lib/sandbox/installers/index.d.ts +1 -0
  24. package/dist/lib/sandbox/installers/index.d.ts.map +1 -1
  25. package/dist/lib/save/save-pipeline.d.ts.map +1 -1
  26. package/dist/lib/skills/fragments.d.ts +2 -2
  27. package/dist/lib/store/sqlite.store.d.ts +1 -0
  28. package/dist/lib/store/sqlite.store.d.ts.map +1 -1
  29. package/dist/lib/store/store.d.ts +8 -0
  30. package/dist/lib/store/store.d.ts.map +1 -1
  31. package/dist/lib/stream/postgres.stream-store.d.ts.map +1 -1
  32. package/dist/lib/stream/sqlite.stream-store.d.ts.map +1 -1
  33. package/dist/lib/stream/stream-manager.d.ts +1 -1
  34. package/dist/lib/stream/stream-manager.d.ts.map +1 -1
  35. package/dist/lib/stream/stream-store.d.ts +8 -1
  36. package/dist/lib/stream/stream-store.d.ts.map +1 -1
  37. package/dist/lib/stream/types.d.ts +7 -0
  38. package/dist/lib/stream/types.d.ts.map +1 -0
  39. package/dist/lib/stream-buffer.d.ts.map +1 -1
  40. package/package.json +6 -2
  41. package/dist/lib/sandbox/container-tool.d.ts +0 -190
  42. package/dist/lib/sandbox/container-tool.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -2623,6 +2623,8 @@ var SavePipeline = class {
2623
2623
  async persist() {
2624
2624
  let parentId = this.#engine.getActiveBranch().headMessageId;
2625
2625
  const now = Date.now();
2626
+ const messages = [];
2627
+ const pendingMessagesById = /* @__PURE__ */ new Map();
2626
2628
  for (const fragment2 of this.#pending) {
2627
2629
  if (!fragment2.codec) {
2628
2630
  throw new Error(`Fragment "${fragment2.name}" is missing codec.`);
@@ -2630,7 +2632,7 @@ var SavePipeline = class {
2630
2632
  const msgId = fragment2.id ?? crypto.randomUUID();
2631
2633
  let msgParentId = parentId;
2632
2634
  if (!this.#shouldBranch && msgId === parentId) {
2633
- const existing = await this.#engine.store.getMessage(msgId);
2635
+ const existing = pendingMessagesById.get(msgId) ?? await this.#engine.store.getMessage(msgId);
2634
2636
  if (existing) msgParentId = existing.parentId;
2635
2637
  }
2636
2638
  const messageData = {
@@ -2642,7 +2644,8 @@ var SavePipeline = class {
2642
2644
  data: fragment2.codec.encode(),
2643
2645
  createdAt: now
2644
2646
  };
2645
- await this.#engine.store.addMessage(messageData);
2647
+ messages.push(messageData);
2648
+ pendingMessagesById.set(messageData.id, messageData);
2646
2649
  parentId = messageData.id;
2647
2650
  }
2648
2651
  if (parentId === null) {
@@ -2650,6 +2653,7 @@ var SavePipeline = class {
2650
2653
  "Pipeline persisted no messages but pending was not empty"
2651
2654
  );
2652
2655
  }
2656
+ await this.#engine.store.addMessages(messages);
2653
2657
  await this.#engine.commitHead(parentId);
2654
2658
  return { headMessageId: parentId };
2655
2659
  }
@@ -2765,6 +2769,18 @@ var ddl_sqlite_default = "-- Context Store DDL for SQLite\n-- This schema implem
2765
2769
 
2766
2770
  // packages/context/src/lib/store/store.ts
2767
2771
  var ContextStore = class {
2772
+ /**
2773
+ * Add multiple messages to the graph.
2774
+ *
2775
+ * Stores can override this for atomic/batched persistence. The default keeps
2776
+ * the single-message contract for implementations that do not need a custom
2777
+ * batch path.
2778
+ */
2779
+ async addMessages(messages) {
2780
+ for (const message2 of messages) {
2781
+ await this.addMessage(message2);
2782
+ }
2783
+ }
2768
2784
  };
2769
2785
 
2770
2786
  // packages/context/src/lib/store/sqlite.store.ts
@@ -2972,7 +2988,7 @@ var SqliteContextStore = class extends ContextStore {
2972
2988
  // ==========================================================================
2973
2989
  // Message Operations (Graph Nodes)
2974
2990
  // ==========================================================================
2975
- async addMessage(message2) {
2991
+ #insertMessage(message2) {
2976
2992
  if (message2.parentId === message2.id) {
2977
2993
  throw new Error(`Message ${message2.id} cannot be its own parent`);
2978
2994
  }
@@ -2999,6 +3015,17 @@ var SqliteContextStore = class extends ContextStore {
2999
3015
  VALUES (?, ?, ?, ?)`
3000
3016
  ).run(message2.id, message2.chatId, message2.name, content);
3001
3017
  }
3018
+ async addMessage(message2) {
3019
+ this.#insertMessage(message2);
3020
+ }
3021
+ async addMessages(messages) {
3022
+ if (messages.length === 0) return;
3023
+ this.#useTransaction(() => {
3024
+ for (const message2 of messages) {
3025
+ this.#insertMessage(message2);
3026
+ }
3027
+ });
3028
+ }
3002
3029
  async getMessage(messageId) {
3003
3030
  const row = this.#stmt("SELECT * FROM messages WHERE id = ?").get(
3004
3031
  messageId
@@ -5836,7 +5863,7 @@ function runWithAbortSignal(signal, fn) {
5836
5863
  return ambientAbortSignal.run(signal, fn);
5837
5864
  }
5838
5865
  function withAbortSignal(sandbox) {
5839
- return {
5866
+ const decorated = {
5840
5867
  ...sandbox,
5841
5868
  async executeCommand(command, options) {
5842
5869
  const signal = options?.signal ?? ambientAbortSignal.getStore();
@@ -5846,11 +5873,20 @@ function withAbortSignal(sandbox) {
5846
5873
  );
5847
5874
  }
5848
5875
  };
5876
+ if (sandbox.spawn) {
5877
+ const innerSpawn = sandbox.spawn.bind(sandbox);
5878
+ decorated.spawn = (command, options) => {
5879
+ const signal = options?.signal ?? ambientAbortSignal.getStore();
5880
+ return innerSpawn(command, signal ? { ...options, signal } : options);
5881
+ };
5882
+ }
5883
+ return decorated;
5849
5884
  }
5850
5885
 
5851
5886
  // packages/context/src/lib/sandbox/agent-os-sandbox.ts
5852
5887
  import "bash-tool";
5853
- var textDecoder = new TextDecoder();
5888
+ import { PassThrough, Readable } from "node:stream";
5889
+ var decoder = new TextDecoder();
5854
5890
  var AgentOsSandboxError = class extends Error {
5855
5891
  constructor(message2) {
5856
5892
  super(message2);
@@ -5882,6 +5918,49 @@ async function importAgentOs() {
5882
5918
  );
5883
5919
  }
5884
5920
  }
5921
+ var SIGKILL_EXIT_CODE = 9;
5922
+ function startKernelProcess(os, command, options) {
5923
+ const { pid } = os.spawn("sh", ["-c", command], options);
5924
+ const stdout = new PassThrough();
5925
+ const stderr = new PassThrough();
5926
+ const unsubOut = os.onProcessStdout(pid, (chunk) => stdout.write(chunk));
5927
+ const unsubErr = os.onProcessStderr(pid, (chunk) => stderr.write(chunk));
5928
+ let killSignalled = false;
5929
+ const exit = os.waitProcess(pid).finally(() => {
5930
+ unsubOut();
5931
+ unsubErr();
5932
+ stdout.end();
5933
+ stderr.end();
5934
+ });
5935
+ return {
5936
+ pid,
5937
+ stdout,
5938
+ stderr,
5939
+ exit,
5940
+ kill: () => {
5941
+ if (killSignalled) return;
5942
+ killSignalled = true;
5943
+ os.killProcess(pid);
5944
+ },
5945
+ wasKilled: (exitCode) => killSignalled && exitCode === SIGKILL_EXIT_CODE
5946
+ };
5947
+ }
5948
+ async function readAll(stream) {
5949
+ const chunks = [];
5950
+ for await (const chunk of stream) chunks.push(chunk);
5951
+ return Buffer.concat(chunks).toString("utf8");
5952
+ }
5953
+ function bindAbort(signal, onAbort) {
5954
+ if (!signal) return () => {
5955
+ };
5956
+ if (signal.aborted) {
5957
+ onAbort();
5958
+ return () => {
5959
+ };
5960
+ }
5961
+ signal.addEventListener("abort", onAbort, { once: true });
5962
+ return () => signal.removeEventListener("abort", onAbort);
5963
+ }
5885
5964
  async function createAgentOsSandbox(options = {}) {
5886
5965
  const { AgentOs } = await importAgentOs();
5887
5966
  let os;
@@ -5892,27 +5971,56 @@ async function createAgentOsSandbox(options = {}) {
5892
5971
  throw new AgentOsCreationError(err.message, err);
5893
5972
  }
5894
5973
  return {
5895
- async executeCommand(command) {
5974
+ async executeCommand(command, { signal } = {}) {
5975
+ if (signal?.aborted) {
5976
+ return { stdout: "", stderr: "", exitCode: SIGKILL_EXIT_CODE };
5977
+ }
5978
+ const proc = startKernelProcess(os, command, {});
5979
+ const unbind = bindAbort(signal, proc.kill);
5896
5980
  try {
5897
- const result = await os.exec(command);
5981
+ const [stdout, stderr, exitCode] = await Promise.all([
5982
+ readAll(proc.stdout),
5983
+ readAll(proc.stderr),
5984
+ proc.exit
5985
+ ]);
5986
+ return { stdout, stderr, exitCode };
5987
+ } finally {
5988
+ unbind();
5989
+ }
5990
+ },
5991
+ spawn(command, { signal, env, cwd } = {}) {
5992
+ if (signal?.aborted) {
5993
+ const empty = () => new ReadableStream({ start: (c) => c.close() });
5898
5994
  return {
5899
- stdout: result.stdout,
5900
- stderr: result.stderr,
5901
- exitCode: result.exitCode
5995
+ stdout: empty(),
5996
+ stderr: empty(),
5997
+ exit: Promise.resolve({
5998
+ code: null,
5999
+ signal: "SIGKILL",
6000
+ success: false
6001
+ })
5902
6002
  };
5903
- } catch (error) {
5904
- const err = error;
6003
+ }
6004
+ const proc = startKernelProcess(os, command, { env, cwd });
6005
+ const unbind = bindAbort(signal, proc.kill);
6006
+ const exit = proc.exit.then((code) => {
6007
+ const killed = proc.wasKilled(code);
5905
6008
  return {
5906
- stdout: err.stdout || "",
5907
- stderr: err.stderr || err.message || "",
5908
- exitCode: err.exitCode ?? 1
6009
+ code: killed ? null : code,
6010
+ signal: killed ? "SIGKILL" : null,
6011
+ success: !killed && code === 0
5909
6012
  };
5910
- }
6013
+ }).finally(unbind);
6014
+ return {
6015
+ stdout: Readable.toWeb(proc.stdout),
6016
+ stderr: Readable.toWeb(proc.stderr),
6017
+ exit
6018
+ };
5911
6019
  },
5912
6020
  async readFile(path5) {
5913
6021
  try {
5914
6022
  const bytes = await os.readFile(path5);
5915
- return textDecoder.decode(bytes);
6023
+ return decoder.decode(bytes);
5916
6024
  } catch (error) {
5917
6025
  throw new Error(
5918
6026
  `Failed to read file "${path5}": ${error instanceof Error ? error.message : String(error)}`
@@ -6017,6 +6125,28 @@ async function snapshot(execute, destination) {
6017
6125
  }
6018
6126
  return snap;
6019
6127
  }
6128
+ function lazyReadable(innerPromise) {
6129
+ let reader = null;
6130
+ return new ReadableStream({
6131
+ async pull(controller) {
6132
+ if (!reader) {
6133
+ const inner = await innerPromise;
6134
+ reader = inner.getReader();
6135
+ }
6136
+ const { done, value } = await reader.read();
6137
+ if (done) controller.close();
6138
+ else controller.enqueue(value);
6139
+ },
6140
+ async cancel(reason) {
6141
+ if (reader) {
6142
+ await reader.cancel(reason);
6143
+ } else {
6144
+ const inner = await innerPromise;
6145
+ await inner.cancel(reason);
6146
+ }
6147
+ }
6148
+ });
6149
+ }
6020
6150
  function diff(before, after) {
6021
6151
  const events = [];
6022
6152
  const ts = Date.now();
@@ -6074,6 +6204,41 @@ function observeSandboxFileEvents(sandbox, options) {
6074
6204
  },
6075
6205
  dispose: sandbox.dispose.bind(sandbox)
6076
6206
  };
6207
+ if (sandbox.spawn) {
6208
+ const innerSpawn = sandbox.spawn.bind(sandbox);
6209
+ decorated.spawn = (command, options2) => {
6210
+ const started = (async () => {
6211
+ const before = await snapshot(innerExecute, destination).catch(
6212
+ () => /* @__PURE__ */ new Map()
6213
+ );
6214
+ const child = innerSpawn(command, options2);
6215
+ return { before, child };
6216
+ })();
6217
+ const exit = (async () => {
6218
+ const { before, child } = await started;
6219
+ try {
6220
+ return await child.exit;
6221
+ } finally {
6222
+ try {
6223
+ const after = await snapshot(innerExecute, destination);
6224
+ buffer.push(...diff(before, after));
6225
+ } catch {
6226
+ }
6227
+ }
6228
+ })();
6229
+ const stdoutPromise = started.then((s) => s.child.stdout);
6230
+ const stderrPromise = started.then((s) => s.child.stderr);
6231
+ stdoutPromise.catch(() => {
6232
+ });
6233
+ stderrPromise.catch(() => {
6234
+ });
6235
+ return {
6236
+ stdout: lazyReadable(stdoutPromise),
6237
+ stderr: lazyReadable(stderrPromise),
6238
+ exit
6239
+ };
6240
+ };
6241
+ }
6077
6242
  return {
6078
6243
  sandbox: decorated,
6079
6244
  drain() {
@@ -6406,13 +6571,513 @@ function resolveRealCwd(ctx) {
6406
6571
  return realCwd;
6407
6572
  }
6408
6573
 
6574
+ // packages/context/src/lib/sandbox/daytona-sandbox.ts
6575
+ import "bash-tool";
6576
+ import { randomUUID } from "node:crypto";
6577
+ import { createRequire } from "node:module";
6578
+ var DAYTONA_DEFAULT_DESTINATION = "/home/daytona";
6579
+ var DAYTONA_EXIT_POLL_INTERVAL_MS = 250;
6580
+ var DAYTONA_EXIT_POLL_TIMEOUT_MS = 3e4;
6581
+ var requireOptional = createRequire(import.meta.url);
6582
+ var DaytonaSandboxError = class extends Error {
6583
+ constructor(message2, cause) {
6584
+ super(message2);
6585
+ this.name = "DaytonaSandboxError";
6586
+ this.cause = cause;
6587
+ }
6588
+ };
6589
+ var DaytonaNotAvailableError = class extends DaytonaSandboxError {
6590
+ constructor(cause) {
6591
+ super(
6592
+ "@daytona/sdk is not installed. Install it with: npm install @daytona/sdk",
6593
+ cause
6594
+ );
6595
+ this.name = "DaytonaNotAvailableError";
6596
+ }
6597
+ };
6598
+ var DaytonaCreationError = class extends DaytonaSandboxError {
6599
+ constructor(message2, cause) {
6600
+ super(`Failed to create Daytona sandbox: ${message2}`, cause);
6601
+ this.name = "DaytonaCreationError";
6602
+ }
6603
+ };
6604
+ var DaytonaCommandError = class extends DaytonaSandboxError {
6605
+ constructor(message2, cause) {
6606
+ super(message2, cause);
6607
+ this.name = "DaytonaCommandError";
6608
+ }
6609
+ };
6610
+ async function createDaytonaSandbox(options = {}) {
6611
+ validateDaytonaOptions(options);
6612
+ const { Daytona } = await importDaytonaSdk();
6613
+ let client;
6614
+ try {
6615
+ client = new Daytona(createDaytonaConfig(options));
6616
+ } catch (error) {
6617
+ const err = toError(error);
6618
+ throw new DaytonaCreationError(err.message, err);
6619
+ }
6620
+ const attached = options.sandboxId !== void 0;
6621
+ const deleteOnDispose = options.deleteOnDispose ?? !attached;
6622
+ let sandbox;
6623
+ try {
6624
+ sandbox = attached ? await client.get(options.sandboxId) : await client.create(createDaytonaParams(options), {
6625
+ timeout: options.createTimeout,
6626
+ onSnapshotCreateLogs: options.onSnapshotCreateLogs
6627
+ });
6628
+ if (attached && sandbox.state && sandbox.state !== "started") {
6629
+ await sandbox.start?.(options.startTimeout ?? options.createTimeout);
6630
+ }
6631
+ } catch (error) {
6632
+ const err = toError(error);
6633
+ throw new DaytonaCreationError(err.message, err);
6634
+ }
6635
+ return createDaytonaSandboxMethods({
6636
+ client,
6637
+ sandbox,
6638
+ commandTimeout: options.commandTimeout,
6639
+ deleteOnDispose,
6640
+ deleteTimeout: options.deleteTimeout
6641
+ });
6642
+ }
6643
+ async function importDaytonaSdk() {
6644
+ try {
6645
+ const mod = requireOptional("@daytona/sdk");
6646
+ if (typeof mod.Daytona !== "function") {
6647
+ throw new DaytonaSandboxError(
6648
+ "@daytona/sdk did not export a Daytona constructor"
6649
+ );
6650
+ }
6651
+ return { Daytona: mod.Daytona };
6652
+ } catch (error) {
6653
+ if (error instanceof DaytonaSandboxError) {
6654
+ throw error;
6655
+ }
6656
+ const err = toError(error);
6657
+ if (isMissingDaytonaSdk(err)) {
6658
+ throw new DaytonaNotAvailableError(err);
6659
+ }
6660
+ throw err;
6661
+ }
6662
+ }
6663
+ function createDaytonaConfig(options) {
6664
+ return compactObject({
6665
+ apiKey: options.apiKey,
6666
+ jwtToken: options.jwtToken,
6667
+ organizationId: options.organizationId,
6668
+ apiUrl: options.apiUrl,
6669
+ target: options.target,
6670
+ otelEnabled: options.otelEnabled,
6671
+ _experimental: options.experimental
6672
+ });
6673
+ }
6674
+ function createDaytonaParams(options) {
6675
+ const base = compactObject({
6676
+ name: options.name,
6677
+ user: options.user,
6678
+ language: options.language,
6679
+ envVars: options.envVars,
6680
+ labels: options.labels,
6681
+ public: options.public,
6682
+ autoStopInterval: options.autoStopInterval,
6683
+ autoArchiveInterval: options.autoArchiveInterval,
6684
+ autoDeleteInterval: options.autoDeleteInterval,
6685
+ volumes: options.volumes,
6686
+ networkBlockAll: options.networkBlockAll,
6687
+ networkAllowList: options.networkAllowList,
6688
+ ephemeral: options.ephemeral
6689
+ });
6690
+ if (options.image) {
6691
+ return compactObject({
6692
+ ...base,
6693
+ image: options.image,
6694
+ resources: options.resources
6695
+ });
6696
+ }
6697
+ const params = compactObject({
6698
+ ...base,
6699
+ snapshot: options.snapshot
6700
+ });
6701
+ return Object.keys(params).length > 0 ? params : void 0;
6702
+ }
6703
+ function validateDaytonaOptions(options) {
6704
+ if (options.image && options.snapshot) {
6705
+ throw new DaytonaSandboxError(
6706
+ 'Daytona sandbox options cannot include both "image" and "snapshot". Choose one environment source.'
6707
+ );
6708
+ }
6709
+ if (options.resources && !options.image) {
6710
+ throw new DaytonaSandboxError(
6711
+ 'Daytona sandbox options can only include "resources" when creating from "image". The Daytona SDK does not apply resources during default or snapshot creation.'
6712
+ );
6713
+ }
6714
+ if (!options.sandboxId) {
6715
+ return;
6716
+ }
6717
+ const creationOnlyFields = [
6718
+ "name",
6719
+ "user",
6720
+ "snapshot",
6721
+ "image",
6722
+ "language",
6723
+ "envVars",
6724
+ "labels",
6725
+ "public",
6726
+ "resources",
6727
+ "volumes",
6728
+ "networkAllowList",
6729
+ "networkBlockAll",
6730
+ "autoStopInterval",
6731
+ "autoArchiveInterval",
6732
+ "autoDeleteInterval",
6733
+ "ephemeral",
6734
+ "onSnapshotCreateLogs"
6735
+ ];
6736
+ const present = creationOnlyFields.filter((field) => {
6737
+ return options[field] !== void 0;
6738
+ });
6739
+ if (present.length > 0) {
6740
+ throw new DaytonaSandboxError(
6741
+ `Daytona sandbox options cannot combine "sandboxId" with creation options: ${present.join(", ")}`
6742
+ );
6743
+ }
6744
+ }
6745
+ function createDaytonaSandboxMethods(args) {
6746
+ const { client, sandbox, commandTimeout, deleteOnDispose, deleteTimeout } = args;
6747
+ let disposed = false;
6748
+ const executeCommand = async (command, options) => {
6749
+ if (options?.signal?.aborted) {
6750
+ return abortedCommandResult();
6751
+ }
6752
+ let aborted = false;
6753
+ const abort = () => {
6754
+ aborted = true;
6755
+ };
6756
+ options?.signal?.addEventListener("abort", abort, { once: true });
6757
+ try {
6758
+ if (aborted || options?.signal?.aborted) {
6759
+ return abortedCommandResult();
6760
+ }
6761
+ const response = await sandbox.process.executeCommand(
6762
+ command,
6763
+ void 0,
6764
+ void 0,
6765
+ commandTimeout
6766
+ );
6767
+ if (aborted) return abortedCommandResult();
6768
+ return {
6769
+ stdout: response.result ?? response.artifacts?.stdout ?? "",
6770
+ stderr: "",
6771
+ exitCode: response.exitCode ?? 0
6772
+ };
6773
+ } catch (error) {
6774
+ if (aborted) return abortedCommandResult();
6775
+ const err = error;
6776
+ return {
6777
+ stdout: err.stdout ?? "",
6778
+ stderr: err.stderr ?? err.message ?? String(error),
6779
+ exitCode: err.exitCode ?? 1
6780
+ };
6781
+ } finally {
6782
+ options?.signal?.removeEventListener("abort", abort);
6783
+ }
6784
+ };
6785
+ return {
6786
+ executeCommand,
6787
+ spawn(command, options) {
6788
+ return spawnDaytonaProcess(sandbox, command, {
6789
+ ...options,
6790
+ commandTimeout
6791
+ });
6792
+ },
6793
+ async readFile(path5) {
6794
+ try {
6795
+ const bytes = await sandbox.fs.downloadFile(path5);
6796
+ return Buffer.from(bytes).toString("utf-8");
6797
+ } catch (error) {
6798
+ throw new DaytonaCommandError(
6799
+ `Failed to read file "${path5}": ${toError(error).message}`,
6800
+ toError(error)
6801
+ );
6802
+ }
6803
+ },
6804
+ async writeFiles(files) {
6805
+ try {
6806
+ for (const dir of uniqueParentDirectories(files.map((f) => f.path))) {
6807
+ const result = await executeCommand(`mkdir -p ${shellQuote2(dir)}`);
6808
+ if (result.exitCode !== 0) {
6809
+ throw new DaytonaCommandError(
6810
+ `Failed to create directory "${dir}": ${result.stderr}`
6811
+ );
6812
+ }
6813
+ }
6814
+ await sandbox.fs.uploadFiles(
6815
+ files.map((file) => ({
6816
+ source: Buffer.from(file.content),
6817
+ destination: file.path
6818
+ }))
6819
+ );
6820
+ } catch (error) {
6821
+ if (error instanceof DaytonaSandboxError) throw error;
6822
+ const err = toError(error);
6823
+ throw new DaytonaCommandError(
6824
+ `Failed to write files: ${err.message}`,
6825
+ err
6826
+ );
6827
+ }
6828
+ },
6829
+ async dispose() {
6830
+ if (disposed) return;
6831
+ disposed = true;
6832
+ try {
6833
+ if (deleteOnDispose) {
6834
+ if (sandbox.delete) await sandbox.delete(deleteTimeout);
6835
+ else if (client.delete) await client.delete(sandbox, deleteTimeout);
6836
+ }
6837
+ } finally {
6838
+ await client[Symbol.asyncDispose]?.().catch(() => {
6839
+ });
6840
+ }
6841
+ }
6842
+ };
6843
+ }
6844
+ function spawnDaytonaProcess(sandbox, command, options = {}) {
6845
+ const sessionId = createSessionId("spawn");
6846
+ const stdout = createTextReadable();
6847
+ const stderr = createTextReadable();
6848
+ const exit = runSpawnedSession({
6849
+ sandbox,
6850
+ sessionId,
6851
+ command: buildSessionCommand(command, options),
6852
+ signal: options.signal,
6853
+ commandTimeout: options.commandTimeout,
6854
+ stdout,
6855
+ stderr
6856
+ });
6857
+ return {
6858
+ stdout: stdout.stream,
6859
+ stderr: stderr.stream,
6860
+ exit
6861
+ };
6862
+ }
6863
+ async function runSpawnedSession(args) {
6864
+ const {
6865
+ sandbox,
6866
+ sessionId,
6867
+ command,
6868
+ signal,
6869
+ commandTimeout,
6870
+ stdout,
6871
+ stderr
6872
+ } = args;
6873
+ let sessionCreated = false;
6874
+ let aborted = signal?.aborted ?? false;
6875
+ let resolveAbort;
6876
+ const abortPromise = new Promise((resolve4) => {
6877
+ resolveAbort = () => resolve4("aborted");
6878
+ });
6879
+ const abort = () => {
6880
+ aborted = true;
6881
+ resolveAbort?.();
6882
+ if (sessionCreated) {
6883
+ sandbox.process.deleteSession(sessionId).catch(() => {
6884
+ });
6885
+ }
6886
+ };
6887
+ if (signal) {
6888
+ if (signal.aborted) abort();
6889
+ else signal.addEventListener("abort", abort, { once: true });
6890
+ }
6891
+ try {
6892
+ await sandbox.process.createSession(sessionId);
6893
+ sessionCreated = true;
6894
+ if (aborted) return abortedExitInfo();
6895
+ const response = await sandbox.process.executeSessionCommand(
6896
+ sessionId,
6897
+ {
6898
+ command,
6899
+ runAsync: true,
6900
+ suppressInputEcho: true
6901
+ },
6902
+ commandTimeout
6903
+ );
6904
+ const commandId = response.cmdId;
6905
+ if (!commandId) {
6906
+ throw new DaytonaCommandError(
6907
+ "Daytona did not return a command id for the spawned session command."
6908
+ );
6909
+ }
6910
+ if (aborted) return abortedExitInfo();
6911
+ const logsTask = sandbox.process.getSessionCommandLogs(
6912
+ sessionId,
6913
+ commandId,
6914
+ (chunk) => stdout.enqueue(chunk),
6915
+ (chunk) => stderr.enqueue(chunk)
6916
+ );
6917
+ logsTask.catch(() => {
6918
+ });
6919
+ const winner = await Promise.race([
6920
+ logsTask.then(() => "logs"),
6921
+ abortPromise
6922
+ ]);
6923
+ if (winner === "aborted") {
6924
+ await sandbox.process.deleteSession(sessionId).catch(() => {
6925
+ });
6926
+ return abortedExitInfo();
6927
+ }
6928
+ await logsTask;
6929
+ const code = await waitForSessionCommandExitCode({
6930
+ sandbox,
6931
+ sessionId,
6932
+ commandId,
6933
+ timeoutMs: sessionExitPollTimeoutMs(commandTimeout),
6934
+ isAborted: () => aborted
6935
+ });
6936
+ return { code, signal: null, success: code === 0 };
6937
+ } catch (error) {
6938
+ if (aborted) return abortedExitInfo();
6939
+ const err = toError(error);
6940
+ stdout.error(err);
6941
+ stderr.error(err);
6942
+ throw err;
6943
+ } finally {
6944
+ if (signal) {
6945
+ signal.removeEventListener("abort", abort);
6946
+ }
6947
+ stdout.close();
6948
+ stderr.close();
6949
+ if (sessionCreated) {
6950
+ await sandbox.process.deleteSession(sessionId).catch(() => {
6951
+ });
6952
+ }
6953
+ }
6954
+ }
6955
+ async function waitForSessionCommandExitCode(args) {
6956
+ const { sandbox, sessionId, commandId, timeoutMs, isAborted } = args;
6957
+ const deadline = Date.now() + timeoutMs;
6958
+ while (true) {
6959
+ if (isAborted()) throw new DaytonaCommandError("Daytona command aborted.");
6960
+ const info = await sandbox.process.getSessionCommand(sessionId, commandId);
6961
+ if (typeof info.exitCode === "number") {
6962
+ return info.exitCode;
6963
+ }
6964
+ if (Date.now() >= deadline) {
6965
+ throw new DaytonaCommandError(
6966
+ `Daytona session command "${commandId}" logs closed before an exit code became available.`
6967
+ );
6968
+ }
6969
+ await delay(DAYTONA_EXIT_POLL_INTERVAL_MS);
6970
+ }
6971
+ }
6972
+ function sessionExitPollTimeoutMs(commandTimeout) {
6973
+ if (commandTimeout === void 0 || commandTimeout === 0) {
6974
+ return DAYTONA_EXIT_POLL_TIMEOUT_MS;
6975
+ }
6976
+ return Math.max(commandTimeout * 1e3, DAYTONA_EXIT_POLL_TIMEOUT_MS);
6977
+ }
6978
+ function delay(ms) {
6979
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
6980
+ }
6981
+ function createTextReadable() {
6982
+ const encoder = new TextEncoder();
6983
+ let controller;
6984
+ let closed = false;
6985
+ return {
6986
+ stream: new ReadableStream({
6987
+ start(streamController) {
6988
+ controller = streamController;
6989
+ }
6990
+ }),
6991
+ enqueue(chunk) {
6992
+ if (closed || !chunk) return;
6993
+ controller?.enqueue(encoder.encode(chunk));
6994
+ },
6995
+ close() {
6996
+ if (closed) return;
6997
+ closed = true;
6998
+ controller?.close();
6999
+ },
7000
+ error(error) {
7001
+ if (closed) return;
7002
+ closed = true;
7003
+ controller?.error(error);
7004
+ }
7005
+ };
7006
+ }
7007
+ function buildSessionCommand(command, options) {
7008
+ const cwdPrefix = options.cwd ? `cd ${shellQuote2(options.cwd)} && ` : "";
7009
+ const env = options.env ?? {};
7010
+ const entries = Object.entries(env);
7011
+ if (entries.length === 0) {
7012
+ return `sh -lc ${shellQuote2(`${cwdPrefix}${command}`)}`;
7013
+ }
7014
+ for (const [key] of entries) {
7015
+ validateEnvKey(key);
7016
+ }
7017
+ const exports = entries.map(([key, value]) => `export ${key}=${shellQuote2(value)}`).join("; ");
7018
+ return `sh -lc ${shellQuote2(`${exports}; ${cwdPrefix}${command}`)}`;
7019
+ }
7020
+ function validateEnvKey(key) {
7021
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
7022
+ throw new DaytonaSandboxError(
7023
+ `Invalid environment variable key: "${key}". Use shell-compatible environment variable names.`
7024
+ );
7025
+ }
7026
+ }
7027
+ function createSessionId(kind) {
7028
+ return `deepagents-${kind}-${randomUUID()}`;
7029
+ }
7030
+ function abortedCommandResult() {
7031
+ return {
7032
+ stdout: "",
7033
+ stderr: "Command aborted",
7034
+ exitCode: 1
7035
+ };
7036
+ }
7037
+ function abortedExitInfo() {
7038
+ return {
7039
+ code: null,
7040
+ signal: "SIGKILL",
7041
+ success: false
7042
+ };
7043
+ }
7044
+ function shellQuote2(value) {
7045
+ return `'${value.replace(/'/g, `'\\''`)}'`;
7046
+ }
7047
+ function uniqueParentDirectories(paths) {
7048
+ const dirs = /* @__PURE__ */ new Set();
7049
+ for (const path5 of paths) {
7050
+ const index = path5.lastIndexOf("/");
7051
+ if (index > 0) {
7052
+ dirs.add(path5.slice(0, index));
7053
+ }
7054
+ }
7055
+ return [...dirs];
7056
+ }
7057
+ function compactObject(input) {
7058
+ const output = {};
7059
+ for (const [key, value] of Object.entries(input)) {
7060
+ if (value !== void 0) {
7061
+ output[key] = value;
7062
+ }
7063
+ }
7064
+ return output;
7065
+ }
7066
+ function isMissingDaytonaSdk(error) {
7067
+ const maybeCode = error.code;
7068
+ return maybeCode === "ERR_MODULE_NOT_FOUND" || maybeCode === "MODULE_NOT_FOUND" || error.message.includes("@daytona/sdk");
7069
+ }
7070
+ function toError(error) {
7071
+ return error instanceof Error ? error : new Error(String(error));
7072
+ }
7073
+
6409
7074
  // packages/context/src/lib/sandbox/docker-sandbox.ts
6410
7075
  import "bash-tool";
6411
7076
  import spawn3 from "nano-spawn";
6412
7077
  import { spawn as childSpawn } from "node:child_process";
6413
7078
  import { createHash } from "node:crypto";
6414
7079
  import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
6415
- import { Readable } from "node:stream";
7080
+ import { Readable as Readable2 } from "node:stream";
6416
7081
 
6417
7082
  // packages/context/src/lib/sandbox/docker-sandbox-errors.ts
6418
7083
  var DockerSandboxError = class extends Error {
@@ -6559,7 +7224,7 @@ function isDebianBased(image) {
6559
7224
  const debianPatterns = ["debian", "ubuntu", "node", "python"];
6560
7225
  return debianPatterns.some((pattern) => lower.includes(pattern));
6561
7226
  }
6562
- function shellQuote2(s) {
7227
+ function shellQuote3(s) {
6563
7228
  return `'${s.replace(/'/g, `'\\''`)}'`;
6564
7229
  }
6565
7230
  function createInstallerContext(containerId, image) {
@@ -6607,7 +7272,7 @@ function createInstallerContext(containerId, image) {
6607
7272
  };
6608
7273
  const installPackages = async (packages) => {
6609
7274
  if (packages.length === 0) return;
6610
- const quoted = packages.map(shellQuote2).join(" ");
7275
+ const quoted = packages.map(shellQuote3).join(" ");
6611
7276
  let cmd;
6612
7277
  if (packageManager === "apt-get") {
6613
7278
  cmd = aptUpdated ? `apt-get install -y ${quoted}` : `apt-get update && apt-get install -y ${quoted}`;
@@ -6629,7 +7294,7 @@ function createInstallerContext(containerId, image) {
6629
7294
  const ensureTool = async (checkName, installName) => {
6630
7295
  const cacheKey = installName ?? checkName;
6631
7296
  if (ensuredTools.has(cacheKey)) return;
6632
- const check = await exec(`which ${shellQuote2(checkName)}`);
7297
+ const check = await exec(`which ${shellQuote3(checkName)}`);
6633
7298
  if (check.exitCode === 0) {
6634
7299
  ensuredTools.add(cacheKey);
6635
7300
  return;
@@ -6666,7 +7331,7 @@ var DockerSandboxStrategy = class {
6666
7331
  constructor(args = {}) {
6667
7332
  const { volumes = [], resources = {}, env = {}, name } = args;
6668
7333
  for (const key of Object.keys(env)) {
6669
- validateEnvKey(key);
7334
+ validateEnvKey2(key);
6670
7335
  }
6671
7336
  if (name !== void 0 && !CONTAINER_NAME_PATTERN.test(name)) {
6672
7337
  throw new DockerSandboxError(
@@ -7071,7 +7736,7 @@ var DockerSandboxStrategy = class {
7071
7736
  return sandbox;
7072
7737
  }
7073
7738
  };
7074
- function validateEnvKey(key) {
7739
+ function validateEnvKey2(key) {
7075
7740
  if (key.length === 0 || key.includes("=")) {
7076
7741
  throw new DockerSandboxError(`Invalid environment variable key: "${key}"`);
7077
7742
  }
@@ -7083,7 +7748,7 @@ function buildDockerExecFlags(options) {
7083
7748
  }
7084
7749
  if (options?.env) {
7085
7750
  for (const [key, value] of Object.entries(options.env)) {
7086
- validateEnvKey(key);
7751
+ validateEnvKey2(key);
7087
7752
  flags.push("-e", `${key}=${value}`);
7088
7753
  }
7089
7754
  }
@@ -7100,8 +7765,8 @@ function toSandboxProcess(child, abortSignal) {
7100
7765
  else abortSignal.addEventListener("abort", onAbort, { once: true });
7101
7766
  }
7102
7767
  return {
7103
- stdout: Readable.toWeb(child.stdout),
7104
- stderr: Readable.toWeb(child.stderr),
7768
+ stdout: Readable2.toWeb(child.stdout),
7769
+ stderr: Readable2.toWeb(child.stderr),
7105
7770
  exit: new Promise((resolve4, reject) => {
7106
7771
  const settle = () => {
7107
7772
  child.removeListener("exit", onExitEvent);
@@ -7347,60 +8012,6 @@ async function useSandbox(options, fn) {
7347
8012
  }
7348
8013
  }
7349
8014
 
7350
- // packages/context/src/lib/sandbox/container-tool.ts
7351
- async function createContainerTool(options = {}) {
7352
- let sandboxOptions;
7353
- let bashOptions;
7354
- let skillInputs = [];
7355
- if (isComposeOptions(options)) {
7356
- const { compose, service, resources, skills: skills2 = [], ...rest } = options;
7357
- sandboxOptions = { compose, service, resources };
7358
- bashOptions = rest;
7359
- skillInputs = skills2;
7360
- } else if (isDockerfileOptions(options)) {
7361
- const {
7362
- dockerfile,
7363
- context,
7364
- volumes,
7365
- resources,
7366
- env,
7367
- name,
7368
- skills: skills2 = [],
7369
- ...rest
7370
- } = options;
7371
- sandboxOptions = { dockerfile, context, volumes, resources, env, name };
7372
- bashOptions = rest;
7373
- skillInputs = skills2;
7374
- } else {
7375
- const {
7376
- image,
7377
- installers,
7378
- volumes,
7379
- resources,
7380
- env,
7381
- name,
7382
- skills: skills2 = [],
7383
- ...rest
7384
- } = options;
7385
- sandboxOptions = { image, installers, volumes, resources, env, name };
7386
- bashOptions = rest;
7387
- skillInputs = skills2;
7388
- }
7389
- const backend = await createDockerSandbox(sandboxOptions);
7390
- const toolkit = await createBashTool({
7391
- ...bashOptions,
7392
- sandbox: backend,
7393
- skills: skillInputs
7394
- });
7395
- return {
7396
- bash: toolkit.bash,
7397
- tools: toolkit.tools,
7398
- sandbox: toolkit.sandbox,
7399
- skills: toolkit.skills,
7400
- drainFileEvents: toolkit.drainFileEvents
7401
- };
7402
- }
7403
-
7404
8015
  // packages/context/src/lib/sandbox/installers/package-manager.ts
7405
8016
  var PackageInstaller = class extends Installer {
7406
8017
  kind;
@@ -7473,9 +8084,9 @@ async function downloadAndInstall(ctx, name, url, binaryPath, source = "url") {
7473
8084
  function buildTarGzInstallCmd(name, url, binaryPathInArchive) {
7474
8085
  return `
7475
8086
  set -e
7476
- NAME=${shellQuote2(name)}
7477
- URL=${shellQuote2(url)}
7478
- BIN_IN_ARCHIVE=${shellQuote2(binaryPathInArchive)}
8087
+ NAME=${shellQuote3(name)}
8088
+ URL=${shellQuote3(url)}
8089
+ BIN_IN_ARCHIVE=${shellQuote3(binaryPathInArchive)}
7479
8090
  TMPDIR=$(mktemp -d)
7480
8091
  cd "$TMPDIR"
7481
8092
  curl -fsSL "$URL" -o archive.tar.gz
@@ -7494,8 +8105,8 @@ function buildTarGzInstallCmd(name, url, binaryPathInArchive) {
7494
8105
  }
7495
8106
  function buildRawInstallCmd(name, url) {
7496
8107
  return `
7497
- NAME=${shellQuote2(name)}
7498
- URL=${shellQuote2(url)}
8108
+ NAME=${shellQuote3(name)}
8109
+ URL=${shellQuote3(url)}
7499
8110
  curl -fsSL "$URL" -o "/usr/local/bin/$NAME"
7500
8111
  chmod +x "/usr/local/bin/$NAME"
7501
8112
  `;
@@ -7548,6 +8159,59 @@ async function ensureNodeRuntime(ctx, ensure) {
7548
8159
  }
7549
8160
  }
7550
8161
 
8162
+ // packages/context/src/lib/sandbox/installers/bin.ts
8163
+ import { basename, posix } from "node:path";
8164
+ var NOT_FOUND_EXIT = 11;
8165
+ var CHMOD_FAILED_EXIT = 12;
8166
+ var BinInstaller = class extends Installer {
8167
+ kind;
8168
+ binary;
8169
+ options;
8170
+ #name;
8171
+ #target;
8172
+ constructor(binary, options = {}) {
8173
+ super();
8174
+ this.binary = binary;
8175
+ this.options = options;
8176
+ this.#name = resolveName(binary, options);
8177
+ this.#target = options.target ?? posix.join("/usr/local/bin", this.#name);
8178
+ this.kind = `bin:${this.#name}`;
8179
+ }
8180
+ async install(ctx) {
8181
+ const b = shellQuote3(this.binary);
8182
+ const t = shellQuote3(this.#target);
8183
+ const dir = shellQuote3(posix.dirname(this.#target));
8184
+ const result = await ctx.exec(
8185
+ `test -f ${b} || { echo "binary not found at ${this.binary}" >&2; exit ${NOT_FOUND_EXIT}; }; if ! test -x ${b}; then chmod +x ${b} || exit ${CHMOD_FAILED_EXIT}; fi; mkdir -p ${dir} && ln -sf ${b} ${t}`
8186
+ );
8187
+ if (result.exitCode === 0) return;
8188
+ throw new InstallError({
8189
+ target: this.#name,
8190
+ source: "bin",
8191
+ reason: explainFailure(result.exitCode, result.stderr, this.binary),
8192
+ containerId: ctx.containerId
8193
+ });
8194
+ }
8195
+ };
8196
+ function bin(binary, options) {
8197
+ return new BinInstaller(binary, options);
8198
+ }
8199
+ function explainFailure(exitCode, stderr, binary) {
8200
+ if (exitCode === NOT_FOUND_EXIT) {
8201
+ return `binary not found at ${binary}`;
8202
+ }
8203
+ if (exitCode === CHMOD_FAILED_EXIT && /read-only file system/i.test(stderr)) {
8204
+ return `${binary} is not executable and the bind mount is read-only \u2014 run \`chmod +x\` on the host, or mount with \`readOnly: false\`. (${stderr.trim()})`;
8205
+ }
8206
+ return stderr || `bin installer failed with exit code ${exitCode}`;
8207
+ }
8208
+ function resolveName(binary, options) {
8209
+ if (options.name) return options.name;
8210
+ const base = basename(binary);
8211
+ const dot = base.lastIndexOf(".");
8212
+ return dot > 0 ? base.slice(0, dot) : base;
8213
+ }
8214
+
7551
8215
  // packages/context/src/lib/sandbox/installers/pip.ts
7552
8216
  var PYTHON_BINARIES = ["python3", "pip3"];
7553
8217
  var PipInstaller = class extends Installer {
@@ -7811,7 +8475,7 @@ function soul() {
7811
8475
  }
7812
8476
 
7813
8477
  // packages/context/src/lib/store/postgres.store.ts
7814
- import { createRequire } from "node:module";
8478
+ import { createRequire as createRequire2 } from "node:module";
7815
8479
 
7816
8480
  // packages/context/src/lib/store/ddl.postgres.ts
7817
8481
  function storeDDL(schema) {
@@ -7923,7 +8587,7 @@ var PostgresContextStore = class _PostgresContextStore extends ContextStore {
7923
8587
  }
7924
8588
  static #requirePg() {
7925
8589
  try {
7926
- const require2 = createRequire(import.meta.url);
8590
+ const require2 = createRequire2(import.meta.url);
7927
8591
  return require2("pg");
7928
8592
  } catch {
7929
8593
  throw new Error(
@@ -8519,7 +9183,7 @@ var PostgresContextStore = class _PostgresContextStore extends ContextStore {
8519
9183
  };
8520
9184
 
8521
9185
  // packages/context/src/lib/store/sqlserver.store.ts
8522
- import { createRequire as createRequire2 } from "node:module";
9186
+ import { createRequire as createRequire3 } from "node:module";
8523
9187
 
8524
9188
  // packages/context/src/lib/store/ddl.sqlserver.ts
8525
9189
  function storeDDL2(schema) {
@@ -8661,7 +9325,7 @@ var SqlServerContextStore = class _SqlServerContextStore extends ContextStore {
8661
9325
  }
8662
9326
  static #requireMssql() {
8663
9327
  try {
8664
- const require2 = createRequire2(import.meta.url);
9328
+ const require2 = createRequire3(import.meta.url);
8665
9329
  return require2("mssql");
8666
9330
  } catch {
8667
9331
  throw new Error(
@@ -9371,11 +10035,12 @@ async function persistedWriter(options) {
9371
10035
  } = options;
9372
10036
  let seq = 0;
9373
10037
  let buffer = [];
10038
+ let failedByErrorChunk = false;
9374
10039
  async function flush() {
9375
10040
  if (buffer.length === 0) return;
9376
10041
  const batch = buffer;
9377
10042
  buffer = [];
9378
- await store2.appendChunks(batch);
10043
+ await appendBatch(batch);
9379
10044
  }
9380
10045
  function makeChunk(part) {
9381
10046
  return {
@@ -9385,9 +10050,19 @@ async function persistedWriter(options) {
9385
10050
  createdAt: Date.now()
9386
10051
  };
9387
10052
  }
10053
+ function isStreamErrorPart(part) {
10054
+ return part.type === "error";
10055
+ }
10056
+ async function appendBatch(batch) {
10057
+ const hasErrorPart = !failedByErrorChunk && batch.map((chunk) => chunk.data).some(isStreamErrorPart);
10058
+ await store2.appendChunks(batch);
10059
+ if (hasErrorPart) {
10060
+ failedByErrorChunk = true;
10061
+ }
10062
+ }
9388
10063
  async function persistChunk(chunk) {
9389
10064
  if (strategy === "immediate") {
9390
- await store2.appendChunks([chunk]);
10065
+ await appendBatch([chunk]);
9391
10066
  } else {
9392
10067
  buffer.push(chunk);
9393
10068
  if (buffer.length >= flushSize) {
@@ -9417,10 +10092,12 @@ async function persistedWriter(options) {
9417
10092
  flush,
9418
10093
  async complete() {
9419
10094
  await flush();
10095
+ if (failedByErrorChunk) return;
9420
10096
  await store2.updateStreamStatus(streamId, "completed");
9421
10097
  },
9422
10098
  async fail(error) {
9423
10099
  await flush();
10100
+ if (failedByErrorChunk) return;
9424
10101
  await store2.updateStreamStatus(streamId, "failed", { error });
9425
10102
  },
9426
10103
  async cleanup() {
@@ -9430,7 +10107,7 @@ async function persistedWriter(options) {
9430
10107
  }
9431
10108
 
9432
10109
  // packages/context/src/lib/stream/polling-change-source.ts
9433
- import { setTimeout as delay } from "node:timers/promises";
10110
+ import { setTimeout as delay2 } from "node:timers/promises";
9434
10111
 
9435
10112
  // packages/context/src/lib/stream/polling-policy.ts
9436
10113
  var DEFAULT_WATCH_POLLING = {
@@ -9475,7 +10152,7 @@ function nextAdaptivePollingDelay(state) {
9475
10152
  state.config.minMs,
9476
10153
  state.config.maxMs
9477
10154
  );
9478
- const delay2 = applyJitter(
10155
+ const delay3 = applyJitter(
9479
10156
  current,
9480
10157
  state.config.jitterRatio,
9481
10158
  state.config.minMs,
@@ -9486,7 +10163,7 @@ function nextAdaptivePollingDelay(state) {
9486
10163
  state.config.minMs,
9487
10164
  state.config.maxMs
9488
10165
  );
9489
- return delay2;
10166
+ return delay3;
9490
10167
  }
9491
10168
  function normalizeAdaptivePolling(polling, fallback) {
9492
10169
  const merged = {
@@ -9586,7 +10263,7 @@ function isTerminal(status) {
9586
10263
  return status !== "queued" && status !== "running";
9587
10264
  }
9588
10265
  function waitForDelay(ms, signal) {
9589
- return delay(ms, true, { signal }).catch((err) => {
10266
+ return delay2(ms, true, { signal }).catch((err) => {
9590
10267
  if (signal.aborted) return false;
9591
10268
  throw err;
9592
10269
  });
@@ -9638,7 +10315,7 @@ function asStaticWordPartText(parts, options = {}) {
9638
10315
  }
9639
10316
 
9640
10317
  // packages/context/src/lib/stream/postgres-notify-change-source.ts
9641
- import { createRequire as createRequire3 } from "node:module";
10318
+ import { createRequire as createRequire4 } from "node:module";
9642
10319
 
9643
10320
  // packages/context/src/lib/stream/ddl.stream.postgres-notify.ts
9644
10321
  var DEFAULT_POSTGRES_STREAM_CHANGES_CHANNEL = "deepagents_stream_changes";
@@ -9740,7 +10417,7 @@ var PostgresNotifyChangeSource = class _PostgresNotifyChangeSource {
9740
10417
  }
9741
10418
  static #requirePg() {
9742
10419
  try {
9743
- const require2 = createRequire3(import.meta.url);
10420
+ const require2 = createRequire4(import.meta.url);
9744
10421
  return require2("pg");
9745
10422
  } catch {
9746
10423
  throw new Error(
@@ -9995,7 +10672,7 @@ function assertIdentifier(value, label) {
9995
10672
  }
9996
10673
 
9997
10674
  // packages/context/src/lib/stream/postgres.stream-store.ts
9998
- import { createRequire as createRequire4 } from "node:module";
10675
+ import { createRequire as createRequire5 } from "node:module";
9999
10676
 
10000
10677
  // packages/context/src/lib/stream/ddl.stream.postgres.ts
10001
10678
  function postgresStreamDDL(schema) {
@@ -10031,6 +10708,15 @@ CREATE INDEX IF NOT EXISTS "idx_${schema}_streams_status_created_at_id"
10031
10708
  }
10032
10709
 
10033
10710
  // packages/context/src/lib/stream/stream-store.ts
10711
+ function collectStreamFailures(chunks) {
10712
+ const failures = /* @__PURE__ */ new Map();
10713
+ for (const chunk of chunks) {
10714
+ if (chunk.data.type === "error" && !failures.has(chunk.streamId)) {
10715
+ failures.set(chunk.streamId, chunk.data.errorText);
10716
+ }
10717
+ }
10718
+ return [...failures].map(([streamId, error]) => ({ streamId, error }));
10719
+ }
10034
10720
  var StreamStore = class {
10035
10721
  async listRunningStreamIds() {
10036
10722
  return this.listStreamIds({ status: "running" });
@@ -10060,7 +10746,7 @@ var PostgresStreamStore = class _PostgresStreamStore extends StreamStore {
10060
10746
  }
10061
10747
  static #requirePg() {
10062
10748
  try {
10063
- const require2 = createRequire4(import.meta.url);
10749
+ const require2 = createRequire5(import.meta.url);
10064
10750
  return require2("pg");
10065
10751
  } catch {
10066
10752
  throw new Error(
@@ -10214,13 +10900,31 @@ var PostgresStreamStore = class _PostgresStreamStore extends StreamStore {
10214
10900
  data: chunk.data,
10215
10901
  created_at: chunk.createdAt
10216
10902
  }));
10217
- await this.#query(
10218
- `INSERT INTO ${this.#t("stream_chunks")} (stream_id, seq, data, created_at)
10903
+ const params = [JSON.stringify(rows)];
10904
+ const insertSql = `INSERT INTO ${this.#t("stream_chunks")} (stream_id, seq, data, created_at)
10219
10905
  SELECT stream_id, seq, data, created_at
10220
10906
  FROM jsonb_to_recordset($1::jsonb)
10221
- AS rows(stream_id TEXT, seq INTEGER, data JSONB, created_at BIGINT)`,
10222
- [JSON.stringify(rows)]
10223
- );
10907
+ AS rows(stream_id TEXT, seq INTEGER, data JSONB, created_at BIGINT)`;
10908
+ const failures = collectStreamFailures(chunks);
10909
+ if (failures.length === 0) {
10910
+ await this.#query(insertSql, params);
10911
+ return;
10912
+ }
10913
+ await this.#useTransaction(async (client) => {
10914
+ await client.query(insertSql, params);
10915
+ const failedAt = Date.now();
10916
+ for (const failure of failures) {
10917
+ const result = await client.query(
10918
+ `UPDATE ${this.#t("streams")}
10919
+ SET status = $1, finished_at = $2, error = $3
10920
+ WHERE id = $4`,
10921
+ ["failed", failedAt, failure.error, failure.streamId]
10922
+ );
10923
+ if (result.rowCount !== 1) {
10924
+ throw new Error(`Stream "${failure.streamId}" not found`);
10925
+ }
10926
+ }
10927
+ });
10224
10928
  }
10225
10929
  async getChunks(streamId, fromSeq, limit) {
10226
10930
  const params = [streamId];
@@ -10467,6 +11171,7 @@ var SqliteStreamStore = class extends StreamStore {
10467
11171
  }
10468
11172
  async appendChunks(chunks) {
10469
11173
  if (chunks.length === 0) return;
11174
+ const failures = collectStreamFailures(chunks);
10470
11175
  this.#db.exec("BEGIN TRANSACTION");
10471
11176
  try {
10472
11177
  for (const chunk of chunks) {
@@ -10480,6 +11185,15 @@ var SqliteStreamStore = class extends StreamStore {
10480
11185
  chunk.createdAt
10481
11186
  );
10482
11187
  }
11188
+ const failedAt = Date.now();
11189
+ for (const failure of failures) {
11190
+ const result = this.#stmt(
11191
+ "UPDATE streams SET status = ?, finishedAt = ?, error = ? WHERE id = ?"
11192
+ ).run("failed", failedAt, failure.error, failure.streamId);
11193
+ if (result.changes !== 1) {
11194
+ throw new Error(`Stream "${failure.streamId}" not found`);
11195
+ }
11196
+ }
10483
11197
  this.#db.exec("COMMIT");
10484
11198
  } catch (error) {
10485
11199
  this.#db.exec("ROLLBACK");
@@ -10881,14 +11595,20 @@ export {
10881
11595
  AsyncResolver,
10882
11596
  BM25Classifier,
10883
11597
  BashException,
11598
+ BinInstaller,
10884
11599
  ComposeStartError,
10885
11600
  ComposeStrategy,
10886
11601
  ContainerCreationError,
10887
11602
  ContextEngine,
10888
11603
  ContextRenderer,
10889
11604
  ContextStore,
11605
+ DAYTONA_DEFAULT_DESTINATION,
10890
11606
  DEFAULT_CANCEL_POLLING,
10891
11607
  DEFAULT_WATCH_POLLING,
11608
+ DaytonaCommandError,
11609
+ DaytonaCreationError,
11610
+ DaytonaNotAvailableError,
11611
+ DaytonaSandboxError,
10892
11612
  DockerNotAvailableError,
10893
11613
  DockerSandboxError,
10894
11614
  DockerSandboxStrategy,
@@ -10950,11 +11670,13 @@ export {
10950
11670
  assertCountSpec,
10951
11671
  assistant,
10952
11672
  assistantText,
11673
+ bin,
10953
11674
  buildSubcommandRepair,
10954
11675
  chat,
10955
11676
  checkCount,
10956
11677
  clarification,
10957
11678
  classifies,
11679
+ collectStreamFailures,
10958
11680
  contentIncludes,
10959
11681
  contentMatches,
10960
11682
  contentPattern,
@@ -10963,7 +11685,7 @@ export {
10963
11685
  createAgentOsSandbox,
10964
11686
  createBashTool,
10965
11687
  createBinaryBridges,
10966
- createContainerTool,
11688
+ createDaytonaSandbox,
10967
11689
  createDockerSandbox,
10968
11690
  createInstallerContext,
10969
11691
  createRepairToolCall,
@@ -11054,7 +11776,7 @@ export {
11054
11776
  seasonChanged,
11055
11777
  seasonReminder,
11056
11778
  selfCritique,
11057
- shellQuote2 as shellQuote,
11779
+ shellQuote3 as shellQuote,
11058
11780
  skills,
11059
11781
  skillsReminder,
11060
11782
  socraticPrompting,