deepspace 0.27.1 → 0.28.1
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/CHANGELOG.md +56 -0
- package/README.md +27 -8
- package/dist/{chunk-CRIG6LPA.js → chunk-PVEUIQN4.js} +2 -2
- package/dist/{chunk-CRIG6LPA.js.map → chunk-PVEUIQN4.js.map} +1 -1
- package/dist/cli.js +2004 -879
- package/dist/cli.js.map +1 -1
- package/dist/documentation-client-core.js +1 -1
- package/dist/documentation-default-renderer.cjs +1 -1
- package/dist/documentation-react.js +1 -1
- package/dist/documentation-runtime.js +1 -1
- package/dist/documentation-server-core.js +1 -1
- package/dist/documentation.js +1 -1
- package/dist/documentation.js.map +1 -1
- package/dist/server.d.ts +24 -2
- package/dist/server.js +59 -18
- package/dist/server.js.map +1 -1
- package/dist/testing.js +2 -2
- package/dist/testing.js.map +1 -1
- package/dist/worker.d.ts +99 -1
- package/dist/worker.js +318 -40
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-Q5YJGF5Z.js +0 -769
- package/dist/chunk-Q5YJGF5Z.js.map +0 -1
- package/dist/repo-api-7GDPVSFV.js +0 -14
- package/dist/repo-api-7GDPVSFV.js.map +0 -1
package/dist/worker.js
CHANGED
|
@@ -1345,7 +1345,7 @@ function handleDelete(ctx, ws, attachment, payload) {
|
|
|
1345
1345
|
ctx.send(ws, serverBuild.error(result.error));
|
|
1346
1346
|
}
|
|
1347
1347
|
}
|
|
1348
|
-
function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRbac = false, systemUpdate = false) {
|
|
1348
|
+
function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRbac = false, systemUpdate = false, updateOnly = false) {
|
|
1349
1349
|
const resolved = resolveCollection(ctx, collection);
|
|
1350
1350
|
if (!resolved.ok) return { success: false, error: resolved.error };
|
|
1351
1351
|
const schema = resolved.schema;
|
|
@@ -1363,6 +1363,12 @@ function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRb
|
|
|
1363
1363
|
}
|
|
1364
1364
|
const existing = getRecord(ctx.sql, collection, recordId, schema);
|
|
1365
1365
|
const isUpdate = existing !== null;
|
|
1366
|
+
if (updateOnly && !isUpdate) {
|
|
1367
|
+
return {
|
|
1368
|
+
success: false,
|
|
1369
|
+
error: `records.update: no record "${recordId}" in ${collection} \u2014 updates never create; use records.create.`
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1366
1372
|
const mergedData = isUpdate ? { ...existing.data, ...data } : { ...data };
|
|
1367
1373
|
for (const col of columns) {
|
|
1368
1374
|
if (col.readonly) continue;
|
|
@@ -2521,7 +2527,7 @@ async function executeTool(ctx, toolName, params, userId, userRole, skipUserRbac
|
|
|
2521
2527
|
if (!collection) return { success: false, error: "Missing required param: collection" };
|
|
2522
2528
|
if (!recordId) return { success: false, error: "Missing required param: recordId" };
|
|
2523
2529
|
if (!data) return { success: false, error: "Missing required param: data" };
|
|
2524
|
-
return putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRbac);
|
|
2530
|
+
return putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRbac, false, true);
|
|
2525
2531
|
}
|
|
2526
2532
|
case "records.delete": {
|
|
2527
2533
|
const collection = params.collection;
|
|
@@ -6186,10 +6192,10 @@ async function writeQuotaSummary(bucket, key, previousEtag, summary) {
|
|
|
6186
6192
|
});
|
|
6187
6193
|
return object ? { etag: object.etag, summary } : null;
|
|
6188
6194
|
}
|
|
6189
|
-
async function ensureQuotaSummary(bucket, storage, prefixes,
|
|
6195
|
+
async function ensureQuotaSummary(bucket, storage, prefixes, measure = "reuse", excludedMarkerKey) {
|
|
6190
6196
|
for (let attempt = 0; attempt < 4; attempt++) {
|
|
6191
6197
|
const current = await readQuotaSummary(bucket, storage.quotaKey);
|
|
6192
|
-
if (
|
|
6198
|
+
if (measure !== "force" && current.summary && accountPrefixesEqual(current.summary.prefixes, prefixes) && !(measure === "repairDirty" && current.summary.dirty && Date.now() - current.summary.measuredAt >= QUOTA_REPAIR_COOLDOWN_MS)) {
|
|
6193
6199
|
return current;
|
|
6194
6200
|
}
|
|
6195
6201
|
const usedBytes = await measuredAllocationUsage(bucket, storage, prefixes, excludedMarkerKey);
|
|
@@ -6377,7 +6383,7 @@ async function reserveQuotaSummary(bucket, storage, prefixes, initial, chargeByt
|
|
|
6377
6383
|
bucket,
|
|
6378
6384
|
storage,
|
|
6379
6385
|
prefixes,
|
|
6380
|
-
|
|
6386
|
+
"reuse",
|
|
6381
6387
|
markerKey ?? void 0
|
|
6382
6388
|
);
|
|
6383
6389
|
if (!ensured) {
|
|
@@ -6402,7 +6408,7 @@ async function reserveQuotaSummary(bucket, storage, prefixes, initial, chargeByt
|
|
|
6402
6408
|
bucket,
|
|
6403
6409
|
storage,
|
|
6404
6410
|
prefixes,
|
|
6405
|
-
|
|
6411
|
+
"force",
|
|
6406
6412
|
markerKey ?? void 0
|
|
6407
6413
|
);
|
|
6408
6414
|
if (!refreshed?.summary) {
|
|
@@ -6495,7 +6501,7 @@ async function storageUsage(bucket, storage) {
|
|
|
6495
6501
|
try {
|
|
6496
6502
|
const prefixes = await allocationPrefixes(storage);
|
|
6497
6503
|
if (prefixes === null) return null;
|
|
6498
|
-
const current = await ensureQuotaSummary(bucket, storage, prefixes);
|
|
6504
|
+
const current = await ensureQuotaSummary(bucket, storage, prefixes, "repairDirty");
|
|
6499
6505
|
return current?.summary?.usedBytes ?? null;
|
|
6500
6506
|
} catch (error) {
|
|
6501
6507
|
console.error("[files:quota] usage:", error);
|
|
@@ -7444,8 +7450,8 @@ function buildCronContext(env, ownerUserId, roomId = "default") {
|
|
|
7444
7450
|
}
|
|
7445
7451
|
|
|
7446
7452
|
// src/server/utils/app-role.ts
|
|
7447
|
-
async function
|
|
7448
|
-
if (userId === env.OWNER_USER_ID) return "admin";
|
|
7453
|
+
async function resolveAppMembership(env, userId, signal) {
|
|
7454
|
+
if (userId === env.OWNER_USER_ID) return { member: true, role: "admin" };
|
|
7449
7455
|
const stub = env.RECORD_ROOMS.get(env.RECORD_ROOMS.idFromName(`app:${env.DEEPSPACE_APP_ID}`));
|
|
7450
7456
|
try {
|
|
7451
7457
|
const res = await stub.fetch(
|
|
@@ -7459,16 +7465,21 @@ async function resolveAppRole(env, userId) {
|
|
|
7459
7465
|
body: JSON.stringify({
|
|
7460
7466
|
tool: "records.get",
|
|
7461
7467
|
params: { collection: "users", recordId: userId }
|
|
7462
|
-
})
|
|
7468
|
+
}),
|
|
7469
|
+
signal
|
|
7463
7470
|
})
|
|
7464
7471
|
);
|
|
7465
7472
|
const json = await res.json();
|
|
7466
|
-
|
|
7467
|
-
|
|
7473
|
+
if (!json.success || !json.data?.record) return { member: false, role: "viewer" };
|
|
7474
|
+
const role = json.data.record.data?.role;
|
|
7475
|
+
return { member: true, role: isWriterRole(role) ? role : "viewer" };
|
|
7468
7476
|
} catch {
|
|
7469
|
-
return
|
|
7477
|
+
return null;
|
|
7470
7478
|
}
|
|
7471
7479
|
}
|
|
7480
|
+
async function resolveAppRole(env, userId) {
|
|
7481
|
+
return (await resolveAppMembership(env, userId))?.role ?? "viewer";
|
|
7482
|
+
}
|
|
7472
7483
|
|
|
7473
7484
|
// src/server/utils/ai.ts
|
|
7474
7485
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
@@ -7903,6 +7914,9 @@ function locateTrimmableArray(result) {
|
|
|
7903
7914
|
}
|
|
7904
7915
|
return void 0;
|
|
7905
7916
|
}
|
|
7917
|
+
function utf8ByteLength(text) {
|
|
7918
|
+
return new TextEncoder().encode(text).byteLength;
|
|
7919
|
+
}
|
|
7906
7920
|
function capToolResultSize(result, byteCap) {
|
|
7907
7921
|
let serialized;
|
|
7908
7922
|
try {
|
|
@@ -7911,7 +7925,7 @@ function capToolResultSize(result, byteCap) {
|
|
|
7911
7925
|
return { success: false, error: "Tool result could not be serialized." };
|
|
7912
7926
|
}
|
|
7913
7927
|
if (typeof serialized !== "string") return result;
|
|
7914
|
-
if (serialized
|
|
7928
|
+
if (utf8ByteLength(serialized) <= byteCap) return result;
|
|
7915
7929
|
if (result && typeof result === "object") {
|
|
7916
7930
|
const located = locateTrimmableArray(result);
|
|
7917
7931
|
if (located) {
|
|
@@ -7920,7 +7934,7 @@ function capToolResultSize(result, byteCap) {
|
|
|
7920
7934
|
const build = (k) => setPath(result, path, items.slice(0, k), { truncated: true, returned: k, total });
|
|
7921
7935
|
const fits = (k) => {
|
|
7922
7936
|
try {
|
|
7923
|
-
return JSON.stringify(build(k))
|
|
7937
|
+
return utf8ByteLength(JSON.stringify(build(k))) <= byteCap;
|
|
7924
7938
|
} catch {
|
|
7925
7939
|
return false;
|
|
7926
7940
|
}
|
|
@@ -7940,7 +7954,7 @@ function capToolResultSize(result, byteCap) {
|
|
|
7940
7954
|
return {
|
|
7941
7955
|
success: false,
|
|
7942
7956
|
truncated: true,
|
|
7943
|
-
error: `Tool result exceeded ${byteCap} bytes (was ${serialized
|
|
7957
|
+
error: `Tool result exceeded ${byteCap} bytes (was ${utf8ByteLength(serialized)}). Retry with a narrower query (e.g. add a \`where\` filter, reduce \`limit\`, or call records.get for a single record).`,
|
|
7944
7958
|
preview: serialized.slice(0, 2e3)
|
|
7945
7959
|
};
|
|
7946
7960
|
}
|
|
@@ -8092,10 +8106,15 @@ async function prepareMessagesWithCompaction(messages, config, options) {
|
|
|
8092
8106
|
newSummary: { text, throughId }
|
|
8093
8107
|
};
|
|
8094
8108
|
} catch (err) {
|
|
8095
|
-
console.error(
|
|
8109
|
+
console.error(
|
|
8110
|
+
"prepareMessagesWithCompaction: summarizer failed, falling back to sliding window",
|
|
8111
|
+
err
|
|
8112
|
+
);
|
|
8096
8113
|
}
|
|
8097
8114
|
} else {
|
|
8098
|
-
console.warn(
|
|
8115
|
+
console.warn(
|
|
8116
|
+
"prepareMessagesWithCompaction: messages lack ids; cannot anchor a summary, falling back to sliding window"
|
|
8117
|
+
);
|
|
8099
8118
|
}
|
|
8100
8119
|
return {
|
|
8101
8120
|
messages: applySlidingWindow(working, config.contextBudget, config.minKept)
|
|
@@ -9094,38 +9113,43 @@ function documentationLimiterErrorSummary(error) {
|
|
|
9094
9113
|
});
|
|
9095
9114
|
}
|
|
9096
9115
|
|
|
9097
|
-
// src/
|
|
9098
|
-
var
|
|
9116
|
+
// src/shared/bounded-body.ts
|
|
9117
|
+
var BodyTooLargeError = class extends Error {
|
|
9099
9118
|
constructor(maxBytes) {
|
|
9100
|
-
super(`
|
|
9119
|
+
super(`Body exceeds ${maxBytes} bytes`);
|
|
9101
9120
|
this.maxBytes = maxBytes;
|
|
9102
|
-
this.name = "
|
|
9121
|
+
this.name = "BodyTooLargeError";
|
|
9103
9122
|
}
|
|
9104
9123
|
};
|
|
9105
|
-
async function
|
|
9124
|
+
async function readBoundedBodyText(source, maxBytes) {
|
|
9106
9125
|
if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) {
|
|
9107
9126
|
throw new TypeError("maxBytes must be a positive safe integer");
|
|
9108
9127
|
}
|
|
9109
|
-
const declared =
|
|
9128
|
+
const declared = source.headers.get("content-length");
|
|
9110
9129
|
if (declared && /^\d+$/.test(declared.trim()) && Number(declared) > maxBytes) {
|
|
9111
|
-
|
|
9130
|
+
await source.body?.cancel().catch(() => void 0);
|
|
9131
|
+
throw new BodyTooLargeError(maxBytes);
|
|
9112
9132
|
}
|
|
9113
|
-
if (!
|
|
9114
|
-
const reader =
|
|
9133
|
+
if (!source.body) return "";
|
|
9134
|
+
const reader = source.body.getReader();
|
|
9115
9135
|
const decoder = new TextDecoder();
|
|
9116
9136
|
let bytes = 0;
|
|
9117
9137
|
let text = "";
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9138
|
+
try {
|
|
9139
|
+
while (true) {
|
|
9140
|
+
const chunk = await reader.read();
|
|
9141
|
+
if (chunk.done) break;
|
|
9142
|
+
bytes += chunk.value.byteLength;
|
|
9143
|
+
if (bytes > maxBytes) {
|
|
9144
|
+
await reader.cancel().catch(() => void 0);
|
|
9145
|
+
throw new BodyTooLargeError(maxBytes);
|
|
9146
|
+
}
|
|
9147
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
9125
9148
|
}
|
|
9126
|
-
text
|
|
9149
|
+
return text + decoder.decode();
|
|
9150
|
+
} finally {
|
|
9151
|
+
reader.releaseLock();
|
|
9127
9152
|
}
|
|
9128
|
-
return text + decoder.decode();
|
|
9129
9153
|
}
|
|
9130
9154
|
|
|
9131
9155
|
// src/documentation/worker/assistant-routes.ts
|
|
@@ -9165,13 +9189,13 @@ function registerDocumentationAssistantRoutes(app, resolveAuth, publicBasePath =
|
|
|
9165
9189
|
}
|
|
9166
9190
|
let body = null;
|
|
9167
9191
|
try {
|
|
9168
|
-
const raw = await
|
|
9192
|
+
const raw = await readBoundedBodyText(c.req.raw, MAX_REQUEST_BYTES);
|
|
9169
9193
|
const parsed = JSON.parse(raw);
|
|
9170
9194
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
9171
9195
|
body = parsed;
|
|
9172
9196
|
}
|
|
9173
9197
|
} catch (error) {
|
|
9174
|
-
if (error instanceof
|
|
9198
|
+
if (error instanceof BodyTooLargeError) {
|
|
9175
9199
|
return c.json({ error: `request exceeds ${MAX_REQUEST_BYTES} bytes` }, 413);
|
|
9176
9200
|
}
|
|
9177
9201
|
return c.json({ error: "request body must be valid JSON" }, 400);
|
|
@@ -9591,9 +9615,9 @@ function registerDocumentationMcpRoutes(app, publicBasePath = DOCUMENTATION_BASE
|
|
|
9591
9615
|
}
|
|
9592
9616
|
let raw;
|
|
9593
9617
|
try {
|
|
9594
|
-
raw = await
|
|
9618
|
+
raw = await readBoundedBodyText(c.req.raw, MAX_REQUEST_BYTES2);
|
|
9595
9619
|
} catch (error) {
|
|
9596
|
-
if (error instanceof
|
|
9620
|
+
if (error instanceof BodyTooLargeError) {
|
|
9597
9621
|
return mcpError(null, -32600, `Request exceeds ${MAX_REQUEST_BYTES2} bytes`, 413);
|
|
9598
9622
|
}
|
|
9599
9623
|
return mcpError(null, -32700, "Unable to read request body", 400);
|
|
@@ -9922,6 +9946,24 @@ async function verifyJwt(config, token) {
|
|
|
9922
9946
|
}
|
|
9923
9947
|
}
|
|
9924
9948
|
|
|
9949
|
+
// src/server/auth/agentToken.ts
|
|
9950
|
+
var AGENT_TOKEN_SCOPE = "agent";
|
|
9951
|
+
function agentTokenIssuer(issuer) {
|
|
9952
|
+
return `${issuer.replace(/\/+$/, "")}/agent`;
|
|
9953
|
+
}
|
|
9954
|
+
async function verifyAgentToken(config, token, targetOrigin) {
|
|
9955
|
+
const outcome = await verifyJwt(
|
|
9956
|
+
{
|
|
9957
|
+
...config,
|
|
9958
|
+
issuer: agentTokenIssuer(config.issuer),
|
|
9959
|
+
audience: targetOrigin
|
|
9960
|
+
},
|
|
9961
|
+
token
|
|
9962
|
+
);
|
|
9963
|
+
if (!outcome.result || outcome.result.claims.scope === AGENT_TOKEN_SCOPE) return outcome;
|
|
9964
|
+
return { ...outcome, result: null, error: new Error("Invalid agent token scope") };
|
|
9965
|
+
}
|
|
9966
|
+
|
|
9925
9967
|
// src/server/auth/internalAuth.ts
|
|
9926
9968
|
var nodeCryptoPromise = null;
|
|
9927
9969
|
async function loadNodeCrypto() {
|
|
@@ -10200,6 +10242,231 @@ function registerClientErrorRoute(app) {
|
|
|
10200
10242
|
app.post(CLIENT_ERROR_PATH, (c) => handleClientErrorReport(c.req.raw));
|
|
10201
10243
|
}
|
|
10202
10244
|
|
|
10245
|
+
// src/server/agent-tools.ts
|
|
10246
|
+
import { asSchema } from "ai";
|
|
10247
|
+
|
|
10248
|
+
// src/shared/agent-tool-protocol.ts
|
|
10249
|
+
var AGENT_TOOL_REQUEST_BODY_CAP = 64 * 1024;
|
|
10250
|
+
var AGENT_TOOL_RESPONSE_BODY_CAP = 1024 * 1024;
|
|
10251
|
+
|
|
10252
|
+
// src/server/agent-tools.ts
|
|
10253
|
+
function jsonResponse3(body, status = 200) {
|
|
10254
|
+
return rawJsonResponse(JSON.stringify(body), status);
|
|
10255
|
+
}
|
|
10256
|
+
function rawJsonResponse(body, status = 200) {
|
|
10257
|
+
return new Response(body, {
|
|
10258
|
+
status,
|
|
10259
|
+
headers: {
|
|
10260
|
+
"Cache-Control": "no-store",
|
|
10261
|
+
"Content-Type": "application/json; charset=utf-8"
|
|
10262
|
+
}
|
|
10263
|
+
});
|
|
10264
|
+
}
|
|
10265
|
+
function errorResponse(status, code) {
|
|
10266
|
+
const errors = {
|
|
10267
|
+
unauthenticated: "Authentication is required.",
|
|
10268
|
+
forbidden: "You are not allowed to use assistant tools.",
|
|
10269
|
+
access_check_unavailable: "Access could not be verified. Try again.",
|
|
10270
|
+
tool_not_found: "The requested tool is not available.",
|
|
10271
|
+
invalid_json: "The request body must be valid JSON.",
|
|
10272
|
+
invalid_tool_input: "The tool input is invalid.",
|
|
10273
|
+
payload_too_large: "The request body is too large.",
|
|
10274
|
+
tool_configuration_error: "Assistant tools are not configured correctly.",
|
|
10275
|
+
tool_execution_failed: "The tool could not be executed.",
|
|
10276
|
+
invalid_tool_result: "The tool returned an invalid result.",
|
|
10277
|
+
tool_result_too_large: "The tool returned a result that is too large."
|
|
10278
|
+
};
|
|
10279
|
+
return jsonResponse3({ ok: false, code, error: errors[code] }, status);
|
|
10280
|
+
}
|
|
10281
|
+
function parseToolRequestBody(text) {
|
|
10282
|
+
let parsed;
|
|
10283
|
+
try {
|
|
10284
|
+
parsed = JSON.parse(text);
|
|
10285
|
+
} catch {
|
|
10286
|
+
return void 0;
|
|
10287
|
+
}
|
|
10288
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
10289
|
+
if (!Object.hasOwn(parsed, "input")) return null;
|
|
10290
|
+
return { input: parsed.input };
|
|
10291
|
+
}
|
|
10292
|
+
function isAsyncIterable(value) {
|
|
10293
|
+
return value !== null && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value;
|
|
10294
|
+
}
|
|
10295
|
+
function jsonText(value) {
|
|
10296
|
+
try {
|
|
10297
|
+
const serialized = JSON.stringify(value);
|
|
10298
|
+
return typeof serialized === "string" ? serialized : void 0;
|
|
10299
|
+
} catch {
|
|
10300
|
+
return void 0;
|
|
10301
|
+
}
|
|
10302
|
+
}
|
|
10303
|
+
function executableTool(tools, name) {
|
|
10304
|
+
if (!Object.hasOwn(tools, name)) return void 0;
|
|
10305
|
+
const tool3 = tools[name];
|
|
10306
|
+
return typeof tool3.execute === "function" ? { ...tool3, execute: tool3.execute } : void 0;
|
|
10307
|
+
}
|
|
10308
|
+
function toolMetadata(tools) {
|
|
10309
|
+
return Object.entries(tools).flatMap(([name, tool3]) => {
|
|
10310
|
+
if (typeof tool3.execute !== "function") return [];
|
|
10311
|
+
const inputSchema = asSchema(tool3.inputSchema);
|
|
10312
|
+
const entry = {
|
|
10313
|
+
name,
|
|
10314
|
+
description: typeof tool3.description === "string" ? tool3.description : "",
|
|
10315
|
+
inputSchema: inputSchema.jsonSchema
|
|
10316
|
+
};
|
|
10317
|
+
if (tool3.outputSchema) entry.outputSchema = asSchema(tool3.outputSchema).jsonSchema;
|
|
10318
|
+
return [entry];
|
|
10319
|
+
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
10320
|
+
}
|
|
10321
|
+
function createUserToolExecutor(env, userId, signal) {
|
|
10322
|
+
const roomId = env.RECORD_ROOMS.idFromName(`app:${env.DEEPSPACE_APP_ID}`);
|
|
10323
|
+
const room = env.RECORD_ROOMS.get(roomId);
|
|
10324
|
+
return async (toolName, params) => {
|
|
10325
|
+
const response = await room.fetch(
|
|
10326
|
+
new Request("https://internal/api/tools/execute", {
|
|
10327
|
+
method: "POST",
|
|
10328
|
+
headers: {
|
|
10329
|
+
"Content-Type": "application/json",
|
|
10330
|
+
"X-User-Id": userId
|
|
10331
|
+
},
|
|
10332
|
+
body: JSON.stringify({ tool: toolName, params }),
|
|
10333
|
+
signal
|
|
10334
|
+
})
|
|
10335
|
+
);
|
|
10336
|
+
return capToolResultSize(await response.json(), DEFAULT_CONTEXT_CONFIG.toolResultCap);
|
|
10337
|
+
};
|
|
10338
|
+
}
|
|
10339
|
+
async function resolveCallerTools(options, request2, env) {
|
|
10340
|
+
let access;
|
|
10341
|
+
try {
|
|
10342
|
+
access = await options.resolveAccess(request2, env);
|
|
10343
|
+
} catch {
|
|
10344
|
+
return errorResponse(500, "tool_configuration_error");
|
|
10345
|
+
}
|
|
10346
|
+
if (!access.ok) {
|
|
10347
|
+
return errorResponse(
|
|
10348
|
+
access.status,
|
|
10349
|
+
access.status === 401 ? "unauthenticated" : access.status === 403 ? "forbidden" : "access_check_unavailable"
|
|
10350
|
+
);
|
|
10351
|
+
}
|
|
10352
|
+
try {
|
|
10353
|
+
return options.buildTools(createUserToolExecutor(env, access.auth.userId, request2.signal));
|
|
10354
|
+
} catch {
|
|
10355
|
+
return errorResponse(500, "tool_configuration_error");
|
|
10356
|
+
}
|
|
10357
|
+
}
|
|
10358
|
+
function registerAgentToolRoutes(app, options) {
|
|
10359
|
+
app.get("/_deepspace/agent/tools", async (c) => {
|
|
10360
|
+
const tools = await resolveCallerTools(options, c.req.raw, c.env);
|
|
10361
|
+
if (tools instanceof Response) return tools;
|
|
10362
|
+
try {
|
|
10363
|
+
const serialized = jsonText({
|
|
10364
|
+
ok: true,
|
|
10365
|
+
app: { id: c.env.DEEPSPACE_APP_ID, name: c.env.APP_NAME },
|
|
10366
|
+
tools: toolMetadata(tools)
|
|
10367
|
+
});
|
|
10368
|
+
if (!serialized || utf8ByteLength(serialized) > AGENT_TOOL_RESPONSE_BODY_CAP) {
|
|
10369
|
+
return errorResponse(500, "tool_configuration_error");
|
|
10370
|
+
}
|
|
10371
|
+
return rawJsonResponse(serialized);
|
|
10372
|
+
} catch {
|
|
10373
|
+
return errorResponse(500, "tool_configuration_error");
|
|
10374
|
+
}
|
|
10375
|
+
});
|
|
10376
|
+
app.post("/_deepspace/agent/tools/:name", async (c) => {
|
|
10377
|
+
const tools = await resolveCallerTools(options, c.req.raw, c.env);
|
|
10378
|
+
if (tools instanceof Response) return tools;
|
|
10379
|
+
let tool3;
|
|
10380
|
+
try {
|
|
10381
|
+
tool3 = executableTool(tools, c.req.param("name"));
|
|
10382
|
+
} catch {
|
|
10383
|
+
return errorResponse(500, "tool_configuration_error");
|
|
10384
|
+
}
|
|
10385
|
+
if (!tool3) return errorResponse(404, "tool_not_found");
|
|
10386
|
+
let text;
|
|
10387
|
+
try {
|
|
10388
|
+
text = await readBoundedBodyText(c.req.raw, AGENT_TOOL_REQUEST_BODY_CAP);
|
|
10389
|
+
} catch (error) {
|
|
10390
|
+
return error instanceof BodyTooLargeError ? errorResponse(413, "payload_too_large") : errorResponse(400, "invalid_json");
|
|
10391
|
+
}
|
|
10392
|
+
const body = parseToolRequestBody(text);
|
|
10393
|
+
if (body === void 0) return errorResponse(400, "invalid_json");
|
|
10394
|
+
if (body === null) return errorResponse(400, "invalid_tool_input");
|
|
10395
|
+
let input = body.input;
|
|
10396
|
+
try {
|
|
10397
|
+
const validation = asSchema(tool3.inputSchema).validate;
|
|
10398
|
+
if (validation) {
|
|
10399
|
+
const result = await validation(input);
|
|
10400
|
+
if (!result.success) return errorResponse(400, "invalid_tool_input");
|
|
10401
|
+
input = result.value;
|
|
10402
|
+
}
|
|
10403
|
+
} catch {
|
|
10404
|
+
return errorResponse(400, "invalid_tool_input");
|
|
10405
|
+
}
|
|
10406
|
+
let output;
|
|
10407
|
+
try {
|
|
10408
|
+
output = await tool3.execute(input, {
|
|
10409
|
+
toolCallId: crypto.randomUUID(),
|
|
10410
|
+
messages: [],
|
|
10411
|
+
abortSignal: c.req.raw.signal
|
|
10412
|
+
});
|
|
10413
|
+
} catch {
|
|
10414
|
+
return errorResponse(500, "tool_execution_failed");
|
|
10415
|
+
}
|
|
10416
|
+
if (isAsyncIterable(output)) return errorResponse(500, "invalid_tool_result");
|
|
10417
|
+
try {
|
|
10418
|
+
if (tool3.outputSchema) {
|
|
10419
|
+
const validation = asSchema(tool3.outputSchema).validate;
|
|
10420
|
+
if (validation) {
|
|
10421
|
+
const result = await validation(output);
|
|
10422
|
+
if (!result.success) return errorResponse(500, "invalid_tool_result");
|
|
10423
|
+
output = result.value;
|
|
10424
|
+
}
|
|
10425
|
+
}
|
|
10426
|
+
} catch {
|
|
10427
|
+
return errorResponse(500, "invalid_tool_result");
|
|
10428
|
+
}
|
|
10429
|
+
const serialized = jsonText(output === void 0 ? null : output);
|
|
10430
|
+
if (!serialized) return errorResponse(500, "invalid_tool_result");
|
|
10431
|
+
if (utf8ByteLength(serialized) > DEFAULT_CONTEXT_CONFIG.toolResultCap) {
|
|
10432
|
+
return errorResponse(500, "tool_result_too_large");
|
|
10433
|
+
}
|
|
10434
|
+
return rawJsonResponse(`{"ok":true,"result":${serialized}}`);
|
|
10435
|
+
});
|
|
10436
|
+
app.all("/_deepspace/agent", () => errorResponse(404, "tool_not_found"));
|
|
10437
|
+
app.all("/_deepspace/agent/*", () => errorResponse(404, "tool_not_found"));
|
|
10438
|
+
}
|
|
10439
|
+
|
|
10440
|
+
// src/server/agent-target.ts
|
|
10441
|
+
var PRODUCTION_OFFICIAL_AGENT_ORIGINS = ["https://admin.deep.space"];
|
|
10442
|
+
var PRODUCTION_APP_DOMAIN = "app.space";
|
|
10443
|
+
function normalizeAgentTargetOrigin(value, policy) {
|
|
10444
|
+
if (typeof value !== "string" || !value) return null;
|
|
10445
|
+
let url;
|
|
10446
|
+
try {
|
|
10447
|
+
url = new URL(value);
|
|
10448
|
+
} catch {
|
|
10449
|
+
return null;
|
|
10450
|
+
}
|
|
10451
|
+
if (url.username || url.password || url.search || url.hash || url.pathname !== "/") return null;
|
|
10452
|
+
const hostname = url.hostname.toLowerCase();
|
|
10453
|
+
const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(hostname);
|
|
10454
|
+
if (loopback) {
|
|
10455
|
+
return policy.allowLoopback && ["http:", "https:"].includes(url.protocol) ? url.origin : null;
|
|
10456
|
+
}
|
|
10457
|
+
if (url.protocol !== "https:" || url.port) return null;
|
|
10458
|
+
if (policy.appDomain.toLowerCase() === PRODUCTION_APP_DOMAIN && PRODUCTION_OFFICIAL_AGENT_ORIGINS.includes(url.origin)) {
|
|
10459
|
+
return url.origin;
|
|
10460
|
+
}
|
|
10461
|
+
const suffix = `.${policy.appDomain.toLowerCase()}`;
|
|
10462
|
+
if (!hostname.endsWith(suffix)) return null;
|
|
10463
|
+
const label = hostname.slice(0, -suffix.length);
|
|
10464
|
+
return !label.includes(".") && validateAppName(label).valid ? url.origin : null;
|
|
10465
|
+
}
|
|
10466
|
+
|
|
10467
|
+
// src/shared/auth-session.ts
|
|
10468
|
+
var SESSION_COOKIE = "__Secure-better-auth.session_token";
|
|
10469
|
+
|
|
10203
10470
|
// src/shared/log-events.ts
|
|
10204
10471
|
var LOG_LEVELS = ["debug", "log", "info", "warn", "error"];
|
|
10205
10472
|
var APP_LOG_EVENT_KEYS = [
|
|
@@ -10217,6 +10484,9 @@ export {
|
|
|
10217
10484
|
ACCOUNT_STORAGE_LIMIT_BYTES,
|
|
10218
10485
|
ACTION_ROUTES_BEARER_GUARD_MIGRATION_ID,
|
|
10219
10486
|
ACTION_TOOLS_DELETE_WHERE_MIGRATION_ID,
|
|
10487
|
+
AGENT_TOKEN_SCOPE,
|
|
10488
|
+
AGENT_TOOL_REQUEST_BODY_CAP,
|
|
10489
|
+
AGENT_TOOL_RESPONSE_BODY_CAP,
|
|
10220
10490
|
AI_CHATS_SCHEMA,
|
|
10221
10491
|
AI_MESSAGES_SCHEMA,
|
|
10222
10492
|
ALLOWED_BINDING_TYPES,
|
|
@@ -10268,6 +10538,7 @@ export {
|
|
|
10268
10538
|
MSG_SYNC_UPDATE,
|
|
10269
10539
|
MSG_YJS_AWARENESS,
|
|
10270
10540
|
MSG_YJS_SYNC,
|
|
10541
|
+
PRODUCTION_OFFICIAL_AGENT_ORIGINS,
|
|
10271
10542
|
PresenceRoom,
|
|
10272
10543
|
REACTIONS_SCHEMA,
|
|
10273
10544
|
READ_RECEIPTS_SCHEMA,
|
|
@@ -10286,6 +10557,7 @@ export {
|
|
|
10286
10557
|
RegistryClientError,
|
|
10287
10558
|
SDK_RUN_WORKER_FIRST,
|
|
10288
10559
|
SECURE_ROOM_BOUNDARIES_MIGRATION_ID,
|
|
10560
|
+
SESSION_COOKIE,
|
|
10289
10561
|
STRICT_APP_ID_RE,
|
|
10290
10562
|
SYSTEM_ASSIGNED_COLUMNS,
|
|
10291
10563
|
SYSTEM_COLLECTIONS,
|
|
@@ -10298,6 +10570,7 @@ export {
|
|
|
10298
10570
|
USERS_COLUMNS,
|
|
10299
10571
|
WORKER_OWNED_NOT_FOUND_MIGRATION_ID,
|
|
10300
10572
|
YjsRoom,
|
|
10573
|
+
agentTokenIssuer,
|
|
10301
10574
|
apiWorkerFetch,
|
|
10302
10575
|
appendMessage,
|
|
10303
10576
|
applyAiToolDefaults,
|
|
@@ -10331,6 +10604,7 @@ export {
|
|
|
10331
10604
|
createDeepSpaceAuth,
|
|
10332
10605
|
createEncoder,
|
|
10333
10606
|
createScopedR2Handler,
|
|
10607
|
+
createUserToolExecutor,
|
|
10334
10608
|
dataToColumnValues,
|
|
10335
10609
|
decodeJwtPayload,
|
|
10336
10610
|
deepSpaceAgentErrorSummary,
|
|
@@ -10376,6 +10650,7 @@ export {
|
|
|
10376
10650
|
mintAppId,
|
|
10377
10651
|
mintUlid,
|
|
10378
10652
|
noopPermissionContext,
|
|
10653
|
+
normalizeAgentTargetOrigin,
|
|
10379
10654
|
normalizeKnowledgeFolder,
|
|
10380
10655
|
parseQuotaLimit,
|
|
10381
10656
|
platformCorsPatterns,
|
|
@@ -10384,10 +10659,12 @@ export {
|
|
|
10384
10659
|
priceBindingUsageEvent,
|
|
10385
10660
|
readVarUint,
|
|
10386
10661
|
readVarUint8Array,
|
|
10662
|
+
registerAgentToolRoutes,
|
|
10387
10663
|
registerClientErrorRoute,
|
|
10388
10664
|
registerDeepSpaceDocumentation,
|
|
10389
10665
|
registryErrorJson,
|
|
10390
10666
|
registryStub,
|
|
10667
|
+
resolveAppMembership,
|
|
10391
10668
|
resolveAppName,
|
|
10392
10669
|
resolveAppRole,
|
|
10393
10670
|
resolveColumn,
|
|
@@ -10411,6 +10688,7 @@ export {
|
|
|
10411
10688
|
validateAppName,
|
|
10412
10689
|
validateBindingManifest,
|
|
10413
10690
|
validateDoManifest,
|
|
10691
|
+
verifyAgentToken,
|
|
10414
10692
|
verifyJwt,
|
|
10415
10693
|
writeVarUint,
|
|
10416
10694
|
writeVarUint8Array
|