@sentry/junior 0.116.0 → 0.117.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 (67) hide show
  1. package/dist/{agent-hooks-67NFITDH.js → agent-hooks-5IK4LPLP.js} +8 -8
  2. package/dist/api/conversations/detail.d.ts +7 -0
  3. package/dist/api/conversations/event-list.d.ts +7 -0
  4. package/dist/api/conversations/events.d.ts +1 -1
  5. package/dist/api/schema/conversation.d.ts +28 -0
  6. package/dist/api/schema.js +1 -1
  7. package/dist/api.js +25 -12
  8. package/dist/app.js +32 -30
  9. package/dist/{catalog-runtime-CWZY6GTH.js → catalog-runtime-MTUYW3AA.js} +5 -5
  10. package/dist/chat/agent/prompt.d.ts +2 -0
  11. package/dist/chat/agent/request.d.ts +2 -1
  12. package/dist/chat/agent/resume.d.ts +2 -0
  13. package/dist/chat/agent/tools.d.ts +1 -0
  14. package/dist/chat/conversations/history.d.ts +22 -1
  15. package/dist/chat/conversations/projection.d.ts +6 -0
  16. package/dist/chat/mcp/client.d.ts +4 -0
  17. package/dist/chat/mcp/errors.d.ts +22 -1
  18. package/dist/chat/oauth-response.d.ts +21 -0
  19. package/dist/chat/plugins/prompt.d.ts +9 -0
  20. package/dist/chat/plugins/types.d.ts +2 -21
  21. package/dist/chat/sandbox/snapshot/install.d.ts +6 -0
  22. package/dist/chat/sandbox/snapshot/profile.d.ts +14 -0
  23. package/dist/chat/sandbox/snapshot/resolve.d.ts +22 -0
  24. package/dist/chat/sandbox/snapshot/span.d.ts +2 -0
  25. package/dist/chat/services/context-compaction-marker.d.ts +1 -0
  26. package/dist/chat/services/turn-session-record.d.ts +2 -0
  27. package/dist/chat/state/turn-session.d.ts +2 -0
  28. package/dist/chat/tools/query-conversation-events.d.ts +1 -1
  29. package/dist/chat/tools/sandbox/view-image.d.ts +11 -0
  30. package/dist/chat/tools/types.d.ts +7 -0
  31. package/dist/{chunk-OF5FODBL.js → chunk-27KWTFP6.js} +33 -12
  32. package/dist/{chunk-MGH5ADQS.js → chunk-3GE3F4LT.js} +1 -1
  33. package/dist/{chunk-JZPQ5K4V.js → chunk-5O3JDQDG.js} +154 -20
  34. package/dist/{chunk-PGKWXHYJ.js → chunk-6G45D3YG.js} +114 -10
  35. package/dist/{chunk-3JOGUT46.js → chunk-72Z3HNTQ.js} +1 -1
  36. package/dist/{chunk-6RQ5GCWH.js → chunk-AKG4TZNH.js} +2 -2
  37. package/dist/{chunk-TC4ZEM2D.js → chunk-BFIRIZPH.js} +9 -0
  38. package/dist/{chunk-25GU5B5E.js → chunk-CU7HTGNI.js} +1 -1
  39. package/dist/{chunk-PZGPCOSD.js → chunk-DS27ZBSP.js} +4 -2
  40. package/dist/{chunk-3H45VOBZ.js → chunk-FAWBONPC.js} +404 -391
  41. package/dist/{chunk-53ZKTQO6.js → chunk-KU6ALEJC.js} +1 -1
  42. package/dist/{chunk-UEVLIYK5.js → chunk-LN765Y4N.js} +6 -6
  43. package/dist/{chunk-4DD6AOCG.js → chunk-LUMEBOWC.js} +1 -1
  44. package/dist/{chunk-5UNB623T.js → chunk-NHZEUHKH.js} +514 -344
  45. package/dist/{chunk-VZCSLYCE.js → chunk-STUI6NIL.js} +78 -16
  46. package/dist/{chunk-BXLS3I4W.js → chunk-W5JEQQEA.js} +1 -1
  47. package/dist/{chunk-VKZ6WVAY.js → chunk-WEK3V5RI.js} +73 -32
  48. package/dist/{chunk-N7TMYLF2.js → chunk-WUNPRM76.js} +1 -1
  49. package/dist/{chunk-CI3VK7X5.js → chunk-YRWJ3KEU.js} +2 -2
  50. package/dist/{chunk-KBNDFU6J.js → chunk-ZRQUQJUV.js} +12 -2
  51. package/dist/cli/chat.js +21 -21
  52. package/dist/cli/check.js +6 -6
  53. package/dist/cli/main.js +1 -1
  54. package/dist/cli/plugins.js +11 -11
  55. package/dist/cli/{snapshot-warmup.js → snapshot-create.js} +17 -19
  56. package/dist/cli/upgrade.js +5 -5
  57. package/dist/{db-57FHVGGQ.js → db-J2ITKS63.js} +5 -5
  58. package/dist/handlers/oauth-html.d.ts +4 -2
  59. package/dist/instrumentation.js +2 -2
  60. package/dist/nitro.js +2 -2
  61. package/dist/{oauth-callback-server-PAQRPXZX.js → oauth-callback-server-NQYKBT24.js} +15 -15
  62. package/dist/{runner-4ISZYJEX.js → runner-53V5GIQM.js} +10 -10
  63. package/dist/{skills-UE2KXQMB.js → skills-BU3ZMLVB.js} +6 -6
  64. package/dist/{validation-PO5LHTJT.js → validation-74EIKKE6.js} +6 -6
  65. package/dist/version.js +1 -1
  66. package/package.json +6 -6
  67. package/dist/chat/sandbox/runtime-dependency-snapshots.d.ts +0 -20
@@ -2,6 +2,8 @@ import {
2
2
  authorizationId
3
3
  } from "./chunk-DIB4GX3G.js";
4
4
  import {
5
+ McpProviderError,
6
+ McpToolError,
5
7
  RetryableDeliveryError,
6
8
  actorFromRouting,
7
9
  addReactionToMessage,
@@ -12,6 +14,9 @@ import {
12
14
  deliverOAuthAuthorization,
13
15
  formatProviderLabel,
14
16
  getMcpAuthSession,
17
+ getMcpAwareErrorType,
18
+ getMcpAwareTelemetryMessage,
19
+ getMcpProviderErrorAttributes,
15
20
  getSlackMessagePermalink,
16
21
  hasEgressCredentialHooks,
17
22
  issuePluginCredential,
@@ -23,9 +28,10 @@ import {
23
28
  slackOutputPolicy,
24
29
  startOAuthFlow,
25
30
  surfaceFromRouting,
31
+ toMcpProviderError,
26
32
  toolInvocationDestination,
27
33
  uploadFilesToConversation
28
- } from "./chunk-PGKWXHYJ.js";
34
+ } from "./chunk-6G45D3YG.js";
29
35
  import {
30
36
  CooperativeTurnYieldError,
31
37
  JUNIOR_THREAD_STATE_TTL_MS,
@@ -67,7 +73,7 @@ import {
67
73
  stripRuntimeTurnContext,
68
74
  trimTrailingAssistantMessages,
69
75
  updateConversationStats
70
- } from "./chunk-OF5FODBL.js";
76
+ } from "./chunk-27KWTFP6.js";
71
77
  import {
72
78
  parseSandboxEgressAuthRequiredSignal,
73
79
  parseSandboxEgressPermissionDeniedSignal,
@@ -78,20 +84,20 @@ import {
78
84
  bindSandboxFileSystem,
79
85
  buildNonInteractiveShellScript,
80
86
  createSandboxSession,
81
- getRuntimeDependencyProfileHash,
82
87
  getSandboxResources,
83
88
  getVercelSandboxCredentials,
89
+ hash,
84
90
  isAlreadyExistsError,
91
+ isMissingError,
85
92
  isSandboxCommandStreamInterruptedError,
86
93
  isSandboxMissingError,
87
94
  isSandboxUnavailableError,
88
- isSnapshotMissingError,
89
95
  isSnapshottingError,
90
- resolveRuntimeDependencySnapshot,
96
+ resolve,
91
97
  runNonInteractiveCommand,
92
98
  throwSandboxOperationError,
93
99
  wrapSandboxSetupError
94
- } from "./chunk-3H45VOBZ.js";
100
+ } from "./chunk-FAWBONPC.js";
95
101
  import {
96
102
  addAgentTurnUsage,
97
103
  hasAgentTurnUsage
@@ -106,7 +112,7 @@ import {
106
112
  getPluginUserPromptContributions,
107
113
  getSlackToolContext,
108
114
  resolveChannelCapabilities
109
- } from "./chunk-VZCSLYCE.js";
115
+ } from "./chunk-STUI6NIL.js";
110
116
  import {
111
117
  SANDBOX_DATA_ROOT,
112
118
  SANDBOX_SKILLS_ROOT,
@@ -114,7 +120,7 @@ import {
114
120
  getStateAdapter,
115
121
  sandboxSkillDir,
116
122
  sandboxSkillFile
117
- } from "./chunk-53ZKTQO6.js";
123
+ } from "./chunk-KU6ALEJC.js";
118
124
  import {
119
125
  SlackActionError,
120
126
  downloadPrivateSlackFile,
@@ -123,7 +129,7 @@ import {
123
129
  isConversationScopedChannel,
124
130
  normalizeSlackConversationId,
125
131
  withSlackRetries
126
- } from "./chunk-CI3VK7X5.js";
132
+ } from "./chunk-YRWJ3KEU.js";
127
133
  import {
128
134
  KNOWN_CONVERSATION_EVENT_TYPES,
129
135
  contextProvenance,
@@ -132,11 +138,12 @@ import {
132
138
  getConversationStore,
133
139
  instructionActors,
134
140
  instructionProvenanceFor
135
- } from "./chunk-KBNDFU6J.js";
141
+ } from "./chunk-ZRQUQJUV.js";
136
142
  import {
137
143
  sleep
138
144
  } from "./chunk-4ZNGQH7C.js";
139
145
  import {
146
+ ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX,
140
147
  COMPACTION_SUMMARY_PREFIX,
141
148
  DEFAULT_HANDOFF_MODEL_PROFILE,
142
149
  GEN_AI_PROVIDER_NAME,
@@ -165,7 +172,7 @@ import {
165
172
  renderCurrentInstruction,
166
173
  resolveGatewayModel,
167
174
  unwrapCurrentInstruction
168
- } from "./chunk-PZGPCOSD.js";
175
+ } from "./chunk-DS27ZBSP.js";
169
176
  import {
170
177
  canExposeConversationPayload,
171
178
  parseSlackThreadId,
@@ -182,15 +189,18 @@ import {
182
189
  findSkillByName,
183
190
  loadSkillsByName,
184
191
  parseSkillInvocation
185
- } from "./chunk-6RQ5GCWH.js";
192
+ } from "./chunk-AKG4TZNH.js";
186
193
  import {
187
194
  pluginCatalogRuntime
188
- } from "./chunk-25GU5B5E.js";
195
+ } from "./chunk-CU7HTGNI.js";
189
196
  import {
190
197
  CredentialUnavailableError,
198
+ OAuthProviderError,
199
+ fetchWithBoundedOAuthErrorBodies,
200
+ getOAuthProviderErrorAttributes,
191
201
  resolveAuthTokenPlaceholder,
192
202
  resolvePluginCommandEnv
193
- } from "./chunk-JZPQ5K4V.js";
203
+ } from "./chunk-5O3JDQDG.js";
194
204
  import {
195
205
  credentialUserSubjectId
196
206
  } from "./chunk-W3U3YQYI.js";
