@deepagents/context 2.1.0 → 2.3.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.
- package/README.md +18 -14
- package/dist/browser.js +37 -2
- package/dist/browser.js.map +3 -3
- package/dist/index.js +845 -112
- package/dist/index.js.map +4 -4
- package/dist/lib/guardrail.d.ts +2 -6
- package/dist/lib/guardrail.d.ts.map +1 -1
- package/dist/lib/sandbox/abort.d.ts.map +1 -1
- package/dist/lib/sandbox/agent-os-sandbox.d.ts +5 -1
- package/dist/lib/sandbox/agent-os-sandbox.d.ts.map +1 -1
- package/dist/lib/sandbox/daytona-sandbox.d.ts +63 -0
- package/dist/lib/sandbox/daytona-sandbox.d.ts.map +1 -0
- package/dist/lib/sandbox/docker-sandbox-errors.d.ts +9 -4
- package/dist/lib/sandbox/docker-sandbox-errors.d.ts.map +1 -1
- package/dist/lib/sandbox/docker-sandbox.d.ts +24 -1
- package/dist/lib/sandbox/docker-sandbox.d.ts.map +1 -1
- package/dist/lib/sandbox/file-events.d.ts +10 -1
- package/dist/lib/sandbox/file-events.d.ts.map +1 -1
- package/dist/lib/sandbox/index.d.ts +1 -1
- package/dist/lib/sandbox/index.d.ts.map +1 -1
- package/dist/lib/sandbox/installers/bin.d.ts +40 -0
- package/dist/lib/sandbox/installers/bin.d.ts.map +1 -0
- package/dist/lib/sandbox/installers/index.d.ts +1 -0
- package/dist/lib/sandbox/installers/index.d.ts.map +1 -1
- package/dist/lib/save/save-pipeline.d.ts.map +1 -1
- package/dist/lib/skills/fragments.d.ts +2 -2
- package/dist/lib/store/sqlite.store.d.ts +1 -0
- package/dist/lib/store/sqlite.store.d.ts.map +1 -1
- package/dist/lib/store/store.d.ts +8 -0
- package/dist/lib/store/store.d.ts.map +1 -1
- package/dist/lib/stream/postgres.stream-store.d.ts.map +1 -1
- package/dist/lib/stream/sqlite.stream-store.d.ts.map +1 -1
- package/dist/lib/stream/stream-manager.d.ts +1 -1
- package/dist/lib/stream/stream-manager.d.ts.map +1 -1
- package/dist/lib/stream/stream-store.d.ts +8 -1
- package/dist/lib/stream/stream-store.d.ts.map +1 -1
- package/dist/lib/stream/types.d.ts +7 -0
- package/dist/lib/stream/types.d.ts.map +1 -0
- package/dist/lib/stream-buffer.d.ts.map +1 -1
- package/package.json +7 -3
- package/dist/lib/sandbox/container-tool.d.ts +0 -190
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
5900
|
-
stderr:
|
|
5901
|
-
|
|
5995
|
+
stdout: empty(),
|
|
5996
|
+
stderr: empty(),
|
|
5997
|
+
exit: Promise.resolve({
|
|
5998
|
+
code: null,
|
|
5999
|
+
signal: "SIGKILL",
|
|
6000
|
+
success: false
|
|
6001
|
+
})
|
|
5902
6002
|
};
|
|
5903
|
-
}
|
|
5904
|
-
|
|
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
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
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
|
|
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
|
|
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(
|
|
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 ${
|
|
7297
|
+
const check = await exec(`which ${shellQuote3(checkName)}`);
|
|
6633
7298
|
if (check.exitCode === 0) {
|
|
6634
7299
|
ensuredTools.add(cacheKey);
|
|
6635
7300
|
return;
|
|
@@ -6662,11 +7327,12 @@ var DockerSandboxStrategy = class {
|
|
|
6662
7327
|
resources;
|
|
6663
7328
|
env;
|
|
6664
7329
|
name;
|
|
7330
|
+
command;
|
|
6665
7331
|
createdVolumes = /* @__PURE__ */ new Set();
|
|
6666
7332
|
constructor(args = {}) {
|
|
6667
|
-
const { volumes = [], resources = {}, env = {}, name } = args;
|
|
7333
|
+
const { volumes = [], resources = {}, env = {}, name, command } = args;
|
|
6668
7334
|
for (const key of Object.keys(env)) {
|
|
6669
|
-
|
|
7335
|
+
validateEnvKey2(key);
|
|
6670
7336
|
}
|
|
6671
7337
|
if (name !== void 0 && !CONTAINER_NAME_PATTERN.test(name)) {
|
|
6672
7338
|
throw new DockerSandboxError(
|
|
@@ -6677,6 +7343,7 @@ var DockerSandboxStrategy = class {
|
|
|
6677
7343
|
this.resources = resources;
|
|
6678
7344
|
this.env = env;
|
|
6679
7345
|
this.name = name;
|
|
7346
|
+
this.command = command;
|
|
6680
7347
|
}
|
|
6681
7348
|
async create() {
|
|
6682
7349
|
const image = await this.getImage();
|
|
@@ -6884,7 +7551,12 @@ var DockerSandboxStrategy = class {
|
|
|
6884
7551
|
for (const volume of this.volumes) {
|
|
6885
7552
|
args.push("--mount", this.buildVolumeMountArg(volume));
|
|
6886
7553
|
}
|
|
6887
|
-
args.push(image
|
|
7554
|
+
args.push(image);
|
|
7555
|
+
if (this.command === void 0) {
|
|
7556
|
+
args.push("tail", "-f", "/dev/null");
|
|
7557
|
+
} else if (this.command !== null) {
|
|
7558
|
+
args.push(...this.command);
|
|
7559
|
+
}
|
|
6888
7560
|
return args;
|
|
6889
7561
|
}
|
|
6890
7562
|
buildVolumeMountArg(volume) {
|
|
@@ -7071,7 +7743,7 @@ var DockerSandboxStrategy = class {
|
|
|
7071
7743
|
return sandbox;
|
|
7072
7744
|
}
|
|
7073
7745
|
};
|
|
7074
|
-
function
|
|
7746
|
+
function validateEnvKey2(key) {
|
|
7075
7747
|
if (key.length === 0 || key.includes("=")) {
|
|
7076
7748
|
throw new DockerSandboxError(`Invalid environment variable key: "${key}"`);
|
|
7077
7749
|
}
|
|
@@ -7083,7 +7755,7 @@ function buildDockerExecFlags(options) {
|
|
|
7083
7755
|
}
|
|
7084
7756
|
if (options?.env) {
|
|
7085
7757
|
for (const [key, value] of Object.entries(options.env)) {
|
|
7086
|
-
|
|
7758
|
+
validateEnvKey2(key);
|
|
7087
7759
|
flags.push("-e", `${key}=${value}`);
|
|
7088
7760
|
}
|
|
7089
7761
|
}
|
|
@@ -7100,8 +7772,8 @@ function toSandboxProcess(child, abortSignal) {
|
|
|
7100
7772
|
else abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
7101
7773
|
}
|
|
7102
7774
|
return {
|
|
7103
|
-
stdout:
|
|
7104
|
-
stderr:
|
|
7775
|
+
stdout: Readable2.toWeb(child.stdout),
|
|
7776
|
+
stderr: Readable2.toWeb(child.stderr),
|
|
7105
7777
|
exit: new Promise((resolve4, reject) => {
|
|
7106
7778
|
const settle = () => {
|
|
7107
7779
|
child.removeListener("exit", onExitEvent);
|
|
@@ -7131,7 +7803,8 @@ var RuntimeStrategy = class extends DockerSandboxStrategy {
|
|
|
7131
7803
|
volumes: args.volumes,
|
|
7132
7804
|
resources: args.resources,
|
|
7133
7805
|
env: args.env,
|
|
7134
|
-
name: args.name
|
|
7806
|
+
name: args.name,
|
|
7807
|
+
command: args.command
|
|
7135
7808
|
});
|
|
7136
7809
|
this.image = args.image ?? "alpine:latest";
|
|
7137
7810
|
this.installers = args.installers ?? [];
|
|
@@ -7155,7 +7828,8 @@ var DockerfileStrategy = class extends DockerSandboxStrategy {
|
|
|
7155
7828
|
volumes: args.volumes,
|
|
7156
7829
|
resources: args.resources,
|
|
7157
7830
|
env: args.env,
|
|
7158
|
-
name: args.name
|
|
7831
|
+
name: args.name,
|
|
7832
|
+
command: args.command
|
|
7159
7833
|
});
|
|
7160
7834
|
this.dockerfile = args.dockerfile;
|
|
7161
7835
|
this.dockerContext = args.context ?? ".";
|
|
@@ -7324,7 +7998,8 @@ async function createDockerSandbox(options = {}) {
|
|
|
7324
7998
|
volumes: options.volumes,
|
|
7325
7999
|
resources: options.resources,
|
|
7326
8000
|
env: options.env,
|
|
7327
|
-
name: options.name
|
|
8001
|
+
name: options.name,
|
|
8002
|
+
command: options.command
|
|
7328
8003
|
});
|
|
7329
8004
|
} else {
|
|
7330
8005
|
strategy = new RuntimeStrategy({
|
|
@@ -7333,7 +8008,8 @@ async function createDockerSandbox(options = {}) {
|
|
|
7333
8008
|
volumes: options.volumes,
|
|
7334
8009
|
resources: options.resources,
|
|
7335
8010
|
env: options.env,
|
|
7336
|
-
name: options.name
|
|
8011
|
+
name: options.name,
|
|
8012
|
+
command: options.command
|
|
7337
8013
|
});
|
|
7338
8014
|
}
|
|
7339
8015
|
return strategy.create();
|
|
@@ -7347,60 +8023,6 @@ async function useSandbox(options, fn) {
|
|
|
7347
8023
|
}
|
|
7348
8024
|
}
|
|
7349
8025
|
|
|
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
8026
|
// packages/context/src/lib/sandbox/installers/package-manager.ts
|
|
7405
8027
|
var PackageInstaller = class extends Installer {
|
|
7406
8028
|
kind;
|
|
@@ -7473,9 +8095,9 @@ async function downloadAndInstall(ctx, name, url, binaryPath, source = "url") {
|
|
|
7473
8095
|
function buildTarGzInstallCmd(name, url, binaryPathInArchive) {
|
|
7474
8096
|
return `
|
|
7475
8097
|
set -e
|
|
7476
|
-
NAME=${
|
|
7477
|
-
URL=${
|
|
7478
|
-
BIN_IN_ARCHIVE=${
|
|
8098
|
+
NAME=${shellQuote3(name)}
|
|
8099
|
+
URL=${shellQuote3(url)}
|
|
8100
|
+
BIN_IN_ARCHIVE=${shellQuote3(binaryPathInArchive)}
|
|
7479
8101
|
TMPDIR=$(mktemp -d)
|
|
7480
8102
|
cd "$TMPDIR"
|
|
7481
8103
|
curl -fsSL "$URL" -o archive.tar.gz
|
|
@@ -7494,8 +8116,8 @@ function buildTarGzInstallCmd(name, url, binaryPathInArchive) {
|
|
|
7494
8116
|
}
|
|
7495
8117
|
function buildRawInstallCmd(name, url) {
|
|
7496
8118
|
return `
|
|
7497
|
-
NAME=${
|
|
7498
|
-
URL=${
|
|
8119
|
+
NAME=${shellQuote3(name)}
|
|
8120
|
+
URL=${shellQuote3(url)}
|
|
7499
8121
|
curl -fsSL "$URL" -o "/usr/local/bin/$NAME"
|
|
7500
8122
|
chmod +x "/usr/local/bin/$NAME"
|
|
7501
8123
|
`;
|
|
@@ -7548,6 +8170,59 @@ async function ensureNodeRuntime(ctx, ensure) {
|
|
|
7548
8170
|
}
|
|
7549
8171
|
}
|
|
7550
8172
|
|
|
8173
|
+
// packages/context/src/lib/sandbox/installers/bin.ts
|
|
8174
|
+
import { basename, posix } from "node:path";
|
|
8175
|
+
var NOT_FOUND_EXIT = 11;
|
|
8176
|
+
var CHMOD_FAILED_EXIT = 12;
|
|
8177
|
+
var BinInstaller = class extends Installer {
|
|
8178
|
+
kind;
|
|
8179
|
+
binary;
|
|
8180
|
+
options;
|
|
8181
|
+
#name;
|
|
8182
|
+
#target;
|
|
8183
|
+
constructor(binary, options = {}) {
|
|
8184
|
+
super();
|
|
8185
|
+
this.binary = binary;
|
|
8186
|
+
this.options = options;
|
|
8187
|
+
this.#name = resolveName(binary, options);
|
|
8188
|
+
this.#target = options.target ?? posix.join("/usr/local/bin", this.#name);
|
|
8189
|
+
this.kind = `bin:${this.#name}`;
|
|
8190
|
+
}
|
|
8191
|
+
async install(ctx) {
|
|
8192
|
+
const b = shellQuote3(this.binary);
|
|
8193
|
+
const t = shellQuote3(this.#target);
|
|
8194
|
+
const dir = shellQuote3(posix.dirname(this.#target));
|
|
8195
|
+
const result = await ctx.exec(
|
|
8196
|
+
`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}`
|
|
8197
|
+
);
|
|
8198
|
+
if (result.exitCode === 0) return;
|
|
8199
|
+
throw new InstallError({
|
|
8200
|
+
target: this.#name,
|
|
8201
|
+
source: "bin",
|
|
8202
|
+
reason: explainFailure(result.exitCode, result.stderr, this.binary),
|
|
8203
|
+
containerId: ctx.containerId
|
|
8204
|
+
});
|
|
8205
|
+
}
|
|
8206
|
+
};
|
|
8207
|
+
function bin(binary, options) {
|
|
8208
|
+
return new BinInstaller(binary, options);
|
|
8209
|
+
}
|
|
8210
|
+
function explainFailure(exitCode, stderr, binary) {
|
|
8211
|
+
if (exitCode === NOT_FOUND_EXIT) {
|
|
8212
|
+
return `binary not found at ${binary}`;
|
|
8213
|
+
}
|
|
8214
|
+
if (exitCode === CHMOD_FAILED_EXIT && /read-only file system/i.test(stderr)) {
|
|
8215
|
+
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()})`;
|
|
8216
|
+
}
|
|
8217
|
+
return stderr || `bin installer failed with exit code ${exitCode}`;
|
|
8218
|
+
}
|
|
8219
|
+
function resolveName(binary, options) {
|
|
8220
|
+
if (options.name) return options.name;
|
|
8221
|
+
const base = basename(binary);
|
|
8222
|
+
const dot = base.lastIndexOf(".");
|
|
8223
|
+
return dot > 0 ? base.slice(0, dot) : base;
|
|
8224
|
+
}
|
|
8225
|
+
|
|
7551
8226
|
// packages/context/src/lib/sandbox/installers/pip.ts
|
|
7552
8227
|
var PYTHON_BINARIES = ["python3", "pip3"];
|
|
7553
8228
|
var PipInstaller = class extends Installer {
|
|
@@ -7811,7 +8486,7 @@ function soul() {
|
|
|
7811
8486
|
}
|
|
7812
8487
|
|
|
7813
8488
|
// packages/context/src/lib/store/postgres.store.ts
|
|
7814
|
-
import { createRequire } from "node:module";
|
|
8489
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
7815
8490
|
|
|
7816
8491
|
// packages/context/src/lib/store/ddl.postgres.ts
|
|
7817
8492
|
function storeDDL(schema) {
|
|
@@ -7923,7 +8598,7 @@ var PostgresContextStore = class _PostgresContextStore extends ContextStore {
|
|
|
7923
8598
|
}
|
|
7924
8599
|
static #requirePg() {
|
|
7925
8600
|
try {
|
|
7926
|
-
const require2 =
|
|
8601
|
+
const require2 = createRequire2(import.meta.url);
|
|
7927
8602
|
return require2("pg");
|
|
7928
8603
|
} catch {
|
|
7929
8604
|
throw new Error(
|
|
@@ -8519,7 +9194,7 @@ var PostgresContextStore = class _PostgresContextStore extends ContextStore {
|
|
|
8519
9194
|
};
|
|
8520
9195
|
|
|
8521
9196
|
// packages/context/src/lib/store/sqlserver.store.ts
|
|
8522
|
-
import { createRequire as
|
|
9197
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
8523
9198
|
|
|
8524
9199
|
// packages/context/src/lib/store/ddl.sqlserver.ts
|
|
8525
9200
|
function storeDDL2(schema) {
|
|
@@ -8661,7 +9336,7 @@ var SqlServerContextStore = class _SqlServerContextStore extends ContextStore {
|
|
|
8661
9336
|
}
|
|
8662
9337
|
static #requireMssql() {
|
|
8663
9338
|
try {
|
|
8664
|
-
const require2 =
|
|
9339
|
+
const require2 = createRequire3(import.meta.url);
|
|
8665
9340
|
return require2("mssql");
|
|
8666
9341
|
} catch {
|
|
8667
9342
|
throw new Error(
|
|
@@ -9371,11 +10046,12 @@ async function persistedWriter(options) {
|
|
|
9371
10046
|
} = options;
|
|
9372
10047
|
let seq = 0;
|
|
9373
10048
|
let buffer = [];
|
|
10049
|
+
let failedByErrorChunk = false;
|
|
9374
10050
|
async function flush() {
|
|
9375
10051
|
if (buffer.length === 0) return;
|
|
9376
10052
|
const batch = buffer;
|
|
9377
10053
|
buffer = [];
|
|
9378
|
-
await
|
|
10054
|
+
await appendBatch(batch);
|
|
9379
10055
|
}
|
|
9380
10056
|
function makeChunk(part) {
|
|
9381
10057
|
return {
|
|
@@ -9385,9 +10061,19 @@ async function persistedWriter(options) {
|
|
|
9385
10061
|
createdAt: Date.now()
|
|
9386
10062
|
};
|
|
9387
10063
|
}
|
|
10064
|
+
function isStreamErrorPart(part) {
|
|
10065
|
+
return part.type === "error";
|
|
10066
|
+
}
|
|
10067
|
+
async function appendBatch(batch) {
|
|
10068
|
+
const hasErrorPart = !failedByErrorChunk && batch.map((chunk) => chunk.data).some(isStreamErrorPart);
|
|
10069
|
+
await store2.appendChunks(batch);
|
|
10070
|
+
if (hasErrorPart) {
|
|
10071
|
+
failedByErrorChunk = true;
|
|
10072
|
+
}
|
|
10073
|
+
}
|
|
9388
10074
|
async function persistChunk(chunk) {
|
|
9389
10075
|
if (strategy === "immediate") {
|
|
9390
|
-
await
|
|
10076
|
+
await appendBatch([chunk]);
|
|
9391
10077
|
} else {
|
|
9392
10078
|
buffer.push(chunk);
|
|
9393
10079
|
if (buffer.length >= flushSize) {
|
|
@@ -9417,10 +10103,12 @@ async function persistedWriter(options) {
|
|
|
9417
10103
|
flush,
|
|
9418
10104
|
async complete() {
|
|
9419
10105
|
await flush();
|
|
10106
|
+
if (failedByErrorChunk) return;
|
|
9420
10107
|
await store2.updateStreamStatus(streamId, "completed");
|
|
9421
10108
|
},
|
|
9422
10109
|
async fail(error) {
|
|
9423
10110
|
await flush();
|
|
10111
|
+
if (failedByErrorChunk) return;
|
|
9424
10112
|
await store2.updateStreamStatus(streamId, "failed", { error });
|
|
9425
10113
|
},
|
|
9426
10114
|
async cleanup() {
|
|
@@ -9430,7 +10118,7 @@ async function persistedWriter(options) {
|
|
|
9430
10118
|
}
|
|
9431
10119
|
|
|
9432
10120
|
// packages/context/src/lib/stream/polling-change-source.ts
|
|
9433
|
-
import { setTimeout as
|
|
10121
|
+
import { setTimeout as delay2 } from "node:timers/promises";
|
|
9434
10122
|
|
|
9435
10123
|
// packages/context/src/lib/stream/polling-policy.ts
|
|
9436
10124
|
var DEFAULT_WATCH_POLLING = {
|
|
@@ -9475,7 +10163,7 @@ function nextAdaptivePollingDelay(state) {
|
|
|
9475
10163
|
state.config.minMs,
|
|
9476
10164
|
state.config.maxMs
|
|
9477
10165
|
);
|
|
9478
|
-
const
|
|
10166
|
+
const delay3 = applyJitter(
|
|
9479
10167
|
current,
|
|
9480
10168
|
state.config.jitterRatio,
|
|
9481
10169
|
state.config.minMs,
|
|
@@ -9486,7 +10174,7 @@ function nextAdaptivePollingDelay(state) {
|
|
|
9486
10174
|
state.config.minMs,
|
|
9487
10175
|
state.config.maxMs
|
|
9488
10176
|
);
|
|
9489
|
-
return
|
|
10177
|
+
return delay3;
|
|
9490
10178
|
}
|
|
9491
10179
|
function normalizeAdaptivePolling(polling, fallback) {
|
|
9492
10180
|
const merged = {
|
|
@@ -9586,7 +10274,7 @@ function isTerminal(status) {
|
|
|
9586
10274
|
return status !== "queued" && status !== "running";
|
|
9587
10275
|
}
|
|
9588
10276
|
function waitForDelay(ms, signal) {
|
|
9589
|
-
return
|
|
10277
|
+
return delay2(ms, true, { signal }).catch((err) => {
|
|
9590
10278
|
if (signal.aborted) return false;
|
|
9591
10279
|
throw err;
|
|
9592
10280
|
});
|
|
@@ -9638,7 +10326,7 @@ function asStaticWordPartText(parts, options = {}) {
|
|
|
9638
10326
|
}
|
|
9639
10327
|
|
|
9640
10328
|
// packages/context/src/lib/stream/postgres-notify-change-source.ts
|
|
9641
|
-
import { createRequire as
|
|
10329
|
+
import { createRequire as createRequire4 } from "node:module";
|
|
9642
10330
|
|
|
9643
10331
|
// packages/context/src/lib/stream/ddl.stream.postgres-notify.ts
|
|
9644
10332
|
var DEFAULT_POSTGRES_STREAM_CHANGES_CHANNEL = "deepagents_stream_changes";
|
|
@@ -9740,7 +10428,7 @@ var PostgresNotifyChangeSource = class _PostgresNotifyChangeSource {
|
|
|
9740
10428
|
}
|
|
9741
10429
|
static #requirePg() {
|
|
9742
10430
|
try {
|
|
9743
|
-
const require2 =
|
|
10431
|
+
const require2 = createRequire4(import.meta.url);
|
|
9744
10432
|
return require2("pg");
|
|
9745
10433
|
} catch {
|
|
9746
10434
|
throw new Error(
|
|
@@ -9995,7 +10683,7 @@ function assertIdentifier(value, label) {
|
|
|
9995
10683
|
}
|
|
9996
10684
|
|
|
9997
10685
|
// packages/context/src/lib/stream/postgres.stream-store.ts
|
|
9998
|
-
import { createRequire as
|
|
10686
|
+
import { createRequire as createRequire5 } from "node:module";
|
|
9999
10687
|
|
|
10000
10688
|
// packages/context/src/lib/stream/ddl.stream.postgres.ts
|
|
10001
10689
|
function postgresStreamDDL(schema) {
|
|
@@ -10031,6 +10719,15 @@ CREATE INDEX IF NOT EXISTS "idx_${schema}_streams_status_created_at_id"
|
|
|
10031
10719
|
}
|
|
10032
10720
|
|
|
10033
10721
|
// packages/context/src/lib/stream/stream-store.ts
|
|
10722
|
+
function collectStreamFailures(chunks) {
|
|
10723
|
+
const failures = /* @__PURE__ */ new Map();
|
|
10724
|
+
for (const chunk of chunks) {
|
|
10725
|
+
if (chunk.data.type === "error" && !failures.has(chunk.streamId)) {
|
|
10726
|
+
failures.set(chunk.streamId, chunk.data.errorText);
|
|
10727
|
+
}
|
|
10728
|
+
}
|
|
10729
|
+
return [...failures].map(([streamId, error]) => ({ streamId, error }));
|
|
10730
|
+
}
|
|
10034
10731
|
var StreamStore = class {
|
|
10035
10732
|
async listRunningStreamIds() {
|
|
10036
10733
|
return this.listStreamIds({ status: "running" });
|
|
@@ -10060,7 +10757,7 @@ var PostgresStreamStore = class _PostgresStreamStore extends StreamStore {
|
|
|
10060
10757
|
}
|
|
10061
10758
|
static #requirePg() {
|
|
10062
10759
|
try {
|
|
10063
|
-
const require2 =
|
|
10760
|
+
const require2 = createRequire5(import.meta.url);
|
|
10064
10761
|
return require2("pg");
|
|
10065
10762
|
} catch {
|
|
10066
10763
|
throw new Error(
|
|
@@ -10214,13 +10911,31 @@ var PostgresStreamStore = class _PostgresStreamStore extends StreamStore {
|
|
|
10214
10911
|
data: chunk.data,
|
|
10215
10912
|
created_at: chunk.createdAt
|
|
10216
10913
|
}));
|
|
10217
|
-
|
|
10218
|
-
|
|
10914
|
+
const params = [JSON.stringify(rows)];
|
|
10915
|
+
const insertSql = `INSERT INTO ${this.#t("stream_chunks")} (stream_id, seq, data, created_at)
|
|
10219
10916
|
SELECT stream_id, seq, data, created_at
|
|
10220
10917
|
FROM jsonb_to_recordset($1::jsonb)
|
|
10221
|
-
AS rows(stream_id TEXT, seq INTEGER, data JSONB, created_at BIGINT)
|
|
10222
|
-
|
|
10223
|
-
)
|
|
10918
|
+
AS rows(stream_id TEXT, seq INTEGER, data JSONB, created_at BIGINT)`;
|
|
10919
|
+
const failures = collectStreamFailures(chunks);
|
|
10920
|
+
if (failures.length === 0) {
|
|
10921
|
+
await this.#query(insertSql, params);
|
|
10922
|
+
return;
|
|
10923
|
+
}
|
|
10924
|
+
await this.#useTransaction(async (client) => {
|
|
10925
|
+
await client.query(insertSql, params);
|
|
10926
|
+
const failedAt = Date.now();
|
|
10927
|
+
for (const failure of failures) {
|
|
10928
|
+
const result = await client.query(
|
|
10929
|
+
`UPDATE ${this.#t("streams")}
|
|
10930
|
+
SET status = $1, finished_at = $2, error = $3
|
|
10931
|
+
WHERE id = $4`,
|
|
10932
|
+
["failed", failedAt, failure.error, failure.streamId]
|
|
10933
|
+
);
|
|
10934
|
+
if (result.rowCount !== 1) {
|
|
10935
|
+
throw new Error(`Stream "${failure.streamId}" not found`);
|
|
10936
|
+
}
|
|
10937
|
+
}
|
|
10938
|
+
});
|
|
10224
10939
|
}
|
|
10225
10940
|
async getChunks(streamId, fromSeq, limit) {
|
|
10226
10941
|
const params = [streamId];
|
|
@@ -10467,6 +11182,7 @@ var SqliteStreamStore = class extends StreamStore {
|
|
|
10467
11182
|
}
|
|
10468
11183
|
async appendChunks(chunks) {
|
|
10469
11184
|
if (chunks.length === 0) return;
|
|
11185
|
+
const failures = collectStreamFailures(chunks);
|
|
10470
11186
|
this.#db.exec("BEGIN TRANSACTION");
|
|
10471
11187
|
try {
|
|
10472
11188
|
for (const chunk of chunks) {
|
|
@@ -10480,6 +11196,15 @@ var SqliteStreamStore = class extends StreamStore {
|
|
|
10480
11196
|
chunk.createdAt
|
|
10481
11197
|
);
|
|
10482
11198
|
}
|
|
11199
|
+
const failedAt = Date.now();
|
|
11200
|
+
for (const failure of failures) {
|
|
11201
|
+
const result = this.#stmt(
|
|
11202
|
+
"UPDATE streams SET status = ?, finishedAt = ?, error = ? WHERE id = ?"
|
|
11203
|
+
).run("failed", failedAt, failure.error, failure.streamId);
|
|
11204
|
+
if (result.changes !== 1) {
|
|
11205
|
+
throw new Error(`Stream "${failure.streamId}" not found`);
|
|
11206
|
+
}
|
|
11207
|
+
}
|
|
10483
11208
|
this.#db.exec("COMMIT");
|
|
10484
11209
|
} catch (error) {
|
|
10485
11210
|
this.#db.exec("ROLLBACK");
|
|
@@ -10881,14 +11606,20 @@ export {
|
|
|
10881
11606
|
AsyncResolver,
|
|
10882
11607
|
BM25Classifier,
|
|
10883
11608
|
BashException,
|
|
11609
|
+
BinInstaller,
|
|
10884
11610
|
ComposeStartError,
|
|
10885
11611
|
ComposeStrategy,
|
|
10886
11612
|
ContainerCreationError,
|
|
10887
11613
|
ContextEngine,
|
|
10888
11614
|
ContextRenderer,
|
|
10889
11615
|
ContextStore,
|
|
11616
|
+
DAYTONA_DEFAULT_DESTINATION,
|
|
10890
11617
|
DEFAULT_CANCEL_POLLING,
|
|
10891
11618
|
DEFAULT_WATCH_POLLING,
|
|
11619
|
+
DaytonaCommandError,
|
|
11620
|
+
DaytonaCreationError,
|
|
11621
|
+
DaytonaNotAvailableError,
|
|
11622
|
+
DaytonaSandboxError,
|
|
10892
11623
|
DockerNotAvailableError,
|
|
10893
11624
|
DockerSandboxError,
|
|
10894
11625
|
DockerSandboxStrategy,
|
|
@@ -10950,11 +11681,13 @@ export {
|
|
|
10950
11681
|
assertCountSpec,
|
|
10951
11682
|
assistant,
|
|
10952
11683
|
assistantText,
|
|
11684
|
+
bin,
|
|
10953
11685
|
buildSubcommandRepair,
|
|
10954
11686
|
chat,
|
|
10955
11687
|
checkCount,
|
|
10956
11688
|
clarification,
|
|
10957
11689
|
classifies,
|
|
11690
|
+
collectStreamFailures,
|
|
10958
11691
|
contentIncludes,
|
|
10959
11692
|
contentMatches,
|
|
10960
11693
|
contentPattern,
|
|
@@ -10963,7 +11696,7 @@ export {
|
|
|
10963
11696
|
createAgentOsSandbox,
|
|
10964
11697
|
createBashTool,
|
|
10965
11698
|
createBinaryBridges,
|
|
10966
|
-
|
|
11699
|
+
createDaytonaSandbox,
|
|
10967
11700
|
createDockerSandbox,
|
|
10968
11701
|
createInstallerContext,
|
|
10969
11702
|
createRepairToolCall,
|
|
@@ -11054,7 +11787,7 @@ export {
|
|
|
11054
11787
|
seasonChanged,
|
|
11055
11788
|
seasonReminder,
|
|
11056
11789
|
selfCritique,
|
|
11057
|
-
|
|
11790
|
+
shellQuote3 as shellQuote,
|
|
11058
11791
|
skills,
|
|
11059
11792
|
skillsReminder,
|
|
11060
11793
|
socraticPrompting,
|