@sandagent/manager 0.1.0-beta.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 +191 -0
- package/dist/__tests__/sand-agent.test.d.ts +2 -0
- package/dist/__tests__/sand-agent.test.d.ts.map +1 -0
- package/dist/__tests__/sand-agent.test.js +284 -0
- package/dist/__tests__/sand-agent.test.js.map +1 -0
- package/dist/__tests__/signal-integration.test.d.ts +2 -0
- package/dist/__tests__/signal-integration.test.d.ts.map +1 -0
- package/dist/__tests__/signal-integration.test.js +136 -0
- package/dist/__tests__/signal-integration.test.js.map +1 -0
- package/dist/__tests__/transcript.test.d.ts +2 -0
- package/dist/__tests__/transcript.test.d.ts.map +1 -0
- package/dist/__tests__/transcript.test.js +144 -0
- package/dist/__tests__/transcript.test.js.map +1 -0
- package/dist/__tests__/types.test.d.ts +2 -0
- package/dist/__tests__/types.test.d.ts.map +1 -0
- package/dist/__tests__/types.test.js +148 -0
- package/dist/__tests__/types.test.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/sand-agent.d.ts +50 -0
- package/dist/sand-agent.d.ts.map +1 -0
- package/dist/sand-agent.js +187 -0
- package/dist/sand-agent.js.map +1 -0
- package/dist/transcript.d.ts +112 -0
- package/dist/transcript.d.ts.map +1 -0
- package/dist/transcript.js +176 -0
- package/dist/transcript.js.map +1 -0
- package/dist/types.d.ts +175 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { ConsoleTranscriptWriter, MemoryTranscriptWriter, MultiTranscriptWriter, } from "../transcript.js";
|
|
3
|
+
describe("Transcript Writers", () => {
|
|
4
|
+
describe("MemoryTranscriptWriter", () => {
|
|
5
|
+
let writer;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
writer = new MemoryTranscriptWriter();
|
|
8
|
+
});
|
|
9
|
+
it("should store entries in memory", () => {
|
|
10
|
+
const entry = {
|
|
11
|
+
timestamp: new Date().toISOString(),
|
|
12
|
+
type: "chunk",
|
|
13
|
+
text: "Hello, world!",
|
|
14
|
+
};
|
|
15
|
+
writer.write(entry);
|
|
16
|
+
const entries = writer.getEntries();
|
|
17
|
+
expect(entries).toHaveLength(1);
|
|
18
|
+
expect(entries[0]).toEqual(entry);
|
|
19
|
+
});
|
|
20
|
+
it("should return chunks as strings", () => {
|
|
21
|
+
writer.write({
|
|
22
|
+
timestamp: new Date().toISOString(),
|
|
23
|
+
type: "chunk",
|
|
24
|
+
text: "Hello, ",
|
|
25
|
+
});
|
|
26
|
+
writer.write({
|
|
27
|
+
timestamp: new Date().toISOString(),
|
|
28
|
+
type: "chunk",
|
|
29
|
+
text: "world!",
|
|
30
|
+
});
|
|
31
|
+
expect(writer.getChunks()).toEqual(["Hello, ", "world!"]);
|
|
32
|
+
});
|
|
33
|
+
it("should return full output as single string", () => {
|
|
34
|
+
writer.write({
|
|
35
|
+
timestamp: new Date().toISOString(),
|
|
36
|
+
type: "chunk",
|
|
37
|
+
text: "Hello, ",
|
|
38
|
+
});
|
|
39
|
+
writer.write({
|
|
40
|
+
timestamp: new Date().toISOString(),
|
|
41
|
+
type: "chunk",
|
|
42
|
+
text: "world!",
|
|
43
|
+
});
|
|
44
|
+
expect(writer.getFullOutput()).toBe("Hello, world!");
|
|
45
|
+
});
|
|
46
|
+
it("should generate valid JSONL output", () => {
|
|
47
|
+
writer.write({
|
|
48
|
+
timestamp: "2024-01-01T00:00:00.000Z",
|
|
49
|
+
type: "start",
|
|
50
|
+
});
|
|
51
|
+
writer.write({
|
|
52
|
+
timestamp: "2024-01-01T00:00:01.000Z",
|
|
53
|
+
type: "chunk",
|
|
54
|
+
text: "test",
|
|
55
|
+
});
|
|
56
|
+
const jsonl = writer.toJsonl();
|
|
57
|
+
const lines = jsonl.trim().split("\n");
|
|
58
|
+
expect(lines).toHaveLength(2);
|
|
59
|
+
const parsed0 = JSON.parse(lines[0]);
|
|
60
|
+
expect(parsed0.type).toBe("start");
|
|
61
|
+
const parsed1 = JSON.parse(lines[1]);
|
|
62
|
+
expect(parsed1.type).toBe("chunk");
|
|
63
|
+
expect(parsed1.text).toBe("test");
|
|
64
|
+
});
|
|
65
|
+
it("should clear all entries", () => {
|
|
66
|
+
writer.write({
|
|
67
|
+
timestamp: new Date().toISOString(),
|
|
68
|
+
type: "chunk",
|
|
69
|
+
text: "test",
|
|
70
|
+
});
|
|
71
|
+
expect(writer.getEntries()).toHaveLength(1);
|
|
72
|
+
writer.clear();
|
|
73
|
+
expect(writer.getEntries()).toHaveLength(0);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe("ConsoleTranscriptWriter", () => {
|
|
77
|
+
it("should write to console", () => {
|
|
78
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
79
|
+
const writer = new ConsoleTranscriptWriter();
|
|
80
|
+
writer.write({
|
|
81
|
+
timestamp: "2024-01-01T00:00:00.000Z",
|
|
82
|
+
type: "chunk",
|
|
83
|
+
text: "Hello",
|
|
84
|
+
});
|
|
85
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
86
|
+
const call = consoleSpy.mock.calls[0][0];
|
|
87
|
+
expect(call).toContain("[Transcript]");
|
|
88
|
+
expect(call).toContain("CHUNK");
|
|
89
|
+
expect(call).toContain("Hello");
|
|
90
|
+
consoleSpy.mockRestore();
|
|
91
|
+
});
|
|
92
|
+
it("should use custom prefix", () => {
|
|
93
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
94
|
+
const writer = new ConsoleTranscriptWriter("[TEST]");
|
|
95
|
+
writer.write({
|
|
96
|
+
timestamp: "2024-01-01T00:00:00.000Z",
|
|
97
|
+
type: "start",
|
|
98
|
+
});
|
|
99
|
+
const call = consoleSpy.mock.calls[0][0];
|
|
100
|
+
expect(call).toContain("[TEST]");
|
|
101
|
+
consoleSpy.mockRestore();
|
|
102
|
+
});
|
|
103
|
+
it("should log errors to console.error", () => {
|
|
104
|
+
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
105
|
+
const writer = new ConsoleTranscriptWriter();
|
|
106
|
+
writer.write({
|
|
107
|
+
timestamp: "2024-01-01T00:00:00.000Z",
|
|
108
|
+
type: "error",
|
|
109
|
+
text: "Something went wrong",
|
|
110
|
+
});
|
|
111
|
+
expect(errorSpy).toHaveBeenCalled();
|
|
112
|
+
const call = errorSpy.mock.calls[0][0];
|
|
113
|
+
expect(call).toContain("ERROR");
|
|
114
|
+
expect(call).toContain("Something went wrong");
|
|
115
|
+
errorSpy.mockRestore();
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
describe("MultiTranscriptWriter", () => {
|
|
119
|
+
it("should write to multiple writers", async () => {
|
|
120
|
+
const writer1 = new MemoryTranscriptWriter();
|
|
121
|
+
const writer2 = new MemoryTranscriptWriter();
|
|
122
|
+
const multiWriter = new MultiTranscriptWriter([writer1, writer2]);
|
|
123
|
+
const entry = {
|
|
124
|
+
timestamp: new Date().toISOString(),
|
|
125
|
+
type: "chunk",
|
|
126
|
+
text: "test",
|
|
127
|
+
};
|
|
128
|
+
await multiWriter.write(entry);
|
|
129
|
+
expect(writer1.getEntries()).toHaveLength(1);
|
|
130
|
+
expect(writer2.getEntries()).toHaveLength(1);
|
|
131
|
+
expect(writer1.getEntries()[0]).toEqual(entry);
|
|
132
|
+
expect(writer2.getEntries()[0]).toEqual(entry);
|
|
133
|
+
});
|
|
134
|
+
it("should close all writers", async () => {
|
|
135
|
+
const closeFn = vi.fn();
|
|
136
|
+
const writer1 = { write: vi.fn(), close: closeFn };
|
|
137
|
+
const writer2 = { write: vi.fn(), close: closeFn };
|
|
138
|
+
const multiWriter = new MultiTranscriptWriter([writer1, writer2]);
|
|
139
|
+
await multiWriter.close();
|
|
140
|
+
expect(closeFn).toHaveBeenCalledTimes(2);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
//# sourceMappingURL=transcript.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcript.test.js","sourceRoot":"","sources":["../../src/__tests__/transcript.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/types.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
describe("Type Definitions", () => {
|
|
3
|
+
describe("ExecOptions", () => {
|
|
4
|
+
it("should accept signal parameter", () => {
|
|
5
|
+
const controller = new AbortController();
|
|
6
|
+
const options = {
|
|
7
|
+
signal: controller.signal,
|
|
8
|
+
};
|
|
9
|
+
expect(options.signal).toBeDefined();
|
|
10
|
+
expect(options.signal).toBe(controller.signal);
|
|
11
|
+
});
|
|
12
|
+
it("should accept signal with other options", () => {
|
|
13
|
+
const controller = new AbortController();
|
|
14
|
+
const options = {
|
|
15
|
+
cwd: "/workspace",
|
|
16
|
+
env: { NODE_ENV: "test" },
|
|
17
|
+
timeout: 5000,
|
|
18
|
+
signal: controller.signal,
|
|
19
|
+
};
|
|
20
|
+
expect(options.signal).toBe(controller.signal);
|
|
21
|
+
expect(options.cwd).toBe("/workspace");
|
|
22
|
+
expect(options.env).toEqual({ NODE_ENV: "test" });
|
|
23
|
+
expect(options.timeout).toBe(5000);
|
|
24
|
+
});
|
|
25
|
+
it("should allow signal to be undefined", () => {
|
|
26
|
+
const options = {
|
|
27
|
+
cwd: "/workspace",
|
|
28
|
+
};
|
|
29
|
+
expect(options.signal).toBeUndefined();
|
|
30
|
+
});
|
|
31
|
+
it("should allow empty options object", () => {
|
|
32
|
+
const options = {};
|
|
33
|
+
expect(options.signal).toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("StreamInput", () => {
|
|
37
|
+
it("should accept signal parameter", () => {
|
|
38
|
+
const controller = new AbortController();
|
|
39
|
+
const input = {
|
|
40
|
+
messages: [{ role: "user", content: "Hello" }],
|
|
41
|
+
signal: controller.signal,
|
|
42
|
+
};
|
|
43
|
+
expect(input.signal).toBeDefined();
|
|
44
|
+
expect(input.signal).toBe(controller.signal);
|
|
45
|
+
});
|
|
46
|
+
it("should accept signal with other options", () => {
|
|
47
|
+
const controller = new AbortController();
|
|
48
|
+
const input = {
|
|
49
|
+
messages: [{ role: "user", content: "Hello" }],
|
|
50
|
+
workspace: { path: "/workspace" },
|
|
51
|
+
contentType: "text/event-stream",
|
|
52
|
+
resume: "session-123",
|
|
53
|
+
signal: controller.signal,
|
|
54
|
+
};
|
|
55
|
+
expect(input.signal).toBe(controller.signal);
|
|
56
|
+
expect(input.workspace?.path).toBe("/workspace");
|
|
57
|
+
expect(input.contentType).toBe("text/event-stream");
|
|
58
|
+
expect(input.resume).toBe("session-123");
|
|
59
|
+
});
|
|
60
|
+
it("should allow signal to be undefined", () => {
|
|
61
|
+
const input = {
|
|
62
|
+
messages: [{ role: "user", content: "Hello" }],
|
|
63
|
+
};
|
|
64
|
+
expect(input.signal).toBeUndefined();
|
|
65
|
+
});
|
|
66
|
+
it("should require messages even with signal", () => {
|
|
67
|
+
const controller = new AbortController();
|
|
68
|
+
const input = {
|
|
69
|
+
messages: [],
|
|
70
|
+
signal: controller.signal,
|
|
71
|
+
};
|
|
72
|
+
expect(input.messages).toEqual([]);
|
|
73
|
+
expect(input.signal).toBe(controller.signal);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe("Signal Type Inference", () => {
|
|
77
|
+
it("should infer AbortSignal type correctly", () => {
|
|
78
|
+
const controller = new AbortController();
|
|
79
|
+
const options = {
|
|
80
|
+
signal: controller.signal,
|
|
81
|
+
};
|
|
82
|
+
// TypeScript should infer the type correctly
|
|
83
|
+
const signal = options.signal;
|
|
84
|
+
expect(signal).toBe(controller.signal);
|
|
85
|
+
});
|
|
86
|
+
it("should allow AbortSignal methods to be called", () => {
|
|
87
|
+
const controller = new AbortController();
|
|
88
|
+
const options = {
|
|
89
|
+
signal: controller.signal,
|
|
90
|
+
};
|
|
91
|
+
if (options.signal) {
|
|
92
|
+
// These should compile without errors
|
|
93
|
+
expect(typeof options.signal.aborted).toBe("boolean");
|
|
94
|
+
expect(typeof options.signal.addEventListener).toBe("function");
|
|
95
|
+
expect(typeof options.signal.removeEventListener).toBe("function");
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
it("should handle pre-aborted signal", () => {
|
|
99
|
+
const controller = new AbortController();
|
|
100
|
+
controller.abort();
|
|
101
|
+
const options = {
|
|
102
|
+
signal: controller.signal,
|
|
103
|
+
};
|
|
104
|
+
expect(options.signal?.aborted).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
it("should handle signal abort event", () => {
|
|
107
|
+
const controller = new AbortController();
|
|
108
|
+
const options = {
|
|
109
|
+
signal: controller.signal,
|
|
110
|
+
};
|
|
111
|
+
let aborted = false;
|
|
112
|
+
options.signal?.addEventListener("abort", () => {
|
|
113
|
+
aborted = true;
|
|
114
|
+
});
|
|
115
|
+
controller.abort();
|
|
116
|
+
expect(aborted).toBe(true);
|
|
117
|
+
expect(options.signal?.aborted).toBe(true);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe("Type Compatibility", () => {
|
|
121
|
+
it("should accept signal from Request object", () => {
|
|
122
|
+
// Simulate a Request object's signal
|
|
123
|
+
const controller = new AbortController();
|
|
124
|
+
const mockRequest = {
|
|
125
|
+
signal: controller.signal,
|
|
126
|
+
};
|
|
127
|
+
const input = {
|
|
128
|
+
messages: [{ role: "user", content: "Hello" }],
|
|
129
|
+
signal: mockRequest.signal,
|
|
130
|
+
};
|
|
131
|
+
expect(input.signal).toBe(mockRequest.signal);
|
|
132
|
+
});
|
|
133
|
+
it("should work with signal passed through multiple layers", () => {
|
|
134
|
+
const controller = new AbortController();
|
|
135
|
+
// Simulate passing signal through layers
|
|
136
|
+
const streamInput = {
|
|
137
|
+
messages: [{ role: "user", content: "Hello" }],
|
|
138
|
+
signal: controller.signal,
|
|
139
|
+
};
|
|
140
|
+
const execOptions = {
|
|
141
|
+
signal: streamInput.signal,
|
|
142
|
+
};
|
|
143
|
+
expect(execOptions.signal).toBe(controller.signal);
|
|
144
|
+
expect(streamInput.signal).toBe(controller.signal);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
//# sourceMappingURL=types.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.test.js","sourceRoot":"","sources":["../../src/__tests__/types.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { SandAgent } from "./sand-agent.js";
|
|
2
|
+
export { JsonlTranscriptWriter, MemoryTranscriptWriter, ConsoleTranscriptWriter, MultiTranscriptWriter, } from "./transcript.js";
|
|
3
|
+
export type { SandAgentOptions, SandboxAdapter, SandboxHandle, RunnerSpec, StreamInput, Message, ExecOptions, TranscriptWriter, TranscriptEntry, } from "./types.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,UAAU,EACV,WAAW,EACX,OAAO,EACP,WAAW,EACX,gBAAgB,EAChB,eAAe,GAChB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { SandAgentOptions, StreamInput } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* SandAgent - A sandboxed agent runtime that speaks AI SDK UI natively.
|
|
4
|
+
*
|
|
5
|
+
* Represents one persistent agent instance with:
|
|
6
|
+
* - An isolated sandbox
|
|
7
|
+
* - A dedicated filesystem volume
|
|
8
|
+
* - Direct passthrough of AI SDK UI messages
|
|
9
|
+
*/
|
|
10
|
+
export declare class SandAgent {
|
|
11
|
+
private readonly sandbox;
|
|
12
|
+
private readonly runner;
|
|
13
|
+
private readonly env;
|
|
14
|
+
private handle;
|
|
15
|
+
constructor(options: SandAgentOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Attach to the sandbox if not already attached
|
|
18
|
+
*/
|
|
19
|
+
private ensureAttached;
|
|
20
|
+
/**
|
|
21
|
+
* Build the CLI command to execute
|
|
22
|
+
*/
|
|
23
|
+
private buildCommand;
|
|
24
|
+
/**
|
|
25
|
+
* Stream a task through the agent.
|
|
26
|
+
*
|
|
27
|
+
* This method:
|
|
28
|
+
* 1. Attaches to the sandbox
|
|
29
|
+
* 2. Executes the CLI runner inside the sandbox
|
|
30
|
+
* 3. Returns a ReadableStream of AI SDK UI messages from stdout
|
|
31
|
+
*
|
|
32
|
+
* The server NEVER parses or modifies the stream.
|
|
33
|
+
*
|
|
34
|
+
* @param input - Stream input including messages and optional transcript writer
|
|
35
|
+
* @returns ReadableStream of AI SDK UI messages
|
|
36
|
+
*/
|
|
37
|
+
stream(input: StreamInput): Promise<ReadableStream<Uint8Array>>;
|
|
38
|
+
/**
|
|
39
|
+
* Upload files to the agent's workspace
|
|
40
|
+
*/
|
|
41
|
+
uploadFiles(files: Array<{
|
|
42
|
+
path: string;
|
|
43
|
+
content: Uint8Array | string;
|
|
44
|
+
}>, targetDir?: string): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Destroy the sandbox and release resources
|
|
47
|
+
*/
|
|
48
|
+
destroy(): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=sand-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sand-agent.d.ts","sourceRoot":"","sources":["../src/sand-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,gBAAgB,EAGhB,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB;;;;;;;GAOG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAyB;IAC7C,OAAO,CAAC,MAAM,CAA8B;gBAEhC,OAAO,EAAE,gBAAgB;IAMrC;;OAEG;YACW,cAAc;IAO5B;;OAEG;IACH,OAAO,CAAC,YAAY;IAwDpB;;;;;;;;;;;;OAYG;IACG,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IA8FrE;;OAEG;IACG,WAAW,CACf,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAAA;KAAE,CAAC,EAC5D,SAAS,SAAe,GACvB,OAAO,CAAC,IAAI,CAAC;IAKhB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAM/B"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SandAgent - A sandboxed agent runtime that speaks AI SDK UI natively.
|
|
3
|
+
*
|
|
4
|
+
* Represents one persistent agent instance with:
|
|
5
|
+
* - An isolated sandbox
|
|
6
|
+
* - A dedicated filesystem volume
|
|
7
|
+
* - Direct passthrough of AI SDK UI messages
|
|
8
|
+
*/
|
|
9
|
+
export class SandAgent {
|
|
10
|
+
sandbox;
|
|
11
|
+
runner;
|
|
12
|
+
env;
|
|
13
|
+
handle = null;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.sandbox = options.sandbox;
|
|
16
|
+
this.runner = options.runner;
|
|
17
|
+
this.env = options.env ?? {};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Attach to the sandbox if not already attached
|
|
21
|
+
*/
|
|
22
|
+
async ensureAttached() {
|
|
23
|
+
if (!this.handle) {
|
|
24
|
+
this.handle = await this.sandbox.attach();
|
|
25
|
+
}
|
|
26
|
+
return this.handle;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build the CLI command to execute
|
|
30
|
+
*/
|
|
31
|
+
buildCommand(input) {
|
|
32
|
+
// Get runner command from sandbox, or use default "sandagent run"
|
|
33
|
+
const cmd = this.sandbox.getRunnerCommand?.() ?? ["sandagent", "run"];
|
|
34
|
+
// Add model
|
|
35
|
+
cmd.push("--model", this.runner.model);
|
|
36
|
+
// Add workspace path
|
|
37
|
+
const workspacePath = input.workspace?.path ?? "/workspace";
|
|
38
|
+
cmd.push("--cwd", workspacePath);
|
|
39
|
+
// Add optional system prompt
|
|
40
|
+
if (this.runner.systemPrompt) {
|
|
41
|
+
cmd.push("--system-prompt", this.runner.systemPrompt);
|
|
42
|
+
}
|
|
43
|
+
// Add optional max turns
|
|
44
|
+
if (this.runner.maxTurns !== undefined) {
|
|
45
|
+
cmd.push("--max-turns", String(this.runner.maxTurns));
|
|
46
|
+
}
|
|
47
|
+
// Add optional allowed tools
|
|
48
|
+
if (this.runner.allowedTools) {
|
|
49
|
+
cmd.push("--allowed-tools", this.runner.allowedTools.join(","));
|
|
50
|
+
}
|
|
51
|
+
// Add resume parameter for multi-turn conversation
|
|
52
|
+
if (input.resume) {
|
|
53
|
+
cmd.push("--resume", input.resume);
|
|
54
|
+
}
|
|
55
|
+
// Add approvalDir for tool approval flow
|
|
56
|
+
if (this.runner.approvalDir) {
|
|
57
|
+
cmd.push("--approval-dir", this.runner.approvalDir);
|
|
58
|
+
}
|
|
59
|
+
// Add output format
|
|
60
|
+
if (this.runner.outputFormat) {
|
|
61
|
+
cmd.push("--output-format", this.runner.outputFormat);
|
|
62
|
+
}
|
|
63
|
+
// Add separator and user input
|
|
64
|
+
cmd.push("--");
|
|
65
|
+
// Get the last user message as input
|
|
66
|
+
const lastUserMessage = input.messages
|
|
67
|
+
.filter((m) => m.role === "user")
|
|
68
|
+
.pop();
|
|
69
|
+
if (lastUserMessage) {
|
|
70
|
+
cmd.push(lastUserMessage.content);
|
|
71
|
+
}
|
|
72
|
+
return cmd;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Stream a task through the agent.
|
|
76
|
+
*
|
|
77
|
+
* This method:
|
|
78
|
+
* 1. Attaches to the sandbox
|
|
79
|
+
* 2. Executes the CLI runner inside the sandbox
|
|
80
|
+
* 3. Returns a ReadableStream of AI SDK UI messages from stdout
|
|
81
|
+
*
|
|
82
|
+
* The server NEVER parses or modifies the stream.
|
|
83
|
+
*
|
|
84
|
+
* @param input - Stream input including messages and optional transcript writer
|
|
85
|
+
* @returns ReadableStream of AI SDK UI messages
|
|
86
|
+
*/
|
|
87
|
+
async stream(input) {
|
|
88
|
+
const handle = await this.ensureAttached();
|
|
89
|
+
const command = this.buildCommand(input);
|
|
90
|
+
const workspacePath = input.workspace?.path ?? "/workspace";
|
|
91
|
+
const transcriptWriter = input.transcriptWriter;
|
|
92
|
+
const signal = input.signal;
|
|
93
|
+
// Check if signal is already aborted
|
|
94
|
+
if (signal?.aborted) {
|
|
95
|
+
throw new Error("Operation was aborted");
|
|
96
|
+
}
|
|
97
|
+
// Write start entry if transcript is enabled
|
|
98
|
+
if (transcriptWriter) {
|
|
99
|
+
await transcriptWriter.write({
|
|
100
|
+
timestamp: new Date().toISOString(),
|
|
101
|
+
type: "start",
|
|
102
|
+
metadata: {
|
|
103
|
+
command: command.join(" "),
|
|
104
|
+
workspace: workspacePath,
|
|
105
|
+
runner: this.runner,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// Execute the command and get stdout as an async iterable
|
|
110
|
+
const stdout = handle.exec(command, {
|
|
111
|
+
cwd: workspacePath,
|
|
112
|
+
env: this.env,
|
|
113
|
+
signal,
|
|
114
|
+
});
|
|
115
|
+
// Create a ReadableStream that passes through the stdout chunks
|
|
116
|
+
// and optionally writes to transcript
|
|
117
|
+
return new ReadableStream({
|
|
118
|
+
async start(controller) {
|
|
119
|
+
let controllerClosed = false;
|
|
120
|
+
try {
|
|
121
|
+
for await (const chunk of stdout) {
|
|
122
|
+
// Write to transcript if enabled
|
|
123
|
+
if (transcriptWriter) {
|
|
124
|
+
const text = new TextDecoder().decode(chunk);
|
|
125
|
+
await transcriptWriter.write({
|
|
126
|
+
timestamp: new Date().toISOString(),
|
|
127
|
+
type: "chunk",
|
|
128
|
+
data: Buffer.from(chunk).toString("base64"),
|
|
129
|
+
text,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
// Passthrough to response
|
|
133
|
+
controller.enqueue(chunk);
|
|
134
|
+
}
|
|
135
|
+
// Write end entry if transcript is enabled
|
|
136
|
+
if (transcriptWriter) {
|
|
137
|
+
await transcriptWriter.write({
|
|
138
|
+
timestamp: new Date().toISOString(),
|
|
139
|
+
type: "end",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
controller.close();
|
|
143
|
+
controllerClosed = true;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
147
|
+
// Normal abort operation - log appropriately
|
|
148
|
+
console.log("[SandAgent] Operation aborted by user");
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// Other errors
|
|
152
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
153
|
+
console.error("[SandAgent] Error:", errorMessage);
|
|
154
|
+
if (transcriptWriter) {
|
|
155
|
+
await transcriptWriter.write({
|
|
156
|
+
timestamp: new Date().toISOString(),
|
|
157
|
+
type: "error",
|
|
158
|
+
text: errorMessage,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Only call controller.error if controller hasn't been closed yet
|
|
163
|
+
if (!controllerClosed) {
|
|
164
|
+
controller.error(error);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Upload files to the agent's workspace
|
|
172
|
+
*/
|
|
173
|
+
async uploadFiles(files, targetDir = "/workspace") {
|
|
174
|
+
const handle = await this.ensureAttached();
|
|
175
|
+
await handle.upload(files, targetDir);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Destroy the sandbox and release resources
|
|
179
|
+
*/
|
|
180
|
+
async destroy() {
|
|
181
|
+
if (this.handle) {
|
|
182
|
+
await this.handle.destroy();
|
|
183
|
+
this.handle = null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=sand-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sand-agent.js","sourceRoot":"","sources":["../src/sand-agent.ts"],"names":[],"mappings":"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"}
|