@@ -214,7 +224,7 @@ import {
214
224
  summarizeMessageText,
215
225
  withLogContext,
216
226
  withSpan
217
- } from "./chunk-3JOGUT46.js";
227
+ } from "./chunk-72Z3HNTQ.js";
218
228
  import {
219
229
  parseSlackChannelId,
220
230
  parseSlackMessageTs,
@@ -2302,6 +2312,33 @@ function withoutTrailingUncheckpointedUserPrompt(messages, userContentParts) {
2302
2312
  function userPromptContentMatches(storedContent, currentContent) {
2303
2313
  return isDeepStrictEqual(storedContent, currentContent);
2304
2314
  }
2315
+ function isUserContentPart(value) {
2316
+ if (typeof value !== "object" || value === null || !("type" in value)) {
2317
+ return false;
2318
+ }
2319
+ if (value.type === "text") {
2320
+ return "text" in value && typeof value.text === "string";
2321
+ }
2322
+ return value.type === "image" && "data" in value && typeof value.data === "string" && "mimeType" in value && typeof value.mimeType === "string";
2323
+ }
2324
+ function checkpointedPromptContent(args) {
2325
+ if (!args.messages || args.turnStartMessageIndex === void 0 || args.turnStartMessageIndex !== args.messages.length - 1) {
2326
+ return void 0;
2327
+ }
2328
+ const message = args.messages[args.turnStartMessageIndex];
2329
+ if (message?.role !== "user" || !Array.isArray(message.content)) {
2330
+ return void 0;
2331
+ }
2332
+ const durableMessage = stripRuntimeTurnContext([message])[0];
2333
+ if (!userPromptContentMatches(durableMessage?.content, args.userContentParts)) {
2334
+ return void 0;
2335
+ }
2336
+ const content = message.content;
2337
+ if (!content.every(isUserContentPart)) {
2338
+ return void 0;
2339
+ }
2340
+ return content;
2341
+ }
2305
2342
  async function assemblePrompt(args) {
2306
2343
  const source = args.routing.source;
2307
2344
  const hasPromptCheckpoint = args.resumedFromSessionRecord && args.existingTurnStartMessageIndex !== void 0;
@@ -2310,13 +2347,18 @@ async function assemblePrompt(args) {
2310
2347
  args.priorPiMessages,
2311
2348
  args.userContentParts
2312
2349
  ) : args.existingSessionPiMessages;
2313
- const needsBootstrapContextForPrompt = shouldPromptAgent && !hasRuntimeTurnContext(promptHistoryMessages);
2350
+ const replayedPromptContent = shouldPromptAgent && !args.resumedFromSessionRecord ? checkpointedPromptContent({
2351
+ messages: args.existingSessionPiMessages,
2352
+ turnStartMessageIndex: args.existingTurnStartMessageIndex,
2353
+ userContentParts: args.userContentParts
2354
+ }) : void 0;
2355
+ const needsBootstrapContextForPrompt = shouldPromptAgent && !replayedPromptContent && !hasRuntimeTurnContext(promptHistoryMessages);
2314
2356
  const systemPromptContributions = await getPluginSystemPromptContributions(source);
2315
2357
  const pluginSystemPrompt = buildPluginSystemPromptContributions(
2316
2358
  systemPromptContributions
2317
2359
  );
2318
2360
  const baseInstructions = [buildSystemPrompt({ source }), pluginSystemPrompt].filter((section) => Boolean(section)).join("\n\n");
2319
- const pluginUserPromptContributions = !shouldPromptAgent ? [] : await getPluginUserPromptContributions({
2361
+ const pluginUserPromptContributions = !shouldPromptAgent || replayedPromptContent ? [] : await getPluginUserPromptContributions({
2320
2362
  context: args.toolRuntimeContext
2321
2363
  });
2322
2364
  const turnContextPrompt = needsBootstrapContextForPrompt || pluginUserPromptContributions.length > 0 ? buildTurnContextPrompt({
@@ -2340,7 +2382,10 @@ async function assemblePrompt(args) {
2340
2382
  configuration: args.configurationValues
2341
2383
  }) : null;
2342
2384
  const turnContextParts = turnContextPrompt ? [{ type: "text", text: turnContextPrompt }] : [];
2343
- const promptContentParts = [...turnContextParts, ...args.userContentParts];
2385
+ const promptContentParts = replayedPromptContent ?? [
2386
+ ...turnContextParts,
2387
+ ...args.userContentParts
2388
+ ];
2344
2389
  const inputMessages = [
2345
2390
  {
2346
2391
  role: "system",
@@ -2371,7 +2416,10 @@ async function assemblePrompt(args) {
2371
2416
  inputMessagesAttribute,
2372
2417
  promptContentParts,
2373
2418
  promptHistoryMessages,
2374
- shouldPromptAgent
2419
+ shouldPromptAgent,
2420
+ turnContexts: pluginUserPromptContributions.flatMap(
2421
+ (contribution) => contribution.context ? [contribution.context] : []
2422
+ )
2375
2423
  };
2376
2424
  }
2377
2425
 
@@ -3240,7 +3288,7 @@ function createSandboxRuntime(options) {
3240
3288
  let closed = false;
3241
3289
  const timeoutMs = options.timeoutMs ?? 1e3 * 60 * 30;
3242
3290
  const traceContext = options.traceContext ?? {};
3243
- const dependencyProfileHash = getRuntimeDependencyProfileHash(SANDBOX_RUNTIME);
3291
+ const dependencyProfileHash = hash(SANDBOX_RUNTIME);
3244
3292
  const resolveCommandEnv = options.commandEnv ?? (async () => ({}));
3245
3293
  const withSandboxSpan = (name, op, attributes, callback) => withSpan(name, op, traceContext, callback, attributes);
3246
3294
  const invalidateSession = (sessionId) => {
@@ -3402,13 +3450,13 @@ function createSandboxRuntime(options) {
3402
3450
  sandboxName
3403
3451
  );
3404
3452
  } catch (error) {
3405
- if (!isSnapshotMissingError(error)) {
3453
+ if (!isMissingError(error)) {
3406
3454
  throw error;
3407
3455
  }
3408
3456
  setSpanAttributes({
3409
3457
  "app.sandbox.snapshot.rebuild_after_missing": true
3410
3458
  });
3411
- const rebuiltSnapshot = await resolveRuntimeDependencySnapshot({
3459
+ const rebuiltSnapshot = await resolve({
3412
3460
  runtime,
3413
3461
  timeoutMs,
3414
3462
  forceRebuild: true,
@@ -3439,7 +3487,7 @@ function createSandboxRuntime(options) {
3439
3487
  "app.sandbox.runtime": runtime
3440
3488
  },
3441
3489
  async () => {
3442
- const snapshot = await resolveRuntimeDependencySnapshot({
3490
+ const snapshot = await resolve({
3443
3491
  runtime,
3444
3492
  timeoutMs
3445
3493
  });
@@ -5846,6 +5894,7 @@ function createAgentSandbox(options) {
5846
5894
  }
5847
5895
 
5848
5896
  // src/chat/mcp/client.ts
5897
+ import { AsyncLocalStorage } from "async_hooks";
5849
5898
  import { Client } from "@modelcontextprotocol/sdk/client";
5850
5899
  import {
5851
5900
  UnauthorizedError
@@ -5887,18 +5936,25 @@ var McpAuthorizationRequiredError = class extends Error {
5887
5936
  this.provider = provider;
5888
5937
  }
5889
5938
  };
5939
+ function isMissingSessionError(error) {
5940
+ return error instanceof StreamableHTTPError && (error.code === 404 || /Session not found/i.test(error.message));
5941
+ }
5890
5942
  var PluginMcpClient = class {
5891
5943
  constructor(plugin, options = {}) {
5892
5944
  this.plugin = plugin;
5893
5945
  this.options = options;
5946
+ const url = plugin.manifest.mcp?.url;
5947
+ this.resourceHost = url ? new URL(url).hostname : void 0;
5894
5948
  }
5895
5949
  plugin;
5896
5950
  options;
5897
5951
  client;
5898
5952
  clientPromise;
5899
5953
  lastAttemptedTransportSessionId;
5954
+ providerStatusStore = new AsyncLocalStorage();
5900
5955
  transport;
5901
5956
  listedTools;
5957
+ resourceHost;
5902
5958
  async listTools() {
5903
5959
  if (this.listedTools) {
5904
5960
  return [...this.listedTools];
@@ -5910,7 +5966,8 @@ var PluginMcpClient = class {
5910
5966
  let cursor;
5911
5967
  do {
5912
5968
  const result = await this.wrapAuth(
5913
- client.listTools(cursor ? { cursor } : void 0)
5969
+ () => client.listTools(cursor ? { cursor } : void 0),
5970
+ "list_tools"
5914
5971
  );
5915
5972
  await this.syncTransportSessionId();
5916
5973
  for (const tool of result.tools) {
@@ -5943,10 +6000,11 @@ var PluginMcpClient = class {
5943
6000
  });
5944
6001
  }
5945
6002
  const result = await this.wrapAuth(
5946
- client.callTool({
6003
+ () => client.callTool({
5947
6004
  name,
5948
6005
  arguments: args ?? {}
5949
- })
6006
+ }),
6007
+ "call_tool"
5950
6008
  );
5951
6009
  await this.syncTransportSessionId();
5952
6010
  return result;
@@ -5964,7 +6022,7 @@ var PluginMcpClient = class {
5964
6022
  throw error;
5965
6023
  }
5966
6024
  await this.clearStoredTransportSessionId();
5967
- await this.disposeClient();
6025
+ await this.cleanupClientAfterFailure();
5968
6026
  return await operation();
5969
6027
  }
5970
6028
  }
@@ -6000,7 +6058,12 @@ var PluginMcpClient = class {
6000
6058
  this.lastAttemptedTransportSessionId = sessionId;
6001
6059
  const transport = new StreamableHTTPClientTransport(new URL(mcp.url), {
6002
6060
  ...Object.keys(requestInit).length > 0 ? { requestInit } : {},
6003
- ...this.options.fetch ? { fetch: this.options.fetch } : {},
6061
+ fetch: fetchWithBoundedOAuthErrorBodies(this.options.fetch, (status) => {
6062
+ const store = this.providerStatusStore.getStore();
6063
+ if (store) {
6064
+ store.status = status;
6065
+ }
6066
+ }),
6004
6067
  ...this.options.authProvider ? { authProvider: this.options.authProvider } : {},
6005
6068
  ...sessionId ? { sessionId } : {}
6006
6069
  });
@@ -6009,48 +6072,79 @@ var PluginMcpClient = class {
6009
6072
  });
6010
6073
  this.transport = transport;
6011
6074
  try {
6012
- await this.wrapAuth(client.connect(transport));
6075
+ await this.wrapAuth(() => client.connect(transport), "connect");
6013
6076
  this.client = client;
6014
6077
  await this.syncTransportSessionId();
6015
6078
  return client;
6016
6079
  } catch (error) {
6017
6080
  await this.syncTransportSessionId();
6018
- await this.disposeClient();
6081
+ await this.cleanupClientAfterFailure();
6019
6082
  throw error;
6020
6083
  }
6021
6084
  }
6022
- async wrapAuth(promise) {
6023
- try {
6024
- return await promise;
6025
- } catch (error) {
6026
- if (error instanceof McpAuthorizationRequiredError) {
6027
- throw error;
6028
- }
6029
- if (error instanceof UnauthorizedError) {
6030
- throw new McpAuthorizationRequiredError(
6031
- this.plugin.manifest.name,
6032
- `MCP authorization required for plugin "${this.plugin.manifest.name}"`
6033
- );
6085
+ async wrapAuth(operation, phase) {
6086
+ const store = {};
6087
+ return await this.providerStatusStore.run(store, async () => {
6088
+ try {
6089
+ return await operation();
6090
+ } catch (error) {
6091
+ if (error instanceof McpAuthorizationRequiredError) {
6092
+ throw error;
6093
+ }
6094
+ if (error instanceof UnauthorizedError) {
6095
+ throw new McpAuthorizationRequiredError(
6096
+ this.plugin.manifest.name,
6097
+ `MCP authorization required for plugin "${this.plugin.manifest.name}"`
6098
+ );
6099
+ }
6100
+ throw toMcpProviderError(error, {
6101
+ phase,
6102
+ provider: this.plugin.manifest.name,
6103
+ missingSession: isMissingSessionError(error) || void 0,
6104
+ resourceHost: this.resourceHost,
6105
+ status: store.status
6106
+ });
6034
6107
  }
6035
- throw error;
6036
- }
6108
+ });
6037
6109
  }
6038
6110
  async shouldResetMissingSession(error) {
6039
- if (!(error instanceof StreamableHTTPError && (error.code === 404 || /Session not found/i.test(error.message)))) {
6111
+ if (!(error instanceof McpProviderError && error.missingSession || isMissingSessionError(error))) {
6040
6112
  return false;
6041
6113
  }
6042
6114
  return Boolean(
6043
6115
  this.transport?.sessionId ?? this.lastAttemptedTransportSessionId ?? await this.getStoredTransportSessionId()
6044
6116
  );
6045
6117
  }
6046
- async disposeClient() {
6118
+ resetClientState() {
6047
6119
  const transport = this.transport;
6048
6120
  this.listedTools = void 0;
6049
6121
  this.transport = void 0;
6050
6122
  this.client = void 0;
6051
6123
  this.clientPromise = void 0;
6052
- if (transport) {
6124
+ return transport;
6125
+ }
6126
+ async cleanupClientAfterFailure() {
6127
+ const transport = this.resetClientState();
6128
+ if (!transport) {
6129
+ return;
6130
+ }
6131
+ try {
6053
6132
  await transport.close();
6133
+ } catch {
6134
+ }
6135
+ }
6136
+ async disposeClient() {
6137
+ const transport = this.resetClientState();
6138
+ if (transport) {
6139
+ try {
6140
+ await transport.close();
6141
+ } catch (error) {
6142
+ throw toMcpProviderError(error, {
6143
+ phase: "close",
6144
+ provider: this.plugin.manifest.name,
6145
+ resourceHost: this.resourceHost
6146
+ });
6147
+ }
6054
6148
  }
6055
6149
  }
6056
6150
  async getStoredTransportSessionId() {
@@ -6073,29 +6167,6 @@ var PluginMcpClient = class {
6073
6167
  }
6074
6168
  };
6075
6169
 
6076
- // src/chat/mcp/errors.ts
6077
- var McpToolError = class extends Error {
6078
- constructor(message) {
6079
- super(message);
6080
- this.name = "McpToolError";
6081
- }
6082
- };
6083
- function getMcpAwareErrorType(error, fallback) {
6084
- if (error instanceof McpToolError) {
6085
- return "tool_error";
6086
- }
6087
- return error instanceof Error ? error.name : fallback;
6088
- }
6089
- function getMcpAwareErrorMessage(error) {
6090
- return error instanceof Error ? error.message : String(error);
6091
- }
6092
- function getMcpAwareTelemetryMessage(error, privacy) {
6093
- if (privacy === "private" && error instanceof McpToolError) {
6094
- return "MCP tool call failed";
6095
- }
6096
- return getMcpAwareErrorMessage(error);
6097
- }
6098
-
6099
6170
  // src/chat/mcp/tool-manager.ts
6100
6171
  var MAX_TOOL_RESULT_TOKENS = 1e4;
6101
6172
  var MAX_TOOL_RESULT_BYTES = 32 * 1024;
@@ -6469,6 +6540,7 @@ var McpToolManager = class {
6469
6540
  }
6470
6541
  const errorAttributes = {
6471
6542
  ...baseAttributes,
6543
+ ...getMcpProviderErrorAttributes(error),
6472
6544
  "error.type": getMcpAwareErrorType(error, "mcp_tool_error"),
6473
6545
  "exception.message": getMcpAwareTelemetryMessage(
6474
6546
  error,
@@ -7207,13 +7279,77 @@ function createSearchMcpToolsTool(mcpToolManager) {
7207
7279
  });
7208
7280
  }
7209
7281
 
7210
- // src/chat/tools/runtime/report-progress.ts
7282
+ // src/chat/tools/sandbox/view-image.ts
7211
7283
  import { z as z15 } from "zod";
7284
+ var MAX_VIEW_IMAGE_BYTES = 5 * 1024 * 1024;
7285
+ var viewImageInputSchema = z15.object({
7286
+ path: z15.string().min(1).describe("Path to an image file in the sandbox workspace.")
7287
+ }).strict();
7288
+ function detectImageMimeType(data) {
7289
+ if (data.length >= 8 && data.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
7290
+ return "image/png";
7291
+ }
7292
+ if (data.length >= 3 && data[0] === 255 && data[1] === 216 && data[2] === 255) {
7293
+ return "image/jpeg";
7294
+ }
7295
+ if (data.length >= 6 && (data.subarray(0, 6).toString("ascii") === "GIF87a" || data.subarray(0, 6).toString("ascii") === "GIF89a")) {
7296
+ return "image/gif";
7297
+ }
7298
+ if (data.length >= 12 && data.subarray(0, 4).toString("ascii") === "RIFF" && data.subarray(8, 12).toString("ascii") === "WEBP") {
7299
+ return "image/webp";
7300
+ }
7301
+ return void 0;
7302
+ }
7303
+ function createViewImageTool(sandbox, supportsImageInput, deps = {}) {
7304
+ return zodTool({
7305
+ description: "View an image file from the sandbox workspace when visual inspection is needed. Supports PNG, JPEG, GIF, and WebP images up to 5 MB.",
7306
+ exposure: "direct",
7307
+ inputSchema: viewImageInputSchema,
7308
+ async execute({ path: path9 }) {
7309
+ if (!supportsImageInput()) {
7310
+ throw new ToolInputError(
7311
+ "viewImage is unavailable because the current model does not support image inputs"
7312
+ );
7313
+ }
7314
+ const targetPath = normalizeSandboxPath(path9);
7315
+ const data = deps.readFile ? await deps.readFile(targetPath) : await sandbox.readFileToBuffer({ path: targetPath });
7316
+ if (!data) {
7317
+ throw new SandboxFileNotFoundError(targetPath);
7318
+ }
7319
+ if (data.byteLength === 0) {
7320
+ throw new ToolInputError(`image file is empty: ${targetPath}`);
7321
+ }
7322
+ if (data.byteLength > MAX_VIEW_IMAGE_BYTES) {
7323
+ throw new ToolInputError(
7324
+ `image exceeds ${MAX_VIEW_IMAGE_BYTES} bytes: ${targetPath} (${data.byteLength} bytes)`
7325
+ );
7326
+ }
7327
+ const mimeType = detectImageMimeType(data);
7328
+ if (!mimeType) {
7329
+ throw new ToolInputError(
7330
+ `unsupported image format: ${targetPath}; use PNG, JPEG, GIF, or WebP`
7331
+ );
7332
+ }
7333
+ return {
7334
+ content: [
7335
+ {
7336
+ type: "image",
7337
+ data: data.toString("base64"),
7338
+ mimeType
7339
+ }
7340
+ ]
7341
+ };
7342
+ }
7343
+ });
7344
+ }
7345
+
7346
+ // src/chat/tools/runtime/report-progress.ts
7347
+ import { z as z16 } from "zod";
7212
7348
  function createReportProgressTool() {
7213
7349
  return zodTool({
7214
7350
  description: "Update the user-visible assistant loading message with a short progress phase. For every non-trivial turn, call this early with the initial major work phase, then call it again only when the major phase meaningfully changes. Messages must be written in sentence case with a present-participle verb (e.g. 'Searching docs', 'Reviewing results', 'Running checks'). Skip trivial direct answers, generic filler, and minor substeps.",
7215
- inputSchema: z15.object({
7216
- message: z15.string().min(1).describe("Short user-facing progress message.")
7351
+ inputSchema: z16.object({
7352
+ message: z16.string().min(1).describe("Short user-facing progress message.")
7217
7353
  }),
7218
7354
  outputSchema: juniorToolResultSchema,
7219
7355
  execute: async () => ({
@@ -7224,34 +7360,34 @@ function createReportProgressTool() {
7224
7360
  }
7225
7361
 
7226
7362
  // src/chat/tools/resource-events.ts
7227
- import { z as z17 } from "zod";
7363
+ import { z as z18 } from "zod";
7228
7364
 
7229
7365
  // src/chat/resource-events/store.ts
7230
7366
  import { createHash } from "crypto";
7231
7367
  import { destinationSchema } from "@sentry/junior-plugin-api";
7232
- import { z as z16 } from "zod";
7368
+ import { z as z17 } from "zod";
7233
7369
  var RESOURCE_EVENT_PREFIX = "junior:resource_event_subscription";
7234
7370
  var INDEX_LOCK_TTL_MS = 1e4;
7235
7371
  var SUBSCRIPTION_LOCK_TTL_MS = 1e4;
7236
7372
  var SUBSCRIPTION_LOCK_WAIT_MS = 1e4;
7237
7373
  var SUBSCRIPTION_LOCK_RETRY_MS = 25;
7238
7374
  var SUBSCRIPTION_LOCK_HEARTBEAT_MS = 3e3;
7239
- var subscriptionStatusSchema = z16.enum(["active", "cancelled", "completed"]);
7240
- var subscriptionIdIndexSchema = z16.array(z16.string().min(1));
7241
- var subscriptionSchema = z16.object({
7242
- conversationId: z16.string().min(1),
7243
- createdAtMs: z16.number().finite(),
7375
+ var subscriptionStatusSchema = z17.enum(["active", "cancelled", "completed"]);
7376
+ var subscriptionIdIndexSchema = z17.array(z17.string().min(1));
7377
+ var subscriptionSchema = z17.object({
7378
+ conversationId: z17.string().min(1),
7379
+ createdAtMs: z17.number().finite(),
7244
7380
  destination: destinationSchema,
7245
- events: z16.array(z16.string().min(1)).min(1),
7246
- expiresAtMs: z16.number().finite(),
7247
- id: z16.string().min(1),
7248
- intent: z16.string().min(1),
7249
- label: z16.string().min(1),
7250
- provider: z16.string().min(1),
7251
- resourceRef: z16.string().min(1),
7252
- resourceType: z16.string().min(1),
7381
+ events: z17.array(z17.string().min(1)).min(1),
7382
+ expiresAtMs: z17.number().finite(),
7383
+ id: z17.string().min(1),
7384
+ intent: z17.string().min(1),
7385
+ label: z17.string().min(1),
7386
+ provider: z17.string().min(1),
7387
+ resourceRef: z17.string().min(1),
7388
+ resourceType: z17.string().min(1),
7253
7389
  status: subscriptionStatusSchema,
7254
- updatedAtMs: z16.number().finite()
7390
+ updatedAtMs: z17.number().finite()
7255
7391
  }).strict();
7256
7392
  function digest(value) {
7257
7393
  return createHash("sha256").update(value).digest("hex").slice(0, 32);
@@ -7272,8 +7408,8 @@ function indexLockKey(key) {
7272
7408
  return `${key}:lock`;
7273
7409
  }
7274
7410
  async function sleep2(ms) {
7275
- await new Promise((resolve) => {
7276
- const timer = setTimeout(resolve, ms);
7411
+ await new Promise((resolve2) => {
7412
+ const timer = setTimeout(resolve2, ms);
7277
7413
  timer.unref?.();
7278
7414
  });
7279
7415
  }
@@ -7607,18 +7743,18 @@ var RESOURCE_WATCH_TOOL_SOURCE = {
7607
7743
  id: "resource-watches",
7608
7744
  description: "Inspect or stop resource watches for the current conversation."
7609
7745
  };
7610
- var subscribeInputSchema = z17.object({
7611
- resourceRef: z17.string().describe("Opaque resource ref copied from a subscribable tool result."),
7612
- provider: z17.string().describe("Provider that owns the resource ref."),
7613
- resourceType: z17.string().describe("Provider-defined resource type from the subscribable hint."),
7614
- label: z17.string().describe("Human-readable resource label from the subscribable hint."),
7615
- events: z17.array(z17.string()).min(1).describe(
7746
+ var subscribeInputSchema = z18.object({
7747
+ resourceRef: z18.string().describe("Opaque resource ref copied from a subscribable tool result."),
7748
+ provider: z18.string().describe("Provider that owns the resource ref."),
7749
+ resourceType: z18.string().describe("Provider-defined resource type from the subscribable hint."),
7750
+ label: z18.string().describe("Human-readable resource label from the subscribable hint."),
7751
+ events: z18.array(z18.string()).min(1).describe(
7616
7752
  "High-signal event names to deliver to this conversation when they occur."
7617
7753
  ),
7618
- intent: z17.string().describe(
7754
+ intent: z18.string().describe(
7619
7755
  "Concise reason this conversation wants these events, used when an event arrives."
7620
7756
  ),
7621
- ttlMs: z17.coerce.number().describe(
7757
+ ttlMs: z18.coerce.number().describe(
7622
7758
  "How long to keep the subscription active. Defaults to 14 days and is capped at 30 days."
7623
7759
  ).optional()
7624
7760
  });
@@ -7711,7 +7847,7 @@ function createListResourceEventSubscriptionsTool(context) {
7711
7847
  description: "List active resource event subscriptions for the current conversation.",
7712
7848
  exposure: "deferred",
7713
7849
  source: RESOURCE_WATCH_TOOL_SOURCE,
7714
- inputSchema: z17.object({}),
7850
+ inputSchema: z18.object({}),
7715
7851
  outputSchema: juniorToolResultSchema,
7716
7852
  async execute() {
7717
7853
  const conversationId = requireConversationContext(context);
@@ -7744,7 +7880,7 @@ function createStopWatchingResourcesTool(context) {
7744
7880
  description: "Stop every resource watch for the current conversation. Infer the user's intent from context instead of requiring a special command, and call this tool before confirming that watching stopped.",
7745
7881
  exposure: "deferred",
7746
7882
  source: RESOURCE_WATCH_TOOL_SOURCE,
7747
- inputSchema: z17.object({}),
7883
+ inputSchema: z18.object({}),
7748
7884
  outputSchema: juniorToolResultSchema,
7749
7885
  async execute() {
7750
7886
  const conversationId = requireConversationContext(context);
@@ -7851,11 +7987,11 @@ async function listThreadReplies(input) {
7851
7987
  }
7852
7988
 
7853
7989
  // src/chat/slack/timestamp-param.ts
7854
- import { z as z18 } from "zod";
7990
+ import { z as z19 } from "zod";
7855
7991
  function slackTimestampParam(description) {
7856
- return z18.preprocess(
7992
+ return z19.preprocess(
7857
7993
  (value) => typeof value === "number" && Number.isFinite(value) ? String(value) : value,
7858
- z18.string().min(1)
7994
+ z19.string().min(1)
7859
7995
  ).describe(description);
7860
7996
  }
7861
7997
  function optionalSlackTimestampParam(description) {
@@ -7886,10 +8022,10 @@ function parseRequiredSlackTimestampParam(field, value) {
7886
8022
  }
7887
8023
 
7888
8024
  // src/chat/slack/tools/channel-list-messages.ts
7889
- import { z as z19 } from "zod";
7890
- var booleanInput2 = (description) => z19.preprocess(
8025
+ import { z as z20 } from "zod";
8026
+ var booleanInput2 = (description) => z20.preprocess(
7891
8027
  (value) => value === "true" ? true : value === "false" ? false : value,
7892
- z19.boolean()
8028
+ z20.boolean()
7893
8029
  ).describe(description);
7894
8030
  function normalizeRangeTimestamp(field, value, targetChannelId) {
7895
8031
  if (value === void 0) {
@@ -7916,9 +8052,9 @@ function createSlackChannelListMessagesTool(context) {
7916
8052
  return zodTool({
7917
8053
  description: "List channel messages from Slack history in the active channel context. Use when the user asks for recent or historical channel context outside this thread. Do not use for live monitoring or when current thread context already answers the question.",
7918
8054
  annotations: { readOnlyHint: true, destructiveHint: false },
7919
- inputSchema: z19.object({
7920
- limit: z19.coerce.number().int().min(1).max(1e3).describe("Maximum number of messages to return across pages.").optional(),
7921
- cursor: z19.string().min(1).describe("Optional cursor to continue from a prior call.").optional(),
8055
+ inputSchema: z20.object({
8056
+ limit: z20.coerce.number().int().min(1).max(1e3).describe("Maximum number of messages to return across pages.").optional(),
8057
+ cursor: z20.string().min(1).describe("Optional cursor to continue from a prior call.").optional(),
7922
8058
  oldest: optionalSlackTimestampParam(
7923
8059
  "Optional oldest message timestamp (Slack ts) for range filtering."
7924
8060
  ),
@@ -7928,7 +8064,7 @@ function createSlackChannelListMessagesTool(context) {
7928
8064
  inclusive: booleanInput2(
7929
8065
  "Whether oldest/latest bounds should be inclusive."
7930
8066
  ).optional(),
7931
- max_pages: z19.coerce.number().int().min(1).max(10).describe("Maximum number of API pages to traverse in a single call.").optional()
8067
+ max_pages: z20.coerce.number().int().min(1).max(10).describe("Maximum number of API pages to traverse in a single call.").optional()
7932
8068
  }),
7933
8069
  outputSchema: juniorToolResultSchema,
7934
8070
  execute: async ({
@@ -8002,20 +8138,20 @@ function createSlackChannelListMessagesTool(context) {
8002
8138
  }
8003
8139
 
8004
8140
  // src/chat/slack/tools/conversation-search.ts
8005
- import { z as z20 } from "zod";
8141
+ import { z as z21 } from "zod";
8006
8142
  var DEFAULT_LIMIT = 5;
8007
8143
  var conversationSearchOutputSchema = juniorToolResultSchema.extend({
8008
- query: z20.string(),
8009
- count: z20.number().int().nonnegative(),
8010
- threads: z20.array(
8011
- z20.object({
8012
- conversation_id: z20.string().min(1),
8013
- thread_ts: z20.string().min(1),
8014
- message_id: z20.string().min(1),
8015
- message_role: z20.enum(["assistant", "user"]),
8016
- message_timestamp: z20.string().datetime(),
8017
- excerpt: z20.string(),
8018
- permalink: z20.string().url().optional()
8144
+ query: z21.string(),
8145
+ count: z21.number().int().nonnegative(),
8146
+ threads: z21.array(
8147
+ z21.object({
8148
+ conversation_id: z21.string().min(1),
8149
+ thread_ts: z21.string().min(1),
8150
+ message_id: z21.string().min(1),
8151
+ message_role: z21.enum(["assistant", "user"]),
8152
+ message_timestamp: z21.string().datetime(),
8153
+ excerpt: z21.string(),
8154
+ permalink: z21.string().url().optional()
8019
8155
  }).strict()
8020
8156
  )
8021
8157
  });
@@ -8028,9 +8164,9 @@ function createSlackConversationSearchTool(scope, currentConversationId, deps =
8028
8164
  description: "Search retained public Junior conversation threads in the current Slack workspace."
8029
8165
  },
8030
8166
  annotations: { readOnlyHint: true, destructiveHint: false },
8031
- inputSchema: z20.object({
8032
- query: z20.string().trim().min(1).max(200).describe("Words or a short phrase to find in prior conversations."),
8033
- limit: z20.number().int().min(1).max(10).describe("Maximum number of prior conversation threads to return.").nullable().optional()
8167
+ inputSchema: z21.object({
8168
+ query: z21.string().trim().min(1).max(200).describe("Words or a short phrase to find in prior conversations."),
8169
+ limit: z21.number().int().min(1).max(10).describe("Maximum number of prior conversation threads to return.").nullable().optional()
8034
8170
  }),
8035
8171
  outputSchema: conversationSearchOutputSchema,
8036
8172
  execute: async ({ query, limit }) => {
@@ -8077,27 +8213,27 @@ function createSlackConversationSearchTool(scope, currentConversationId, deps =
8077
8213
  }
8078
8214
 
8079
8215
  // src/chat/slack/tools/public-search.ts
8080
- import { z as z21 } from "zod";
8216
+ import { z as z22 } from "zod";
8081
8217
  var DEFAULT_LIMIT2 = 10;
8082
- var optionalTimestampSchema = z21.preprocess(
8218
+ var optionalTimestampSchema = z22.preprocess(
8083
8219
  (value) => typeof value === "string" && value.trim() === "" ? void 0 : value,
8084
- z21.coerce.number().int().nonnegative().describe("Optional Unix timestamp bound.").optional()
8220
+ z22.coerce.number().int().nonnegative().describe("Optional Unix timestamp bound.").optional()
8085
8221
  );
8086
- var searchMessageSchema = z21.object({
8087
- author_name: z21.string().optional(),
8088
- author_user_id: z21.string().optional(),
8089
- channel_id: z21.string().min(1),
8090
- channel_name: z21.string().optional(),
8091
- message_ts: z21.string().min(1),
8092
- content: z21.string(),
8093
- is_author_bot: z21.boolean().optional(),
8094
- permalink: z21.string().url()
8222
+ var searchMessageSchema = z22.object({
8223
+ author_name: z22.string().optional(),
8224
+ author_user_id: z22.string().optional(),
8225
+ channel_id: z22.string().min(1),
8226
+ channel_name: z22.string().optional(),
8227
+ message_ts: z22.string().min(1),
8228
+ content: z22.string(),
8229
+ is_author_bot: z22.boolean().optional(),
8230
+ permalink: z22.string().url()
8095
8231
  });
8096
8232
  var publicSearchOutputSchema = juniorToolResultSchema.extend({
8097
- query: z21.string(),
8098
- count: z21.number().int().nonnegative(),
8099
- messages: z21.array(searchMessageSchema),
8100
- next_cursor: z21.string().optional()
8233
+ query: z22.string(),
8234
+ count: z22.number().int().nonnegative(),
8235
+ messages: z22.array(searchMessageSchema),
8236
+ next_cursor: z22.string().optional()
8101
8237
  });
8102
8238
  function normalizeMessage(value) {
8103
8239
  const parsed = searchMessageSchema.safeParse(value);
@@ -8119,8 +8255,8 @@ function createSlackPublicSearchTool(actionToken) {
8119
8255
  return zodTool({
8120
8256
  description: "Search public Slack channel messages across the current workspace. Use when the user asks about company activity, announcements, public mentions, or context outside the active channel. Search only when requested or clearly needed, prefer focused keywords and time bounds, and cite returned permalinks. This never searches private channels or DMs.",
8121
8257
  annotations: { readOnlyHint: true, destructiveHint: false },
8122
- inputSchema: z21.object({
8123
- query: z21.string().trim().min(1).max(500).describe(
8258
+ inputSchema: z22.object({
8259
+ query: z22.string().trim().min(1).max(500).describe(
8124
8260
  "A focused Slack search query, including Slack search filters when useful."
8125
8261
  ),
8126
8262
  after: optionalTimestampSchema.describe(
@@ -8129,10 +8265,10 @@ function createSlackPublicSearchTool(actionToken) {
8129
8265
  before: optionalTimestampSchema.describe(
8130
8266
  "Optional Unix timestamp upper bound."
8131
8267
  ),
8132
- cursor: z21.string().min(1).describe("Cursor for the next result page.").optional(),
8133
- limit: z21.coerce.number().int().min(1).max(20).describe("Maximum results to return; Slack allows at most 20.").optional(),
8134
- sort: z21.enum(["score", "timestamp"]).describe("Rank by relevance or timestamp.").optional(),
8135
- sort_dir: z21.enum(["asc", "desc"]).describe("Sort direction.").optional()
8268
+ cursor: z22.string().min(1).describe("Cursor for the next result page.").optional(),
8269
+ limit: z22.coerce.number().int().min(1).max(20).describe("Maximum results to return; Slack allows at most 20.").optional(),
8270
+ sort: z22.enum(["score", "timestamp"]).describe("Rank by relevance or timestamp.").optional(),
8271
+ sort_dir: z22.enum(["asc", "desc"]).describe("Sort direction.").optional()
8136
8272
  }),
8137
8273
  outputSchema: publicSearchOutputSchema,
8138
8274
  execute: async ({
@@ -8198,7 +8334,7 @@ function createSlackPublicSearchTool(actionToken) {
8198
8334
  }
8199
8335
 
8200
8336
  // src/chat/slack/tools/message-add-reaction.ts
8201
- import { z as z22 } from "zod";
8337
+ import { z as z23 } from "zod";
8202
8338
 
8203
8339
  // src/chat/tools/idempotency.ts
8204
8340
  function stableSerialize(value) {
@@ -8222,8 +8358,8 @@ function createOperationKey(toolName, input) {
8222
8358
  function createSlackMessageAddReactionTool(context, state) {
8223
8359
  return zodTool({
8224
8360
  description: "Add an emoji reaction to the current inbound Slack message. Use when the user asks for a reaction on the current message without another target. Provide a Slack emoji alias name (for example `thumbsup`, `white_check_mark`, or `thumbsup::skin-tone-6`), not a unicode emoji glyph. The target message is injected by runtime context; do not use this for arbitrary historical messages.",
8225
- inputSchema: z22.object({
8226
- emoji: z22.string().min(1).max(64).describe(
8361
+ inputSchema: z23.object({
8362
+ emoji: z23.string().min(1).max(64).describe(
8227
8363
  "Slack emoji alias name to react with (for example `thumbsup`, `white_check_mark`, or `thumbsup::skin-tone-6`). Optional surrounding colons are allowed."
8228
8364
  )
8229
8365
  }),
@@ -8274,18 +8410,18 @@ function createSlackMessageAddReactionTool(context, state) {
8274
8410
 
8275
8411
  // src/chat/slack/tools/send-files.ts
8276
8412
  import { createHash as createHash2 } from "crypto";
8277
- import { z as z23 } from "zod";
8278
- var sendFilesDataSchema = z23.object({
8279
- channel_id: z23.string().min(1),
8280
- deduplicated: z23.boolean().optional(),
8281
- file_count: z23.number().int().nonnegative(),
8282
- file_ids: z23.array(z23.string().min(1)).optional(),
8283
- thread_ts: z23.string().min(1)
8413
+ import { z as z24 } from "zod";
8414
+ var sendFilesDataSchema = z24.object({
8415
+ channel_id: z24.string().min(1),
8416
+ deduplicated: z24.boolean().optional(),
8417
+ file_count: z24.number().int().nonnegative(),
8418
+ file_ids: z24.array(z24.string().min(1)).optional(),
8419
+ thread_ts: z24.string().min(1)
8284
8420
  });
8285
8421
  var sendFilesResultSchema = juniorToolResultSchema.extend({
8286
- ok: z23.literal(true),
8287
- status: z23.literal("success"),
8288
- target: z23.string().min(1),
8422
+ ok: z24.literal(true),
8423
+ status: z24.literal("success"),
8424
+ target: z24.string().min(1),
8289
8425
  data: sendFilesDataSchema
8290
8426
  });
8291
8427
  function normalizeFiles(files) {
@@ -8310,8 +8446,8 @@ function fileOperationInput(files) {
8310
8446
  function createSendFilesTool(context, state, materializeFile) {
8311
8447
  return zodTool({
8312
8448
  description: "Send one or more sandbox files into the active Slack conversation. Use when the user asks to attach, send, or share files here, in this conversation, or in this thread. Do not use for ordinary assistant text, top-level channel posts, other named channels, inline @mentions, or pinging mentioned users.",
8313
- inputSchema: z23.object({
8314
- files: z23.array(sandboxFileReferenceSchema).min(1).describe(
8449
+ inputSchema: z24.object({
8450
+ files: z24.array(sandboxFileReferenceSchema).min(1).describe(
8315
8451
  "One or more existing sandbox files. Objects returned by imageGenerate or webFetch can be passed unchanged."
8316
8452
  )
8317
8453
  }),
@@ -8615,13 +8751,13 @@ function storedCanvasUrl(state, canvasId) {
8615
8751
  }
8616
8752
 
8617
8753
  // src/chat/slack/tools/canvas/create.ts
8618
- import { z as z24 } from "zod";
8754
+ import { z as z25 } from "zod";
8619
8755
  function createSlackCanvasCreateTool(context, state) {
8620
8756
  return zodTool({
8621
8757
  description: "Create a Slack canvas for long-form output in the active assistant context channel. Use when the answer is better as a reusable document than a thread reply: long-form research, timelines, bios/profiles, structured notes, plans, comparisons, or anything likely to exceed one compact Slack reply. After creating it, reply with one or two short sentences plus the canvas link; do not recap the canvas contents. Do not use for short answers that fit cleanly in one normal thread reply.",
8622
- inputSchema: z24.object({
8623
- title: z24.string().min(1).max(160).describe("Canvas title."),
8624
- markdown: z24.string().min(1).describe("Canvas markdown body content.")
8758
+ inputSchema: z25.object({
8759
+ title: z25.string().min(1).max(160).describe("Canvas title."),
8760
+ markdown: z25.string().min(1).describe("Canvas markdown body content.")
8625
8761
  }),
8626
8762
  outputSchema: juniorToolResultSchema,
8627
8763
  execute: async ({ title, markdown }) => {
@@ -8684,35 +8820,35 @@ function createSlackCanvasCreateTool(context, state) {
8684
8820
  }
8685
8821
 
8686
8822
  // src/chat/slack/tools/canvas/edit.ts
8687
- import { z as z25 } from "zod";
8823
+ import { z as z26 } from "zod";
8688
8824
  function prepareCanvasEditArguments(input) {
8689
8825
  return prepareTextReplacementArguments(input);
8690
8826
  }
8691
- var editReplacementSchema2 = z25.object({
8692
- oldText: z25.string().min(1).describe(
8827
+ var editReplacementSchema2 = z26.object({
8828
+ oldText: z26.string().min(1).describe(
8693
8829
  "Exact Canvas markdown to replace. It must be unique in the current Canvas body and must not overlap another edit."
8694
8830
  ),
8695
- newText: z25.string().describe("Replacement Canvas markdown for this edit.")
8831
+ newText: z26.string().describe("Replacement Canvas markdown for this edit.")
8696
8832
  });
8697
8833
  var slackCanvasEditOutputSchema = juniorToolResultSchema.extend({
8698
- canvas_id: z25.string().optional(),
8699
- title: z25.string().optional(),
8700
- permalink: z25.string().optional(),
8701
- diff: z25.string().optional(),
8702
- first_changed_line: z25.number().int().positive().optional(),
8703
- replacements: z25.number().int().nonnegative().optional(),
8704
- normalized_heading_count: z25.number().int().nonnegative().optional(),
8705
- summary: z25.string().optional(),
8706
- deduplicated: z25.boolean().optional()
8834
+ canvas_id: z26.string().optional(),
8835
+ title: z26.string().optional(),
8836
+ permalink: z26.string().optional(),
8837
+ diff: z26.string().optional(),
8838
+ first_changed_line: z26.number().int().positive().optional(),
8839
+ replacements: z26.number().int().nonnegative().optional(),
8840
+ normalized_heading_count: z26.number().int().nonnegative().optional(),
8841
+ summary: z26.string().optional(),
8842
+ deduplicated: z26.boolean().optional()
8707
8843
  }).strict();
8708
8844
  function createSlackCanvasEditTool(state) {
8709
8845
  return zodTool({
8710
8846
  description: "Edit one Slack canvas with exact markdown replacements. Use for precise changes to existing Canvas content; prefer this over slackCanvasWrite for targeted changes. Each oldText must match exactly, be unique, and not overlap another edit. Returns a diff. Multiple changes to the same canvas: use one edits[] call.",
8711
8847
  prepareArguments: prepareCanvasEditArguments,
8712
8848
  executionMode: "sequential",
8713
- inputSchema: z25.object({
8714
- canvas: z25.string().min(1).describe("Canvas/file ID (e.g. `F0ABCDEF`) or Slack canvas/docs URL."),
8715
- edits: z25.array(editReplacementSchema2).min(1).describe(
8849
+ inputSchema: z26.object({
8850
+ canvas: z26.string().min(1).describe("Canvas/file ID (e.g. `F0ABCDEF`) or Slack canvas/docs URL."),
8851
+ edits: z26.array(editReplacementSchema2).min(1).describe(
8716
8852
  "Exact replacements matched against the current Canvas body, not incrementally."
8717
8853
  )
8718
8854
  }),
@@ -8790,29 +8926,29 @@ function createSlackCanvasEditTool(state) {
8790
8926
  }
8791
8927
 
8792
8928
  // src/chat/slack/tools/canvas/read.ts
8793
- import { z as z26 } from "zod";
8929
+ import { z as z27 } from "zod";
8794
8930
  var slackCanvasReadOutputSchema = juniorToolResultSchema.extend({
8795
- canvas_id: z26.string().optional(),
8796
- title: z26.string().optional(),
8797
- permalink: z26.string().optional(),
8798
- mimetype: z26.string().optional(),
8799
- filetype: z26.string().optional(),
8800
- original_byte_length: z26.number().int().nonnegative().optional(),
8801
- content: z26.string().optional(),
8802
- start_line: z26.number().int().positive().optional(),
8803
- end_line: z26.number().int().nonnegative().optional(),
8804
- total_lines: z26.number().int().nonnegative().optional()
8931
+ canvas_id: z27.string().optional(),
8932
+ title: z27.string().optional(),
8933
+ permalink: z27.string().optional(),
8934
+ mimetype: z27.string().optional(),
8935
+ filetype: z27.string().optional(),
8936
+ original_byte_length: z27.number().int().nonnegative().optional(),
8937
+ content: z27.string().optional(),
8938
+ start_line: z27.number().int().positive().optional(),
8939
+ end_line: z27.number().int().nonnegative().optional(),
8940
+ total_lines: z27.number().int().nonnegative().optional()
8805
8941
  }).strict();
8806
8942
  function createSlackCanvasReadTool() {
8807
8943
  return zodTool({
8808
8944
  description: "Read a bounded line range from a Slack canvas as markdown. Use when you need exact Canvas contents to verify facts or make edits safely. Do not use for generic web pages \u2014 use webFetch for those.",
8809
8945
  annotations: { readOnlyHint: true, destructiveHint: false },
8810
- inputSchema: z26.object({
8811
- canvas: z26.string().min(1).describe(
8946
+ inputSchema: z27.object({
8947
+ canvas: z27.string().min(1).describe(
8812
8948
  "Canvas/file ID (e.g. `F0ABCDEF`) or Slack canvas/docs URL (e.g. `https://team.slack.com/docs/T.../F...`)."
8813
8949
  ),
8814
- offset: z26.coerce.number().int().min(1).describe("1-indexed line number to start reading from.").optional(),
8815
- limit: z26.coerce.number().int().min(1).describe("Maximum number of lines to read. Defaults to 1000.").optional()
8950
+ offset: z27.coerce.number().int().min(1).describe("1-indexed line number to start reading from.").optional(),
8951
+ limit: z27.coerce.number().int().min(1).describe("Maximum number of lines to read. Defaults to 1000.").optional()
8816
8952
  }),
8817
8953
  outputSchema: slackCanvasReadOutputSchema,
8818
8954
  execute: async ({ canvas, offset, limit }) => {
@@ -8869,14 +9005,14 @@ function createSlackCanvasReadTool() {
8869
9005
  }
8870
9006
 
8871
9007
  // src/chat/slack/tools/canvas/write.ts
8872
- import { z as z27 } from "zod";
9008
+ import { z as z28 } from "zod";
8873
9009
  function createSlackCanvasWriteTool(state) {
8874
9010
  return zodTool({
8875
9011
  description: "Write UTF-8 markdown content to a Slack canvas. Use for deliberate full-Canvas replacement after validation; use slackCanvasEdit for targeted changes to existing canvas content.",
8876
9012
  executionMode: "sequential",
8877
- inputSchema: z27.object({
8878
- canvas: z27.string().min(1).describe("Canvas/file ID (e.g. `F0ABCDEF`) or Slack canvas/docs URL."),
8879
- content: z27.string().describe("UTF-8 markdown content to write.")
9013
+ inputSchema: z28.object({
9014
+ canvas: z28.string().min(1).describe("Canvas/file ID (e.g. `F0ABCDEF`) or Slack canvas/docs URL."),
9015
+ content: z28.string().describe("UTF-8 markdown content to write.")
8880
9016
  }),
8881
9017
  outputSchema: juniorToolResultSchema,
8882
9018
  execute: async ({ canvas, content }) => {
@@ -9112,12 +9248,12 @@ async function updateListItem(input) {
9112
9248
  }
9113
9249
 
9114
9250
  // src/chat/slack/id-param.ts
9115
- import { z as z28 } from "zod";
9251
+ import { z as z29 } from "zod";
9116
9252
  function slackChannelIdParam(description) {
9117
- return z28.string().min(1).describe(description);
9253
+ return z29.string().min(1).describe(description);
9118
9254
  }
9119
9255
  function slackUserIdParam(description) {
9120
- return z28.string().min(1).describe(description);
9256
+ return z29.string().min(1).describe(description);
9121
9257
  }
9122
9258
  function parseRequiredSlackChannelIdParam(field, value) {
9123
9259
  const channelId = parseSlackChannelId(value);
@@ -9141,16 +9277,16 @@ function parseRequiredSlackUserIdParam(field, value) {
9141
9277
  }
9142
9278
 
9143
9279
  // src/chat/slack/tools/list/add-items.ts
9144
- import { z as z29 } from "zod";
9280
+ import { z as z30 } from "zod";
9145
9281
  function createSlackListAddItemsTool(state) {
9146
9282
  return zodTool({
9147
9283
  description: "Add tasks to the active Slack list tracked in artifact context. Use when the user wants actionable items recorded in the current thread list. Do not use when no list exists and list creation was not requested.",
9148
- inputSchema: z29.object({
9149
- items: z29.array(z29.string().min(1)).min(1).max(25).describe("List item titles to create."),
9284
+ inputSchema: z30.object({
9285
+ items: z30.array(z30.string().min(1)).min(1).max(25).describe("List item titles to create."),
9150
9286
  assignee_user_id: slackUserIdParam(
9151
9287
  "Optional Slack user ID assigned to all created items."
9152
9288
  ).optional(),
9153
- due_date: z29.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Optional due date in YYYY-MM-DD format.").optional()
9289
+ due_date: z30.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Optional due date in YYYY-MM-DD format.").optional()
9154
9290
  }),
9155
9291
  outputSchema: juniorToolResultSchema,
9156
9292
  execute: async ({ items, assignee_user_id, due_date }) => {
@@ -9204,12 +9340,12 @@ function createSlackListAddItemsTool(state) {
9204
9340
  }
9205
9341
 
9206
9342
  // src/chat/slack/tools/list/create.ts
9207
- import { z as z30 } from "zod";
9343
+ import { z as z31 } from "zod";
9208
9344
  function createSlackListCreateTool(state) {
9209
9345
  return zodTool({
9210
9346
  description: "Create a Slack todo list for action tracking. Use when the user needs structured tasks with ownership/completion tracking. Do not use for one-off notes without task management needs.",
9211
- inputSchema: z30.object({
9212
- name: z30.string().min(1).max(160).describe("Name for the new Slack list.")
9347
+ inputSchema: z31.object({
9348
+ name: z31.string().min(1).max(160).describe("Name for the new Slack list.")
9213
9349
  }),
9214
9350
  outputSchema: juniorToolResultSchema,
9215
9351
  execute: async ({ name }) => {
@@ -9241,13 +9377,13 @@ function createSlackListCreateTool(state) {
9241
9377
  }
9242
9378
 
9243
9379
  // src/chat/slack/tools/list/get-items.ts
9244
- import { z as z31 } from "zod";
9380
+ import { z as z32 } from "zod";
9245
9381
  function createSlackListGetItemsTool(state) {
9246
9382
  return zodTool({
9247
9383
  description: "Read items from the active Slack list tracked in artifact context. Use when the user asks for task status, open items, or list contents. Do not use when list state is already known from the immediately prior result.",
9248
9384
  annotations: { readOnlyHint: true, destructiveHint: false },
9249
- inputSchema: z31.object({
9250
- limit: z31.coerce.number().int().min(1).max(200).describe("Maximum number of list items to return.").optional()
9385
+ inputSchema: z32.object({
9386
+ limit: z32.coerce.number().int().min(1).max(200).describe("Maximum number of list items to return.").optional()
9251
9387
  }),
9252
9388
  outputSchema: juniorToolResultSchema,
9253
9389
  execute: async ({ limit }) => {
@@ -9272,21 +9408,21 @@ function createSlackListGetItemsTool(state) {
9272
9408
  }
9273
9409
 
9274
9410
  // src/chat/slack/tools/list/update-item.ts
9275
- import { z as z32 } from "zod";
9276
- var booleanInput3 = (description) => z32.preprocess(
9411
+ import { z as z33 } from "zod";
9412
+ var booleanInput3 = (description) => z33.preprocess(
9277
9413
  (value) => value === "true" ? true : value === "false" ? false : value,
9278
- z32.boolean()
9414
+ z33.boolean()
9279
9415
  ).describe(description);
9280
- var updateListItemInputSchema = z32.union([
9281
- z32.object({
9282
- item_id: z32.string().min(1).describe("ID of the Slack list item to update."),
9416
+ var updateListItemInputSchema = z33.union([
9417
+ z33.object({
9418
+ item_id: z33.string().min(1).describe("ID of the Slack list item to update."),
9283
9419
  completed: booleanInput3("Optional completion status update."),
9284
- title: z32.string().min(1).describe("Optional new item title.").optional()
9420
+ title: z33.string().min(1).describe("Optional new item title.").optional()
9285
9421
  }),
9286
- z32.object({
9287
- item_id: z32.string().min(1).describe("ID of the Slack list item to update."),
9422
+ z33.object({
9423
+ item_id: z33.string().min(1).describe("ID of the Slack list item to update."),
9288
9424
  completed: booleanInput3("Optional completion status update.").optional(),
9289
- title: z32.string().min(1).describe("Optional new item title.")
9425
+ title: z33.string().min(1).describe("Optional new item title.")
9290
9426
  })
9291
9427
  ]);
9292
9428
  function createSlackListUpdateItemTool(state) {
@@ -9362,7 +9498,7 @@ async function checkSlackChannelReadAccess(args) {
9362
9498
  }
9363
9499
 
9364
9500
  // src/chat/slack/tools/thread-read.ts
9365
- import { z as z33 } from "zod";
9501
+ import { z as z34 } from "zod";
9366
9502
 
9367
9503
  // src/chat/slack/tools/slack-message-url.ts
9368
9504
  var SLACK_HOST_PATTERN = /^[a-z0-9-]+\.slack(?:-gov)?\.com$/;
@@ -9535,8 +9671,8 @@ function createSlackThreadReadTool(context, deps = {}) {
9535
9671
  return zodTool({
9536
9672
  description: "Read a Slack thread from a shared Slack message archive URL or explicit channel + timestamp. Use when the user shares a Slack message link (https://*.slack.com/archives/...) and you need the referenced message and its thread context. Only the current conversation and public channels Junior has seen in this workspace are readable.",
9537
9673
  annotations: { readOnlyHint: true, destructiveHint: false },
9538
- inputSchema: z33.object({
9539
- url: z33.string().min(1).describe(
9674
+ inputSchema: z34.object({
9675
+ url: z34.string().min(1).describe(
9540
9676
  "Slack message archive URL, e.g. https://workspace.slack.com/archives/C123/p1700000000123456"
9541
9677
  ).optional(),
9542
9678
  channel_id: slackChannelIdParam(
@@ -9545,8 +9681,8 @@ function createSlackThreadReadTool(context, deps = {}) {
9545
9681
  ts: slackTimestampParam(
9546
9682
  "Slack message timestamp (e.g. 1700000000.123456). May be the thread root or any message in the thread."
9547
9683
  ).optional(),
9548
- limit: z33.coerce.number().int().min(1).max(1e3).describe("Maximum number of thread messages to fetch.").optional(),
9549
- max_pages: z33.coerce.number().int().min(1).max(10).describe("Maximum number of Slack API pages to traverse.").optional()
9684
+ limit: z34.coerce.number().int().min(1).max(1e3).describe("Maximum number of thread messages to fetch.").optional(),
9685
+ max_pages: z34.coerce.number().int().min(1).max(10).describe("Maximum number of Slack API pages to traverse.").optional()
9550
9686
  }),
9551
9687
  outputSchema: juniorToolResultSchema,
9552
9688
  execute: async ({ url, channel_id, ts, limit, max_pages }) => {
@@ -9802,29 +9938,29 @@ async function searchSlackUsers(options) {
9802
9938
  }
9803
9939
 
9804
9940
  // src/chat/slack/tools/user-lookup.ts
9805
- import { z as z34 } from "zod";
9806
- var booleanInput4 = (description) => z34.preprocess(
9941
+ import { z as z35 } from "zod";
9942
+ var booleanInput4 = (description) => z35.preprocess(
9807
9943
  (value) => value === "true" ? true : value === "false" ? false : value,
9808
- z34.boolean()
9944
+ z35.boolean()
9809
9945
  ).describe(description);
9810
9946
  function createSlackUserLookupTool() {
9811
9947
  return zodTool({
9812
9948
  description: "Look up Slack user profiles by user ID, email, or name search. Use when you need to identify a user, resolve cross-platform identity, or look up profile details like title or status. Returns profile fields including custom fields. For user ID lookup, pass a Slack user ID (e.g. U039RR91S). For search, pass a name query.",
9813
9949
  annotations: { readOnlyHint: true, destructiveHint: false },
9814
- inputSchema: z34.object({
9950
+ inputSchema: z35.object({
9815
9951
  user_id: slackUserIdParam(
9816
9952
  "Slack user ID to look up (e.g. U039RR91S). Mutually exclusive with email and query."
9817
9953
  ).optional(),
9818
- email: z34.string().min(3).describe(
9954
+ email: z35.string().min(3).describe(
9819
9955
  "Email address to look up. Mutually exclusive with user_id and query."
9820
9956
  ).optional(),
9821
- query: z34.string().min(2).describe(
9957
+ query: z35.string().min(2).describe(
9822
9958
  "Name to search for (matches against username, display name, real name). Mutually exclusive with user_id and email."
9823
9959
  ).optional(),
9824
- limit: z34.coerce.number().int().min(1).max(20).describe(
9960
+ limit: z35.coerce.number().int().min(1).max(20).describe(
9825
9961
  "Maximum number of results to return for name search. Defaults to 10."
9826
9962
  ).optional(),
9827
- max_pages: z34.coerce.number().int().min(1).max(5).describe(
9963
+ max_pages: z35.coerce.number().int().min(1).max(5).describe(
9828
9964
  "Maximum number of Slack API pages to scan for name search. Defaults to 3."
9829
9965
  ).optional(),
9830
9966
  include_bots: booleanInput4(
@@ -9928,18 +10064,18 @@ function createSlackUserLookupTool() {
9928
10064
  }
9929
10065
 
9930
10066
  // src/chat/tools/system-time.ts
9931
- import { z as z35 } from "zod";
10067
+ import { z as z36 } from "zod";
9932
10068
  var systemTimeOutputSchema = juniorToolResultSchema.extend({
9933
- unix_ms: z35.number(),
9934
- iso_utc: z35.string(),
9935
- iso_local: z35.string(),
9936
- timezone_offset_minutes: z35.number()
10069
+ unix_ms: z36.number(),
10070
+ iso_utc: z36.string(),
10071
+ iso_local: z36.string(),
10072
+ timezone_offset_minutes: z36.number()
9937
10073
  });
9938
10074
  function createSystemTimeTool() {
9939
10075
  return zodTool({
9940
10076
  description: "Return current system time in UTC and local ISO formats. Use when the user asks for current time/date context. Do not use as a substitute for historical or timezone-conversion research.",
9941
10077
  annotations: { readOnlyHint: true, destructiveHint: false },
9942
- inputSchema: z35.object({}),
10078
+ inputSchema: z36.object({}),
9943
10079
  outputSchema: systemTimeOutputSchema,
9944
10080
  privateTraceResult: (result) => ({
9945
10081
  ok: result.ok,
@@ -9968,32 +10104,32 @@ function createSystemTimeTool() {
9968
10104
  }
9969
10105
 
9970
10106
  // src/chat/tools/query-conversation-events.ts
9971
- import { z as z36 } from "zod";
10107
+ import { z as z37 } from "zod";
9972
10108
  var DEFAULT_LIMIT3 = 25;
9973
10109
  var MAX_LIMIT = 100;
9974
10110
  var CONVERSATION_EVENTS_TOOL_SOURCE = {
9975
10111
  id: "conversation-events",
9976
10112
  description: "Inspect Junior's durable conversation event log for debugging runtime behavior."
9977
10113
  };
9978
- var knownEventTypeSchema = z36.enum(KNOWN_CONVERSATION_EVENT_TYPES);
9979
- var projectedEventSchema = z36.object({
9980
- seq: z36.number().int().nonnegative().describe("Stable event position; use it for pagination bounds."),
9981
- history_version: z36.number().int().nonnegative().describe(
10114
+ var knownEventTypeSchema = z37.enum(KNOWN_CONVERSATION_EVENT_TYPES);
10115
+ var projectedEventSchema = z37.object({
10116
+ seq: z37.number().int().nonnegative().describe("Stable event position; use it for pagination bounds."),
10117
+ history_version: z37.number().int().nonnegative().describe(
9982
10118
  "Model-history generation. It increments when handoff or compaction replaces active model context."
9983
10119
  ),
9984
- created_at: z36.iso.datetime().describe("When the event was recorded."),
9985
- idempotency_key: z36.string().min(1).optional().describe("Retry-stable event identity, when one was assigned."),
9986
- data: z36.record(z36.string(), z36.unknown()).describe(
10120
+ created_at: z37.iso.datetime().describe("When the event was recorded."),
10121
+ idempotency_key: z37.string().min(1).optional().describe("Retry-stable event identity, when one was assigned."),
10122
+ data: z37.record(z37.string(), z37.unknown()).describe(
9987
10123
  "Event payload. The type field identifies the event; replacement-history events report replacement_history_count instead of replaying the full model context."
9988
10124
  )
9989
10125
  }).strict();
9990
10126
  var queryConversationEventsOutputSchema = juniorToolResultSchema.extend({
9991
- conversation_id: z36.string().min(1),
9992
- events: z36.array(projectedEventSchema),
9993
- has_older: z36.boolean().describe(
10127
+ conversation_id: z37.string().min(1),
10128
+ events: z37.array(projectedEventSchema),
10129
+ has_older: z37.boolean().describe(
9994
10130
  "Whether matching events exist before this page; request them with before_seq set to the first returned seq."
9995
10131
  ),
9996
- has_newer: z36.boolean().describe(
10132
+ has_newer: z37.boolean().describe(
9997
10133
  "Whether matching events exist after this page; request them with after_seq set to the last returned seq."
9998
10134
  )
9999
10135
  });
@@ -10003,20 +10139,20 @@ function createQueryConversationEventsTool(context) {
10003
10139
  exposure: "deferred",
10004
10140
  source: CONVERSATION_EVENTS_TOOL_SOURCE,
10005
10141
  annotations: { readOnlyHint: true, destructiveHint: false },
10006
- inputSchema: z36.object({
10007
- conversation_id: z36.string().trim().min(1).describe(
10142
+ inputSchema: z37.object({
10143
+ conversation_id: z37.string().trim().min(1).describe(
10008
10144
  "Conversation ID to inspect, such as slack:{channelId}:{threadTs} or a child conversation id."
10009
10145
  ),
10010
- after_seq: z36.number().int().nonnegative().nullable().describe(
10146
+ after_seq: z37.number().int().nonnegative().nullable().describe(
10011
10147
  "Exclusive lower bound on event seq. When set, returns the next newer page in ascending order."
10012
10148
  ).optional(),
10013
- before_seq: z36.number().int().nonnegative().nullable().describe(
10149
+ before_seq: z37.number().int().nonnegative().nullable().describe(
10014
10150
  "Exclusive upper bound on event seq. Combine with defaults or after_seq to page older or bounded ranges."
10015
10151
  ).optional(),
10016
- limit: z36.number().int().min(1).max(MAX_LIMIT).nullable().describe(
10152
+ limit: z37.number().int().min(1).max(MAX_LIMIT).nullable().describe(
10017
10153
  `Maximum events to return. Defaults to ${DEFAULT_LIMIT3}; max ${MAX_LIMIT}.`
10018
10154
  ).optional(),
10019
- types: z36.array(knownEventTypeSchema).min(1).nullable().describe(
10155
+ types: z37.array(knownEventTypeSchema).min(1).nullable().describe(
10020
10156
  "Optional event-type filter. Omit to return every durable event type."
10021
10157
  ).optional()
10022
10158
  }).strict(),
@@ -10206,10 +10342,10 @@ function stripReplacementHistoryField(value) {
10206
10342
  }
10207
10343
 
10208
10344
  // src/chat/tools/handoff/tool.ts
10209
- import { z as z37 } from "zod";
10345
+ import { z as z38 } from "zod";
10210
10346
  var HANDOFF_TOOL_NAME = "handoff";
10211
10347
  function createHandoffTool(handoff) {
10212
- const profileSchema = z37.enum(handoff.profiles);
10348
+ const profileSchema = z38.enum(handoff.profiles);
10213
10349
  const handoffResultSchema = juniorToolResultSchema.extend({
10214
10350
  model_profile: profileSchema
10215
10351
  });
@@ -10217,7 +10353,7 @@ function createHandoffTool(handoff) {
10217
10353
  return zodTool({
10218
10354
  description: `Switch to another execution profile and continue the same task. Profiles: ${profileNames}. Call this as the only tool.`,
10219
10355
  executionMode: "sequential",
10220
- inputSchema: z37.object({
10356
+ inputSchema: z38.object({
10221
10357
  profile: profileSchema.describe("Target execution profile")
10222
10358
  }).strict(),
10223
10359
  outputSchema: handoffResultSchema,
@@ -10240,7 +10376,7 @@ function createHandoffTool(handoff) {
10240
10376
  }
10241
10377
 
10242
10378
  // src/chat/tools/web/fetch-tool.ts
10243
- import { z as z38 } from "zod";
10379
+ import { z as z39 } from "zod";
10244
10380
 
10245
10381
  // src/chat/tools/web/constants.ts
10246
10382
  var USER_AGENT = "junior-bot/0.1";
@@ -10368,7 +10504,7 @@ async function fetchWithPinnedLookup(url, resolved, signal) {
10368
10504
  }
10369
10505
  const client = url.protocol === "https:" ? https : http;
10370
10506
  const lookup = createPinnedLookup(resolved);
10371
- return new Promise((resolve, reject) => {
10507
+ return new Promise((resolve2, reject) => {
10372
10508
  const request = client.request(
10373
10509
  {
10374
10510
  protocol: url.protocol,
@@ -10398,7 +10534,7 @@ async function fetchWithPinnedLookup(url, resolved, signal) {
10398
10534
  }
10399
10535
  const rawStatus = response.statusCode ?? 500;
10400
10536
  const status = rawStatus >= 200 && rawStatus <= 599 ? rawStatus : 502;
10401
- resolve(
10537
+ resolve2(
10402
10538
  new Response(Buffer.concat(chunks), {
10403
10539
  status,
10404
10540
  headers
@@ -10690,9 +10826,9 @@ function createWebFetchTool(hooks, options = {}) {
10690
10826
  destructiveHint: false,
10691
10827
  openWorldHint: true
10692
10828
  },
10693
- inputSchema: z38.object({
10694
- url: z38.string().min(1).describe("HTTP(S) URL to fetch."),
10695
- max_chars: z38.coerce.number().int().min(500).max(MAX_FETCH_CHARS).describe("Optional maximum number of extracted characters to return.").optional()
10829
+ inputSchema: z39.object({
10830
+ url: z39.string().min(1).describe("HTTP(S) URL to fetch."),
10831
+ max_chars: z39.coerce.number().int().min(500).max(MAX_FETCH_CHARS).describe("Optional maximum number of extracted characters to return.").optional()
10696
10832
  }),
10697
10833
  outputSchema: juniorToolResultSchema,
10698
10834
  execute: async ({ url, max_chars }) => {
@@ -10753,7 +10889,7 @@ function createWebFetchTool(hooks, options = {}) {
10753
10889
  }
10754
10890
 
10755
10891
  // src/chat/tools/web/search.ts
10756
- import { z as z39 } from "zod";
10892
+ import { z as z40 } from "zod";
10757
10893
  import { generateText } from "ai";
10758
10894
  import { createGatewayProvider } from "@ai-sdk/gateway";
10759
10895
  var SEARCH_TIMEOUT_MS = 6e4;
@@ -10802,9 +10938,9 @@ function createWebSearchTool(modelId, override) {
10802
10938
  destructiveHint: false,
10803
10939
  openWorldHint: true
10804
10940
  },
10805
- inputSchema: z39.object({
10806
- query: z39.string().min(1).max(500).describe("Search query."),
10807
- max_results: z39.coerce.number().int().min(1).max(MAX_RESULTS2).describe("Max results to return.").optional()
10941
+ inputSchema: z40.object({
10942
+ query: z40.string().min(1).max(500).describe("Search query."),
10943
+ max_results: z40.coerce.number().int().min(1).max(MAX_RESULTS2).describe("Max results to return.").optional()
10808
10944
  }),
10809
10945
  outputSchema: juniorToolResultSchema,
10810
10946
  execute: async ({ query, max_results }) => {
@@ -10873,14 +11009,14 @@ function createWebSearchTool(modelId, override) {
10873
11009
  }
10874
11010
 
10875
11011
  // src/chat/tools/sandbox/write-file.ts
10876
- import { z as z40 } from "zod";
11012
+ import { z as z41 } from "zod";
10877
11013
  function createWriteFileTool() {
10878
11014
  return zodTool({
10879
11015
  description: "Write UTF-8 content to a file in the sandbox workspace. Use for intentional file creation or deliberate full-file replacement after validation; use editFile instead for targeted changes to existing files. Do not use for exploratory analysis-only turns.",
10880
11016
  executionMode: "sequential",
10881
- inputSchema: z40.object({
10882
- path: z40.string().min(1).describe("Path to write in the sandbox workspace."),
10883
- content: z40.string().describe("UTF-8 file content to write.")
11017
+ inputSchema: z41.object({
11018
+ path: z41.string().min(1).describe("Path to write in the sandbox workspace."),
11019
+ content: z41.string().describe("UTF-8 file content to write.")
10884
11020
  }),
10885
11021
  outputSchema: juniorToolResultSchema,
10886
11022
  execute: async () => {
@@ -10952,6 +11088,13 @@ function createTools(availableSkills, hooks = {}, context) {
10952
11088
  if (context.conversationId) {
10953
11089
  tools.queryConversationEvents = createQueryConversationEventsTool(context);
10954
11090
  }
11091
+ if (context.supportsImageInput) {
11092
+ tools.viewImage = createViewImageTool(
11093
+ context.workspace,
11094
+ context.supportsImageInput,
11095
+ hooks.toolOverrides?.viewImage
11096
+ );
11097
+ }
10955
11098
  if (hooks.writeGeneratedArtifacts) {
10956
11099
  tools.imageGenerate = createImageGenerateTool(
10957
11100
  {
@@ -11546,6 +11689,8 @@ function isPluginToolInputError(error) {
11546
11689
  }
11547
11690
  function getToolErrorType(error) {
11548
11691
  if (error instanceof McpToolError) return "tool_error";
11692
+ if (error instanceof McpProviderError) return "mcp_provider_error";
11693
+ if (error instanceof OAuthProviderError) return "oauth_provider_error";
11549
11694
  if (error instanceof ToolInputError || isPluginToolInputError(error)) {
11550
11695
  return "tool_input_error";
11551
11696
  }
@@ -11568,6 +11713,8 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
11568
11713
  const errorMessage = getMcpAwareTelemetryMessage(error, conversationPrivacy);
11569
11714
  const errorAttributes = {
11570
11715
  "error.type": errorType,
11716
+ ...getMcpProviderErrorAttributes(error),
11717
+ ...getOAuthProviderErrorAttributes(error),
11571
11718
  ...error instanceof PluginCredentialFailureError ? { "app.credential.provider": error.provider } : {}
11572
11719
  };
11573
11720
  if (setExecutionSpanAttributes) {
@@ -11600,7 +11747,7 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
11600
11747
  "gen_ai.operation.name": "execute_tool",
11601
11748
  "gen_ai.tool.name": toolName,
11602
11749
  ...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
11603
- "error.type": errorType,
11750
+ ...errorAttributes,
11604
11751
  "exception.message": errorMessage
11605
11752
  },
11606
11753
  "Agent tool call failed"
@@ -11616,6 +11763,7 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
11616
11763
  "gen_ai.operation.name": "execute_tool",
11617
11764
  "gen_ai.tool.name": toolName,
11618
11765
  ...toolCallId ? { "gen_ai.tool.call.id": toolCallId } : {},
11766
+ ...errorAttributes,
11619
11767
  ...getToolErrorAttributes(error)
11620
11768
  },
11621
11769
  "Agent tool call failed"
@@ -11625,17 +11773,17 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
11625
11773
  }
11626
11774
 
11627
11775
  // src/chat/tools/execute-tool.ts
11628
- import { z as z41 } from "zod";
11776
+ import { z as z42 } from "zod";
11629
11777
  var EXECUTE_TOOL_NAME = "executeTool";
11630
11778
  function createExecuteToolTool() {
11631
11779
  return zodTool({
11632
11780
  description: "Execute any catalog tool by exact tool_name from searchTools or a tool-result execution hint. Put tool-specific parameters inside arguments.",
11633
11781
  executionMode: "sequential",
11634
- inputSchema: z41.object({
11635
- tool_name: z41.string().min(1).describe(
11782
+ inputSchema: z42.object({
11783
+ tool_name: z42.string().min(1).describe(
11636
11784
  "Exact catalog tool_name returned by searchTools or a tool-result execution hint."
11637
11785
  ),
11638
- arguments: z41.record(z41.string(), z41.unknown()).describe(
11786
+ arguments: z42.record(z42.string(), z42.unknown()).describe(
11639
11787
  'Arguments matching the selected catalog tool schema, for example { "query": "..." }.'
11640
11788
  ).optional()
11641
11789
  }).strict(),
@@ -11675,42 +11823,42 @@ function planToolExposure(tools) {
11675
11823
  }
11676
11824
 
11677
11825
  // src/chat/tools/search-tools.ts
11678
- import { z as z42 } from "zod";
11826
+ import { z as z43 } from "zod";
11679
11827
  var SEARCH_TOOLS_NAME = "searchTools";
11680
11828
  var DEFAULT_MAX_RESULTS2 = 5;
11681
11829
  var MAX_RESULTS3 = 20;
11682
11830
  var MODEL_VISIBLE_DESCRIPTION_CAP = 180;
11683
- var searchToolsSourceSchema = z42.object({
11684
- id: z42.string(),
11685
- description: z42.string()
11831
+ var searchToolsSourceSchema = z43.object({
11832
+ id: z43.string(),
11833
+ description: z43.string()
11686
11834
  }).strict();
11687
- var toolCallExampleSchema = z42.object({
11688
- tool_name: z42.string(),
11689
- arguments: z42.record(z42.string(), z42.string())
11835
+ var toolCallExampleSchema = z43.object({
11836
+ tool_name: z43.string(),
11837
+ arguments: z43.record(z43.string(), z43.string())
11690
11838
  }).strict();
11691
- var searchToolsToolSchema = z42.object({
11692
- tool_name: z42.string(),
11693
- description: z42.string(),
11694
- exposure: z42.enum(["direct", "deferred", "modelOnly", "hidden"]),
11695
- source: z42.string().optional(),
11696
- signature: z42.string(),
11839
+ var searchToolsToolSchema = z43.object({
11840
+ tool_name: z43.string(),
11841
+ description: z43.string(),
11842
+ exposure: z43.enum(["direct", "deferred", "modelOnly", "hidden"]),
11843
+ source: z43.string().optional(),
11844
+ signature: z43.string(),
11697
11845
  call: toolCallExampleSchema,
11698
- input_schema: z42.unknown(),
11699
- input_schema_summary: z42.string(),
11700
- call_notes: z42.array(z42.string()),
11701
- annotations: z42.record(z42.string(), z42.unknown())
11846
+ input_schema: z43.unknown(),
11847
+ input_schema_summary: z43.string(),
11848
+ call_notes: z43.array(z43.string()),
11849
+ annotations: z43.record(z43.string(), z43.unknown())
11702
11850
  }).strict();
11703
11851
  var searchToolsOutputSchema = juniorToolResultSchema.extend({
11704
- query: z42.string().nullable(),
11705
- source: z42.string().nullable(),
11706
- sources: z42.array(searchToolsSourceSchema),
11707
- total_catalog_tools: z42.number().int().nonnegative(),
11708
- total_eligible_tools: z42.number().int().nonnegative(),
11709
- total_matches: z42.number().int().nonnegative(),
11710
- returned_tools: z42.number().int().nonnegative(),
11711
- execution_tool: z42.literal("executeTool"),
11852
+ query: z43.string().nullable(),
11853
+ source: z43.string().nullable(),
11854
+ sources: z43.array(searchToolsSourceSchema),
11855
+ total_catalog_tools: z43.number().int().nonnegative(),
11856
+ total_eligible_tools: z43.number().int().nonnegative(),
11857
+ total_matches: z43.number().int().nonnegative(),
11858
+ returned_tools: z43.number().int().nonnegative(),
11859
+ execution_tool: z43.literal("executeTool"),
11712
11860
  execution_example: toolCallExampleSchema,
11713
- tools: z42.array(searchToolsToolSchema)
11861
+ tools: z43.array(searchToolsToolSchema)
11714
11862
  }).strict();
11715
11863
  function normalize2(value) {
11716
11864
  return value.toLowerCase().replace(/[^a-z0-9_]+/g, " ").trim();
@@ -11902,14 +12050,14 @@ function createSearchToolsTool(catalogTools) {
11902
12050
  return zodTool({
11903
12051
  description: renderSearchToolsDescription(knownSources),
11904
12052
  annotations: { readOnlyHint: true, destructiveHint: false },
11905
- inputSchema: z42.object({
11906
- query: z42.string().nullable().describe(
12053
+ inputSchema: z43.object({
12054
+ query: z43.string().nullable().describe(
11907
12055
  "Optional search terms describing the tool, owner, action, or arguments needed. Empty string lists catalog tools."
11908
12056
  ).optional(),
11909
- source: z42.string().nullable().describe(
12057
+ source: z43.string().nullable().describe(
11910
12058
  "Optional source id to search within, such as a plugin source returned in sources."
11911
12059
  ).optional(),
11912
- max_results: z42.number().int().min(1).max(MAX_RESULTS3).nullable().describe("Maximum matching catalog tool descriptors to return.").optional()
12060
+ max_results: z43.number().int().min(1).max(MAX_RESULTS3).nullable().describe("Maximum matching catalog tool descriptors to return.").optional()
11913
12061
  }).strict(),
11914
12062
  outputSchema: searchToolsOutputSchema,
11915
12063
  privateTraceResult: (result) => ({
@@ -13272,6 +13420,7 @@ async function wireAgentTools(args) {
13272
13420
  }),
13273
13421
  mcpToolManager,
13274
13422
  workspace: agentSandbox.workspace,
13423
+ supportsImageInput: args.supportsImageInput,
13275
13424
  surface: args.surface,
13276
13425
  ...args.requestHandoff ? { handoff: args.requestHandoff } : {}
13277
13426
  };
@@ -13430,7 +13579,11 @@ async function wireAgentTools(args) {
13430
13579
  "mcp_tool_manager_close_failed",
13431
13580
  {},
13432
13581
  {
13433
- "exception.message": closeError instanceof Error ? closeError.message : String(closeError)
13582
+ ...getMcpProviderErrorAttributes(closeError),
13583
+ "exception.message": getMcpAwareTelemetryMessage(
13584
+ closeError,
13585
+ args.conversationPrivacy
13586
+ )
13434
13587
  },
13435
13588
  "Failed to close MCP tool manager"
13436
13589
  );
@@ -13454,6 +13607,7 @@ function createResumeState(args) {
13454
13607
  let latestSafeBoundaryMessages = [];
13455
13608
  let timedOut = false;
13456
13609
  let resumeMessages = [];
13610
+ let turnContexts = [];
13457
13611
  let turnStartMessageIndex;
13458
13612
  const currentSliceId = args.sessionRecordState.currentSliceId;
13459
13613
  const currentDurationMs = () => Date.now() - args.startedAtMs;
@@ -13487,6 +13641,9 @@ function createResumeState(args) {
13487
13641
  setBeforeMessageCount(count) {
13488
13642
  beforeMessageCount = count;
13489
13643
  },
13644
+ setTurnContexts(contexts) {
13645
+ turnContexts = contexts;
13646
+ },
13490
13647
  /** Adopt an already committed epoch replacement as every resume baseline. */
13491
13648
  adoptCommittedBoundary(messages) {
13492
13649
  latestSafeBoundaryMessages = [...messages];
@@ -13514,6 +13671,7 @@ function createResumeState(args) {
13514
13671
  sliceId: currentSliceId,
13515
13672
  messages,
13516
13673
  ...trailingMessageProvenance ? { trailingMessageProvenance } : {},
13674
+ ...turnContexts.length > 0 ? { turnContexts } : {},
13517
13675
  ...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {}
13518
13676
  });
13519
13677
  if (!persisted) {
@@ -13780,6 +13938,27 @@ function renderSummaryInput(piMessages, conversationContext) {
13780
13938
  }
13781
13939
  async function summarizeContext(args, deps) {
13782
13940
  const source = renderSummaryInput(args.piMessages, args.conversationContext);
13941
+ const instructions = args.purpose === "active_turn" ? [
13942
+ "You are performing an ACTIVE-TURN CONTEXT CHECKPOINT COMPACTION for Junior.",
13943
+ "Create concise internal continuation state for the same agent run, which must continue the unfinished task immediately after this checkpoint.",
13944
+ "",
13945
+ "Include:",
13946
+ "- Work completed and concrete outcomes",
13947
+ "- Exact work currently in progress",
13948
+ "- The immediate next action",
13949
+ "- Durable constraints, user preferences, IDs, URLs, artifacts, sandbox references, auth state, and unresolved blockers",
13950
+ "",
13951
+ "Do not write a user-facing reply, announce a plan, or imply that the task is complete unless the source history proves it is complete."
13952
+ ] : [
13953
+ "You are performing a CONTEXT CHECKPOINT COMPACTION for Junior.",
13954
+ "Create a concise continuation summary for the agent that will continue this Slack thread.",
13955
+ "",
13956
+ "Include:",
13957
+ "- Current outstanding asks",
13958
+ "- Key decisions, completed work, and outcomes",
13959
+ "- Durable constraints, user preferences, IDs, URLs, artifacts, canvas links, sandbox references, and auth state",
13960
+ "- Clear next steps and unresolved blockers"
13961
+ ];
13783
13962
  const result = await deps.completeText({
13784
13963
  modelId: botConfig.fastModelId,
13785
13964
  messageAttributeMode: "metadata",
@@ -13789,14 +13968,7 @@ async function summarizeContext(args, deps) {
13789
13968
  {
13790
13969
  role: "user",
13791
13970
  content: [
13792
- "You are performing a CONTEXT CHECKPOINT COMPACTION for Junior.",
13793
- "Create a concise continuation summary for the agent that will continue this Slack thread.",
13794
- "",
13795
- "Include:",
13796
- "- Current outstanding asks",
13797
- "- Key decisions, completed work, and outcomes",
13798
- "- Durable constraints, user preferences, IDs, URLs, artifacts, canvas links, sandbox references, and auth state",
13799
- "- Clear next steps and unresolved blockers",
13971
+ ...instructions,
13800
13972
  "",
13801
13973
  "Do not invent details. Do not include raw secrets or credentials.",
13802
13974
  "",
@@ -14022,7 +14194,8 @@ async function compactActiveContextIfNeeded(args, deps) {
14022
14194
  summary = await summarizeContext(
14023
14195
  {
14024
14196
  ...args,
14025
- piMessages: args.piMessages
14197
+ piMessages: args.piMessages,
14198
+ purpose: "active_turn"
14026
14199
  },
14027
14200
  deps
14028
14201
  );
@@ -14052,22 +14225,15 @@ async function compactActiveContextIfNeeded(args, deps) {
14052
14225
  );
14053
14226
  return { compacted: false, reason: "summary_failed" };
14054
14227
  }
14055
- const summaryText = `${COMPACTION_SUMMARY_PREFIX}
14056
- ${summary}`;
14057
- const runtimeMessage = retainRuntimeTurnContext(args.piMessages).at(-1);
14058
- const summaryMessages = runtimeMessage ? [
14059
- {
14060
- ...runtimeMessage,
14061
- content: [
14062
- ...runtimeMessage.content,
14063
- { type: "text", text: summaryText }
14064
- ]
14065
- }
14066
- ] : [userMessage(summaryText)];
14228
+ const summaryMessage = userMessage(
14229
+ `${ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX}
14230
+ ${summary}`
14231
+ );
14232
+ const runtimeMessages = retainRuntimeTurnContext(args.piMessages);
14067
14233
  const retainedInstruction = pendingMessages.length === 0 ? await loadLastInstruction(args.conversationId) : void 0;
14068
14234
  const instructionMessages = retainedInstruction ? [retainedInstruction.message] : pendingMessages.map((entry) => entry.message);
14069
14235
  const instructionProvenance = retainedInstruction ? [retainedInstruction.provenance] : pendingMessages.map((entry) => entry.provenance);
14070
- const messages = [...summaryMessages, ...instructionMessages];
14236
+ const messages = [...runtimeMessages, ...instructionMessages, summaryMessage];
14071
14237
  const replacementInputTokens = estimateHistoryTokens(messages);
14072
14238
  if (replacementInputTokens >= inputLimitTokens) {
14073
14239
  throw new ContextInputLimitExceededError(
@@ -14100,10 +14266,11 @@ ${summary}`;
14100
14266
  },
14101
14267
  summary,
14102
14268
  replacementHistory: replacementMessages.map((message, index) => {
14103
- const provenance = index === 0 ? contextProvenance : instructionProvenance[index - 1];
14269
+ const isSummary = index === replacementMessages.length - 1;
14270
+ const provenance = isSummary ? contextProvenance : instructionProvenance[index];
14104
14271
  return {
14105
14272
  item: historyItemFromPiMessage(message, provenance),
14106
- ...index === 1 && retainedInstruction ? { sourceEventSeq: retainedInstruction.sourceEventSeq } : {}
14273
+ ...index === 0 && retainedInstruction ? { sourceEventSeq: retainedInstruction.sourceEventSeq } : {}
14107
14274
  };
14108
14275
  })
14109
14276
  }
@@ -14130,12 +14297,12 @@ var AssistantMessageDeliveryError = class extends Error {
14130
14297
  originalError;
14131
14298
  };
14132
14299
  function waitForAbortSettlement(promise, timeoutMs) {
14133
- return new Promise((resolve) => {
14300
+ return new Promise((resolve2) => {
14134
14301
  let done = false;
14135
14302
  const timeoutId = setTimeout(() => {
14136
14303
  if (!done) {
14137
14304
  done = true;
14138
- resolve(false);
14305
+ resolve2(false);
14139
14306
  }
14140
14307
  }, timeoutMs);
14141
14308
  timeoutId.unref?.();
@@ -14144,14 +14311,14 @@ function waitForAbortSettlement(promise, timeoutMs) {
14144
14311
  if (!done) {
14145
14312
  done = true;
14146
14313
  clearTimeout(timeoutId);
14147
- resolve(true);
14314
+ resolve2(true);
14148
14315
  }
14149
14316
  },
14150
14317
  () => {
14151
14318
  if (!done) {
14152
14319
  done = true;
14153
14320
  clearTimeout(timeoutId);
14154
- resolve(true);
14321
+ resolve2(true);
14155
14322
  }
14156
14323
  }
14157
14324
  );
@@ -14577,6 +14744,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
14577
14744
  skillSandbox,
14578
14745
  spanContext,
14579
14746
  state,
14747
+ supportsImageInput: () => resolveGatewayModel(activeModelId).input.includes("image"),
14580
14748
  surface,
14581
14749
  syncLoadedSkillNamesForResume,
14582
14750
  toolCalls,
@@ -14592,7 +14760,8 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
14592
14760
  inputMessagesAttribute,
14593
14761
  promptContentParts,
14594
14762
  promptHistoryMessages,
14595
- shouldPromptAgent
14763
+ shouldPromptAgent,
14764
+ turnContexts
14596
14765
  } = await assemblePrompt({
14597
14766
  activeMcpCatalogs: wiring.activeMcpCatalogs,
14598
14767
  currentActor: actor,
@@ -14611,6 +14780,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
14611
14780
  toolRuntimeContext: wiring.toolRuntimeContext,
14612
14781
  userContentParts
14613
14782
  });
14783
+ runResume.setTurnContexts(turnContexts);
14614
14784
  const applyPendingHandoff = () => {
14615
14785
  if (!pendingHandoff) {
14616
14786
  return void 0;