@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,91 @@
|
|
|
1
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/platform/runtime-ai/gateway.ts
|
|
2
|
+
import { createGateway } from "ai";
|
|
3
|
+
|
|
4
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/platform/runtime-ai/session-fetch.ts
|
|
5
|
+
var EVE_SESSION_HEADER = "x-zo-eve-session";
|
|
6
|
+
var EVE_TURN_HEADER = "x-zo-eve-turn";
|
|
7
|
+
var EVE_CONTEXT_STORAGE_KEY = Symbol.for("eve.context-storage");
|
|
8
|
+
var SESSION_ID_KEY_NAME = "eve.sessionId";
|
|
9
|
+
var SESSION_KEY_NAME = "eve.session";
|
|
10
|
+
function hasMethod(value, name) {
|
|
11
|
+
return typeof value === "object" && value !== null && typeof value[name] === "function";
|
|
12
|
+
}
|
|
13
|
+
function ambientEveSessionId() {
|
|
14
|
+
const value = ambientContextValue(SESSION_ID_KEY_NAME);
|
|
15
|
+
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
16
|
+
}
|
|
17
|
+
function ambientEveTurnId() {
|
|
18
|
+
const session = ambientContextValue(SESSION_KEY_NAME);
|
|
19
|
+
if (typeof session !== "object" || session === null)
|
|
20
|
+
return;
|
|
21
|
+
const turn = session["turn"];
|
|
22
|
+
if (typeof turn !== "object" || turn === null)
|
|
23
|
+
return;
|
|
24
|
+
const id = turn["id"];
|
|
25
|
+
return typeof id === "string" && id.trim().length > 0 ? id : undefined;
|
|
26
|
+
}
|
|
27
|
+
function ambientContextValue(keyName) {
|
|
28
|
+
const storage = Reflect.get(globalThis, EVE_CONTEXT_STORAGE_KEY);
|
|
29
|
+
if (!hasMethod(storage, "getStore"))
|
|
30
|
+
return;
|
|
31
|
+
const store = storage.getStore();
|
|
32
|
+
if (!hasMethod(store, "get"))
|
|
33
|
+
return;
|
|
34
|
+
return store.get({ name: keyName });
|
|
35
|
+
}
|
|
36
|
+
function eveSessionFetch(getSessionId = ambientEveSessionId, baseFetch = globalThis.fetch, getTurnId = ambientEveTurnId) {
|
|
37
|
+
return Object.assign((input, init) => {
|
|
38
|
+
const sessionId = getSessionId()?.trim();
|
|
39
|
+
if (!sessionId)
|
|
40
|
+
return baseFetch(input, init);
|
|
41
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));
|
|
42
|
+
headers.set(EVE_SESSION_HEADER, sessionId);
|
|
43
|
+
const turnId = getTurnId()?.trim();
|
|
44
|
+
if (turnId)
|
|
45
|
+
headers.set(EVE_TURN_HEADER, turnId);
|
|
46
|
+
else
|
|
47
|
+
headers.delete(EVE_TURN_HEADER);
|
|
48
|
+
return baseFetch(input, { ...init, headers });
|
|
49
|
+
}, baseFetch);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/platform/runtime-ai/gateway.ts
|
|
53
|
+
var ZO_TOOL_HEADER = "x-zo-tool";
|
|
54
|
+
var DEFAULT_ZO_AI_BASE_URL = "http://localhost:4000/runtime/ai/v4/ai";
|
|
55
|
+
var DEFAULT_ZO_AI_KEY = "dev-proxy";
|
|
56
|
+
var AGENT_TOKEN_HEADER = "x-zo-agent-token";
|
|
57
|
+
var AGENT_TOKEN_ENV = "ZO_AGENT_TOKEN";
|
|
58
|
+
function agentAuthHeaders(token = process.env[AGENT_TOKEN_ENV]) {
|
|
59
|
+
const trimmed = token?.trim();
|
|
60
|
+
return trimmed ? { [AGENT_TOKEN_HEADER]: trimmed } : {};
|
|
61
|
+
}
|
|
62
|
+
function resolveZoGatewayBaseUrl(baseURL = process.env.ZO_AI_BASE_URL) {
|
|
63
|
+
const trimmed = baseURL?.trim();
|
|
64
|
+
return trimmed && trimmed.length > 0 ? trimmed : DEFAULT_ZO_AI_BASE_URL;
|
|
65
|
+
}
|
|
66
|
+
function resolveZoGatewayApiKey(apiKey = process.env.ZO_AI_KEY) {
|
|
67
|
+
const trimmed = apiKey?.trim();
|
|
68
|
+
return trimmed && trimmed.length > 0 ? trimmed : DEFAULT_ZO_AI_KEY;
|
|
69
|
+
}
|
|
70
|
+
function zoGateway(options = {}) {
|
|
71
|
+
return createGateway({
|
|
72
|
+
...options,
|
|
73
|
+
headers: { ...agentAuthHeaders(), ...options.headers },
|
|
74
|
+
apiKey: resolveZoGatewayApiKey(options.apiKey),
|
|
75
|
+
baseURL: resolveZoGatewayBaseUrl(options.baseURL),
|
|
76
|
+
fetch: eveSessionFetch(undefined, options.fetch)
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
export {
|
|
80
|
+
zoGateway,
|
|
81
|
+
resolveZoGatewayBaseUrl,
|
|
82
|
+
resolveZoGatewayApiKey,
|
|
83
|
+
eveSessionFetch,
|
|
84
|
+
ambientEveTurnId,
|
|
85
|
+
ambientEveSessionId,
|
|
86
|
+
ZO_TOOL_HEADER,
|
|
87
|
+
EVE_TURN_HEADER,
|
|
88
|
+
EVE_SESSION_HEADER,
|
|
89
|
+
DEFAULT_ZO_AI_KEY,
|
|
90
|
+
DEFAULT_ZO_AI_BASE_URL
|
|
91
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/platform/runtime-ai/gateway.ts
|
|
2
|
+
import { createGateway } from "ai";
|
|
3
|
+
|
|
4
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/platform/runtime-ai/session-fetch.ts
|
|
5
|
+
var EVE_SESSION_HEADER = "x-zo-eve-session";
|
|
6
|
+
var EVE_TURN_HEADER = "x-zo-eve-turn";
|
|
7
|
+
var EVE_CONTEXT_STORAGE_KEY = Symbol.for("eve.context-storage");
|
|
8
|
+
var SESSION_ID_KEY_NAME = "eve.sessionId";
|
|
9
|
+
var SESSION_KEY_NAME = "eve.session";
|
|
10
|
+
function hasMethod(value, name) {
|
|
11
|
+
return typeof value === "object" && value !== null && typeof value[name] === "function";
|
|
12
|
+
}
|
|
13
|
+
function ambientEveSessionId() {
|
|
14
|
+
const value = ambientContextValue(SESSION_ID_KEY_NAME);
|
|
15
|
+
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
16
|
+
}
|
|
17
|
+
function ambientEveTurnId() {
|
|
18
|
+
const session = ambientContextValue(SESSION_KEY_NAME);
|
|
19
|
+
if (typeof session !== "object" || session === null)
|
|
20
|
+
return;
|
|
21
|
+
const turn = session["turn"];
|
|
22
|
+
if (typeof turn !== "object" || turn === null)
|
|
23
|
+
return;
|
|
24
|
+
const id = turn["id"];
|
|
25
|
+
return typeof id === "string" && id.trim().length > 0 ? id : undefined;
|
|
26
|
+
}
|
|
27
|
+
function ambientContextValue(keyName) {
|
|
28
|
+
const storage = Reflect.get(globalThis, EVE_CONTEXT_STORAGE_KEY);
|
|
29
|
+
if (!hasMethod(storage, "getStore"))
|
|
30
|
+
return;
|
|
31
|
+
const store = storage.getStore();
|
|
32
|
+
if (!hasMethod(store, "get"))
|
|
33
|
+
return;
|
|
34
|
+
return store.get({ name: keyName });
|
|
35
|
+
}
|
|
36
|
+
function eveSessionFetch(getSessionId = ambientEveSessionId, baseFetch = globalThis.fetch, getTurnId = ambientEveTurnId) {
|
|
37
|
+
return Object.assign((input, init) => {
|
|
38
|
+
const sessionId = getSessionId()?.trim();
|
|
39
|
+
if (!sessionId)
|
|
40
|
+
return baseFetch(input, init);
|
|
41
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));
|
|
42
|
+
headers.set(EVE_SESSION_HEADER, sessionId);
|
|
43
|
+
const turnId = getTurnId()?.trim();
|
|
44
|
+
if (turnId)
|
|
45
|
+
headers.set(EVE_TURN_HEADER, turnId);
|
|
46
|
+
else
|
|
47
|
+
headers.delete(EVE_TURN_HEADER);
|
|
48
|
+
return baseFetch(input, { ...init, headers });
|
|
49
|
+
}, baseFetch);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/platform/runtime-ai/gateway.ts
|
|
53
|
+
var DEFAULT_ZO_AI_BASE_URL = "http://localhost:4000/runtime/ai/v4/ai";
|
|
54
|
+
var DEFAULT_ZO_AI_KEY = "dev-proxy";
|
|
55
|
+
var AGENT_TOKEN_HEADER = "x-zo-agent-token";
|
|
56
|
+
var AGENT_TOKEN_ENV = "ZO_AGENT_TOKEN";
|
|
57
|
+
function agentAuthHeaders(token = process.env[AGENT_TOKEN_ENV]) {
|
|
58
|
+
const trimmed = token?.trim();
|
|
59
|
+
return trimmed ? { [AGENT_TOKEN_HEADER]: trimmed } : {};
|
|
60
|
+
}
|
|
61
|
+
function resolveZoGatewayBaseUrl(baseURL = process.env.ZO_AI_BASE_URL) {
|
|
62
|
+
const trimmed = baseURL?.trim();
|
|
63
|
+
return trimmed && trimmed.length > 0 ? trimmed : DEFAULT_ZO_AI_BASE_URL;
|
|
64
|
+
}
|
|
65
|
+
function resolveZoGatewayApiKey(apiKey = process.env.ZO_AI_KEY) {
|
|
66
|
+
const trimmed = apiKey?.trim();
|
|
67
|
+
return trimmed && trimmed.length > 0 ? trimmed : DEFAULT_ZO_AI_KEY;
|
|
68
|
+
}
|
|
69
|
+
function zoGateway(options = {}) {
|
|
70
|
+
return createGateway({
|
|
71
|
+
...options,
|
|
72
|
+
headers: { ...agentAuthHeaders(), ...options.headers },
|
|
73
|
+
apiKey: resolveZoGatewayApiKey(options.apiKey),
|
|
74
|
+
baseURL: resolveZoGatewayBaseUrl(options.baseURL),
|
|
75
|
+
fetch: eveSessionFetch(undefined, options.fetch)
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/platform/runtime-ai/register.ts
|
|
80
|
+
var SLOT = "AI_SDK_DEFAULT_PROVIDER";
|
|
81
|
+
if (!(SLOT in globalThis)) {
|
|
82
|
+
Object.defineProperty(globalThis, SLOT, {
|
|
83
|
+
value: zoGateway(),
|
|
84
|
+
writable: false,
|
|
85
|
+
configurable: false,
|
|
86
|
+
enumerable: false
|
|
87
|
+
});
|
|
88
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/platform/runtime-ai/session-fetch.ts
|
|
2
|
+
var EVE_SESSION_HEADER = "x-zo-eve-session";
|
|
3
|
+
var EVE_TURN_HEADER = "x-zo-eve-turn";
|
|
4
|
+
var EVE_CONTEXT_STORAGE_KEY = Symbol.for("eve.context-storage");
|
|
5
|
+
var SESSION_ID_KEY_NAME = "eve.sessionId";
|
|
6
|
+
var SESSION_KEY_NAME = "eve.session";
|
|
7
|
+
function hasMethod(value, name) {
|
|
8
|
+
return typeof value === "object" && value !== null && typeof value[name] === "function";
|
|
9
|
+
}
|
|
10
|
+
function ambientEveSessionId() {
|
|
11
|
+
const value = ambientContextValue(SESSION_ID_KEY_NAME);
|
|
12
|
+
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
13
|
+
}
|
|
14
|
+
function ambientEveTurnId() {
|
|
15
|
+
const session = ambientContextValue(SESSION_KEY_NAME);
|
|
16
|
+
if (typeof session !== "object" || session === null)
|
|
17
|
+
return;
|
|
18
|
+
const turn = session["turn"];
|
|
19
|
+
if (typeof turn !== "object" || turn === null)
|
|
20
|
+
return;
|
|
21
|
+
const id = turn["id"];
|
|
22
|
+
return typeof id === "string" && id.trim().length > 0 ? id : undefined;
|
|
23
|
+
}
|
|
24
|
+
function ambientContextValue(keyName) {
|
|
25
|
+
const storage = Reflect.get(globalThis, EVE_CONTEXT_STORAGE_KEY);
|
|
26
|
+
if (!hasMethod(storage, "getStore"))
|
|
27
|
+
return;
|
|
28
|
+
const store = storage.getStore();
|
|
29
|
+
if (!hasMethod(store, "get"))
|
|
30
|
+
return;
|
|
31
|
+
return store.get({ name: keyName });
|
|
32
|
+
}
|
|
33
|
+
function eveSessionFetch(getSessionId = ambientEveSessionId, baseFetch = globalThis.fetch, getTurnId = ambientEveTurnId) {
|
|
34
|
+
return Object.assign((input, init) => {
|
|
35
|
+
const sessionId = getSessionId()?.trim();
|
|
36
|
+
if (!sessionId)
|
|
37
|
+
return baseFetch(input, init);
|
|
38
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));
|
|
39
|
+
headers.set(EVE_SESSION_HEADER, sessionId);
|
|
40
|
+
const turnId = getTurnId()?.trim();
|
|
41
|
+
if (turnId)
|
|
42
|
+
headers.set(EVE_TURN_HEADER, turnId);
|
|
43
|
+
else
|
|
44
|
+
headers.delete(EVE_TURN_HEADER);
|
|
45
|
+
return baseFetch(input, { ...init, headers });
|
|
46
|
+
}, baseFetch);
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
eveSessionFetch,
|
|
50
|
+
ambientEveTurnId,
|
|
51
|
+
ambientEveSessionId,
|
|
52
|
+
EVE_TURN_HEADER,
|
|
53
|
+
EVE_SESSION_HEADER
|
|
54
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/platform/runtime-auth/index.ts
|
|
2
|
+
import { SignJWT, jwtVerify } from "jose";
|
|
3
|
+
var AGENT_TOKEN_HEADER = "x-zo-agent-token";
|
|
4
|
+
var EVE_SESSION_HEADER = "x-zo-eve-session";
|
|
5
|
+
var EVE_TURN_HEADER = "x-zo-eve-turn";
|
|
6
|
+
var AGENT_TOKEN_ENV = "ZO_AGENT_TOKEN";
|
|
7
|
+
var ZO_PLATFORM_ORG = {
|
|
8
|
+
id: "org_zo",
|
|
9
|
+
name: "Zo",
|
|
10
|
+
slug: "zo"
|
|
11
|
+
};
|
|
12
|
+
var BUILDER_AGENT_IDENTITY = {
|
|
13
|
+
agentProjectId: "agt_builder",
|
|
14
|
+
ownerOrgId: ZO_PLATFORM_ORG.id
|
|
15
|
+
};
|
|
16
|
+
var LOCAL_AGENT_IDENTITY = {
|
|
17
|
+
agentProjectId: "agt_local",
|
|
18
|
+
ownerOrgId: ZO_PLATFORM_ORG.id
|
|
19
|
+
};
|
|
20
|
+
var RESERVED_AGENT_PROJECT_IDS = [
|
|
21
|
+
BUILDER_AGENT_IDENTITY.agentProjectId,
|
|
22
|
+
LOCAL_AGENT_IDENTITY.agentProjectId
|
|
23
|
+
];
|
|
24
|
+
var ISSUER = "zo-api";
|
|
25
|
+
var AGENT_TOKEN_TYP = "zo-agent";
|
|
26
|
+
var defaultClock = () => Math.floor(Date.now() / 1000);
|
|
27
|
+
function key(secret) {
|
|
28
|
+
return new TextEncoder().encode(secret);
|
|
29
|
+
}
|
|
30
|
+
function asString(v) {
|
|
31
|
+
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
32
|
+
}
|
|
33
|
+
async function mintAgentToken(input) {
|
|
34
|
+
const now = (input.clock ?? defaultClock)();
|
|
35
|
+
const payload = {
|
|
36
|
+
typ: AGENT_TOKEN_TYP,
|
|
37
|
+
agentProjectId: input.claims.agentProjectId,
|
|
38
|
+
ownerOrgId: input.claims.ownerOrgId,
|
|
39
|
+
...input.claims.deploymentId ? { deploymentId: input.claims.deploymentId } : {}
|
|
40
|
+
};
|
|
41
|
+
return new SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuer(ISSUER).setIssuedAt(now).setExpirationTime(now + input.ttlSeconds).sign(key(input.secret));
|
|
42
|
+
}
|
|
43
|
+
async function verifyAgentToken(token, secret, clock = defaultClock) {
|
|
44
|
+
try {
|
|
45
|
+
const { payload } = await jwtVerify(token, key(secret), {
|
|
46
|
+
issuer: ISSUER,
|
|
47
|
+
currentDate: new Date(clock() * 1000)
|
|
48
|
+
});
|
|
49
|
+
if (payload.typ !== AGENT_TOKEN_TYP)
|
|
50
|
+
return null;
|
|
51
|
+
const agentProjectId = asString(payload.agentProjectId);
|
|
52
|
+
const ownerOrgId = asString(payload.ownerOrgId);
|
|
53
|
+
if (!agentProjectId || !ownerOrgId)
|
|
54
|
+
return null;
|
|
55
|
+
const deploymentId = asString(payload.deploymentId);
|
|
56
|
+
return { agentProjectId, ownerOrgId, ...deploymentId ? { deploymentId } : {} };
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function resolveAgentContext(agentToken, secret, eveSessionId, clock = defaultClock) {
|
|
62
|
+
const claims = await verifyAgentToken(agentToken, secret, clock);
|
|
63
|
+
if (!claims)
|
|
64
|
+
return null;
|
|
65
|
+
return {
|
|
66
|
+
actor: {
|
|
67
|
+
kind: "agent",
|
|
68
|
+
agentProjectId: claims.agentProjectId,
|
|
69
|
+
ownerOrgId: claims.ownerOrgId,
|
|
70
|
+
...claims.deploymentId ? { deploymentId: claims.deploymentId } : {}
|
|
71
|
+
},
|
|
72
|
+
...eveSessionId ? { eveSessionId } : {}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
var IDENTITY_BEARER_TYP = "zo-identity";
|
|
76
|
+
async function mintIdentityBearer(input) {
|
|
77
|
+
const now = (input.clock ?? defaultClock)();
|
|
78
|
+
const payload = {
|
|
79
|
+
typ: IDENTITY_BEARER_TYP,
|
|
80
|
+
userId: input.claims.userId,
|
|
81
|
+
agentId: input.claims.agentId
|
|
82
|
+
};
|
|
83
|
+
return new SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuer(ISSUER).setIssuedAt(now).setExpirationTime(now + input.ttlSeconds).sign(key(input.secret));
|
|
84
|
+
}
|
|
85
|
+
async function verifyIdentityBearer(bearer, secret, clock = defaultClock) {
|
|
86
|
+
try {
|
|
87
|
+
const { payload } = await jwtVerify(bearer, key(secret), {
|
|
88
|
+
issuer: ISSUER,
|
|
89
|
+
currentDate: new Date(clock() * 1000)
|
|
90
|
+
});
|
|
91
|
+
if (payload.typ !== IDENTITY_BEARER_TYP)
|
|
92
|
+
return null;
|
|
93
|
+
const userId = asString(payload.userId);
|
|
94
|
+
const agentId = asString(payload.agentId);
|
|
95
|
+
if (!userId || !agentId)
|
|
96
|
+
return null;
|
|
97
|
+
return { userId, agentId };
|
|
98
|
+
} catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
var INITIATOR_HEADER = "x-zo-initiator";
|
|
103
|
+
function formatInitiator(identity) {
|
|
104
|
+
return JSON.stringify({ userId: identity.userId, agentId: identity.agentId });
|
|
105
|
+
}
|
|
106
|
+
function parseInitiator(value) {
|
|
107
|
+
if (!value)
|
|
108
|
+
return null;
|
|
109
|
+
let parsed;
|
|
110
|
+
try {
|
|
111
|
+
parsed = JSON.parse(value);
|
|
112
|
+
} catch {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
116
|
+
return null;
|
|
117
|
+
const { userId, agentId } = parsed;
|
|
118
|
+
if (typeof userId !== "string" || !userId)
|
|
119
|
+
return null;
|
|
120
|
+
if (typeof agentId !== "string" || !agentId)
|
|
121
|
+
return null;
|
|
122
|
+
return { userId, agentId };
|
|
123
|
+
}
|
|
124
|
+
export {
|
|
125
|
+
verifyIdentityBearer,
|
|
126
|
+
verifyAgentToken,
|
|
127
|
+
resolveAgentContext,
|
|
128
|
+
parseInitiator,
|
|
129
|
+
mintIdentityBearer,
|
|
130
|
+
mintAgentToken,
|
|
131
|
+
formatInitiator,
|
|
132
|
+
ZO_PLATFORM_ORG,
|
|
133
|
+
RESERVED_AGENT_PROJECT_IDS,
|
|
134
|
+
LOCAL_AGENT_IDENTITY,
|
|
135
|
+
INITIATOR_HEADER,
|
|
136
|
+
EVE_TURN_HEADER,
|
|
137
|
+
EVE_SESSION_HEADER,
|
|
138
|
+
BUILDER_AGENT_IDENTITY,
|
|
139
|
+
AGENT_TOKEN_HEADER,
|
|
140
|
+
AGENT_TOKEN_ENV
|
|
141
|
+
};
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
// ../../var/folders/vh/qdfcqc514qj47bbvzslcwjsc0000gn/T/agent-sdk-publish-eDWqsZ/src/state-files.ts
|
|
2
|
+
var STATE_FILES_HANDLE_PATH = "/state/handles";
|
|
3
|
+
var ZO_AGENT_TOKEN_HEADER = "x-zo-agent-token";
|
|
4
|
+
var ZO_EVE_SESSION_HEADER = "x-zo-eve-session";
|
|
5
|
+
|
|
6
|
+
class StateFilesHandleError extends Error {
|
|
7
|
+
status;
|
|
8
|
+
code;
|
|
9
|
+
constructor(message, options) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "StateFilesHandleError";
|
|
12
|
+
this.status = options.status;
|
|
13
|
+
this.code = options.code ?? null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function requestStateFilesHandle(options) {
|
|
17
|
+
const response = await options.fetch(buildStateFilesHandleUrl(options.apiBaseUrl), {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: buildStateFilesHandleHeaders(options),
|
|
20
|
+
body: JSON.stringify(buildStateFilesHandleRequest(options))
|
|
21
|
+
});
|
|
22
|
+
const json = await response.json().catch(() => null);
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
const error = parseStateFilesBrokerError(json);
|
|
25
|
+
throw new StateFilesHandleError(error.message, {
|
|
26
|
+
status: response.status,
|
|
27
|
+
code: error.code
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const handle = parseStateFilesHandle(json);
|
|
31
|
+
if (handle === null) {
|
|
32
|
+
throw new StateFilesHandleError("state files broker returned a malformed handle", {
|
|
33
|
+
status: response.status,
|
|
34
|
+
code: "malformed_handle"
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return handle;
|
|
38
|
+
}
|
|
39
|
+
function parseStateFilesHandle(value) {
|
|
40
|
+
if (!isRecord(value)) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const credentials = parseStateFilesCredentials(value.credentials);
|
|
44
|
+
if (credentials === null) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const access = parseStateFilesAccess(value.access);
|
|
48
|
+
if (access === null) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
if (value.interface !== "files" || value.engine !== "zo-blob-r2") {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const handleId = readString(value, "handleId");
|
|
55
|
+
const declarationName = readString(value, "declarationName");
|
|
56
|
+
const storeId = readString(value, "storeId");
|
|
57
|
+
const stateInstanceId = readString(value, "stateInstanceId");
|
|
58
|
+
const partition = parseStateFilesPartition(value.partition);
|
|
59
|
+
const bucketName = readString(value, "bucketName");
|
|
60
|
+
const endpoint = readString(value, "endpoint");
|
|
61
|
+
if (handleId === null || declarationName === null || storeId === null || stateInstanceId === null || partition === null || bucketName === null || endpoint === null) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return Object.freeze({
|
|
65
|
+
handleId,
|
|
66
|
+
declarationName,
|
|
67
|
+
interface: "files",
|
|
68
|
+
access,
|
|
69
|
+
engine: "zo-blob-r2",
|
|
70
|
+
storeId,
|
|
71
|
+
stateInstanceId,
|
|
72
|
+
partition,
|
|
73
|
+
bucketName,
|
|
74
|
+
endpoint,
|
|
75
|
+
credentials
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function createStateFilesClient(options) {
|
|
79
|
+
return createStateFilesClientFromHandleSource({
|
|
80
|
+
getHandle: async () => options.handle,
|
|
81
|
+
s3: options.s3
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function createRefreshingStateFilesClient(options) {
|
|
85
|
+
let cached = null;
|
|
86
|
+
const now = options.now ?? (() => new Date);
|
|
87
|
+
const refreshWindowMs = options.refreshWindowMs ?? 60000;
|
|
88
|
+
return createStateFilesClientFromHandleSource({
|
|
89
|
+
getHandle: async () => {
|
|
90
|
+
if (cached === null || shouldRefreshStateFilesHandle(cached, now(), refreshWindowMs)) {
|
|
91
|
+
cached = await options.loadHandle();
|
|
92
|
+
}
|
|
93
|
+
return cached;
|
|
94
|
+
},
|
|
95
|
+
s3: options.s3
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function shouldRefreshStateFilesHandle(handle, now, refreshWindowMs = 60000) {
|
|
99
|
+
const expiresAtMs = Date.parse(handle.credentials.expiresAt);
|
|
100
|
+
if (!Number.isFinite(expiresAtMs)) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
return expiresAtMs - now.getTime() <= refreshWindowMs;
|
|
104
|
+
}
|
|
105
|
+
function createStateFilesClientFromHandleSource(options) {
|
|
106
|
+
return {
|
|
107
|
+
async list(prefix) {
|
|
108
|
+
const handle = await options.getHandle();
|
|
109
|
+
const normalizedPrefix = normalizeStateFilePrefix(prefix);
|
|
110
|
+
return options.s3.listObjects({
|
|
111
|
+
...buildS3Context(handle),
|
|
112
|
+
...normalizedPrefix === undefined ? {} : { prefix: normalizedPrefix }
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
async read(path) {
|
|
116
|
+
const handle = await options.getHandle();
|
|
117
|
+
return options.s3.readObject({
|
|
118
|
+
...buildS3Context(handle),
|
|
119
|
+
key: normalizeStateFilePath(path)
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
async write(path, body, writeOptions) {
|
|
123
|
+
const handle = await options.getHandle();
|
|
124
|
+
assertStateFilesWriteAccess(handle);
|
|
125
|
+
return options.s3.writeObject({
|
|
126
|
+
...buildS3Context(handle),
|
|
127
|
+
key: normalizeStateFilePath(path),
|
|
128
|
+
body,
|
|
129
|
+
...writeOptions?.contentType === undefined ? {} : { contentType: writeOptions.contentType }
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
async delete(path) {
|
|
133
|
+
const handle = await options.getHandle();
|
|
134
|
+
assertStateFilesWriteAccess(handle);
|
|
135
|
+
return options.s3.deleteObject({
|
|
136
|
+
...buildS3Context(handle),
|
|
137
|
+
key: normalizeStateFilePath(path)
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function normalizeStateFilePath(path) {
|
|
143
|
+
if (path.length === 0) {
|
|
144
|
+
throw new Error("state file path must not be empty");
|
|
145
|
+
}
|
|
146
|
+
if (path.startsWith("/")) {
|
|
147
|
+
throw new Error(`state file path "${path}" must be relative`);
|
|
148
|
+
}
|
|
149
|
+
const segments = path.split("/");
|
|
150
|
+
if (segments.some((segment) => segment.length === 0 || segment === "." || segment === "..")) {
|
|
151
|
+
throw new Error(`state file path "${path}" must not contain empty, . or .. segments`);
|
|
152
|
+
}
|
|
153
|
+
return path;
|
|
154
|
+
}
|
|
155
|
+
function normalizeStateFilePrefix(prefix) {
|
|
156
|
+
if (prefix === undefined || prefix.length === 0) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (prefix.endsWith("/")) {
|
|
160
|
+
return normalizeStateFilePath(prefix.slice(0, -1)) + "/";
|
|
161
|
+
}
|
|
162
|
+
return normalizeStateFilePath(prefix);
|
|
163
|
+
}
|
|
164
|
+
function buildStateFilesHandleRequest(options) {
|
|
165
|
+
const request = {
|
|
166
|
+
declarationName: options.declarationName,
|
|
167
|
+
interface: "files",
|
|
168
|
+
access: options.access
|
|
169
|
+
};
|
|
170
|
+
return request;
|
|
171
|
+
}
|
|
172
|
+
function buildStateFilesHandleUrl(apiBaseUrl) {
|
|
173
|
+
const url = new URL(String(apiBaseUrl));
|
|
174
|
+
url.pathname = joinUrlPath(url.pathname, STATE_FILES_HANDLE_PATH);
|
|
175
|
+
url.search = "";
|
|
176
|
+
url.hash = "";
|
|
177
|
+
return url.toString();
|
|
178
|
+
}
|
|
179
|
+
function joinUrlPath(basePath, childPath) {
|
|
180
|
+
const base = basePath.replace(/\/+$/, "");
|
|
181
|
+
const child = childPath.replace(/^\/+/, "");
|
|
182
|
+
return `${base}/${child}`;
|
|
183
|
+
}
|
|
184
|
+
function buildStateFilesHandleHeaders(options) {
|
|
185
|
+
const headers = createHeaders(options.headers);
|
|
186
|
+
headers.set("content-type", "application/json");
|
|
187
|
+
if (options.agentToken !== undefined) {
|
|
188
|
+
headers.set(ZO_AGENT_TOKEN_HEADER, options.agentToken);
|
|
189
|
+
}
|
|
190
|
+
if (options.eveSessionKey !== undefined) {
|
|
191
|
+
headers.set(ZO_EVE_SESSION_HEADER, options.eveSessionKey);
|
|
192
|
+
}
|
|
193
|
+
return headers;
|
|
194
|
+
}
|
|
195
|
+
function createHeaders(init) {
|
|
196
|
+
const headers = new Headers;
|
|
197
|
+
if (init === undefined) {
|
|
198
|
+
return headers;
|
|
199
|
+
}
|
|
200
|
+
if (init instanceof Headers) {
|
|
201
|
+
init.forEach((value, key) => headers.set(key, value));
|
|
202
|
+
return headers;
|
|
203
|
+
}
|
|
204
|
+
if (Array.isArray(init)) {
|
|
205
|
+
for (const [key, value] of init) {
|
|
206
|
+
headers.set(key, value);
|
|
207
|
+
}
|
|
208
|
+
return headers;
|
|
209
|
+
}
|
|
210
|
+
for (const [key, value] of Object.entries(init)) {
|
|
211
|
+
headers.set(key, value);
|
|
212
|
+
}
|
|
213
|
+
return headers;
|
|
214
|
+
}
|
|
215
|
+
function parseStateFilesBrokerError(value) {
|
|
216
|
+
if (!isRecord(value)) {
|
|
217
|
+
return { message: "state files broker request failed", code: null };
|
|
218
|
+
}
|
|
219
|
+
const routeError = readString(value, "error");
|
|
220
|
+
if (routeError !== null) {
|
|
221
|
+
return {
|
|
222
|
+
message: readString(value, "message") ?? "state files broker request failed",
|
|
223
|
+
code: routeError
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
const error = isRecord(value.error) ? value.error : value;
|
|
227
|
+
const message = readString(error, "message") ?? "state files broker request failed";
|
|
228
|
+
const code = readString(error, "code") ?? readString(error, "error");
|
|
229
|
+
return { message, code };
|
|
230
|
+
}
|
|
231
|
+
function parseStateFilesCredentials(value) {
|
|
232
|
+
if (!isRecord(value)) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
const accessKeyId = readString(value, "accessKeyId");
|
|
236
|
+
const secretAccessKey = readString(value, "secretAccessKey");
|
|
237
|
+
const sessionToken = readString(value, "sessionToken");
|
|
238
|
+
const expiresAt = readString(value, "expiresAt");
|
|
239
|
+
if (accessKeyId === null || secretAccessKey === null || sessionToken === null || expiresAt === null || !Number.isFinite(Date.parse(expiresAt))) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
return Object.freeze({ accessKeyId, secretAccessKey, sessionToken, expiresAt });
|
|
243
|
+
}
|
|
244
|
+
function parseStateFilesPartition(value) {
|
|
245
|
+
if (value === "none" || value === "team" || value === "user" || value === "session") {
|
|
246
|
+
return value;
|
|
247
|
+
}
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
function parseStateFilesAccess(value) {
|
|
251
|
+
if (value === "r" || value === "rw") {
|
|
252
|
+
return value;
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
function buildS3Context(handle) {
|
|
257
|
+
return {
|
|
258
|
+
endpoint: handle.endpoint,
|
|
259
|
+
bucketName: handle.bucketName,
|
|
260
|
+
credentials: handle.credentials
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function assertStateFilesWriteAccess(handle) {
|
|
264
|
+
if (handle.access !== "rw") {
|
|
265
|
+
throw new Error(`state files handle "${handle.handleId}" is read-only`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function isRecord(value) {
|
|
269
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
270
|
+
}
|
|
271
|
+
function readString(record, key) {
|
|
272
|
+
const value = record[key];
|
|
273
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
274
|
+
}
|
|
275
|
+
export {
|
|
276
|
+
shouldRefreshStateFilesHandle,
|
|
277
|
+
requestStateFilesHandle,
|
|
278
|
+
parseStateFilesHandle,
|
|
279
|
+
normalizeStateFilePrefix,
|
|
280
|
+
normalizeStateFilePath,
|
|
281
|
+
createStateFilesClient,
|
|
282
|
+
createRefreshingStateFilesClient,
|
|
283
|
+
ZO_EVE_SESSION_HEADER,
|
|
284
|
+
ZO_AGENT_TOKEN_HEADER,
|
|
285
|
+
StateFilesHandleError,
|
|
286
|
+
STATE_FILES_HANDLE_PATH
|
|
287
|
+
};
|