deepspace 0.28.1 → 0.29.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/dist/worker.js CHANGED
@@ -72,6 +72,116 @@ var ROLE_DEFAULT = "member";
72
72
  var ROLE_ADMIN = "admin";
73
73
  var RECORD_NOT_FOUND = "Record not found";
74
74
 
75
+ // src/shared/log-events.ts
76
+ var LOG_LEVELS = ["debug", "log", "info", "warn", "error"];
77
+ var APP_LOG_EVENT_KEYS = [
78
+ "id",
79
+ "timestamp",
80
+ "level",
81
+ "eventType",
82
+ "message",
83
+ "outcome",
84
+ "request",
85
+ "exception"
86
+ ];
87
+ function logEventText(e) {
88
+ if (e.eventType === "exception" && e.exception) {
89
+ const where = e.request ? ` \u2014 ${e.request.method} ${e.request.path}` : "";
90
+ return `${e.exception.name}: ${e.exception.message}${where}`;
91
+ }
92
+ if (e.eventType === "request" && e.request) {
93
+ const status = e.request.status !== void 0 ? ` ${e.request.status}` : "";
94
+ const outcome = e.outcome && e.outcome !== "ok" ? ` (${e.outcome})` : "";
95
+ return `${e.request.method} ${e.request.path}${status}${outcome}`;
96
+ }
97
+ return e.message;
98
+ }
99
+ function loggableError(err) {
100
+ try {
101
+ return truncateLogText(renderError(err, 0));
102
+ } catch {
103
+ return tagOf(err);
104
+ }
105
+ }
106
+ function truncateLogText(s) {
107
+ if (s.length <= MAX_LOG_TEXT_LENGTH) return s;
108
+ let cut = MAX_LOG_TEXT_LENGTH - TRUNCATION_MARKER.length;
109
+ const last = s.charCodeAt(cut - 1);
110
+ if (last >= 55296 && last <= 56319) cut -= 1;
111
+ return s.slice(0, cut) + TRUNCATION_MARKER;
112
+ }
113
+ var MAX_LOG_TEXT_LENGTH = 8 * 1024;
114
+ var TRUNCATION_MARKER = "\u2026 [truncated]";
115
+ var MAX_CAUSE_DEPTH = 4;
116
+ function tagOf(err) {
117
+ try {
118
+ return Object.prototype.toString.call(err);
119
+ } catch {
120
+ return "[unloggable error]";
121
+ }
122
+ }
123
+ function renderError(err, depth) {
124
+ let isError;
125
+ try {
126
+ isError = err instanceof Error;
127
+ } catch {
128
+ return tagOf(err);
129
+ }
130
+ if (!isError) {
131
+ try {
132
+ return String(err).slice(0, MAX_LOG_TEXT_LENGTH + 1);
133
+ } catch {
134
+ return tagOf(err);
135
+ }
136
+ }
137
+ const e = err;
138
+ let out;
139
+ try {
140
+ const stack = typeof e.stack === "string" ? e.stack : void 0;
141
+ const head = (e.message ? `${e.name}: ${e.message}` : `${e.name}`).slice(
142
+ 0,
143
+ MAX_LOG_TEXT_LENGTH + 1
144
+ );
145
+ if (!stack) out = head;
146
+ else if (stack.startsWith(head)) out = stack.slice(0, MAX_LOG_TEXT_LENGTH + 1);
147
+ else out = `${head}
148
+ ${stack.slice(0, MAX_LOG_TEXT_LENGTH + 1)}`;
149
+ } catch {
150
+ return tagOf(err);
151
+ }
152
+ try {
153
+ if (e instanceof AggregateError && Array.isArray(e.errors)) {
154
+ if (depth < MAX_CAUSE_DEPTH) {
155
+ for (const sub of e.errors.slice(0, MAX_CAUSE_DEPTH)) {
156
+ if (out.length >= MAX_LOG_TEXT_LENGTH) return out + "\n\u2026 [cause chain truncated]";
157
+ out += `
158
+ caused by: ${renderError(sub, depth + 1)}`;
159
+ }
160
+ if (e.errors.length > MAX_CAUSE_DEPTH) {
161
+ out += `
162
+ \u2026 [${e.errors.length - MAX_CAUSE_DEPTH} more errors]`;
163
+ }
164
+ } else {
165
+ out += "\n\u2026 [cause chain truncated]";
166
+ }
167
+ }
168
+ const cause = e.cause;
169
+ if (cause != null) {
170
+ if (depth >= MAX_CAUSE_DEPTH) {
171
+ if (!out.endsWith("\u2026 [cause chain truncated]")) out += "\n\u2026 [cause chain truncated]";
172
+ } else if (out.length < MAX_LOG_TEXT_LENGTH) {
173
+ out += `
174
+ caused by: ${renderError(cause, depth + 1)}`;
175
+ } else {
176
+ out += "\n\u2026 [cause chain truncated]";
177
+ }
178
+ }
179
+ } catch {
180
+ out += "\n\u2026 [cause chain unrenderable]";
181
+ }
182
+ return out;
183
+ }
184
+
75
185
  // src/shared/room-identity-headers.ts
