@sentry/junior 0.110.0 → 0.111.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.
Files changed (66) hide show
  1. package/dist/{agent-hooks-ELT4ODFF.js → agent-hooks-QQ2IWKOP.js} +8 -8
  2. package/dist/api.js +11 -11
  3. package/dist/app.js +521 -394
  4. package/dist/build/virtual-config.d.ts +2 -0
  5. package/dist/{catalog-runtime-4GI22PXK.js → catalog-runtime-D22W6QEJ.js} +5 -5
  6. package/dist/chat/agent/request.d.ts +3 -6
  7. package/dist/chat/agent/sandbox.d.ts +36 -11
  8. package/dist/chat/agent/tools.d.ts +5 -8
  9. package/dist/chat/config.d.ts +8 -1
  10. package/dist/chat/pi/sdk.d.ts +1 -1
  11. package/dist/chat/plugins/agent-hooks.d.ts +2 -2
  12. package/dist/chat/runtime/agent-continue-runner.d.ts +7 -3
  13. package/dist/chat/runtime/slack-runtime.d.ts +1 -2
  14. package/dist/chat/runtime/thread-state.d.ts +3 -7
  15. package/dist/chat/runtime/turn-preparation.d.ts +2 -2
  16. package/dist/chat/sandbox/command-result.d.ts +91 -0
  17. package/dist/chat/sandbox/errors.d.ts +3 -1
  18. package/dist/chat/sandbox/ref.d.ts +5 -0
  19. package/dist/chat/sandbox/sandbox.d.ts +19 -46
  20. package/dist/chat/sandbox/session.d.ts +16 -20
  21. package/dist/chat/sandbox/skill-sync.d.ts +2 -2
  22. package/dist/chat/sandbox/workspace.d.ts +14 -12
  23. package/dist/chat/services/turn-result.d.ts +3 -4
  24. package/dist/chat/task-execution/slack-work.d.ts +3 -1
  25. package/dist/chat/task-execution/state.d.ts +75 -22
  26. package/dist/chat/task-execution/store.d.ts +34 -3
  27. package/dist/chat/task-execution/worker.d.ts +0 -1
  28. package/dist/chat/tool-support/normalize-result.d.ts +2 -2
  29. package/dist/chat/tool-support/pi-tool-adapter.d.ts +2 -2
  30. package/dist/chat/tool-support/structured-result.d.ts +1 -2
  31. package/dist/chat/tools/sandbox/file-uploads.d.ts +1 -1
  32. package/dist/chat/{runtime → tools/sandbox}/generated-artifacts.d.ts +3 -3
  33. package/dist/chat/tools/types.d.ts +1 -1
  34. package/dist/chat/tools/web/fetch-content.d.ts +5 -0
  35. package/dist/chat/tools/web/image-generate.d.ts +2 -1
  36. package/dist/chat/tools/web/search.d.ts +1 -1
  37. package/dist/{chunk-W6RJZG7F.js → chunk-B45FPP2A.js} +306 -31
  38. package/dist/{chunk-SBOBTS27.js → chunk-BTRNMS6A.js} +2 -2
  39. package/dist/{chunk-L5XQPJ7T.js → chunk-IFAHK54X.js} +2 -2
  40. package/dist/{chunk-IYKPU7H6.js → chunk-J7APPQIJ.js} +1 -1
  41. package/dist/{chunk-3S7YYHBI.js → chunk-L6JPKANW.js} +1 -1
  42. package/dist/{chunk-W75ZPAGG.js → chunk-MPVES2IC.js} +1 -1
  43. package/dist/{chunk-WNOVRQ67.js → chunk-NQLWOTY4.js} +46 -18
  44. package/dist/{chunk-RHHRKSPI.js → chunk-OOLU34J4.js} +8714 -9027
  45. package/dist/{chunk-GK47NBDE.js → chunk-PYKKM4MM.js} +1 -1
  46. package/dist/{chunk-3UBQI73J.js → chunk-PZELBSHC.js} +7 -8
  47. package/dist/{chunk-2T7TIEXI.js → chunk-QQIVLZW4.js} +11 -15
  48. package/dist/{chunk-C5XAFTHY.js → chunk-SL3ZKNLQ.js} +16 -13
  49. package/dist/{chunk-3TV7OEHL.js → chunk-WSRBFHPX.js} +1 -1
  50. package/dist/{chunk-Y3H2DN6F.js → chunk-XQAYFRWT.js} +1 -1
  51. package/dist/{chunk-Y5FK3CNG.js → chunk-Z2W4SJZ7.js} +1 -1
  52. package/dist/{chunk-ZKIOWEFL.js → chunk-Z4G3WCP3.js} +1 -1
  53. package/dist/{chunk-4QU44P7Q.js → chunk-ZRZ4SVWG.js} +2 -2
  54. package/dist/cli/chat.js +19 -19
  55. package/dist/cli/check.js +6 -6
  56. package/dist/cli/plugins.js +11 -11
  57. package/dist/cli/snapshot-warmup.js +8 -8
  58. package/dist/cli/upgrade.js +5 -5
  59. package/dist/{db-Y6W6CWWW.js → db-WXQOQESG.js} +5 -5
  60. package/dist/instrumentation.js +2 -2
  61. package/dist/nitro.js +14 -8
  62. package/dist/{runner-BBFV5GLR.js → runner-4QY4XH4B.js} +19 -28
  63. package/dist/{skills-AR4AF32L.js → skills-P5MU4EBX.js} +6 -6
  64. package/dist/{validation-FBIEPTC2.js → validation-PQF5OP6T.js} +6 -6
  65. package/dist/version.js +1 -1
  66. package/package.json +6 -6
