@zocomputer/agent-sdk 0.5.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/LICENSE +21 -0
- package/README.md +673 -0
- package/dist/attachments.js +52 -0
- package/dist/gateway-fetch.js +67 -0
- package/dist/index.js +4169 -0
- package/dist/initiator-auth.js +49 -0
- package/dist/platform/agent-sandbox/index.js +691 -0
- package/dist/platform/cloud-tools/image.js +498 -0
- package/dist/platform/cloud-tools/index.js +507 -0
- package/dist/platform/cloud-tools/web-search.js +87 -0
- package/dist/platform/runtime-ai/gateway.js +87 -0
- package/dist/platform/runtime-ai/index.js +91 -0
- package/dist/platform/runtime-ai/register.js +88 -0
- package/dist/platform/runtime-ai/session-fetch.js +54 -0
- package/dist/platform/runtime-auth/index.js +141 -0
- package/dist/state-files.js +287 -0
- package/dist/state-sandbox.js +383 -0
- package/dist/state.js +29 -0
- package/dist/steer-inbox.js +84 -0
- package/dist/steer.js +83 -0
- package/package.json +143 -0
- package/platform/agent-sandbox/api-client.ts +196 -0
- package/platform/agent-sandbox/index.ts +27 -0
- package/platform/agent-sandbox/pure.ts +83 -0
- package/platform/agent-sandbox/sftp.ts +141 -0
- package/platform/agent-sandbox/ssh-connection.ts +165 -0
- package/platform/agent-sandbox/ssh-exec.ts +98 -0
- package/platform/agent-sandbox/ssh-session.ts +487 -0
- package/platform/agent-sandbox/zo-backend.ts +88 -0
- package/platform/agent-sandbox/zo-sandbox.ts +39 -0
- package/platform/cloud-tools/image-path.ts +44 -0
- package/platform/cloud-tools/image.ts +225 -0
- package/platform/cloud-tools/index.ts +22 -0
- package/platform/cloud-tools/state-files.ts +368 -0
- package/platform/cloud-tools/tool-meta.ts +32 -0
- package/platform/cloud-tools/web-search.ts +15 -0
- package/platform/runtime-ai/gateway.ts +76 -0
- package/platform/runtime-ai/index.ts +20 -0
- package/platform/runtime-ai/register.ts +26 -0
- package/platform/runtime-ai/session-fetch.ts +124 -0
- package/platform/runtime-auth/index.ts +331 -0
- package/src/async-tasks.ts +273 -0
- package/src/attachments.ts +109 -0
- package/src/backgroundable.ts +88 -0
- package/src/bounded-output.ts +159 -0
- package/src/dir-conventions.ts +238 -0
- package/src/extract/cache.ts +40 -0
- package/src/extract/docx.ts +18 -0
- package/src/extract/pdf.ts +54 -0
- package/src/extract/sheet.ts +56 -0
- package/src/file-kind.ts +258 -0
- package/src/file-view.ts +80 -0
- package/src/gateway-fetch.ts +115 -0
- package/src/glob-match.ts +13 -0
- package/src/hooks.ts +213 -0
- package/src/index.ts +419 -0
- package/src/initiator-auth.ts +81 -0
- package/src/instructions.ts +224 -0
- package/src/list-files.ts +41 -0
- package/src/mock-model.ts +572 -0
- package/src/park-delivery.ts +247 -0
- package/src/path-locks.ts +52 -0
- package/src/read-file-content.ts +142 -0
- package/src/read-text.ts +40 -0
- package/src/redeliver.ts +155 -0
- package/src/run.ts +159 -0
- package/src/sandbox-io.ts +414 -0
- package/src/state-files.ts +460 -0
- package/src/state-sandbox.ts +710 -0
- package/src/state.ts +96 -0
- package/src/steer-inbox.ts +105 -0
- package/src/steer-tool.ts +83 -0
- package/src/steer.ts +146 -0
- package/src/task.ts +320 -0
- package/src/tools/bash.ts +143 -0
- package/src/tools/edit.ts +58 -0
- package/src/tools/glob.ts +56 -0
- package/src/tools/grep.ts +188 -0
- package/src/tools/read.ts +319 -0
- package/src/tools/tasks.ts +241 -0
- package/src/tools/webfetch.ts +368 -0
- package/src/tools/write.ts +42 -0
- package/src/walk.ts +112 -0
- package/src/watch-output.ts +104 -0
- package/src/web-fetch.ts +324 -0
- package/src/web-page.ts +179 -0
- package/src/workspace-io.ts +225 -0
- package/src/workspace.ts +41 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/src/state-files.ts
|
|
2
|
+
function normalizeStateFilePath(path) {
|
|
3
|
+
if (path.length === 0) {
|
|
4
|
+
throw new Error("state file path must not be empty");
|
|
5
|
+
}
|
|
6
|
+
if (path.startsWith("/")) {
|
|
7
|
+
throw new Error(`state file path "${path}" must be relative`);
|
|
8
|
+
}
|
|
9
|
+
const segments = path.split("/");
|
|
10
|
+
if (segments.some((segment) => segment.length === 0 || segment === "." || segment === "..")) {
|
|
11
|
+
throw new Error(`state file path "${path}" must not contain empty, . or .. segments`);
|
|
12
|
+
}
|
|
13
|
+
return path;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/src/state-sandbox.ts
|
|
17
|
+
var STATE_SANDBOX_HANDLE_PATH = "/state/handles";
|
|
18
|
+
var ZO_AGENT_TOKEN_HEADER = "x-zo-agent-token";
|
|
19
|
+
var ZO_EVE_SESSION_HEADER = "x-zo-eve-session";
|
|
20
|
+
|
|
21
|
+
class StateSandboxHandleError extends Error {
|
|
22
|
+
status;
|
|
23
|
+
code;
|
|
24
|
+
constructor(message, options) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = "StateSandboxHandleError";
|
|
27
|
+
this.status = options.status;
|
|
28
|
+
this.code = options.code ?? null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function requestStateSandboxHandle(options) {
|
|
32
|
+
const response = await options.fetch(buildStateSandboxHandleUrl(options.apiBaseUrl), {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: buildStateSandboxHandleHeaders(options),
|
|
35
|
+
body: JSON.stringify(buildStateSandboxHandleRequest(options))
|
|
36
|
+
});
|
|
37
|
+
const json = await response.json().catch(() => null);
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
const error = parseStateSandboxBrokerError(json);
|
|
40
|
+
throw new StateSandboxHandleError(error.message, {
|
|
41
|
+
status: response.status,
|
|
42
|
+
code: error.code
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const handle = parseStateSandboxHandle(json);
|
|
46
|
+
if (handle === null) {
|
|
47
|
+
throw new StateSandboxHandleError("state sandbox broker returned a malformed handle", {
|
|
48
|
+
status: response.status,
|
|
49
|
+
code: "malformed_handle"
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return handle;
|
|
53
|
+
}
|
|
54
|
+
function parseStateSandboxHandle(value) {
|
|
55
|
+
if (!isRecord(value)) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const access = parseStateSandboxAccess(value.access);
|
|
59
|
+
const iface = parseStateSandboxInterface(value.interface);
|
|
60
|
+
const partition = parseStateSandboxPartition(value.partition);
|
|
61
|
+
const lifecycle = parseStateSandboxLifecycle(value.lifecycle ?? value.status);
|
|
62
|
+
const sandbox = parseStateSandboxSshAccess(value.sandbox ?? value.ssh ?? value.accessHandle ?? value.sshAccess);
|
|
63
|
+
if (access === null || iface === null || partition === null || lifecycle === null || sandbox === null || value.engine !== "sandbox-daytona") {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const handleId = readString(value, "handleId");
|
|
67
|
+
const declarationName = readString(value, "declarationName");
|
|
68
|
+
const storeId = readString(value, "storeId");
|
|
69
|
+
const stateInstanceId = readString(value, "stateInstanceId");
|
|
70
|
+
const sandboxResourceId = readString(value, "sandboxResourceId");
|
|
71
|
+
const rootPath = readString(value, "rootPath");
|
|
72
|
+
if (handleId === null || declarationName === null || storeId === null || stateInstanceId === null || sandboxResourceId === null || rootPath === null || !rootPath.startsWith("/")) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return Object.freeze({
|
|
76
|
+
handleId,
|
|
77
|
+
declarationName,
|
|
78
|
+
interface: iface,
|
|
79
|
+
access,
|
|
80
|
+
engine: "sandbox-daytona",
|
|
81
|
+
storeId,
|
|
82
|
+
stateInstanceId,
|
|
83
|
+
partition,
|
|
84
|
+
sandboxResourceId,
|
|
85
|
+
rootPath,
|
|
86
|
+
lifecycle,
|
|
87
|
+
sandbox
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function createStateSandboxClient(options) {
|
|
91
|
+
const now = options.now ?? (() => new Date);
|
|
92
|
+
const refreshWindowMs = options.refreshWindowMs ?? 60000;
|
|
93
|
+
let cached = null;
|
|
94
|
+
let pending = null;
|
|
95
|
+
let pendingLeaseWaiters = 0;
|
|
96
|
+
let status = { status: "idle" };
|
|
97
|
+
async function disposeCachedSession(record, options2 = {}) {
|
|
98
|
+
if (record.activeUses > 0 || options2.waitForPendingLeases === true && pendingLeaseWaiters > 0) {
|
|
99
|
+
record.disposeWhenIdle = true;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (cached === record) {
|
|
103
|
+
cached = null;
|
|
104
|
+
}
|
|
105
|
+
await record.session.dispose?.();
|
|
106
|
+
}
|
|
107
|
+
async function releaseCachedSession(record) {
|
|
108
|
+
record.activeUses -= 1;
|
|
109
|
+
if (record.activeUses === 0 && record.disposeWhenIdle) {
|
|
110
|
+
await disposeCachedSession(record);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function ensureSession() {
|
|
114
|
+
const current = cached;
|
|
115
|
+
if (current !== null && !shouldRefreshStateSandboxHandle(current.handle, now(), refreshWindowMs)) {
|
|
116
|
+
return Promise.resolve(current);
|
|
117
|
+
}
|
|
118
|
+
if (pending !== null)
|
|
119
|
+
return pending;
|
|
120
|
+
const previous = cached;
|
|
121
|
+
pending = (async () => {
|
|
122
|
+
try {
|
|
123
|
+
const handle = await options.loadHandle();
|
|
124
|
+
if (handle.lifecycle === "resuming") {
|
|
125
|
+
status = { status: "resuming", handleId: handle.handleId };
|
|
126
|
+
}
|
|
127
|
+
const session = await options.createSession(handle);
|
|
128
|
+
const next = {
|
|
129
|
+
handle,
|
|
130
|
+
session,
|
|
131
|
+
activeUses: 0,
|
|
132
|
+
disposeWhenIdle: false
|
|
133
|
+
};
|
|
134
|
+
cached = next;
|
|
135
|
+
status = { status: "ready", handleId: handle.handleId };
|
|
136
|
+
if (previous !== null) {
|
|
137
|
+
await disposeCachedSession(previous, { waitForPendingLeases: false });
|
|
138
|
+
}
|
|
139
|
+
return next;
|
|
140
|
+
} finally {
|
|
141
|
+
pending = null;
|
|
142
|
+
}
|
|
143
|
+
})();
|
|
144
|
+
return pending;
|
|
145
|
+
}
|
|
146
|
+
async function leaseSession() {
|
|
147
|
+
const sessionPromise = ensureSession();
|
|
148
|
+
pendingLeaseWaiters += 1;
|
|
149
|
+
let record;
|
|
150
|
+
try {
|
|
151
|
+
record = await sessionPromise;
|
|
152
|
+
} finally {
|
|
153
|
+
pendingLeaseWaiters -= 1;
|
|
154
|
+
}
|
|
155
|
+
record.activeUses += 1;
|
|
156
|
+
return {
|
|
157
|
+
handle: record.handle,
|
|
158
|
+
session: record.session,
|
|
159
|
+
release: () => releaseCachedSession(record)
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function buildRemotePath(handle, path) {
|
|
163
|
+
return `${handle.rootPath}/${normalizeStateFilePath(path)}`;
|
|
164
|
+
}
|
|
165
|
+
function workingDirectoryFor(handle, explicit) {
|
|
166
|
+
return explicit === undefined ? handle.rootPath : buildRemotePath(handle, explicit);
|
|
167
|
+
}
|
|
168
|
+
function commandEnv(handle, explicit) {
|
|
169
|
+
const base = options.passAmbientEnvToSessionPartition === true && handle.partition === "session" ? options.ambientEnv : undefined;
|
|
170
|
+
if (base === undefined) {
|
|
171
|
+
return explicit;
|
|
172
|
+
}
|
|
173
|
+
if (explicit === undefined) {
|
|
174
|
+
return base;
|
|
175
|
+
}
|
|
176
|
+
return { ...base, ...explicit };
|
|
177
|
+
}
|
|
178
|
+
function maybeEnv(handle, explicit) {
|
|
179
|
+
const env = commandEnv(handle, explicit);
|
|
180
|
+
return env === undefined ? {} : { env };
|
|
181
|
+
}
|
|
182
|
+
async function withSession(use) {
|
|
183
|
+
const resolved = await leaseSession();
|
|
184
|
+
try {
|
|
185
|
+
return await use(resolved);
|
|
186
|
+
} finally {
|
|
187
|
+
await resolved.release();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async function withWriteSession(use) {
|
|
191
|
+
return await withSession(async (resolved) => {
|
|
192
|
+
if (resolved.handle.access !== "rw") {
|
|
193
|
+
throw new Error(`state sandbox handle "${resolved.handle.handleId}" is read-only`);
|
|
194
|
+
}
|
|
195
|
+
return await use(resolved);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
files: {
|
|
200
|
+
async read(path) {
|
|
201
|
+
return await withSession(async ({ handle, session }) => await session.readBinaryFile({
|
|
202
|
+
path: buildRemotePath(handle, path)
|
|
203
|
+
}));
|
|
204
|
+
},
|
|
205
|
+
async write(path, content) {
|
|
206
|
+
await withWriteSession(async ({ handle, session }) => {
|
|
207
|
+
const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
208
|
+
await session.writeBinaryFile({
|
|
209
|
+
path: buildRemotePath(handle, path),
|
|
210
|
+
content: bytes
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
},
|
|
214
|
+
async delete(path, deleteOptions) {
|
|
215
|
+
await withWriteSession(async ({ handle, session }) => {
|
|
216
|
+
await session.removePath({
|
|
217
|
+
path: buildRemotePath(handle, path),
|
|
218
|
+
...deleteOptions?.recursive === undefined ? {} : { recursive: deleteOptions.recursive },
|
|
219
|
+
...deleteOptions?.force === undefined ? {} : { force: deleteOptions.force }
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
status: () => status,
|
|
225
|
+
async exec(command, runOptions) {
|
|
226
|
+
return await withWriteSession(async ({ handle, session }) => await session.run({
|
|
227
|
+
command,
|
|
228
|
+
workingDirectory: workingDirectoryFor(handle, runOptions?.workingDirectory),
|
|
229
|
+
...maybeEnv(handle, runOptions?.env),
|
|
230
|
+
...runOptions?.abortSignal === undefined ? {} : { abortSignal: runOptions.abortSignal }
|
|
231
|
+
}));
|
|
232
|
+
},
|
|
233
|
+
async spawn(command, runOptions) {
|
|
234
|
+
return await withWriteSession(async ({ handle, session }) => await session.spawn({
|
|
235
|
+
command,
|
|
236
|
+
workingDirectory: workingDirectoryFor(handle, runOptions?.workingDirectory),
|
|
237
|
+
...maybeEnv(handle, runOptions?.env),
|
|
238
|
+
...runOptions?.abortSignal === undefined ? {} : { abortSignal: runOptions.abortSignal }
|
|
239
|
+
}));
|
|
240
|
+
},
|
|
241
|
+
async dispose() {
|
|
242
|
+
const resolved = pending === null ? cached : await pending;
|
|
243
|
+
if (resolved !== null) {
|
|
244
|
+
await disposeCachedSession(resolved, { waitForPendingLeases: true });
|
|
245
|
+
}
|
|
246
|
+
status = { status: "idle" };
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function shouldRefreshStateSandboxHandle(handle, now, refreshWindowMs = 60000) {
|
|
251
|
+
const expiresAtMs = Date.parse(handle.sandbox.expiresAt);
|
|
252
|
+
if (!Number.isFinite(expiresAtMs)) {
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
return expiresAtMs - now.getTime() <= refreshWindowMs;
|
|
256
|
+
}
|
|
257
|
+
function buildStateSandboxHandleRequest(options) {
|
|
258
|
+
return {
|
|
259
|
+
declarationName: options.declarationName,
|
|
260
|
+
interface: options.interface,
|
|
261
|
+
access: options.access,
|
|
262
|
+
suggestedDefaults: {
|
|
263
|
+
...options.suggestedDefaults,
|
|
264
|
+
engine: options.suggestedDefaults?.engine ?? "sandbox-daytona"
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function buildStateSandboxHandleUrl(apiBaseUrl) {
|
|
269
|
+
const url = new URL(String(apiBaseUrl));
|
|
270
|
+
url.pathname = joinUrlPath(url.pathname, STATE_SANDBOX_HANDLE_PATH);
|
|
271
|
+
url.search = "";
|
|
272
|
+
url.hash = "";
|
|
273
|
+
return url.toString();
|
|
274
|
+
}
|
|
275
|
+
function joinUrlPath(basePath, childPath) {
|
|
276
|
+
const base = basePath.replace(/\/+$/, "");
|
|
277
|
+
const child = childPath.replace(/^\/+/, "");
|
|
278
|
+
return `${base}/${child}`;
|
|
279
|
+
}
|
|
280
|
+
function buildStateSandboxHandleHeaders(options) {
|
|
281
|
+
const headers = createHeaders(options.headers);
|
|
282
|
+
headers.set("content-type", "application/json");
|
|
283
|
+
if (options.agentToken !== undefined) {
|
|
284
|
+
headers.set(ZO_AGENT_TOKEN_HEADER, options.agentToken);
|
|
285
|
+
}
|
|
286
|
+
if (options.eveSessionKey !== undefined) {
|
|
287
|
+
headers.set(ZO_EVE_SESSION_HEADER, options.eveSessionKey);
|
|
288
|
+
}
|
|
289
|
+
return headers;
|
|
290
|
+
}
|
|
291
|
+
function createHeaders(init) {
|
|
292
|
+
const headers = new Headers;
|
|
293
|
+
if (init === undefined) {
|
|
294
|
+
return headers;
|
|
295
|
+
}
|
|
296
|
+
if (init instanceof Headers) {
|
|
297
|
+
init.forEach((value, key) => headers.set(key, value));
|
|
298
|
+
return headers;
|
|
299
|
+
}
|
|
300
|
+
if (Array.isArray(init)) {
|
|
301
|
+
for (const [key, value] of init) {
|
|
302
|
+
headers.set(key, value);
|
|
303
|
+
}
|
|
304
|
+
return headers;
|
|
305
|
+
}
|
|
306
|
+
for (const [key, value] of Object.entries(init)) {
|
|
307
|
+
headers.set(key, value);
|
|
308
|
+
}
|
|
309
|
+
return headers;
|
|
310
|
+
}
|
|
311
|
+
function parseStateSandboxBrokerError(value) {
|
|
312
|
+
if (!isRecord(value)) {
|
|
313
|
+
return { message: "state sandbox broker request failed", code: null };
|
|
314
|
+
}
|
|
315
|
+
const routeError = readString(value, "error");
|
|
316
|
+
if (routeError !== null) {
|
|
317
|
+
return {
|
|
318
|
+
message: readString(value, "message") ?? "state sandbox broker request failed",
|
|
319
|
+
code: routeError
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
const error = isRecord(value.error) ? value.error : value;
|
|
323
|
+
const message = readString(error, "message") ?? "state sandbox broker request failed";
|
|
324
|
+
const code = readString(error, "code") ?? readString(error, "error");
|
|
325
|
+
return { message, code };
|
|
326
|
+
}
|
|
327
|
+
function parseStateSandboxSshAccess(value) {
|
|
328
|
+
if (!isRecord(value)) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
const sandboxId = readString(value, "sandboxId");
|
|
332
|
+
const sshHost = readString(value, "sshHost");
|
|
333
|
+
const sshUser = readString(value, "sshUser");
|
|
334
|
+
const expiresAt = readString(value, "expiresAt");
|
|
335
|
+
if (sandboxId === null || sshHost === null || sshUser === null || expiresAt === null || !Number.isFinite(Date.parse(expiresAt))) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
return Object.freeze({ sandboxId, sshHost, sshUser, expiresAt });
|
|
339
|
+
}
|
|
340
|
+
function parseStateSandboxPartition(value) {
|
|
341
|
+
if (value === "none" || value === "team" || value === "user" || value === "session") {
|
|
342
|
+
return value;
|
|
343
|
+
}
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
function parseStateSandboxAccess(value) {
|
|
347
|
+
if (value === "r" || value === "rw") {
|
|
348
|
+
return value;
|
|
349
|
+
}
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
function parseStateSandboxInterface(value) {
|
|
353
|
+
if (value === "exec" || value === "files") {
|
|
354
|
+
return value;
|
|
355
|
+
}
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
function parseStateSandboxLifecycle(value) {
|
|
359
|
+
if (value === "ready" || value === undefined || value === null) {
|
|
360
|
+
return "ready";
|
|
361
|
+
}
|
|
362
|
+
if (value === "resuming") {
|
|
363
|
+
return "resuming";
|
|
364
|
+
}
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
function isRecord(value) {
|
|
368
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
369
|
+
}
|
|
370
|
+
function readString(record, key) {
|
|
371
|
+
const value = record[key];
|
|
372
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
373
|
+
}
|
|
374
|
+
export {
|
|
375
|
+
shouldRefreshStateSandboxHandle,
|
|
376
|
+
requestStateSandboxHandle,
|
|
377
|
+
parseStateSandboxHandle,
|
|
378
|
+
createStateSandboxClient,
|
|
379
|
+
ZO_EVE_SESSION_HEADER,
|
|
380
|
+
ZO_AGENT_TOKEN_HEADER,
|
|
381
|
+
StateSandboxHandleError,
|
|
382
|
+
STATE_SANDBOX_HANDLE_PATH
|
|
383
|
+
};
|
package/dist/state.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/src/state.ts
|
|
2
|
+
var STATE_NAME_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
3
|
+
var INTERFACES = ["files", "sql", "kv", "http", "exec"];
|
|
4
|
+
var ACCESSES = ["r", "rw"];
|
|
5
|
+
var INTENTS = ["private", "shared"];
|
|
6
|
+
var PARTITIONS = ["none", "team", "user", "session"];
|
|
7
|
+
function defineExternalState(declaration) {
|
|
8
|
+
if (!STATE_NAME_PATTERN.test(declaration.name)) {
|
|
9
|
+
throw new Error(`external-state declaration name "${declaration.name}" must match ${STATE_NAME_PATTERN} and equal the declaring filename`);
|
|
10
|
+
}
|
|
11
|
+
if (!INTERFACES.includes(declaration.interface)) {
|
|
12
|
+
throw new Error(`external-state declaration "${declaration.name}": unknown interface "${String(declaration.interface)}" (expected ${INTERFACES.join(" | ")})`);
|
|
13
|
+
}
|
|
14
|
+
if (!ACCESSES.includes(declaration.access)) {
|
|
15
|
+
throw new Error(`external-state declaration "${declaration.name}": unknown access "${String(declaration.access)}" (expected ${ACCESSES.join(" | ")})`);
|
|
16
|
+
}
|
|
17
|
+
if (!INTENTS.includes(declaration.intent)) {
|
|
18
|
+
throw new Error(`external-state declaration "${declaration.name}": unknown intent "${String(declaration.intent)}" (expected ${INTENTS.join(" | ")})`);
|
|
19
|
+
}
|
|
20
|
+
const partition = declaration.suggestedDefaults?.partition;
|
|
21
|
+
if (partition !== undefined && !PARTITIONS.includes(partition)) {
|
|
22
|
+
throw new Error(`external-state declaration "${declaration.name}": unknown suggested partition "${String(partition)}" (expected ${PARTITIONS.join(" | ")})`);
|
|
23
|
+
}
|
|
24
|
+
return Object.freeze(declaration);
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
defineExternalState,
|
|
28
|
+
STATE_NAME_PATTERN
|
|
29
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/src/steer-inbox.ts
|
|
2
|
+
import {
|
|
3
|
+
appendFileSync,
|
|
4
|
+
linkSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
renameSync,
|
|
8
|
+
rmSync
|
|
9
|
+
} from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
|
|
12
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/src/steer.ts
|
|
13
|
+
function isRecord(value) {
|
|
14
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15
|
+
}
|
|
16
|
+
function isSteerMessage(value) {
|
|
17
|
+
return isRecord(value) && typeof value.id === "string" && typeof value.text === "string" && typeof value.at === "number";
|
|
18
|
+
}
|
|
19
|
+
function serializeSteerLine(message) {
|
|
20
|
+
return JSON.stringify(message);
|
|
21
|
+
}
|
|
22
|
+
function parseSteerLine(line) {
|
|
23
|
+
const trimmed = line.trim();
|
|
24
|
+
if (trimmed === "")
|
|
25
|
+
return null;
|
|
26
|
+
try {
|
|
27
|
+
const parsed = JSON.parse(trimmed);
|
|
28
|
+
return isSteerMessage(parsed) ? parsed : null;
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/src/steer-inbox.ts
|
|
35
|
+
var drainSequence = 0;
|
|
36
|
+
function createSteerInbox(options) {
|
|
37
|
+
const now = options.now ?? Date.now;
|
|
38
|
+
const newId = options.newId ?? (() => crypto.randomUUID());
|
|
39
|
+
const readFile = options.readFile ?? ((path) => readFileSync(path, "utf8"));
|
|
40
|
+
const fileFor = (sessionId) => join(options.dir, `${encodeURIComponent(sessionId)}.ndjson`);
|
|
41
|
+
function appendMessage(sessionId, message) {
|
|
42
|
+
mkdirSync(options.dir, { recursive: true });
|
|
43
|
+
appendFileSync(fileFor(sessionId), `${serializeSteerLine(message)}
|
|
44
|
+
`, "utf8");
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
append(sessionId, text) {
|
|
48
|
+
const message = { id: newId(), text, at: now() };
|
|
49
|
+
appendMessage(sessionId, message);
|
|
50
|
+
return message;
|
|
51
|
+
},
|
|
52
|
+
appendMessage,
|
|
53
|
+
drain(sessionId) {
|
|
54
|
+
const file = fileFor(sessionId);
|
|
55
|
+
const claimed = `${file}.drain-${process.pid}-${drainSequence++}`;
|
|
56
|
+
try {
|
|
57
|
+
renameSync(file, claimed);
|
|
58
|
+
} catch {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
let raw;
|
|
62
|
+
try {
|
|
63
|
+
raw = readFile(claimed);
|
|
64
|
+
} catch {
|
|
65
|
+
try {
|
|
66
|
+
linkSync(claimed, file);
|
|
67
|
+
rmSync(claimed, { force: true });
|
|
68
|
+
} catch {
|
|
69
|
+
try {
|
|
70
|
+
appendFileSync(file, readFileSync(claimed));
|
|
71
|
+
rmSync(claimed, { force: true });
|
|
72
|
+
} catch {}
|
|
73
|
+
}
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
rmSync(claimed, { force: true });
|
|
77
|
+
return raw.split(`
|
|
78
|
+
`).map(parseSteerLine).filter((message) => message !== null);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
createSteerInbox
|
|
84
|
+
};
|
package/dist/steer.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/src/steer.ts
|
|
2
|
+
var STEER_FIELD = "user_steer";
|
|
3
|
+
var STEER_WRAPPED_OUTPUT_FIELD = "steer_wrapped_output";
|
|
4
|
+
var STEER_DIRNAME = "steer";
|
|
5
|
+
var STEER_NOTE = "The user sent these messages while this tool was running. They take priority: address them now and adjust your current approach before continuing.";
|
|
6
|
+
function buildSteerPayload(messages) {
|
|
7
|
+
return { note: STEER_NOTE, messages: [...messages] };
|
|
8
|
+
}
|
|
9
|
+
function isRecord(value) {
|
|
10
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
function isSteerMessage(value) {
|
|
13
|
+
return isRecord(value) && typeof value.id === "string" && typeof value.text === "string" && typeof value.at === "number";
|
|
14
|
+
}
|
|
15
|
+
function attachSteerToOutput(output, messages) {
|
|
16
|
+
if (isRecord(output)) {
|
|
17
|
+
const existing = readSteerMessages(output) ?? [];
|
|
18
|
+
return { ...output, [STEER_FIELD]: buildSteerPayload([...existing, ...messages]) };
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
[STEER_WRAPPED_OUTPUT_FIELD]: output,
|
|
22
|
+
[STEER_FIELD]: buildSteerPayload(messages)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function stripSteerFromOutput(record) {
|
|
26
|
+
const { [STEER_FIELD]: _steer, ...rest } = record;
|
|
27
|
+
const keys = Object.keys(rest);
|
|
28
|
+
if (keys.length === 1 && keys[0] === STEER_WRAPPED_OUTPUT_FIELD) {
|
|
29
|
+
return rest[STEER_WRAPPED_OUTPUT_FIELD];
|
|
30
|
+
}
|
|
31
|
+
return rest;
|
|
32
|
+
}
|
|
33
|
+
function readSteerMessages(output) {
|
|
34
|
+
if (!isRecord(output))
|
|
35
|
+
return null;
|
|
36
|
+
const payload = output[STEER_FIELD];
|
|
37
|
+
if (!isRecord(payload) || !Array.isArray(payload.messages))
|
|
38
|
+
return null;
|
|
39
|
+
const messages = payload.messages.filter(isSteerMessage);
|
|
40
|
+
return messages.length > 0 ? messages : null;
|
|
41
|
+
}
|
|
42
|
+
function formatSteerText(messages) {
|
|
43
|
+
const lines = messages.map((message) => `- ${message.text}`);
|
|
44
|
+
return `[${STEER_FIELD}] ${STEER_NOTE}
|
|
45
|
+
${lines.join(`
|
|
46
|
+
`)}`;
|
|
47
|
+
}
|
|
48
|
+
function mergeSteerIntoModelOutput(output, messages) {
|
|
49
|
+
if (output.type === "text") {
|
|
50
|
+
return { type: "text", value: `${output.value}
|
|
51
|
+
|
|
52
|
+
${formatSteerText(messages)}` };
|
|
53
|
+
}
|
|
54
|
+
return { type: "json", value: attachSteerToOutput(output.value, messages) };
|
|
55
|
+
}
|
|
56
|
+
function serializeSteerLine(message) {
|
|
57
|
+
return JSON.stringify(message);
|
|
58
|
+
}
|
|
59
|
+
function parseSteerLine(line) {
|
|
60
|
+
const trimmed = line.trim();
|
|
61
|
+
if (trimmed === "")
|
|
62
|
+
return null;
|
|
63
|
+
try {
|
|
64
|
+
const parsed = JSON.parse(trimmed);
|
|
65
|
+
return isSteerMessage(parsed) ? parsed : null;
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
stripSteerFromOutput,
|
|
72
|
+
serializeSteerLine,
|
|
73
|
+
readSteerMessages,
|
|
74
|
+
parseSteerLine,
|
|
75
|
+
mergeSteerIntoModelOutput,
|
|
76
|
+
formatSteerText,
|
|
77
|
+
buildSteerPayload,
|
|
78
|
+
attachSteerToOutput,
|
|
79
|
+
STEER_WRAPPED_OUTPUT_FIELD,
|
|
80
|
+
STEER_NOTE,
|
|
81
|
+
STEER_FIELD,
|
|
82
|
+
STEER_DIRNAME
|
|
83
|
+
};
|