76
186
  var BASE64URL = /^[A-Za-z0-9_-]*$/;
77
187
  var IDENTITY_QUERY_PARAMS = ["userId", "userName", "userEmail", "userImageUrl", "role"];
@@ -215,7 +325,7 @@ var BaseRoom = class {
215
325
  try {
216
326
  await this.onBinaryMessage(ws, attachment, message);
217
327
  } catch (e) {
218
- console.error(`[${this.constructor.name}] Binary message error:`, e);
328
+ console.error(`[${this.constructor.name}] Binary message error: ${loggableError(e)}`);
219
329
  }
220
330
  }
221
331
  return;
@@ -224,7 +334,7 @@ var BaseRoom = class {
224
334
  const msg = JSON.parse(message);
225
335
  await this.onMessage(ws, attachment, msg);
226
336
  } catch (e) {
227
- console.error(`[${this.constructor.name}] Message error:`, e);
337
+ console.error(`[${this.constructor.name}] Message error: ${loggableError(e)}`);
228
338
  }
229
339
  }
230
340
  async webSocketClose(ws, _code, _reason) {
@@ -237,7 +347,7 @@ var BaseRoom = class {
237
347
  }
238
348
  }
239
349
  async webSocketError(_ws, error) {
240
- console.error(`[${this.constructor.name}] webSocketError:`, error);
350
+ console.error(`[${this.constructor.name}] webSocketError: ${loggableError(error)}`);
241
351
  }
242
352
  async alarm() {
243
353
  if (this.onAlarm) {
@@ -1684,7 +1794,7 @@ function getOrCreateYjsDoc(ctx, docKey) {
1684
1794
  try {
1685
1795
  Y2.applyUpdate(doc, new Uint8Array(row.state));
1686
1796
  } catch (e) {
1687
- console.error(`Failed to load Yjs doc ${docKey}:`, e);
1797
+ console.error(`Failed to load Yjs doc ${docKey}: ${loggableError(e)}`);
1688
1798
  }
1689
1799
  }
1690
1800
  const saveDoc = () => {
@@ -2600,7 +2710,12 @@ async function executeTool(ctx, toolName, params, userId, userRole, skipUserRbac
2600
2710
  case "user.current": {
2601
2711
  if (!userId) return { success: false, error: "No userId provided" };
2602
2712
  const user = getUser(ctx.sql, userId, ctx.schemaRegistry);
2603
- if (!user) return { success: false, error: "User not found" };
2713
+ if (!user) {
2714
+ return {
2715
+ success: false,
2716
+ 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."
2717
+ };
2718
+ }
2604
2719
  return { success: true, data: { user } };
2605
2720
  }
2606
2721
  // The same roster the socket's `user.list` returns, for the same caller.
@@ -3193,7 +3308,7 @@ var RecordRoom = class extends BaseRoom {
3193
3308
  new Uint8Array(message)
3194
3309
  );
3195
3310
  } catch (e) {
3196
- console.error("[RecordRoom] Yjs binary message error:", e);
3311
+ console.error(`[RecordRoom] Yjs binary message error: ${loggableError(e)}`);
3197
3312
  }
3198
3313
  return;
3199
3314
  }
@@ -3203,7 +3318,9 @@ var RecordRoom = class extends BaseRoom {
3203
3318
  } catch (e) {
3204
3319
  const errMsg = e instanceof Error ? e.message : String(e);
3205
3320
  const msgPreview = typeof message === "string" ? message.slice(0, 200) : "(non-string)";
3206
- console.error(`[RecordRoom] Message handler error: ${errMsg}`, { message: msgPreview });
3321
+ console.error(`[RecordRoom] Message handler error: ${loggableError(e)}`, {
3322
+ message: msgPreview
3323
+ });
3207
3324
  this.send(ws, { type: MSG.ERROR, payload: { error: `Invalid message: ${errMsg}` } });
3208
3325
  }
3209
3326
  }
@@ -3217,9 +3334,6 @@ var RecordRoom = class extends BaseRoom {
3217
3334
  } catch {
3218
3335
  }
3219
3336
  }
