deepspace 0.28.0 → 0.28.2
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 +43 -0
- package/README.md +8 -0
- package/dist/{chunk-652TIGI4.js → chunk-DMUR67NG.js} +2 -2
- package/dist/{chunk-652TIGI4.js.map → chunk-DMUR67NG.js.map} +1 -1
- package/dist/cli.js +546 -72
- 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 +21 -1
- package/dist/server.js +52 -12
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +99 -1
- package/dist/worker.js +360 -34
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
package/dist/worker.js
CHANGED
|
@@ -2600,7 +2600,12 @@ async function executeTool(ctx, toolName, params, userId, userRole, skipUserRbac
|
|
|
2600
2600
|
case "user.current": {
|
|
2601
2601
|
if (!userId) return { success: false, error: "No userId provided" };
|
|
2602
2602
|
const user = getUser(ctx.sql, userId, ctx.schemaRegistry);
|
|
2603
|
-
if (!user)
|
|
2603
|
+
if (!user) {
|
|
2604
|
+
return {
|
|
2605
|
+
success: false,
|
|
2606
|
+
error: "No users row for this identity yet \u2014 it is created by signing in to the app in a browser. Tool access does not require one, so other tools keep working."
|
|
2607
|
+
};
|
|
2608
|
+
}
|
|
2604
2609
|
return { success: true, data: { user } };
|
|
2605
2610
|
}
|
|
2606
2611
|
// The same roster the socket's `user.list` returns, for the same caller.
|
|
@@ -7450,8 +7455,8 @@ function buildCronContext(env, ownerUserId, roomId = "default") {
|
|
|
7450
7455
|
}
|
|
7451
7456
|
|
|
7452
7457
|
// src/server/utils/app-role.ts
|
|
7453
|
-
async function
|
|
7454
|
-
if (userId === env.OWNER_USER_ID) return "admin";
|
|
7458
|
+
async function resolveAppMembership(env, userId, signal) {
|
|
7459
|
+
if (userId === env.OWNER_USER_ID) return { member: true, role: "admin" };
|
|
7455
7460
|
const stub = env.RECORD_ROOMS.get(env.RECORD_ROOMS.idFromName(`app:${env.DEEPSPACE_APP_ID}`));
|
|
7456
7461
|
try {
|
|
7457
7462
|
const res = await stub.fetch(
|
|
@@ -7465,16 +7470,21 @@ async function resolveAppRole(env, userId) {
|
|
|
7465
7470
|
body: JSON.stringify({
|
|
7466
7471
|
tool: "records.get",
|
|
7467
7472
|
params: { collection: "users", recordId: userId }
|
|
7468
|
-
})
|
|
7473
|
+
}),
|
|
7474
|
+
signal
|
|
7469
7475
|
})
|
|
7470
7476
|
);
|
|
7471
7477
|
const json = await res.json();
|
|
7472
|
-
|
|
7473
|
-
|
|
7478
|
+
if (!json.success || !json.data?.record) return { member: false, role: "viewer" };
|
|
7479
|
+
const role = json.data.record.data?.role;
|
|
7480
|
+
return { member: true, role: isWriterRole(role) ? role : "viewer" };
|
|
7474
7481
|
} catch {
|
|
7475
|
-
return
|
|
7482
|
+
return null;
|
|
7476
7483
|
}
|
|
7477
7484
|
}
|
|
7485
|
+
async function resolveAppRole(env, userId) {
|
|
7486
|
+
return (await resolveAppMembership(env, userId))?.role ?? "viewer";
|
|
7487
|
+
}
|
|
7478
7488
|
|
|
7479
7489
|
// src/server/utils/ai.ts
|
|
7480
7490
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
@@ -7909,6 +7919,9 @@ function locateTrimmableArray(result) {
|
|
|
7909
7919
|
}
|
|
7910
7920
|
return void 0;
|
|
7911
7921
|
}
|
|
7922
|
+
function utf8ByteLength(text) {
|
|
7923
|
+
return new TextEncoder().encode(text).byteLength;
|
|
7924
|
+
}
|
|
7912
7925
|
function capToolResultSize(result, byteCap) {
|
|
7913
7926
|
let serialized;
|
|
7914
7927
|
try {
|
|
@@ -7917,7 +7930,7 @@ function capToolResultSize(result, byteCap) {
|
|
|
7917
7930
|
return { success: false, error: "Tool result could not be serialized." };
|
|
7918
7931
|
}
|
|
7919
7932
|
if (typeof serialized !== "string") return result;
|
|
7920
|
-
if (serialized
|
|
7933
|
+
if (utf8ByteLength(serialized) <= byteCap) return result;
|
|
7921
7934
|
if (result && typeof result === "object") {
|
|
7922
7935
|
const located = locateTrimmableArray(result);
|
|
7923
7936
|
if (located) {
|
|
@@ -7926,7 +7939,7 @@ function capToolResultSize(result, byteCap) {
|
|
|
7926
7939
|
const build = (k) => setPath(result, path, items.slice(0, k), { truncated: true, returned: k, total });
|
|
7927
7940
|
const fits = (k) => {
|
|
7928
7941
|
try {
|
|
7929
|
-
return JSON.stringify(build(k))
|
|
7942
|
+
return utf8ByteLength(JSON.stringify(build(k))) <= byteCap;
|
|
7930
7943
|
} catch {
|
|
7931
7944
|
return false;
|
|
7932
7945
|
}
|
|
@@ -7946,7 +7959,7 @@ function capToolResultSize(result, byteCap) {
|
|
|
7946
7959
|
return {
|
|
7947
7960
|
success: false,
|
|
7948
7961
|
truncated: true,
|
|
7949
|
-
error: `Tool result exceeded ${byteCap} bytes (was ${serialized
|
|
7962
|
+
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).`,
|
|
7950
7963
|
preview: serialized.slice(0, 2e3)
|
|
7951
7964
|
};
|
|
7952
7965
|
}
|
|
@@ -8098,10 +8111,15 @@ async function prepareMessagesWithCompaction(messages, config, options) {
|
|
|
8098
8111
|
newSummary: { text, throughId }
|
|
8099
8112
|
};
|
|
8100
8113
|
} catch (err) {
|
|
8101
|
-
console.error(
|
|
8114
|
+
console.error(
|
|
8115
|
+
"prepareMessagesWithCompaction: summarizer failed, falling back to sliding window",
|
|
8116
|
+
err
|
|
8117
|
+
);
|
|
8102
8118
|
}
|
|
8103
8119
|
} else {
|
|
8104
|
-
console.warn(
|
|
8120
|
+
console.warn(
|
|
8121
|
+
"prepareMessagesWithCompaction: messages lack ids; cannot anchor a summary, falling back to sliding window"
|
|
8122
|
+
);
|
|
8105
8123
|
}
|
|
8106
8124
|
return {
|
|
8107
8125
|
messages: applySlidingWindow(working, config.contextBudget, config.minKept)
|
|
@@ -9100,38 +9118,43 @@ function documentationLimiterErrorSummary(error) {
|
|
|
9100
9118
|
});
|
|
9101
9119
|
}
|
|
9102
9120
|
|
|
9103
|
-
// src/
|
|
9104
|
-
var
|
|
9121
|
+
// src/shared/bounded-body.ts
|
|
9122
|
+
var BodyTooLargeError = class extends Error {
|
|
9105
9123
|
constructor(maxBytes) {
|
|
9106
|
-
super(`
|
|
9124
|
+
super(`Body exceeds ${maxBytes} bytes`);
|
|
9107
9125
|
this.maxBytes = maxBytes;
|
|
9108
|
-
this.name = "
|
|
9126
|
+
this.name = "BodyTooLargeError";
|
|
9109
9127
|
}
|
|
9110
9128
|
};
|
|
9111
|
-
async function
|
|
9129
|
+
async function readBoundedBodyText(source, maxBytes) {
|
|
9112
9130
|
if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) {
|
|
9113
9131
|
throw new TypeError("maxBytes must be a positive safe integer");
|
|
9114
9132
|
}
|
|
9115
|
-
const declared =
|
|
9133
|
+
const declared = source.headers.get("content-length");
|
|
9116
9134
|
if (declared && /^\d+$/.test(declared.trim()) && Number(declared) > maxBytes) {
|
|
9117
|
-
|
|
9135
|
+
await source.body?.cancel().catch(() => void 0);
|
|
9136
|
+
throw new BodyTooLargeError(maxBytes);
|
|
9118
9137
|
}
|
|
9119
|
-
if (!
|
|
9120
|
-
const reader =
|
|
9138
|
+
if (!source.body) return "";
|
|
9139
|
+
const reader = source.body.getReader();
|
|
9121
9140
|
const decoder = new TextDecoder();
|
|
9122
9141
|
let bytes = 0;
|
|
9123
9142
|
let text = "";
|
|
9124
|
-
|
|
9125
|
-
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9130
|
-
|
|
9143
|
+
try {
|
|
9144
|
+
while (true) {
|
|
9145
|
+
const chunk = await reader.read();
|
|
9146
|
+
if (chunk.done) break;
|
|
9147
|
+
bytes += chunk.value.byteLength;
|
|
9148
|
+
if (bytes > maxBytes) {
|
|
9149
|
+
await reader.cancel().catch(() => void 0);
|
|
9150
|
+
throw new BodyTooLargeError(maxBytes);
|
|
9151
|
+
}
|
|
9152
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
9131
9153
|
}
|
|
9132
|
-
text
|
|
9154
|
+
return text + decoder.decode();
|
|
9155
|
+
} finally {
|
|
9156
|
+
reader.releaseLock();
|
|
9133
9157
|
}
|
|
9134
|
-
return text + decoder.decode();
|
|
9135
9158
|
}
|
|
9136
9159
|
|
|
9137
9160
|
// src/documentation/worker/assistant-routes.ts
|
|
@@ -9171,13 +9194,13 @@ function registerDocumentationAssistantRoutes(app, resolveAuth, publicBasePath =
|
|
|
9171
9194
|
}
|
|
9172
9195
|
let body = null;
|
|
9173
9196
|
try {
|
|
9174
|
-
const raw = await
|
|
9197
|
+
const raw = await readBoundedBodyText(c.req.raw, MAX_REQUEST_BYTES);
|
|
9175
9198
|
const parsed = JSON.parse(raw);
|
|
9176
9199
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
9177
9200
|
body = parsed;
|
|
9178
9201
|
}
|
|
9179
9202
|
} catch (error) {
|
|
9180
|
-
if (error instanceof
|
|
9203
|
+
if (error instanceof BodyTooLargeError) {
|
|
9181
9204
|
return c.json({ error: `request exceeds ${MAX_REQUEST_BYTES} bytes` }, 413);
|
|
9182
9205
|
}
|
|
9183
9206
|
return c.json({ error: "request body must be valid JSON" }, 400);
|
|
@@ -9597,9 +9620,9 @@ function registerDocumentationMcpRoutes(app, publicBasePath = DOCUMENTATION_BASE
|
|
|
9597
9620
|
}
|
|
9598
9621
|
let raw;
|
|
9599
9622
|
try {
|
|
9600
|
-
raw = await
|
|
9623
|
+
raw = await readBoundedBodyText(c.req.raw, MAX_REQUEST_BYTES2);
|
|
9601
9624
|
} catch (error) {
|
|
9602
|
-
if (error instanceof
|
|
9625
|
+
if (error instanceof BodyTooLargeError) {
|
|
9603
9626
|
return mcpError(null, -32600, `Request exceeds ${MAX_REQUEST_BYTES2} bytes`, 413);
|
|
9604
9627
|
}
|
|
9605
9628
|
return mcpError(null, -32700, "Unable to read request body", 400);
|
|
@@ -9928,6 +9951,24 @@ async function verifyJwt(config, token) {
|
|
|
9928
9951
|
}
|
|
9929
9952
|
}
|
|
9930
9953
|
|
|
9954
|
+
// src/server/auth/agentToken.ts
|
|
9955
|
+
var AGENT_TOKEN_SCOPE = "agent";
|
|
9956
|
+
function agentTokenIssuer(issuer) {
|
|
9957
|
+
return `${issuer.replace(/\/+$/, "")}/agent`;
|
|
9958
|
+
}
|
|
9959
|
+
async function verifyAgentToken(config, token, targetOrigin) {
|
|
9960
|
+
const outcome = await verifyJwt(
|
|
9961
|
+
{
|
|
9962
|
+
...config,
|
|
9963
|
+
issuer: agentTokenIssuer(config.issuer),
|
|
9964
|
+
audience: targetOrigin
|
|
9965
|
+
},
|
|
9966
|
+
token
|
|
9967
|
+
);
|
|
9968
|
+
if (!outcome.result || outcome.result.claims.scope === AGENT_TOKEN_SCOPE) return outcome;
|
|
9969
|
+
return { ...outcome, result: null, error: new Error("Invalid agent token scope") };
|
|
9970
|
+
}
|
|
9971
|
+
|
|
9931
9972
|
// src/server/auth/internalAuth.ts
|
|
9932
9973
|
var nodeCryptoPromise = null;
|
|
9933
9974
|
async function loadNodeCrypto() {
|
|
@@ -10206,6 +10247,280 @@ function registerClientErrorRoute(app) {
|
|
|
10206
10247
|
app.post(CLIENT_ERROR_PATH, (c) => handleClientErrorReport(c.req.raw));
|
|
10207
10248
|
}
|
|
10208
10249
|
|
|
10250
|
+
// src/server/agent-tools.ts
|
|
10251
|
+
import { asSchema } from "ai";
|
|
10252
|
+
|
|
10253
|
+
// src/shared/agent-tool-protocol.ts
|
|
10254
|
+
var AGENT_TOOL_REQUEST_BODY_CAP = 64 * 1024;
|
|
10255
|
+
var AGENT_TOOL_RESPONSE_BODY_CAP = 1024 * 1024;
|
|
10256
|
+
|
|
10257
|
+
// src/server/agent-tools.ts
|
|
10258
|
+
function jsonResponse3(body, status = 200) {
|
|
10259
|
+
return rawJsonResponse(JSON.stringify(body), status);
|
|
10260
|
+
}
|
|
10261
|
+
function rawJsonResponse(body, status = 200) {
|
|
10262
|
+
return new Response(body, {
|
|
10263
|
+
status,
|
|
10264
|
+
headers: {
|
|
10265
|
+
"Cache-Control": "no-store",
|
|
10266
|
+
"Content-Type": "application/json; charset=utf-8"
|
|
10267
|
+
}
|
|
10268
|
+
});
|
|
10269
|
+
}
|
|
10270
|
+
function errorResponse(status, code, detail) {
|
|
10271
|
+
const errors = {
|
|
10272
|
+
unauthenticated: "Authentication is required.",
|
|
10273
|
+
// The remedy is documented and single-step (local-agent-tools.md): a
|
|
10274
|
+
// signed-in app visit creates or refreshes the caller's user row.
|
|
10275
|
+
forbidden: "You are not allowed to use assistant tools. Sign in to the app once in a browser (a signed-in visit creates your user row), or ask the app owner for access.",
|
|
10276
|
+
access_check_unavailable: "Access could not be verified. Try again.",
|
|
10277
|
+
tool_not_found: "The requested tool is not available.",
|
|
10278
|
+
invalid_json: "The request body must be valid JSON.",
|
|
10279
|
+
invalid_tool_input: "The tool input is invalid.",
|
|
10280
|
+
payload_too_large: "The request body is too large.",
|
|
10281
|
+
tool_configuration_error: "Assistant tools are not configured correctly.",
|
|
10282
|
+
tool_execution_failed: "The tool could not be executed.",
|
|
10283
|
+
invalid_tool_result: "The tool returned an invalid result.",
|
|
10284
|
+
tool_result_too_large: "The tool returned a result that is too large."
|
|
10285
|
+
};
|
|
10286
|
+
const error = detail ? `${errors[code]} ${detail}` : errors[code];
|
|
10287
|
+
return jsonResponse3({ ok: false, code, error }, status);
|
|
10288
|
+
}
|
|
10289
|
+
function validationDetail(error) {
|
|
10290
|
+
const issues = error.issues;
|
|
10291
|
+
if (Array.isArray(issues) && issues.length > 0) {
|
|
10292
|
+
const shown = issues.slice(0, 5).map((issue) => {
|
|
10293
|
+
const { path, message } = issue ?? {};
|
|
10294
|
+
const at = Array.isArray(path) && path.length > 0 ? `${path.join(".")}: ` : "";
|
|
10295
|
+
return `${at}${typeof message === "string" ? message : "invalid"}`;
|
|
10296
|
+
});
|
|
10297
|
+
const more = issues.length - shown.length;
|
|
10298
|
+
return `${shown.join("; ")}${more > 0 ? ` (+${more} more)` : ""}`;
|
|
10299
|
+
}
|
|
10300
|
+
if (!(error instanceof Error) || !error.message) return void 0;
|
|
10301
|
+
const line = error.message.replace(/\s+/g, " ").trim();
|
|
10302
|
+
return line.length > 400 ? `${line.slice(0, 400)}\u2026` : line;
|
|
10303
|
+
}
|
|
10304
|
+
function droppedTopLevelKeys(schema, input, validated) {
|
|
10305
|
+
if (input === null || typeof input !== "object" || Array.isArray(input) || validated === null || typeof validated !== "object" || Array.isArray(validated)) {
|
|
10306
|
+
return [];
|
|
10307
|
+
}
|
|
10308
|
+
try {
|
|
10309
|
+
const jsonSchema2 = schema.jsonSchema;
|
|
10310
|
+
if (jsonSchema2?.type !== "object" || jsonSchema2.additionalProperties !== false) return [];
|
|
10311
|
+
} catch {
|
|
10312
|
+
return [];
|
|
10313
|
+
}
|
|
10314
|
+
return Object.keys(input).filter((key) => !Object.hasOwn(validated, key));
|
|
10315
|
+
}
|
|
10316
|
+
function parseToolRequestBody(text) {
|
|
10317
|
+
let parsed;
|
|
10318
|
+
try {
|
|
10319
|
+
parsed = JSON.parse(text);
|
|
10320
|
+
} catch {
|
|
10321
|
+
return void 0;
|
|
10322
|
+
}
|
|
10323
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
10324
|
+
if (!Object.hasOwn(parsed, "input")) return null;
|
|
10325
|
+
return { input: parsed.input };
|
|
10326
|
+
}
|
|
10327
|
+
function isAsyncIterable(value) {
|
|
10328
|
+
return value !== null && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value;
|
|
10329
|
+
}
|
|
10330
|
+
function jsonText(value) {
|
|
10331
|
+
try {
|
|
10332
|
+
const serialized = JSON.stringify(value);
|
|
10333
|
+
return typeof serialized === "string" ? serialized : void 0;
|
|
10334
|
+
} catch {
|
|
10335
|
+
return void 0;
|
|
10336
|
+
}
|
|
10337
|
+
}
|
|
10338
|
+
function executableTool(tools, name) {
|
|
10339
|
+
if (!Object.hasOwn(tools, name)) return void 0;
|
|
10340
|
+
const tool3 = tools[name];
|
|
10341
|
+
return typeof tool3.execute === "function" ? { ...tool3, execute: tool3.execute } : void 0;
|
|
10342
|
+
}
|
|
10343
|
+
function toolMetadata(tools) {
|
|
10344
|
+
return Object.entries(tools).flatMap(([name, tool3]) => {
|
|
10345
|
+
if (typeof tool3.execute !== "function") return [];
|
|
10346
|
+
const inputSchema = asSchema(tool3.inputSchema);
|
|
10347
|
+
const entry = {
|
|
10348
|
+
name,
|
|
10349
|
+
description: typeof tool3.description === "string" ? tool3.description : "",
|
|
10350
|
+
inputSchema: inputSchema.jsonSchema
|
|
10351
|
+
};
|
|
10352
|
+
if (tool3.outputSchema) entry.outputSchema = asSchema(tool3.outputSchema).jsonSchema;
|
|
10353
|
+
return [entry];
|
|
10354
|
+
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
10355
|
+
}
|
|
10356
|
+
function createUserToolExecutor(env, userId, signal) {
|
|
10357
|
+
const roomId = env.RECORD_ROOMS.idFromName(`app:${env.DEEPSPACE_APP_ID}`);
|
|
10358
|
+
const room = env.RECORD_ROOMS.get(roomId);
|
|
10359
|
+
return async (toolName, params) => {
|
|
10360
|
+
const response = await room.fetch(
|
|
10361
|
+
new Request("https://internal/api/tools/execute", {
|
|
10362
|
+
method: "POST",
|
|
10363
|
+
headers: {
|
|
10364
|
+
"Content-Type": "application/json",
|
|
10365
|
+
"X-User-Id": userId
|
|
10366
|
+
},
|
|
10367
|
+
body: JSON.stringify({ tool: toolName, params }),
|
|
10368
|
+
signal
|
|
10369
|
+
})
|
|
10370
|
+
);
|
|
10371
|
+
return capToolResultSize(await response.json(), DEFAULT_CONTEXT_CONFIG.toolResultCap);
|
|
10372
|
+
};
|
|
10373
|
+
}
|
|
10374
|
+
async function resolveCallerTools(options, request2, env) {
|
|
10375
|
+
let access;
|
|
10376
|
+
try {
|
|
10377
|
+
access = await options.resolveAccess(request2, env);
|
|
10378
|
+
} catch {
|
|
10379
|
+
return errorResponse(500, "tool_configuration_error");
|
|
10380
|
+
}
|
|
10381
|
+
if (!access.ok) {
|
|
10382
|
+
return errorResponse(
|
|
10383
|
+
access.status,
|
|
10384
|
+
access.status === 401 ? "unauthenticated" : access.status === 403 ? "forbidden" : "access_check_unavailable"
|
|
10385
|
+
);
|
|
10386
|
+
}
|
|
10387
|
+
try {
|
|
10388
|
+
return options.buildTools(createUserToolExecutor(env, access.auth.userId, request2.signal));
|
|
10389
|
+
} catch {
|
|
10390
|
+
return errorResponse(500, "tool_configuration_error");
|
|
10391
|
+
}
|
|
10392
|
+
}
|
|
10393
|
+
function registerAgentToolRoutes(app, options) {
|
|
10394
|
+
app.get("/_deepspace/agent/tools", async (c) => {
|
|
10395
|
+
const tools = await resolveCallerTools(options, c.req.raw, c.env);
|
|
10396
|
+
if (tools instanceof Response) return tools;
|
|
10397
|
+
try {
|
|
10398
|
+
const serialized = jsonText({
|
|
10399
|
+
ok: true,
|
|
10400
|
+
app: { id: c.env.DEEPSPACE_APP_ID, name: c.env.APP_NAME },
|
|
10401
|
+
tools: toolMetadata(tools)
|
|
10402
|
+
});
|
|
10403
|
+
if (!serialized || utf8ByteLength(serialized) > AGENT_TOOL_RESPONSE_BODY_CAP) {
|
|
10404
|
+
return errorResponse(500, "tool_configuration_error");
|
|
10405
|
+
}
|
|
10406
|
+
return rawJsonResponse(serialized);
|
|
10407
|
+
} catch {
|
|
10408
|
+
return errorResponse(500, "tool_configuration_error");
|
|
10409
|
+
}
|
|
10410
|
+
});
|
|
10411
|
+
app.post("/_deepspace/agent/tools/:name", async (c) => {
|
|
10412
|
+
const tools = await resolveCallerTools(options, c.req.raw, c.env);
|
|
10413
|
+
if (tools instanceof Response) return tools;
|
|
10414
|
+
let tool3;
|
|
10415
|
+
try {
|
|
10416
|
+
tool3 = executableTool(tools, c.req.param("name"));
|
|
10417
|
+
} catch {
|
|
10418
|
+
return errorResponse(500, "tool_configuration_error");
|
|
10419
|
+
}
|
|
10420
|
+
if (!tool3) {
|
|
10421
|
+
const names = Object.keys(tools).filter((name) => typeof tools[name]?.execute === "function").sort();
|
|
10422
|
+
const listed = names.slice(0, 20).join(", ");
|
|
10423
|
+
return errorResponse(
|
|
10424
|
+
404,
|
|
10425
|
+
"tool_not_found",
|
|
10426
|
+
names.length > 0 ? `Available tools: ${listed}${names.length > 20 ? ", \u2026" : ""}.` : void 0
|
|
10427
|
+
);
|
|
10428
|
+
}
|
|
10429
|
+
let text;
|
|
10430
|
+
try {
|
|
10431
|
+
text = await readBoundedBodyText(c.req.raw, AGENT_TOOL_REQUEST_BODY_CAP);
|
|
10432
|
+
} catch (error) {
|
|
10433
|
+
return error instanceof BodyTooLargeError ? errorResponse(413, "payload_too_large") : errorResponse(400, "invalid_json");
|
|
10434
|
+
}
|
|
10435
|
+
const body = parseToolRequestBody(text);
|
|
10436
|
+
if (body === void 0) return errorResponse(400, "invalid_json");
|
|
10437
|
+
if (body === null) return errorResponse(400, "invalid_tool_input");
|
|
10438
|
+
let input = body.input;
|
|
10439
|
+
const schema = asSchema(tool3.inputSchema);
|
|
10440
|
+
try {
|
|
10441
|
+
const validation = schema.validate;
|
|
10442
|
+
if (validation) {
|
|
10443
|
+
const result = await validation(input);
|
|
10444
|
+
if (!result.success) {
|
|
10445
|
+
return errorResponse(400, "invalid_tool_input", validationDetail(result.error));
|
|
10446
|
+
}
|
|
10447
|
+
const dropped = droppedTopLevelKeys(schema, input, result.value);
|
|
10448
|
+
if (dropped.length > 0) {
|
|
10449
|
+
return errorResponse(
|
|
10450
|
+
400,
|
|
10451
|
+
"invalid_tool_input",
|
|
10452
|
+
`Unknown input field(s): ${dropped.join(", ")} \u2014 the tool's inputSchema lists the accepted fields.`
|
|
10453
|
+
);
|
|
10454
|
+
}
|
|
10455
|
+
input = result.value;
|
|
10456
|
+
}
|
|
10457
|
+
} catch (error) {
|
|
10458
|
+
return errorResponse(400, "invalid_tool_input", validationDetail(error));
|
|
10459
|
+
}
|
|
10460
|
+
let output;
|
|
10461
|
+
try {
|
|
10462
|
+
output = await tool3.execute(input, {
|
|
10463
|
+
toolCallId: crypto.randomUUID(),
|
|
10464
|
+
messages: [],
|
|
10465
|
+
abortSignal: c.req.raw.signal
|
|
10466
|
+
});
|
|
10467
|
+
} catch {
|
|
10468
|
+
return errorResponse(500, "tool_execution_failed");
|
|
10469
|
+
}
|
|
10470
|
+
if (isAsyncIterable(output)) return errorResponse(500, "invalid_tool_result");
|
|
10471
|
+
try {
|
|
10472
|
+
if (tool3.outputSchema) {
|
|
10473
|
+
const validation = asSchema(tool3.outputSchema).validate;
|
|
10474
|
+
if (validation) {
|
|
10475
|
+
const result = await validation(output);
|
|
10476
|
+
if (!result.success) return errorResponse(500, "invalid_tool_result");
|
|
10477
|
+
output = result.value;
|
|
10478
|
+
}
|
|
10479
|
+
}
|
|
10480
|
+
} catch {
|
|
10481
|
+
return errorResponse(500, "invalid_tool_result");
|
|
10482
|
+
}
|
|
10483
|
+
const serialized = jsonText(output === void 0 ? null : output);
|
|
10484
|
+
if (!serialized) return errorResponse(500, "invalid_tool_result");
|
|
10485
|
+
if (utf8ByteLength(serialized) > DEFAULT_CONTEXT_CONFIG.toolResultCap) {
|
|
10486
|
+
return errorResponse(500, "tool_result_too_large");
|
|
10487
|
+
}
|
|
10488
|
+
return rawJsonResponse(`{"ok":true,"result":${serialized}}`);
|
|
10489
|
+
});
|
|
10490
|
+
app.all("/_deepspace/agent", () => errorResponse(404, "tool_not_found"));
|
|
10491
|
+
app.all("/_deepspace/agent/*", () => errorResponse(404, "tool_not_found"));
|
|
10492
|
+
}
|
|
10493
|
+
|
|
10494
|
+
// src/server/agent-target.ts
|
|
10495
|
+
var PRODUCTION_OFFICIAL_AGENT_ORIGINS = ["https://admin.deep.space"];
|
|
10496
|
+
var PRODUCTION_APP_DOMAIN = "app.space";
|
|
10497
|
+
function normalizeAgentTargetOrigin(value, policy) {
|
|
10498
|
+
if (typeof value !== "string" || !value) return null;
|
|
10499
|
+
let url;
|
|
10500
|
+
try {
|
|
10501
|
+
url = new URL(value);
|
|
10502
|
+
} catch {
|
|
10503
|
+
return null;
|
|
10504
|
+
}
|
|
10505
|
+
if (url.username || url.password || url.search || url.hash || url.pathname !== "/") return null;
|
|
10506
|
+
const hostname = url.hostname.toLowerCase();
|
|
10507
|
+
const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(hostname);
|
|
10508
|
+
if (loopback) {
|
|
10509
|
+
return policy.allowLoopback && ["http:", "https:"].includes(url.protocol) ? url.origin : null;
|
|
10510
|
+
}
|
|
10511
|
+
if (url.protocol !== "https:" || url.port) return null;
|
|
10512
|
+
if (policy.appDomain.toLowerCase() === PRODUCTION_APP_DOMAIN && PRODUCTION_OFFICIAL_AGENT_ORIGINS.includes(url.origin)) {
|
|
10513
|
+
return url.origin;
|
|
10514
|
+
}
|
|
10515
|
+
const suffix = `.${policy.appDomain.toLowerCase()}`;
|
|
10516
|
+
if (!hostname.endsWith(suffix)) return null;
|
|
10517
|
+
const label = hostname.slice(0, -suffix.length);
|
|
10518
|
+
return !label.includes(".") && validateAppName(label).valid ? url.origin : null;
|
|
10519
|
+
}
|
|
10520
|
+
|
|
10521
|
+
// src/shared/auth-session.ts
|
|
10522
|
+
var SESSION_COOKIE = "__Secure-better-auth.session_token";
|
|
10523
|
+
|
|
10209
10524
|
// src/shared/log-events.ts
|
|
10210
10525
|
var LOG_LEVELS = ["debug", "log", "info", "warn", "error"];
|
|
10211
10526
|
var APP_LOG_EVENT_KEYS = [
|
|
@@ -10223,6 +10538,9 @@ export {
|
|
|
10223
10538
|
ACCOUNT_STORAGE_LIMIT_BYTES,
|
|
10224
10539
|
ACTION_ROUTES_BEARER_GUARD_MIGRATION_ID,
|
|
10225
10540
|
ACTION_TOOLS_DELETE_WHERE_MIGRATION_ID,
|
|
10541
|
+
AGENT_TOKEN_SCOPE,
|
|
10542
|
+
AGENT_TOOL_REQUEST_BODY_CAP,
|
|
10543
|
+
AGENT_TOOL_RESPONSE_BODY_CAP,
|
|
10226
10544
|
AI_CHATS_SCHEMA,
|
|
10227
10545
|
AI_MESSAGES_SCHEMA,
|
|
10228
10546
|
ALLOWED_BINDING_TYPES,
|
|
@@ -10274,6 +10592,7 @@ export {
|
|
|
10274
10592
|
MSG_SYNC_UPDATE,
|
|
10275
10593
|
MSG_YJS_AWARENESS,
|
|
10276
10594
|
MSG_YJS_SYNC,
|
|
10595
|
+
PRODUCTION_OFFICIAL_AGENT_ORIGINS,
|
|
10277
10596
|
PresenceRoom,
|
|
10278
10597
|
REACTIONS_SCHEMA,
|
|
10279
10598
|
READ_RECEIPTS_SCHEMA,
|
|
@@ -10292,6 +10611,7 @@ export {
|
|
|
10292
10611
|
RegistryClientError,
|
|
10293
10612
|
SDK_RUN_WORKER_FIRST,
|
|
10294
10613
|
SECURE_ROOM_BOUNDARIES_MIGRATION_ID,
|
|
10614
|
+
SESSION_COOKIE,
|
|
10295
10615
|
STRICT_APP_ID_RE,
|
|
10296
10616
|
SYSTEM_ASSIGNED_COLUMNS,
|
|
10297
10617
|
SYSTEM_COLLECTIONS,
|
|
@@ -10304,6 +10624,7 @@ export {
|
|
|
10304
10624
|
USERS_COLUMNS,
|
|
10305
10625
|
WORKER_OWNED_NOT_FOUND_MIGRATION_ID,
|
|
10306
10626
|
YjsRoom,
|
|
10627
|
+
agentTokenIssuer,
|
|
10307
10628
|
apiWorkerFetch,
|
|
10308
10629
|
appendMessage,
|
|
10309
10630
|
applyAiToolDefaults,
|
|
@@ -10337,6 +10658,7 @@ export {
|
|
|
10337
10658
|
createDeepSpaceAuth,
|
|
10338
10659
|
createEncoder,
|
|
10339
10660
|
createScopedR2Handler,
|
|
10661
|
+
createUserToolExecutor,
|
|
10340
10662
|
dataToColumnValues,
|
|
10341
10663
|
decodeJwtPayload,
|
|
10342
10664
|
deepSpaceAgentErrorSummary,
|
|
@@ -10382,6 +10704,7 @@ export {
|
|
|
10382
10704
|
mintAppId,
|
|
10383
10705
|
mintUlid,
|
|
10384
10706
|
noopPermissionContext,
|
|
10707
|
+
normalizeAgentTargetOrigin,
|
|
10385
10708
|
normalizeKnowledgeFolder,
|
|
10386
10709
|
parseQuotaLimit,
|
|
10387
10710
|
platformCorsPatterns,
|
|
@@ -10390,10 +10713,12 @@ export {
|
|
|
10390
10713
|
priceBindingUsageEvent,
|
|
10391
10714
|
readVarUint,
|
|
10392
10715
|
readVarUint8Array,
|
|
10716
|
+
registerAgentToolRoutes,
|
|
10393
10717
|
registerClientErrorRoute,
|
|
10394
10718
|
registerDeepSpaceDocumentation,
|
|
10395
10719
|
registryErrorJson,
|
|
10396
10720
|
registryStub,
|
|
10721
|
+
resolveAppMembership,
|
|
10397
10722
|
resolveAppName,
|
|
10398
10723
|
resolveAppRole,
|
|
10399
10724
|
resolveColumn,
|
|
@@ -10417,6 +10742,7 @@ export {
|
|
|
10417
10742
|
validateAppName,
|
|
10418
10743
|
validateBindingManifest,
|
|
10419
10744
|
validateDoManifest,
|
|
10745
|
+
verifyAgentToken,
|
|
10420
10746
|
verifyJwt,
|
|
10421
10747
|
writeVarUint,
|
|
10422
10748
|
writeVarUint8Array
|