@@ -1,19 +1,21 @@
1
1
  import {
2
2
  SANDBOX_WORKSPACE_ROOT,
3
3
  getStateAdapter
4
- } from "./chunk-GK47NBDE.js";
4
+ } from "./chunk-PYKKM4MM.js";
5
5
  import {
6
6
  sleep
7
7
  } from "./chunk-4ZNGQH7C.js";
8
8
  import {
9
9
  toOptionalTrimmed
10
- } from "./chunk-WNOVRQ67.js";
10
+ } from "./chunk-NQLWOTY4.js";
11
11
  import {
12
12
  pluginCatalogRuntime
13
- } from "./chunk-3TV7OEHL.js";
13
+ } from "./chunk-WSRBFHPX.js";
14
14
  import {
15
+ setSpanAttributes,
16
+ setSpanStatus,
15
17
  withSpan
16
- } from "./chunk-IYKPU7H6.js";
18
+ } from "./chunk-J7APPQIJ.js";
17
19
 
18
20
  // src/chat/sandbox/runtime-dependencies.ts
19
21
  var GLOBAL_RUNTIME_DEPENDENCIES = [
@@ -105,37 +107,303 @@ function getVercelSandboxCredentials() {
105
107
  }
106
108
 
107
109
  // src/chat/sandbox/workspace.ts
108
- function createSandboxInstance(sandbox) {
110
+ import {
111
+ FileSystem
112
+ } from "@vercel/sandbox";
113
+
114
+ // src/chat/sandbox/http-error-details.ts
115
+ var DEFAULT_PREVIEW_LIMIT = 512;
116
+ function toTrimmedString(value, maxChars) {
117
+ if (typeof value !== "string") {
118
+ return void 0;
119
+ }
120
+ const normalized = value.trim();
121
+ if (!normalized) {
122
+ return void 0;
123
+ }
124
+ return normalized.length > maxChars ? `${normalized.slice(0, maxChars)}\u2026` : normalized;
125
+ }
126
+ function extractHttpErrorDetails(error, options = {}) {
127
+ const prefix = options.attributePrefix ?? "app.http_error";
128
+ const previewLimit = options.previewLimit ?? DEFAULT_PREVIEW_LIMIT;
129
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
130
+ const err = error ?? {};
131
+ const attributes = {
132
+ "error.type": normalizedError.name || "Error",
133
+ "exception.message": toTrimmedString(normalizedError.message, previewLimit) ?? "HTTP error"
134
+ };
135
+ const response = err.response;
136
+ const statusCode = typeof response?.status === "number" ? response.status : void 0;
137
+ const statusText = toTrimmedString(response?.statusText, previewLimit);
138
+ const responseUrl = toTrimmedString(response?.url, previewLimit);
139
+ const responseText = toTrimmedString(err.text, previewLimit);
140
+ const responseJson = toTrimmedString(
141
+ err.json && typeof err.json === "object" ? JSON.stringify(err.json) : void 0,
142
+ previewLimit
143
+ );
144
+ const contentType = toTrimmedString(
145
+ response?.headers?.get?.("content-type"),
146
+ previewLimit
147
+ );
148
+ const requestIdHeader = toTrimmedString(
149
+ response?.headers?.get?.("x-request-id"),
150
+ previewLimit
151
+ );
152
+ const vercelIdHeader = toTrimmedString(
153
+ response?.headers?.get?.("x-vercel-id"),
154
+ previewLimit
155
+ );
156
+ const requestId = requestIdHeader ?? vercelIdHeader;
157
+ if (statusCode !== void 0) {
158
+ attributes["http.response.status_code"] = statusCode;
159
+ }
160
+ if (statusText) {
161
+ attributes[`${prefix}.status_text`] = statusText;
162
+ }
163
+ if (responseUrl) {
164
+ attributes["url.full"] = responseUrl;
165
+ }
166
+ if (contentType) {
167
+ attributes["http.response.header.content-type"] = [contentType];
168
+ }
169
+ if (requestIdHeader) {
170
+ attributes["http.response.header.x-request-id"] = [requestIdHeader];
171
+ }
172
+ if (vercelIdHeader) {
173
+ attributes["http.response.header.x-vercel-id"] = [vercelIdHeader];
174
+ }
175
+ if (responseText) {
176
+ attributes[`${prefix}.response_text_preview`] = responseText;
177
+ attributes[`${prefix}.response_text_length`] = responseText.length;
178
+ }
179
+ if (responseJson) {
180
+ attributes[`${prefix}.response_json_preview`] = responseJson;
181
+ }
182
+ const summaryParts = [];
183
+ if (statusCode !== void 0) {
184
+ summaryParts.push(`status=${statusCode}`);
185
+ }
186
+ if (statusText) {
187
+ summaryParts.push(`statusText=${statusText}`);
188
+ }
189
+ if (responseUrl) {
190
+ summaryParts.push(`url=${responseUrl}`);
191
+ }
192
+ if (requestId) {
193
+ summaryParts.push(`requestId=${requestId}`);
194
+ }
195
+ for (const field of options.extraFields ?? []) {
196
+ const value = toTrimmedString(err[field.sourceKey], previewLimit);
197
+ if (!value) {
198
+ continue;
199
+ }
200
+ attributes[`${prefix}.${field.attributeKey}`] = value;
201
+ summaryParts.push(`${field.summaryKey ?? field.attributeKey}=${value}`);
202
+ }
203
+ if (responseJson) {
204
+ summaryParts.push(`json=${responseJson}`);
205
+ } else if (responseText) {
206
+ summaryParts.push(`text=${responseText}`);
207
+ }
208
+ const searchableText = `${normalizedError.message} ${responseText ?? ""} ${responseJson ?? ""}`.toLowerCase();
209
+ return {
210
+ attributes,
211
+ summary: summaryParts.join(", "),
212
+ searchableText
213
+ };
214
+ }
215
+
216
+ // src/chat/sandbox/errors.ts
217
+ var SANDBOX_ERROR_FIELDS = [
218
+ {
219
+ sourceKey: "sandboxId",
220
+ attributeKey: "sandbox_id",
221
+ summaryKey: "sandboxId"
222
+ }
223
+ ];
224
+ function getSandboxErrorDetails(error) {
225
+ return extractHttpErrorDetails(error, {
226
+ attributePrefix: "app.sandbox.api_error",
227
+ extraFields: [...SANDBOX_ERROR_FIELDS]
228
+ });
229
+ }
230
+ function findInErrorChain(error, predicate) {
231
+ const seen = /* @__PURE__ */ new Set();
232
+ let current = error;
233
+ while (current && !seen.has(current)) {
234
+ if (predicate(current)) {
235
+ return true;
236
+ }
237
+ seen.add(current);
238
+ current = typeof current === "object" ? current.cause : void 0;
239
+ }
240
+ return false;
241
+ }
242
+ function isRecord(value) {
243
+ return typeof value === "object" && value !== null;
244
+ }
245
+ function isInvalidSandboxSessionError(error) {
246
+ if (!isRecord(error)) {
247
+ return false;
248
+ }
249
+ if (isRecord(error.json) && error.json.invalidToken === true) {
250
+ return true;
251
+ }
252
+ const response = error.response;
253
+ return isRecord(response) && response.status === 403 && typeof response.url === "string" && response.url.includes("/sandboxes/sessions");
254
+ }
255
+ function getFirstErrorMessage(error) {
256
+ const seen = /* @__PURE__ */ new Set();
257
+ let current = error;
258
+ while (current && !seen.has(current)) {
259
+ if (current instanceof Error) {
260
+ const message = current.message.trim();
261
+ if (message) {
262
+ return message;
263
+ }
264
+ }
265
+ seen.add(current);
266
+ current = typeof current === "object" ? current.cause : void 0;
267
+ }
268
+ return void 0;
269
+ }
270
+ function isAlreadyExistsError(error) {
271
+ const details = getSandboxErrorDetails(error);
272
+ return details.searchableText.includes("already exists") || details.searchableText.includes("file exists") || details.searchableText.includes("eexist");
273
+ }
274
+ function isSandboxUnavailableError(error) {
275
+ return findInErrorChain(error, (candidate) => {
276
+ if (isInvalidSandboxSessionError(candidate)) {
277
+ return true;
278
+ }
279
+ const details = getSandboxErrorDetails(candidate);
280
+ const searchable = `${details.searchableText} ${details.summary}`.toLowerCase();
281
+ return searchable.includes("sandbox_stopped") || searchable.includes("status=410") || searchable.includes("status code 410") || searchable.includes("no longer available") || searchable.includes("stream was closed and is not accepting commands");
282
+ });
283
+ }
284
+ function isSandboxMissingError(error) {
285
+ return findInErrorChain(error, (candidate) => {
286
+ const details = getSandboxErrorDetails(candidate);
287
+ const searchable = `${details.searchableText} ${details.summary}`.toLowerCase();
288
+ return searchable.includes("status=404") || searchable.includes("status code 404") || searchable.includes("snapshot_not_found");
289
+ });
290
+ }
291
+ function isSnapshottingError(error) {
292
+ return findInErrorChain(error, (candidate) => {
293
+ const details = getSandboxErrorDetails(candidate);
294
+ const searchable = `${details.searchableText} ${details.summary}`.toLowerCase();
295
+ return searchable.includes("sandbox_snapshotting") || searchable.includes("creating a snapshot") || searchable.includes("stopped shortly");
296
+ });
297
+ }
298
+ function isSandboxCommandStreamInterruptedError(error) {
299
+ return findInErrorChain(error, (candidate) => {
300
+ if (!(candidate instanceof Error)) {
301
+ return false;
302
+ }
303
+ return candidate.name === "StreamError" && candidate.message.toLowerCase().includes("stream ended before command finished");
304
+ });
305
+ }
306
+ function wrapSandboxSetupError(error) {
307
+ try {
308
+ const details = getSandboxErrorDetails(error);
309
+ if (details.summary) {
310
+ return new Error(`sandbox setup failed (${details.summary})`, {
311
+ cause: error
312
+ });
313
+ }
314
+ } catch {
315
+ }
316
+ let causeMessage;
317
+ try {
318
+ causeMessage = getFirstErrorMessage(error);
319
+ } catch (cause) {
320
+ causeMessage = cause instanceof Error ? cause.message : void 0;
321
+ }
322
+ if (causeMessage && causeMessage.trim() && causeMessage !== "sandbox setup failed") {
323
+ const oneLine = causeMessage.replace(/\s+/g, " ").trim();
324
+ return new Error(`sandbox setup failed (${oneLine})`, { cause: error });
325
+ }
326
+ return new Error("sandbox setup failed", { cause: error });
327
+ }
328
+ function throwSandboxOperationError(action, error, includeMissingPath = false) {
329
+ const details = getSandboxErrorDetails(error);
330
+ setSpanAttributes({
331
+ ...details.attributes,
332
+ ...includeMissingPath ? {
333
+ "app.sandbox.api_error.missing_path": details.searchableText.includes("no such file") || details.searchableText.includes("enoent")
334
+ } : {},
335
+ "app.sandbox.success": false
336
+ });
337
+ setSpanStatus("error");
338
+ throw new Error(
339
+ details.summary ? `${action} failed (${details.summary})` : `${action} failed`,
340
+ {
341
+ cause: error
342
+ }
343
+ );
344
+ }
345
+
346
+ // src/chat/sandbox/workspace.ts
347
+ function createSandboxSession(sandbox, options) {
348
+ const session = sandbox.currentSession();
349
+ const fileSystem = new FileSystem(session);
350
+ const run = async (operation) => {
351
+ try {
352
+ return await operation();
353
+ } catch (error) {
354
+ if (isSandboxUnavailableError(error)) {
355
+ options?.onUnavailable?.(session.sessionId);
356
+ }
357
+ throw error;
358
+ }
359
+ };
360
+ const fs = {
361
+ readFile: async (filePath, readOptions) => await run(async () => await fileSystem.readFile(filePath, readOptions)),
362
+ writeFile: async (filePath, content, writeOptions) => await run(
363
+ async () => await fileSystem.writeFile(filePath, content, writeOptions)
364
+ ),
365
+ readdir: async (filePath) => await run(async () => await fileSystem.readdir(filePath)),
366
+ stat: async (filePath) => await run(async () => await fileSystem.stat(filePath))
367
+ };
109
368
  return {
110
369
  sandboxId: sandbox.name,
111
- get sandboxEgressId() {
112
- return sandbox.currentSession().sessionId;
113
- },
114
- fs: sandbox.fs,
370
+ sessionId: session.sessionId,
371
+ fs,
115
372
  extendTimeout(duration) {
116
- return sandbox.extendTimeout(duration);
373
+ return run(async () => await session.extendTimeout(duration));
117
374
  },
118
375
  mkDir(path) {
119
- return sandbox.mkDir(path);
376
+ return run(async () => await session.mkDir(path));
120
377
  },
121
378
  readFileToBuffer(input) {
122
- return sandbox.readFileToBuffer(input);
379
+ return run(async () => await session.readFileToBuffer(input));
123
380
  },
124
- runCommand(input) {
125
- return sandbox.runCommand(input);
381
+ async runCommand(input) {
382
+ const result = await run(async () => await session.runCommand(input));
383
+ const [stdout, stderr] = await Promise.all([
384
+ run(async () => await result.stdout()),
385
+ run(async () => await result.stderr())
386
+ ]);
387
+ return {
388
+ exitCode: result.exitCode,
389
+ stdout,
390
+ stderr
391
+ };
126
392
  },
127
- async snapshot() {
128
- const snapshot = await sandbox.snapshot();
129
- return { snapshotId: snapshot.snapshotId };
393
+ snapshot() {
394
+ return run(async () => {
395
+ const snapshot = await session.snapshot();
396
+ return { snapshotId: snapshot.snapshotId };
397
+ });
130
398
  },
131
399
  stop() {
132
- return sandbox.stop();
400
+ return run(async () => await session.stop());
133
401
  },
134
402
  update(params) {
135
- return sandbox.update(params);
403
+ return run(async () => await session.update(params));
136
404
  },
137
405
  writeFiles(files) {
138
- return sandbox.writeFiles(files);
406
+ return run(async () => await session.writeFiles(files));
139
407
  }
140
408
  };
141
409
  }
@@ -258,8 +526,8 @@ async function runOrThrow(sandbox, params, label) {
258
526
  if (result.exitCode === 0) {
259
527
  return;
260
528
  }
261
- const stderr = (await result.stderr()).trim();
262
- const stdout = (await result.stdout()).trim();
529
+ const stderr = result.stderr.trim();
530
+ const stdout = result.stdout.trim();
263
531
  const detail = stderr || stdout || "command failed";
264
532
  throw new Error(`${label} failed: ${detail}`);
265
533
  }
@@ -268,8 +536,8 @@ async function tryRun(sandbox, params) {
268
536
  if (result.exitCode === 0) {
269
537
  return { ok: true };
270
538
  }
271
- const stderr = (await result.stderr()).trim();
272
- const stdout = (await result.stdout()).trim();
539
+ const stderr = result.stderr.trim();
540
+ const stdout = result.stdout.trim();
273
541
  return { ok: false, detail: stderr || stdout || "command failed" };
274
542
  }
275
543
  async function installGhCliViaDnf(sandbox) {
@@ -368,8 +636,8 @@ async function installRuntimeDependencies(sandbox, deps) {
368
636
  cmd: "sha256sum",
369
637
  args: [rpmPath]
370
638
  });
371
- const checksumStdout = (await checksumResult.stdout()).trim();
372
- const checksumStderr = (await checksumResult.stderr()).trim();
639
+ const checksumStdout = checksumResult.stdout.trim();
640
+ const checksumStderr = checksumResult.stderr.trim();
373
641
  if (checksumResult.exitCode !== 0) {
374
642
  throw new Error(
375
643
  `sha256sum failed: ${checksumStderr || checksumStdout || "command failed"}`
@@ -460,8 +728,8 @@ async function runRuntimePostinstall(sandbox, commands) {
460
728
  if (result.exitCode === 0) {
461
729
  continue;
462
730
  }
463
- const stderr = (await result.stderr()).trim();
464
- const stdout = (await result.stdout()).trim();
731
+ const stderr = result.stderr.trim();
732
+ const stdout = result.stdout.trim();
465
733
  const detail = stderr || stdout || "command failed";
466
734
  throw new Error(`runtime-postinstall ${command.cmd} failed: ${detail}`);
467
735
  }
@@ -479,7 +747,7 @@ async function createDependencySnapshot(profile, runtime, timeoutMs) {
479
747
  async () => {
480
748
  const sandboxCredentials = getVercelSandboxCredentials();
481
749
  const resources = getSandboxResources();
482
- const sandbox = createSandboxInstance(
750
+ const sandbox = createSandboxSession(
483
751
  await Sandbox.create({
484
752
  timeout: timeoutMs,
485
753
  runtime,
@@ -697,12 +965,19 @@ function isSnapshotMissingError(error) {
697
965
  }
698
966
 
699
967
  export {
968
+ isAlreadyExistsError,
969
+ isSandboxUnavailableError,
970
+ isSandboxMissingError,
971
+ isSnapshottingError,
972
+ isSandboxCommandStreamInterruptedError,
973
+ wrapSandboxSetupError,
974
+ throwSandboxOperationError,
975
+ getVercelSandboxCredentials,
700
976
  buildNonInteractiveShellScript,
701
977
  runNonInteractiveCommand,
702
- getVercelSandboxCredentials,
703
978
  getSandboxResources,
704
979
  GLOBAL_RUNTIME_DEPENDENCIES,
705
- createSandboxInstance,
980
+ createSandboxSession,
706
981
  getRuntimeDependencyProfileHash,
707
982
  resolveRuntimeDependencySnapshot,
708
983
  isSnapshotMissingError
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-3TV7OEHL.js";
3
+ } from "./chunk-WSRBFHPX.js";
4
4
  import {
5
5
  logWarn
6
- } from "./chunk-IYKPU7H6.js";
6
+ } from "./chunk-J7APPQIJ.js";
7
7
  import {
8
8
  skillRoots
9
9
  } from "./chunk-3V7OFJZC.js";
@@ -3,13 +3,13 @@ import {
3
3
  } from "./chunk-4ZNGQH7C.js";
4
4
  import {
5
5
  getSlackBotToken
6
- } from "./chunk-WNOVRQ67.js";
6
+ } from "./chunk-NQLWOTY4.js";
7
7
  import {
8
8
  logWarn,
9
9
  setSpanAttributes,
10
10
  setSpanStatus,
11
11
  withSpan
12
- } from "./chunk-IYKPU7H6.js";
12
+ } from "./chunk-J7APPQIJ.js";
13
13
  import {
14
14
  parseSlackChannelReferenceId
15
15
  } from "./chunk-42WRQLJ6.js";
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-6GWA276C.js";
14
14
  import {
15
15
  getDeploymentTelemetryAttributes
16
- } from "./chunk-W75ZPAGG.js";
16
+ } from "./chunk-MPVES2IC.js";
17
17
 
18
18
  // src/chat/logging.ts
19
19
  import path from "path";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-2ZTTXTSZ.js";
4
4
  import {
5
5
  normalizeSlackConversationId
6
- } from "./chunk-L5XQPJ7T.js";
6
+ } from "./chunk-IFAHK54X.js";
7
7
  import {
8
8
  parseSlackThreadId
9
9
  } from "./chunk-6Y5L4BOM.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  JUNIOR_VERSION
3
- } from "./chunk-ZKIOWEFL.js";
3
+ } from "./chunk-Z4G3WCP3.js";
4
4
 
5
5
  // src/deployment.ts
6
6
  var JUNIOR_HEARTBEAT_ROUTE = "/api/internal/heartbeat";
@@ -12,7 +12,7 @@ import {
12
12
  normalizeGenAiFinishReason,
13
13
  serializeGenAiAttribute,
14
14
  withSpan
15
- } from "./chunk-IYKPU7H6.js";
15
+ } from "./chunk-J7APPQIJ.js";
16
16
 
17
17
  // src/chat/xml.ts
18
18
  function escapeXml(value) {
@@ -172,7 +172,7 @@ function stripRuntimeTurnContext(messages) {
172
172
  }
173
173
 
174
174
  // src/chat/config.ts
175
- import { getModel } from "@earendil-works/pi-ai/compat";
175
+ import { getModel as getModel2 } from "@earendil-works/pi-ai/compat";
176
176
 
177
177
  // src/chat/optional-string.ts
178
178
  function toOptionalTrimmed(value) {
@@ -187,7 +187,9 @@ function toOptionalTrimmed(value) {
187
187
  import {
188
188
  completeSimple,
189
189
  getEnvApiKey,
190
+ getModel,
190
191
  getModels,
192
+ isRetryableAssistantError,
191
193
  registerApiProvider
192
194
  } from "@earendil-works/pi-ai/compat";
193
195
  import {
@@ -592,6 +594,7 @@ var DEFAULT_SLACK_SLASH_COMMAND = "/jr";
592
594
  var DEFAULT_PROCESSING_REACTION_EMOJI = "eyes";
593
595
  var DEFAULT_COMPLETED_REACTION_EMOJI = "white_check_mark";
594
596
  var FUNCTION_TIMEOUT_BUFFER_SECONDS = 20;
597
+ var CONVERSATION_WORK_SOFT_YIELD_BUFFER_SECONDS = 40;
595
598
  var DEFAULT_ASSISTANT_LOADING_MESSAGES = [
596
599
  "Consulting the orb",
597
600
  "Bribing the gremlins",
@@ -616,13 +619,14 @@ function parseAgentTurnTimeoutMs(rawValue, maxTimeoutMs) {
616
619
  }
617
620
  return Math.max(MIN_AGENT_TURN_TIMEOUT_MS, Math.min(value, maxTimeoutMs));
618
621
  }
619
- function resolveFunctionMaxDurationSeconds(env) {
620
- const raw = env.FUNCTION_MAX_DURATION_SECONDS ?? env.QUEUE_CALLBACK_MAX_DURATION_SECONDS;
621
- const value = Number.parseInt(raw ?? "", 10);
622
- if (Number.isNaN(value) || value <= 0) {
623
- return DEFAULT_FUNCTION_MAX_DURATION_SECONDS;
624
- }
625
- return value;
622
+ function resolveFunctionMaxDurationSeconds(functionMaxDurationSeconds) {
623
+ return functionMaxDurationSeconds ?? DEFAULT_FUNCTION_MAX_DURATION_SECONDS;
624
+ }
625
+ function resolveConversationWorkSoftYieldAfterMs(functionMaxDurationSeconds) {
626
+ return Math.max(
627
+ MIN_AGENT_TURN_TIMEOUT_MS,
628
+ (functionMaxDurationSeconds - CONVERSATION_WORK_SOFT_YIELD_BUFFER_SECONDS) * 1e3
629
+ );
626
630
  }
627
631
  function resolveMaxTurnTimeoutMs(functionMaxDurationSeconds) {
628
632
  const budgetSeconds = functionMaxDurationSeconds - FUNCTION_TIMEOUT_BUFFER_SECONDS;
@@ -669,16 +673,21 @@ function parseSlashCommand(rawValue) {
669
673
  }
670
674
  return command;
671
675
  }
672
- var DEFAULT_MODEL_ID = getModel("vercel-ai-gateway", "xai/grok-4.5").id;
673
- var DEFAULT_FAST_MODEL_ID = getModel(
676
+ var DEFAULT_MODEL_ID = getModel2("vercel-ai-gateway", "xai/grok-4.5").id;
677
+ var DEFAULT_FAST_MODEL_ID = getModel2(
674
678
  "vercel-ai-gateway",
675
679
  "anthropic/claude-haiku-4.5"
676
680
  ).id;
677
- var DEFAULT_HANDOFF_MODEL_ID = getModel(
681
+ var DEFAULT_HANDOFF_MODEL_ID = getModel2(
678
682
  "vercel-ai-gateway",
679
683
  "openai/gpt-5.6-sol"
680
684
  ).id;
685
+ var DEFAULT_WEB_SEARCH_MODEL_ID = getModel2(
686
+ "vercel-ai-gateway",
687
+ "openai/gpt-5.4"
688
+ ).id;
681
689
  var DEFAULT_EMBEDDING_MODEL_ID = "openai/text-embedding-3-small";
690
+ var DEFAULT_IMAGE_GENERATION_MODEL_ID = "google/gemini-3-pro-image";
682
691
  function validateGatewayModelId(raw) {
683
692
  const trimmed = toOptionalTrimmed(raw);
684
693
  if (trimmed === void 0) return void 0;
@@ -742,8 +751,7 @@ function parseReactionEmoji(envName, rawValue, defaultEmoji) {
742
751
  }
743
752
  return normalized;
744
753
  }
745
- function readBotConfig(env) {
746
- const functionMaxDurationSeconds = resolveFunctionMaxDurationSeconds(env);
754
+ function readBotConfig(env, functionMaxDurationSeconds) {
747
755
  const maxTurnTimeoutMs = resolveMaxTurnTimeoutMs(functionMaxDurationSeconds);
748
756
  const modelId = validateGatewayModelId(env.AI_MODEL) ?? DEFAULT_MODEL_ID;
749
757
  const reasoningLevel = toOptionalTrimmed(env.AI_REASONING_LEVEL);
@@ -758,6 +766,7 @@ function readBotConfig(env) {
758
766
  ),
759
767
  reasoningLevel: reasoningLevel === void 0 ? void 0 : parseTurnReasoningLevel(reasoningLevel),
760
768
  fastModelId,
769
+ imageGenerationModelId: toOptionalTrimmed(env.AI_IMAGE_MODEL) ?? DEFAULT_IMAGE_GENERATION_MODEL_ID,
761
770
  embeddingModelId: validateEmbeddingModelId(env.AI_EMBEDDING_MODEL) ?? DEFAULT_EMBEDDING_MODEL_ID,
762
771
  loadingMessages: parseLoadingMessages(env.JUNIOR_LOADING_MESSAGES),
763
772
  visionModelId: validateGatewayModelId(env.AI_VISION_MODEL),
@@ -765,7 +774,8 @@ function readBotConfig(env) {
765
774
  turnTimeoutMs: parseAgentTurnTimeoutMs(
766
775
  env.AGENT_TURN_TIMEOUT_MS,
767
776
  maxTurnTimeoutMs
768
- )
777
+ ),
778
+ webSearchModelId: validateGatewayModelId(env.AI_WEB_SEARCH_MODEL) ?? DEFAULT_WEB_SEARCH_MODEL_ID
769
779
  };
770
780
  }
771
781
  function readDatabaseUrl(env) {
@@ -796,11 +806,17 @@ function readSqlDriver(env, databaseUrl) {
796
806
  }
797
807
  throw new Error("JUNIOR_DATABASE_DRIVER must be postgres or neon");
798
808
  }
799
- function readChatConfig(env = process.env) {
809
+ function readChatConfig(env = process.env, functionMaxDurationSeconds = DEFAULT_FUNCTION_MAX_DURATION_SECONDS) {
800
810
  const databaseUrl = readDatabaseUrl(env);
811
+ const resolvedFunctionMaxDurationSeconds = resolveFunctionMaxDurationSeconds(
812
+ functionMaxDurationSeconds
813
+ );
801
814
  return {
802
- bot: readBotConfig(env),
803
- functionMaxDurationSeconds: resolveFunctionMaxDurationSeconds(env),
815
+ bot: readBotConfig(env, resolvedFunctionMaxDurationSeconds),
816
+ functionMaxDurationSeconds: resolvedFunctionMaxDurationSeconds,
817
+ conversationWorkSoftYieldAfterMs: resolveConversationWorkSoftYieldAfterMs(
818
+ resolvedFunctionMaxDurationSeconds
819
+ ),
804
820
  sql: {
805
821
  databaseUrl,
806
822
  driver: readSqlDriver(env, databaseUrl)
@@ -822,6 +838,17 @@ function readChatConfig(env = process.env) {
822
838
  };
823
839
  }
824
840
  var chatConfig = readChatConfig(process.env);
841
+ function configureFunctionMaxDurationSeconds(functionMaxDurationSeconds) {
842
+ const resolved = resolveFunctionMaxDurationSeconds(
843
+ functionMaxDurationSeconds
844
+ );
845
+ chatConfig.functionMaxDurationSeconds = resolved;
846
+ chatConfig.conversationWorkSoftYieldAfterMs = resolveConversationWorkSoftYieldAfterMs(resolved);
847
+ chatConfig.bot.turnTimeoutMs = parseAgentTurnTimeoutMs(
848
+ process.env.AGENT_TURN_TIMEOUT_MS,
849
+ resolveMaxTurnTimeoutMs(resolved)
850
+ );
851
+ }
825
852
  function getChatConfig() {
826
853
  return chatConfig;
827
854
  }
@@ -910,6 +937,7 @@ export {
910
937
  standardModelId,
911
938
  profileConfig,
912
939
  FUNCTION_TIMEOUT_BUFFER_SECONDS,
940
+ configureFunctionMaxDurationSeconds,
913
941
  getChatConfig,
914
942
  botConfig,
915
943
  getSlackBotToken,