3220
- async webSocketError(_ws, error) {
3221
- console.error(`[RecordRoom] webSocketError:`, error);
3222
- }
3223
3337
  // ============================================================================
3224
3338
  // Message Routing
3225
3339
  // ============================================================================
@@ -4359,8 +4473,7 @@ var CronRoom = class extends BaseRoom {
4359
4473
  if (success) {
4360
4474
  console.log(`[cron] ${taskName} ok ${durationMs}ms`);
4361
4475
  } else {
4362
- const stack = thrown instanceof Error ? thrown.stack : void 0;
4363
- console.error(`[cron] ${taskName} failed ${durationMs}ms: ${error}`, ...stack ? [stack] : []);
4476
+ console.error(`[cron] ${taskName} failed ${durationMs}ms: ${loggableError(thrown)}`);
4364
4477
  }
4365
4478
  this.sql.exec(
4366
4479
  `INSERT INTO cron_history (task_name, started_at, completed_at, success, duration_ms, error, created_at)
@@ -4543,12 +4656,8 @@ var JobRoom = class extends BaseRoom {
4543
4656
  next_run_at TEXT
4544
4657
  )
4545
4658
  `);
4546
- this.sql.exec(
4547
- `CREATE INDEX IF NOT EXISTS jobs_status_next_run ON jobs (status, next_run_at)`
4548
- );
4549
- this.sql.exec(
4550
- `CREATE INDEX IF NOT EXISTS jobs_completed_at ON jobs (completed_at)`
4551
- );
4659
+ this.sql.exec(`CREATE INDEX IF NOT EXISTS jobs_status_next_run ON jobs (status, next_run_at)`);
4660
+ this.sql.exec(`CREATE INDEX IF NOT EXISTS jobs_completed_at ON jobs (completed_at)`);
4552
4661
  this.recoverStuckRunning();
4553
4662
  this.scheduleNextAlarm();
4554
4663
  }
@@ -4816,8 +4925,7 @@ var JobRoom = class extends BaseRoom {
4816
4925
  } catch (e) {
4817
4926
  outcome = "failed";
4818
4927
  errorMessage = e instanceof Error ? e.message : String(e);
4819
- const stack = e instanceof Error ? e.stack : void 0;
4820
- console.error(`[jobs] ${row.type} (${row.id}) failed: ${errorMessage}`, ...stack ? [stack] : []);
4928
+ console.error(`[jobs] ${row.type} (${row.id}) failed: ${loggableError(e)}`);
4821
4929
  } finally {
4822
4930
  this.inFlight.delete(row.id);
4823
4931
  }
@@ -6164,7 +6272,7 @@ async function measuredAllocationUsage(bucket, storage, prefixes, excludedMarker
6164
6272
  );
6165
6273
  if (budget.staleKeys.length > 0) {
6166
6274
  await bucket.delete(budget.staleKeys).catch((error) => {
6167
- console.error("[files:quota] stale marker cleanup:", error);
6275
+ console.error(`[files:quota] stale marker cleanup: ${loggableError(error)}`);
6168
6276
  });
6169
6277
  }
6170
6278
  return total;
@@ -6224,7 +6332,7 @@ async function markQuotaDirty(bucket, storage) {
6224
6332
  }
6225
6333
  console.error("[files:quota] could not mark summary reclaimable after concurrent writes");
6226
6334
  } catch (error) {
6227
- console.error("[files:quota] could not mark summary reclaimable:", error);
6335
+ console.error(`[files:quota] could not mark summary reclaimable: ${loggableError(error)}`);
6228
6336
  }
6229
6337
  }
6230
6338
  async function neutralizeMarker(bucket, markerKey) {
@@ -6264,7 +6372,7 @@ async function releaseQuotaMarker(bucket, storage, markerKey, summaryMayBeStale)
6264
6372
  }
6265
6373
  return true;
6266
6374
  } catch (error) {
6267
- console.error("[files:quota] reservation cleanup:", error);
6375
+ console.error(`[files:quota] reservation cleanup: ${loggableError(error)}`);
6268
6376
  return false;
6269
6377
  }
6270
6378
  }
@@ -6294,7 +6402,7 @@ async function readMultipartReservation(bucket, storage, reservationId) {
6294
6402
  try {
6295
6403
  object = await bucket.get(key);
6296
6404
  } catch (error) {
6297
- console.error("[files:quota] reservation read:", error);
6405
+ console.error(`[files:quota] reservation read: ${loggableError(error)}`);
6298
6406
  return "invalid";
6299
6407
  }
6300
6408
  if (!object) return null;
@@ -6490,7 +6598,7 @@ async function admitStorage(bucket, storage, incomingBytes, replacedBytes, marke
6490
6598
  }
6491
6599
  return { markerKey: effectiveMarker?.key ?? null };
6492
6600
  } catch (error) {
6493
- console.error("[files:quota] admission:", error);
6601
+ console.error(`[files:quota] admission: ${loggableError(error)}`);
6494
6602
  await releaseQuotaMarker(bucket, storage, markerKey, true);
6495
6603
  return quotaUnavailable(
6496
6604
  "The storage used by this account could not be verified. Retry shortly."
@@ -6504,7 +6612,7 @@ async function storageUsage(bucket, storage) {
6504
6612
  const current = await ensureQuotaSummary(bucket, storage, prefixes, "repairDirty");
6505
6613
  return current?.summary?.usedBytes ?? null;
6506
6614
  } catch (error) {
6507
- console.error("[files:quota] usage:", error);
6615
+ console.error(`[files:quota] usage: ${loggableError(error)}`);
6508
6616
  return null;
6509
6617
  }
6510
6618
  }
@@ -7090,7 +7198,7 @@ async function finishCompletedMultipart(bucket, session, reservation, object, au
7090
7198
  if (current?.etag === object.etag) await bucket.delete(session.key);
7091
7199
  remaining = await bucket.head(session.key);
7092
7200
  } catch (error) {
7093
- console.error("[files:multipart] invalid object cleanup:", error);
7201
+ console.error(`[files:multipart] invalid object cleanup: ${loggableError(error)}`);
7094
7202
  return quotaUnavailable("The invalid assembled file could not be removed. Retry completion.");
7095
7203
  }
7096
7204
  if (remaining?.etag === object.etag) {
@@ -8107,8 +8215,7 @@ async function prepareMessagesWithCompaction(messages, config, options) {
8107
8215
  };
8108
8216
  } catch (err) {
8109
8217
  console.error(
8110
- "prepareMessagesWithCompaction: summarizer failed, falling back to sliding window",
8111
- err
8218
+ `prepareMessagesWithCompaction: summarizer failed, falling back to sliding window: ${loggableError(err)}`
8112
8219
  );
8113
8220
  }
8114
8221
  } else {
@@ -9586,7 +9693,7 @@ async function callDocumentationTool(rawRequest, request2, corpus, env, basePath
9586
9693
  url: new URL(documentationPublicPath(basePath, page.route), origin).toString()
9587
9694
  });
9588
9695
  } catch (error) {
9589
- console.error("[documentation-mcp] page unavailable:", error);
9696
+ console.error(`[documentation-mcp] page unavailable: ${loggableError(error)}`);
9590
9697
  return toolError(request2.id, "The documentation page could not be read");
9591
9698
  }
9592
9699
  }
@@ -10060,7 +10167,9 @@ function createDeepSpaceAuth(config) {
10060
10167
  try {
10061
10168
  return { clientId: apple.clientId, clientSecret: await generateAppleClientSecret(apple) };
10062
10169
  } catch (err) {
10063
- console.error("[deepspace] failed to mint Apple client secret; Apple sign-in disabled", err);
10170
+ console.error(
10171
+ `[deepspace] failed to mint Apple client secret; Apple sign-in disabled: ${loggableError(err)}`
10172
+ );
10064
10173
  return { clientId: apple.clientId, clientSecret: "" };
10065
10174
  }
10066
10175
  };
@@ -10135,7 +10244,9 @@ function buildDatabaseHooks(onUserCreated) {
10135
10244
  ctx ? { request: ctx.request, headers: ctx.headers ?? void 0 } : null
10136
10245
  );
10137
10246
  } catch (err) {
10138
- console.error("[deepspace] onUserCreated hook failed (signup unaffected)", err);
10247
+ console.error(
10248
+ `[deepspace] onUserCreated hook failed (signup unaffected): ${loggableError(err)}`
10249
+ );
10139
10250
  }
10140
10251
  }
10141
10252
  }
@@ -10156,92 +10267,6 @@ async function generateAppleClientSecret(apple) {
10156
10267
  return token;
10157
10268
  }
10158
10269
 
10159
- // src/shared/client-errors.ts
10160
- var CLIENT_LOG_MARKER = "[deepspace:client-error]";
10161
- var CLIENT_ERROR_PATH = "/_deepspace/client-errors";
10162
- var CLIENT_ERROR_CAPS = {
10163
- message: 1024,
10164
- stack: 4096,
10165
- name: 256,
10166
- url: 512
10167
- };
10168
- function capText(value, max) {
10169
- if (typeof value !== "string") return void 0;
10170
- return value.length > max ? value.slice(0, max) : value;
10171
- }
10172
- function finiteNumber(value) {
10173
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
10174
- }
10175
- function normalizeClientErrorReport(raw) {
10176
- if (typeof raw !== "object" || raw === null) return null;
10177
- const o = raw;
10178
- const kind = o.kind === "unhandledrejection" || o.kind === "react" ? o.kind : "error";
10179
- const message = capText(o.message, CLIENT_ERROR_CAPS.message) ?? "";
10180
- const name = capText(o.name, CLIENT_ERROR_CAPS.name);
10181
- const stack = capText(o.stack, CLIENT_ERROR_CAPS.stack);
10182
- const url = capText(o.url, CLIENT_ERROR_CAPS.url);
10183
- const line = finiteNumber(o.line);
10184
- const col = finiteNumber(o.col);
10185
- if (!message && !stack) return null;
10186
- const report = { kind, message: message || (name ?? "Error") };
10187
- if (name) report.name = name;
10188
- if (stack) report.stack = stack;
10189
- if (url) report.url = url;
10190
- if (line !== void 0) report.line = line;
10191
- if (col !== void 0) report.col = col;
10192
- return report;
10193
- }
10194
- function clientErrorToLogLine(report) {
10195
- return `${CLIENT_LOG_MARKER} ${JSON.stringify(report)}`;
10196
- }
10197
-
10198
- // src/server/client-errors.ts
10199
- var THROTTLE_WINDOW_MS = 1e3;
10200
- var THROTTLE_MAX = 20;
10201
- var windowStart = 0;
10202
- var windowCount = 0;
10203
- var MAX_BODY_BYTES = 64 * 1024;
10204
- function shouldThrottleClientError(now = Date.now()) {
10205
- if (now - windowStart >= THROTTLE_WINDOW_MS) {
10206
- windowStart = now;
10207
- windowCount = 0;
10208
- }
10209
- windowCount += 1;
10210
- return windowCount > THROTTLE_MAX;
10211
- }
10212
- function jsonResponse2(body, status) {
10213
- return new Response(JSON.stringify(body), {
10214
- status,
10215
- headers: { "Content-Type": "application/json" }
10216
- });
10217
- }
10218
- async function handleClientErrorReport(request2) {
10219
- const site = request2.headers.get("sec-fetch-site");
10220
- if (site && site !== "same-origin" && site !== "none") {
10221
- return new Response(null, { status: 403 });
10222
- }
10223
- if (shouldThrottleClientError()) {
10224
- return new Response(null, { status: 429, headers: { "Retry-After": "1" } });
10225
- }
10226
- const declared = Number(request2.headers.get("content-length"));
10227
- if (Number.isFinite(declared) && declared > MAX_BODY_BYTES) {
10228
- return jsonResponse2({ error: "payload_too_large" }, 413);
10229
- }
10230
- let body;
10231
- try {
10232
- body = await request2.json();
10233
- } catch {
10234
- return jsonResponse2({ error: "invalid_json" }, 400);
10235
- }
10236
- const report = normalizeClientErrorReport(body);
10237
- if (!report) return jsonResponse2({ error: "invalid_report" }, 400);
10238
- console.error(clientErrorToLogLine(report));
10239
- return new Response(null, { status: 204 });
10240
- }
10241
- function registerClientErrorRoute(app) {
10242
- app.post(CLIENT_ERROR_PATH, (c) => handleClientErrorReport(c.req.raw));
10243
- }
10244
-
10245
10270
  // src/server/agent-tools.ts
10246
10271
  import { asSchema } from "ai";
10247
10272
 
@@ -10250,7 +10275,7 @@ var AGENT_TOOL_REQUEST_BODY_CAP = 64 * 1024;
10250
10275
  var AGENT_TOOL_RESPONSE_BODY_CAP = 1024 * 1024;
10251
10276
 
10252
10277
  // src/server/agent-tools.ts
10253
- function jsonResponse3(body, status = 200) {
10278
+ function jsonResponse2(body, status = 200) {
10254
10279
  return rawJsonResponse(JSON.stringify(body), status);
10255
10280
  }
10256
10281
  function rawJsonResponse(body, status = 200) {
@@ -10262,10 +10287,12 @@ function rawJsonResponse(body, status = 200) {
10262
10287
  }
10263
10288
  });
10264
10289
  }
10265
- function errorResponse(status, code) {
10290
+ function errorResponse(status, code, detail) {
10266
10291
  const errors = {
10267
10292
  unauthenticated: "Authentication is required.",
10268
- forbidden: "You are not allowed to use assistant tools.",
10293
+ // The remedy is documented and single-step (local-agent-tools.md): a
10294
+ // signed-in app visit creates or refreshes the caller's user row.
10295
+ 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.",
10269
10296
  access_check_unavailable: "Access could not be verified. Try again.",
10270
10297
  tool_not_found: "The requested tool is not available.",
10271
10298
  invalid_json: "The request body must be valid JSON.",
@@ -10276,7 +10303,35 @@ function errorResponse(status, code) {
10276
10303
  invalid_tool_result: "The tool returned an invalid result.",
10277
10304
  tool_result_too_large: "The tool returned a result that is too large."
10278
10305
  };
10279
- return jsonResponse3({ ok: false, code, error: errors[code] }, status);
10306
+ const error = detail ? `${errors[code]} ${detail}` : errors[code];
10307
+ return jsonResponse2({ ok: false, code, error }, status);
10308
+ }
10309
+ function validationDetail(error) {
10310
+ const issues = error.issues;
10311
+ if (Array.isArray(issues) && issues.length > 0) {
10312
+ const shown = issues.slice(0, 5).map((issue) => {
10313
+ const { path, message } = issue ?? {};
10314
+ const at = Array.isArray(path) && path.length > 0 ? `${path.join(".")}: ` : "";
10315
+ return `${at}${typeof message === "string" ? message : "invalid"}`;
10316
+ });
10317
+ const more = issues.length - shown.length;
10318
+ return `${shown.join("; ")}${more > 0 ? ` (+${more} more)` : ""}`;
10319
+ }
10320
+ if (!(error instanceof Error) || !error.message) return void 0;
10321
+ const line = error.message.replace(/\s+/g, " ").trim();
10322
+ return line.length > 400 ? `${line.slice(0, 400)}\u2026` : line;
10323
+ }
10324
+ function droppedTopLevelKeys(schema, input, validated) {
10325
+ if (input === null || typeof input !== "object" || Array.isArray(input) || validated === null || typeof validated !== "object" || Array.isArray(validated)) {
10326
+ return [];
10327
+ }
10328
+ try {
10329
+ const jsonSchema2 = schema.jsonSchema;
10330
+ if (jsonSchema2?.type !== "object" || jsonSchema2.additionalProperties !== false) return [];
10331
+ } catch {
10332
+ return [];
10333
+ }
10334
+ return Object.keys(input).filter((key) => !Object.hasOwn(validated, key));
10280
10335
  }
10281
10336
  function parseToolRequestBody(text) {
10282
10337
  let parsed;
@@ -10382,7 +10437,15 @@ function registerAgentToolRoutes(app, options) {
10382
10437
  } catch {
10383
10438
  return errorResponse(500, "tool_configuration_error");
10384
10439
  }
10385
- if (!tool3) return errorResponse(404, "tool_not_found");
10440
+ if (!tool3) {
10441
+ const names = Object.keys(tools).filter((name) => typeof tools[name]?.execute === "function").sort();
10442
+ const listed = names.slice(0, 20).join(", ");
10443
+ return errorResponse(
10444
+ 404,
10445
+ "tool_not_found",
10446
+ names.length > 0 ? `Available tools: ${listed}${names.length > 20 ? ", \u2026" : ""}.` : void 0
10447
+ );
10448
+ }
10386
10449
  let text;
10387
10450
  try {
10388
10451
  text = await readBoundedBodyText(c.req.raw, AGENT_TOOL_REQUEST_BODY_CAP);
@@ -10393,15 +10456,26 @@ function registerAgentToolRoutes(app, options) {
10393
10456
  if (body === void 0) return errorResponse(400, "invalid_json");
10394
10457
  if (body === null) return errorResponse(400, "invalid_tool_input");
10395
10458
  let input = body.input;
10459
+ const schema = asSchema(tool3.inputSchema);
10396
10460
  try {
10397
- const validation = asSchema(tool3.inputSchema).validate;
10461
+ const validation = schema.validate;
10398
10462
  if (validation) {
10399
10463
  const result = await validation(input);
10400
- if (!result.success) return errorResponse(400, "invalid_tool_input");
10464
+ if (!result.success) {
10465
+ return errorResponse(400, "invalid_tool_input", validationDetail(result.error));
10466
+ }
10467
+ const dropped = droppedTopLevelKeys(schema, input, result.value);
10468
+ if (dropped.length > 0) {
10469
+ return errorResponse(
10470
+ 400,
10471
+ "invalid_tool_input",
10472
+ `Unknown input field(s): ${dropped.join(", ")} \u2014 the tool's inputSchema lists the accepted fields.`
10473
+ );
10474
+ }
10401
10475
  input = result.value;
10402
10476
  }
10403
- } catch {
10404
- return errorResponse(400, "invalid_tool_input");
10477
+ } catch (error) {
10478
+ return errorResponse(400, "invalid_tool_input", validationDetail(error));
10405
10479
  }
10406
10480
  let output;
10407
10481
  try {
@@ -10467,19 +10541,19 @@ function normalizeAgentTargetOrigin(value, policy) {
10467
10541
  // src/shared/auth-session.ts
10468
10542
  var SESSION_COOKIE = "__Secure-better-auth.session_token";
10469
10543
 
10470
- // src/shared/log-events.ts
10471
- var LOG_LEVELS = ["debug", "log", "info", "warn", "error"];
10472
- var APP_LOG_EVENT_KEYS = [
10473
- "id",
10474
- "timestamp",
10475
- "level",
10476
- "eventType",
10477
- "message",
10478
- "source",
10479
- "outcome",
10480
- "request",
10481
- "exception"
10482
- ];
10544
+ // src/server/worker-error.ts
10545
+ function workerErrorHandler(prefix, respond = (c) => c.text("Internal Server Error", 500)) {
10546
+ return (err, c) => {
10547
+ if ("getResponse" in err) {
10548
+ const res = err.getResponse();
10549
+ return c.newResponse(res.body, res);
10550
+ }
10551
+ console.error(
10552
+ `[${prefix}] ${c.req.method} ${new URL(c.req.url).pathname}: ${loggableError(err)}`
10553
+ );
10554
+ return respond(c);
10555
+ };
10556
+ }
10483
10557
  export {
10484
10558
  ACCOUNT_STORAGE_LIMIT_BYTES,
10485
10559
  ACTION_ROUTES_BEARER_GUARD_MIGRATION_ID,
@@ -10505,7 +10579,6 @@ export {
10505
10579
  BaseRoom,
10506
10580
  CHANNELS_SCHEMA,
10507
10581
  CHANNEL_MEMBERS_SCHEMA,
10508
- CLIENT_LOG_MARKER,
10509
10582
  COST_RATES,
10510
10583
  CanvasRoom,
10511
10584
  CronRoom,
@@ -10527,6 +10600,7 @@ export {
10527
10600
  MAX_DELETE_WHERE_LIMIT,
10528
10601
  MAX_DEPLOY_ASSET_FILE_BYTES,
10529
10602
  MAX_ENV_VAR_BYTES,
10603
+ MAX_LOG_TEXT_LENGTH,
10530
10604
  MAX_UPLOAD_PARTS,
10531
10605
  MAX_UPLOAD_REQUEST_BYTES,
10532
10606
  MESSAGES_SCHEMA,
@@ -10624,7 +10698,6 @@ export {
10624
10698
  getMessageType,
10625
10699
  getRolePermissions,
10626
10700
  handleAwarenessMessage,
10627
- handleClientErrorReport,
10628
10701
  handleSyncMessage,
10629
10702
  hasContent,
10630
10703
  isAnonymousUserId,
@@ -10642,6 +10715,8 @@ export {
10642
10715
  lintSchemas,
10643
10716
  listDeepSpaceAgentModels,
10644
10717
  loadMessages,
10718
+ logEventText,
10719
+ loggableError,
10645
10720
  makeDefaultSummarizer,
10646
10721
  matchOrigin,
10647
10722
  meterAi,
@@ -10660,7 +10735,6 @@ export {
10660
10735
  readVarUint,
10661
10736
  readVarUint8Array,
10662
10737
  registerAgentToolRoutes,
10663
- registerClientErrorRoute,
10664
10738
  registerDeepSpaceDocumentation,
10665
10739
  registryErrorJson,
10666
10740
  registryStub,
@@ -10680,6 +10754,7 @@ export {
10680
10754
  timingSafeEqualStrings,
10681
10755
  toUint8Array,
10682
10756
  totalChars,
10757
+ truncateLogText,
10683
10758
  truncateOldToolResults,
10684
10759
  turnsToCoreMessages,
10685
10760
  unwrapToolOutput,
@@ -10690,6 +10765,7 @@ export {
10690
10765
  validateDoManifest,
10691
10766
  verifyAgentToken,
10692
10767
  verifyJwt,
10768
+ workerErrorHandler,
10693
10769
  writeVarUint,
10694
10770
  writeVarUint8Array
10695
10771
  };