@sentry/junior 0.150.1 → 0.152.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 (77) hide show
  1. package/dist/{agent-hooks-G4LEACQB.js → agent-hooks-U66Q3X2P.js} +10 -10
  2. package/dist/api/schema/conversation.d.ts +35 -4
  3. package/dist/api/schema.d.ts +1 -1
  4. package/dist/api/schema.js +3 -1
  5. package/dist/api.js +81 -38
  6. package/dist/app.js +129 -206
  7. package/dist/{catalog-runtime-ZRSNE2MH.js → catalog-runtime-CVCR7SND.js} +5 -5
  8. package/dist/chat/agent/skills.d.ts +5 -4
  9. package/dist/chat/agent/tools.d.ts +5 -5
  10. package/dist/chat/api-turns/authorization.d.ts +23 -0
  11. package/dist/chat/conversations/history.d.ts +12 -3
  12. package/dist/chat/conversations/projection.d.ts +7 -3
  13. package/dist/chat/mcp/tool-manager.d.ts +0 -4
  14. package/dist/chat/runtime/agent-run-outcome.d.ts +4 -0
  15. package/dist/chat/tools/search-conversation-events.d.ts +1 -1
  16. package/dist/chat/tools/skill/call-mcp-tool.d.ts +0 -1
  17. package/dist/chat/tools/skill/load-skill.d.ts +2 -5
  18. package/dist/chat/tools/types.d.ts +1 -2
  19. package/dist/{chunk-2AWDPNP7.js → chunk-3PCKG4BT.js} +16 -10
  20. package/dist/{chunk-2Z7YX5PI.js → chunk-3UJ3QYRV.js} +156 -19
  21. package/dist/{chunk-IQW6RFXG.js → chunk-5LDOQV7Y.js} +72 -218
  22. package/dist/{chunk-JBYWR6FW.js → chunk-67VR4BJK.js} +5 -5
  23. package/dist/{chunk-5NOHC2Z4.js → chunk-732P2RBQ.js} +1 -1
  24. package/dist/{chunk-3WIFZBJL.js → chunk-7TZM33YX.js} +1 -1
  25. package/dist/{chunk-JVOLC6JZ.js → chunk-AYPU5T5L.js} +4 -4
  26. package/dist/{chunk-TZRYLW3R.js → chunk-CLX3T7Q3.js} +1 -1
  27. package/dist/{chunk-JUBPTYNO.js → chunk-ELAVLP7Z.js} +1 -1
  28. package/dist/{chunk-LSI3EKZQ.js → chunk-ETXLHT3S.js} +4 -4
  29. package/dist/{chunk-N6QJAPZS.js → chunk-I4LR7MS2.js} +45 -11
  30. package/dist/{chunk-6ZYGORV4.js → chunk-KC47ZY6Q.js} +2 -2
  31. package/dist/{chunk-6A24WEKX.js → chunk-KC5XZBRB.js} +4 -4
  32. package/dist/{chunk-D2PVJU5E.js → chunk-KTYC3GDO.js} +3 -3
  33. package/dist/{chunk-AD6N2KNE.js → chunk-KW2MGCW5.js} +5 -5
  34. package/dist/{chunk-QO3OSJDS.js → chunk-LETPYIDF.js} +1 -1
  35. package/dist/{chunk-6IWDFUXW.js → chunk-M6PWM3OK.js} +1 -1
  36. package/dist/{chunk-LWFHRWJI.js → chunk-N2472SQK.js} +8 -8
  37. package/dist/{chunk-QNSV46AW.js → chunk-NF733C66.js} +6 -6
  38. package/dist/{chunk-FGP5W3NS.js → chunk-OEECXAGT.js} +2 -2
  39. package/dist/{chunk-SZ74ECCC.js → chunk-QKPIW2CY.js} +6 -6
  40. package/dist/{chunk-4JV7GUUH.js → chunk-RCBAXKMB.js} +1 -1
  41. package/dist/{chunk-QZGYKKH6.js → chunk-SDMVFTH4.js} +173 -70
  42. package/dist/chunk-SFYDSI34.js +89 -0
  43. package/dist/{chunk-W3FQZAX5.js → chunk-TSQMITMQ.js} +6 -6
  44. package/dist/{chunk-IZE2EGCX.js → chunk-UFKSILED.js} +5 -5
  45. package/dist/{chunk-3JVUWLR7.js → chunk-UG5UCHHJ.js} +15 -1
  46. package/dist/{chunk-OWLJZ6I7.js → chunk-VD6CRYCT.js} +1 -1
  47. package/dist/{chunk-2DIRU2C2.js → chunk-WZN4RQ64.js} +1 -1
  48. package/dist/{chunk-KFHJQYKQ.js → chunk-X4RM4TBW.js} +1 -1
  49. package/dist/{chunk-B2YA2G26.js → chunk-X6JP6AMX.js} +1 -1
  50. package/dist/{chunk-GZ25ZSTX.js → chunk-XTLF7C4I.js} +11 -4
  51. package/dist/{chunk-R53UTQ2Q.js → chunk-Z5WLTGME.js} +1 -1
  52. package/dist/cli/chat.js +30 -30
  53. package/dist/cli/check.js +6 -6
  54. package/dist/cli/plugins.js +13 -13
  55. package/dist/cli/snapshot-create.js +9 -9
  56. package/dist/cli/upgrade.js +7 -7
  57. package/dist/{db-WRA5ZHYE.js → db-HQAZQASY.js} +7 -7
  58. package/dist/handlers/mcp-oauth-callback.d.ts +3 -0
  59. package/dist/handlers/oauth-callback.d.ts +3 -0
  60. package/dist/instrumentation.js +4 -4
  61. package/dist/nitro.js +2 -2
  62. package/dist/{oauth-callback-server-QWAYG3MI.js → oauth-callback-server-OJONZ7T3.js} +23 -24
  63. package/dist/{runner-5JQ54J6P.js → runner-BIJAVQDX.js} +14 -16
  64. package/dist/{skills-3YD55WPO.js → skills-SIPNY4AT.js} +6 -6
  65. package/dist/spawn-ABDIBQT6.js +38 -0
  66. package/dist/{validation-ZXE3IRSB.js → validation-KRPOY5RQ.js} +6 -6
  67. package/dist/version.js +1 -1
  68. package/dist/{work-7G2U64WI.js → work-KS3JOEI2.js} +17 -17
  69. package/dist/{worker-HJM2FZNI.js → worker-CZ5KNZUI.js} +11 -11
  70. package/migrations/0025_mcp_credential_subject.sql +8 -0
  71. package/migrations/meta/0025_snapshot.json +2275 -0
  72. package/migrations/meta/_journal.json +7 -0
  73. package/package.json +5 -5
  74. package/dist/chat/pi/derived-state.d.ts +0 -5
  75. package/dist/chunk-4CODA7P5.js +0 -43
  76. package/dist/chunk-XED3H34M.js +0 -48
  77. package/dist/spawn-OOO26XDL.js +0 -38
@@ -0,0 +1,23 @@
1
+ import type { OAuthAuthorizationRequest } from "@/chat/oauth-authorization";
2
+ export interface WebAuthorizationState extends OAuthAuthorizationRequest {
3
+ actorId: string;
4
+ conversationId: string;
5
+ }
6
+ /** Build authorization delivery for one web turn. */
7
+ export declare function createWebAuthorization(args: {
8
+ actorId: string;
9
+ conversationId: string;
10
+ }): {
11
+ createState: () => Promise<`${string}-${string}-${string}-${string}-${string}`>;
12
+ deliver: (request: OAuthAuthorizationRequest) => Promise<void>;
13
+ };
14
+ /** Read the pending authorization request for one web actor. */
15
+ export declare function getWebAuthorization(args: {
16
+ actorId: string;
17
+ conversationId: string;
18
+ }): Promise<WebAuthorizationState | undefined>;
19
+ /** Remove a web authorization request after the parked turn continues. */
20
+ export declare function deleteWebAuthorization(args: {
21
+ actorId: string;
22
+ conversationId: string;
23
+ }): Promise<void>;
@@ -230,6 +230,7 @@ export declare const conversationEventDataSchema: z.ZodUnion<readonly [z.ZodUnio
230
230
  }, z.core.$loose>], "type">, z.ZodObject<{
231
231
  type: z.ZodLiteral<"mcp_provider_connected">;
232
232
  provider: z.ZodString;
233
+ credentialSubjectId: z.ZodString;
233
234
  }, z.core.$strict>, z.ZodObject<{
234
235
  type: z.ZodLiteral<"authorization_requested">;
235
236
  kind: z.ZodUnion<readonly [z.ZodLiteral<"plugin">, z.ZodLiteral<"mcp">]>;
@@ -455,11 +456,14 @@ export declare const conversationEventDataSchema: z.ZodUnion<readonly [z.ZodUnio
455
456
  }, z.core.$loose>], "type">;
456
457
  sourceEventSeq: z.ZodOptional<z.ZodNumber>;
457
458
  }, z.core.$strict>>;
458
- }, z.core.$strict>], "type">]>;
459
+ }, z.core.$strict>], "type">, z.ZodObject<{
460
+ type: z.ZodLiteral<"mcp_provider_connected_unowned">;
461
+ provider: z.ZodString;
462
+ }, z.core.$strict>]>;
459
463
  /** One durable conversation event's validated data. */
460
464
  export type ConversationEventData = z.output<typeof conversationEventDataSchema>;
461
465
  /** Event type names recognized by current readers and observational queries. */
462
- export declare const KNOWN_CONVERSATION_EVENT_TYPES: readonly ["message", "message_updated", "user_message", "assistant_message", "tool_result", "mcp_provider_connected", "authorization_requested", "authorization_completed", "tool_execution_started", "guardian_action_reviewed", "message_handled", "messages_summarized", "turn_started", "turn_context", "structured_event", "turn_routed", "turn_completed", "turn_failed", "subagent_started", "subagent_ended", "handoff", "compaction"];
466
+ export declare const KNOWN_CONVERSATION_EVENT_TYPES: readonly ["message", "message_updated", "user_message", "assistant_message", "tool_result", "mcp_provider_connected", "mcp_provider_connected_unowned", "authorization_requested", "authorization_completed", "tool_execution_started", "guardian_action_reviewed", "message_handled", "messages_summarized", "turn_started", "turn_context", "structured_event", "turn_routed", "turn_completed", "turn_failed", "subagent_started", "subagent_ended", "handoff", "compaction"];
463
467
  /** One known durable conversation event type name. */
464
468
  export type KnownConversationEventType = (typeof KNOWN_CONVERSATION_EVENT_TYPES)[number];
465
469
  declare const unknownConversationEventDataSchema: z.ZodObject<{
@@ -531,6 +535,7 @@ export declare const conversationEventSchema: z.ZodUnion<readonly [z.ZodObject<{
531
535
  }, z.core.$loose>], "type">, z.ZodObject<{
532
536
  type: z.ZodLiteral<"mcp_provider_connected">;
533
537
  provider: z.ZodString;
538
+ credentialSubjectId: z.ZodString;
534
539
  }, z.core.$strict>, z.ZodObject<{
535
540
  type: z.ZodLiteral<"authorization_requested">;
536
541
  kind: z.ZodUnion<readonly [z.ZodLiteral<"plugin">, z.ZodLiteral<"mcp">]>;
@@ -756,7 +761,10 @@ export declare const conversationEventSchema: z.ZodUnion<readonly [z.ZodObject<{
756
761
  }, z.core.$loose>], "type">;
757
762
  sourceEventSeq: z.ZodOptional<z.ZodNumber>;
758
763
  }, z.core.$strict>>;
759
- }, z.core.$strict>], "type">]>;
764
+ }, z.core.$strict>], "type">, z.ZodObject<{
765
+ type: z.ZodLiteral<"mcp_provider_connected_unowned">;
766
+ provider: z.ZodString;
767
+ }, z.core.$strict>]>;
760
768
  }, z.core.$strict>, z.ZodObject<{
761
769
  schemaVersion: z.ZodNumber;
762
770
  seq: z.ZodNumber;
@@ -855,6 +863,7 @@ export declare const newConversationEventSchema: z.ZodObject<{
855
863
  }, z.core.$loose>], "type">, z.ZodObject<{
856
864
  type: z.ZodLiteral<"mcp_provider_connected">;
857
865
  provider: z.ZodString;
866
+ credentialSubjectId: z.ZodString;
858
867
  }, z.core.$strict>, z.ZodObject<{
859
868
  type: z.ZodLiteral<"authorization_requested">;
860
869
  kind: z.ZodUnion<readonly [z.ZodLiteral<"plugin">, z.ZodLiteral<"mcp">]>;
@@ -39,8 +39,11 @@ export declare function loadTurnProjection(args: {
39
39
  committedSeq: number;
40
40
  includeTail: boolean;
41
41
  }): Promise<PiConversationEventProjection | undefined>;
42
- /** Load MCP providers connected in the current agent-history version. */
43
- export declare function loadConnectedMcpProviders(args: ScopedConversation): Promise<string[]>;
42
+ /** Load MCP providers the credential subject connected in this conversation. */
43
+ export declare function loadConnectedMcpProviders(args: {
44
+ conversationId: string;
45
+ credentialSubjectId: string;
46
+ }): Promise<string[]>;
44
47
  /**
45
48
  * Append newly stable native history items.
46
49
  *
@@ -90,10 +93,11 @@ export declare function commitAcceptedReply(args: {
90
93
  providerConversationBindings?: Array<Omit<ProviderConversationBinding, "conversationId">>;
91
94
  repliedAtMs?: number;
92
95
  }): Promise<void>;
93
- /** Record a successful MCP provider connection without duplicating the fact. */
96
+ /** Record a successful MCP provider connection for one credential subject without duplicating it. */
94
97
  export declare function recordMcpProviderConnected(args: {
95
98
  conversationId: string;
96
99
  provider: string;
100
+ credentialSubjectId: string;
97
101
  }): Promise<void>;
98
102
  /** Record that an OAuth/MCP authorization link was delivered or reused. */
99
103
  export declare function recordAuthorizationRequested(args: {
@@ -10,7 +10,6 @@ import type { ImageContent, TextContent } from "@earendil-works/pi-ai";
10
10
  import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
11
11
  import { type PluginMcpToolResult, type ToolAnnotations } from "@sentry/junior-plugin-api";
12
12
  import type { ConversationPrivacy } from "@/chat/conversation-privacy";
13
- import type { SkillMetadata } from "@/chat/skills";
14
13
  import type { PluginDefinition } from "@/chat/plugins/types";
15
14
  import { McpAuthorizationRequiredError } from "./client";
16
15
  export interface McpToolSuccessHookInput {
@@ -50,7 +49,6 @@ export interface ManagedMcpToolDescriptor {
50
49
  annotations?: ToolAnnotations;
51
50
  provider: string;
52
51
  }
53
- type ActiveMcpSkill = Pick<SkillMetadata, "name" | "pluginProvider">;
54
52
  export interface ManagedMcpTool extends ManagedMcpToolDescriptor {
55
53
  execute: (args: Record<string, unknown>, options?: {
56
54
  conversationPrivacy?: ConversationPrivacy;
@@ -73,7 +71,6 @@ export declare class McpToolManager {
73
71
  description: string;
74
72
  active: boolean;
75
73
  }>;
76
- activateForSkill(skill: ActiveMcpSkill): Promise<boolean>;
77
74
  activateProvider(provider: string): Promise<boolean>;
78
75
  close(): Promise<void>;
79
76
  /** Return descriptors for all active MCP provider tools, optionally filtered by provider. */
@@ -96,4 +93,3 @@ export declare class McpToolManager {
96
93
  }): Promise<PluginMcpToolResult>;
97
94
  private toToolDescriptor;
98
95
  }
99
- export {};
@@ -8,11 +8,15 @@ import type { AgentTurnUsage } from "@/chat/usage";
8
8
  * the session record's optimistic-concurrency version. `awaiting_auth` means
9
9
  * the run parked for user authorization.
10
10
  */
11
+ /** Why a run parked at a safe boundary and may continue. */
12
+ export type AgentSuspensionReason = "timeout" | "yield" | "retry";
11
13
  export type AgentRunOutcome = {
12
14
  status: "completed";
13
15
  result: AgentRunResult;
14
16
  } | {
15
17
  status: "suspended";
18
+ /** Why this slice stopped. Callers use this to choose wake vs yield. */
19
+ reason: AgentSuspensionReason;
16
20
  resumeVersion: number;
17
21
  usage?: AgentTurnUsage;
18
22
  } | {
@@ -9,7 +9,7 @@ export declare function createSearchConversationEventsTool(context: ToolRuntimeC
9
9
  after_seq?: number | null | undefined;
10
10
  before_seq?: number | null | undefined;
11
11
  limit?: number | null | undefined;
12
- types?: ("message" | "message_handled" | "assistant_message" | "turn_routed" | "guardian_action_reviewed" | "turn_context" | "structured_event" | "compaction" | "handoff" | "user_message" | "tool_result" | "mcp_provider_connected" | "authorization_requested" | "authorization_completed" | "tool_execution_started" | "message_updated" | "messages_summarized" | "turn_started" | "turn_completed" | "turn_failed" | "subagent_started" | "subagent_ended")[] | null | undefined;
12
+ types?: ("message" | "message_handled" | "assistant_message" | "turn_routed" | "guardian_action_reviewed" | "turn_context" | "structured_event" | "compaction" | "handoff" | "user_message" | "tool_result" | "mcp_provider_connected" | "mcp_provider_connected_unowned" | "authorization_requested" | "authorization_completed" | "tool_execution_started" | "message_updated" | "messages_summarized" | "turn_started" | "turn_completed" | "turn_failed" | "subagent_started" | "subagent_ended")[] | null | undefined;
13
13
  };
14
14
  execute?: ((input: unknown, options: import("./definition").ToolExecuteOptions) => {
15
15
  [x: string]: unknown;
@@ -1,6 +1,5 @@
1
1
  import type { ManagedMcpTool } from "@/chat/mcp/tool-manager";
2
2
  interface CallMcpToolManager {
3
- activateProvider(provider: string): Promise<boolean>;
4
3
  getResolvedActiveTools(): ManagedMcpTool[];
5
4
  }
6
5
  /** Create the stable dispatcher for active MCP provider tools. */
@@ -7,13 +7,10 @@ export type LoadSkillResult = {
7
7
  location?: string;
8
8
  path_resolution?: string;
9
9
  instructions?: string;
10
- mcp_provider?: string;
11
- available_tool_count?: number;
12
10
  } & Record<string, unknown>;
13
- export type LoadSkillMetadata = Pick<LoadSkillResult, "mcp_provider" | "available_tool_count">;
14
- /** Create the skill-loading tool that injects skill instructions and activates provider catalogs. */
11
+ /** Create the tool that loads skill instructions for the current turn. */
15
12
  export declare function createLoadSkillTool(availableSkills: SkillMetadata[], options?: {
16
- onSkillLoaded?: (skill: Skill) => void | LoadSkillMetadata | Promise<void | LoadSkillMetadata>;
13
+ onSkillLoaded?: (skill: Skill) => void | Promise<void>;
17
14
  }): Omit<import("../definition").AnyToolDefinition, "inputSchema" | "outputSchema" | "prepareArguments" | "execute"> & {
18
15
  inputSchema: import("../definition").JsonSchemaObject;
19
16
  outputSchema: import("../definition").JsonSchemaObject;
@@ -4,7 +4,6 @@ import type { McpToolManager } from "@/chat/mcp/tool-manager";
4
4
  import type { SandboxWorkspace } from "@/chat/sandbox/workspace";
5
5
  import type { AgentTurnSurface } from "@/chat/task-execution/checkpoint";
6
6
  import type { Skill } from "@/chat/skills";
7
- import type { LoadSkillMetadata } from "@/chat/tools/skill/load-skill";
8
7
  import type { JuniorToolOutput } from "@/chat/tool-support/structured-result";
9
8
  import type { WebActor, LocalActor, Actor, SlackActor } from "@/chat/actor";
10
9
  import type { SlackActionToken } from "@/chat/slack/action-token";
@@ -44,7 +43,7 @@ export interface ToolHooks {
44
43
  * generating tool reports success.
45
44
  */
46
45
  writeGeneratedArtifacts?: (files: FileUpload[]) => GeneratedArtifactFileRef[] | Promise<GeneratedArtifactFileRef[]>;
47
- onSkillLoaded?: (skill: Skill) => void | LoadSkillMetadata | Promise<void | LoadSkillMetadata>;
46
+ onSkillLoaded?: (skill: Skill) => void | Promise<void>;
48
47
  toolOverrides?: {
49
48
  imageGenerate?: ImageGenerateToolDeps;
50
49
  viewImage?: ViewImageToolDeps;
@@ -13,7 +13,7 @@ import {
13
13
  instructionProvenanceFor,
14
14
  sanitizePostgresJson,
15
15
  withConversationEventLock
16
- } from "./chunk-GZ25ZSTX.js";
16
+ } from "./chunk-XTLF7C4I.js";
17
17
  import {
18
18
  SANDBOX_WORKSPACE_ROOT,
19
19
  sleep
@@ -23,14 +23,14 @@ import {
23
23
  fenceLock,
24
24
  getStateAdapter,
25
25
  withLock
26
- } from "./chunk-B2YA2G26.js";
26
+ } from "./chunk-X6JP6AMX.js";
27
27
  import {
28
28
  botConfig,
29
29
  completeText,
30
30
  escapeXml,
31
31
  resolveGatewayModel,
32
32
  unwrapCurrentInstruction
33
- } from "./chunk-FGP5W3NS.js";
33
+ } from "./chunk-OEECXAGT.js";
34
34
  import {
35
35
  toStoredSlackActor
36
36
  } from "./chunk-HZF5P5UN.js";
@@ -42,7 +42,7 @@ import {
42
42
  logException,
43
43
  logWarn,
44
44
  setSpanAttributes
45
- } from "./chunk-3WIFZBJL.js";
45
+ } from "./chunk-7TZM33YX.js";
46
46
 
47
47
  // src/chat/turn-context-tag.ts
48
48
  var TURN_CONTEXT_TAG = "runtime-turn-context";
@@ -1142,10 +1142,10 @@ function projectConversationEvents(events, options) {
1142
1142
  }
1143
1143
 
1144
1144
  // src/chat/conversations/projection.ts
1145
- function connectedMcpProvidersFromEvents(events) {
1145
+ function connectedMcpProvidersFromEvents(events, credentialSubjectId) {
1146
1146
  const providers = /* @__PURE__ */ new Set();
1147
1147
  for (const event of events) {
1148
- if (event.data.type === "mcp_provider_connected") {
1148
+ if (event.data.type === "mcp_provider_connected" && event.data.credentialSubjectId === credentialSubjectId) {
1149
1149
  providers.add(event.data.provider);
1150
1150
  }
1151
1151
  }
@@ -1285,10 +1285,10 @@ async function loadTurnProjection(args) {
1285
1285
  return projectConversationEvents(historyEvents);
1286
1286
  }
1287
1287
  async function loadConnectedMcpProviders(args) {
1288
- const events = await getConversationEventStore().loadCurrentHistory(
1288
+ const events = await getConversationEventStore().loadHistory(
1289
1289
  args.conversationId
1290
1290
  );
1291
- return connectedMcpProvidersFromEvents(events);
1291
+ return connectedMcpProvidersFromEvents(events, args.credentialSubjectId);
1292
1292
  }
1293
1293
  function messageTimestamp2(message) {
1294
1294
  const timestamp = message.timestamp;
@@ -1404,12 +1404,18 @@ async function commitMessagesLocked(args, executor) {
1404
1404
  async function recordMcpProviderConnected(args) {
1405
1405
  const eventStore = getConversationEventStore();
1406
1406
  const events = await eventStore.loadCurrentHistory(args.conversationId);
1407
- if (connectedMcpProvidersFromEvents(events).includes(args.provider)) {
1407
+ if (connectedMcpProvidersFromEvents(events, args.credentialSubjectId).includes(
1408
+ args.provider
1409
+ )) {
1408
1410
  return;
1409
1411
  }
1410
1412
  await eventStore.append(args.conversationId, [
1411
1413
  {
1412
- data: { type: "mcp_provider_connected", provider: args.provider },
1414
+ data: {
1415
+ type: "mcp_provider_connected",
1416
+ provider: args.provider,
1417
+ credentialSubjectId: args.credentialSubjectId
1418
+ },
1413
1419
  createdAtMs: Date.now()
1414
1420
  }
1415
1421
  ]);
@@ -1,28 +1,34 @@
1
+ import {
2
+ createWebAuthorization,
3
+ deleteWebAuthorization
4
+ } from "./chunk-SFYDSI34.js";
1
5
  import {
2
6
  appendAndEnqueueInboundMessage
3
- } from "./chunk-JVOLC6JZ.js";
7
+ } from "./chunk-AYPU5T5L.js";
4
8
  import {
5
9
  buildDeliveredTurnStatePatch,
10
+ completeAuthPauseTurn,
6
11
  finalizeFailedTurnReplyWithEvent,
7
12
  getTurnUserMessage,
8
13
  processPluginTask,
9
14
  scheduleSessionCompletedPluginTasks
10
- } from "./chunk-N6QJAPZS.js";
15
+ } from "./chunk-I4LR7MS2.js";
11
16
  import {
12
17
  ConversationTurnLifecycleService,
13
18
  coerceThreadConversationState,
14
19
  getPersistedSandboxState,
15
20
  getPersistedThreadState,
16
21
  persistThreadStateById
17
- } from "./chunk-JBYWR6FW.js";
22
+ } from "./chunk-67VR4BJK.js";
18
23
  import {
19
24
  healthReportSchema
20
25
  } from "./chunk-UTL3MHPC.js";
21
26
  import {
22
27
  parseSlackThreadId
23
- } from "./chunk-4JV7GUUH.js";
28
+ } from "./chunk-RCBAXKMB.js";
24
29
  import {
25
30
  TurnInputCommitLostError,
31
+ abandonTurnRecord,
26
32
  buildConversationContext,
27
33
  buildDeterministicTurnId,
28
34
  getAssistantReplyText,
@@ -33,6 +39,7 @@ import {
33
39
  listTurnSummaries,
34
40
  loadProjection,
35
41
  markConversationMessage,
42
+ markTurnClosed,
36
43
  markTurnFailed,
37
44
  normalizeConversationText,
38
45
  persistConversationMessages,
@@ -41,22 +48,26 @@ import {
41
48
  saveTurnCheckpoint,
42
49
  startActiveTurn,
43
50
  upsertConversationMessage
44
- } from "./chunk-2AWDPNP7.js";
51
+ } from "./chunk-3PCKG4BT.js";
45
52
  import {
46
53
  normalizeSlackConversationId
47
- } from "./chunk-D2PVJU5E.js";
54
+ } from "./chunk-KTYC3GDO.js";
48
55
  import {
49
56
  getConversationEventStore,
50
57
  getConversationStore
51
- } from "./chunk-GZ25ZSTX.js";
58
+ } from "./chunk-XTLF7C4I.js";
59
+ import {
60
+ getSlackBotToken
61
+ } from "./chunk-OEECXAGT.js";
52
62
  import {
53
63
  credentialContextForActor
54
64
  } from "./chunk-RUIXF3YQ.js";
55
65
  import {
56
66
  logException,
67
+ logWarn,
57
68
  setTags,
58
69
  withLogContext
59
- } from "./chunk-3WIFZBJL.js";
70
+ } from "./chunk-7TZM33YX.js";
60
71
 
61
72
  // src/handlers/health.ts
62
73
  function readHealthReport() {
@@ -70,20 +81,105 @@ function GET() {
70
81
  return Response.json(readHealthReport());
71
82
  }
72
83
 
84
+ // src/chat/slack/user.ts
85
+ import { z } from "zod";
86
+ var slackUserInfoSchema = z.object({
87
+ ok: z.literal(true),
88
+ user: z.object({
89
+ name: z.string().nullish(),
90
+ profile: z.object({
91
+ email: z.string().nullish(),
92
+ real_name: z.string().nullish()
93
+ }).optional()
94
+ })
95
+ });
96
+ var USER_CACHE_TTL_MS = 5 * 60 * 1e3;
97
+ var userCache = /* @__PURE__ */ new Map();
98
+ function userCacheKey(teamId, userId) {
99
+ return `${teamId}:${userId}`;
100
+ }
101
+ function readFromCache(teamId, userId) {
102
+ const hit = userCache.get(userCacheKey(teamId, userId));
103
+ if (!hit) return null;
104
+ if (hit.expiresAt < Date.now()) {
105
+ userCache.delete(userCacheKey(teamId, userId));
106
+ return null;
107
+ }
108
+ return hit.value;
109
+ }
110
+ function writeToCache(teamId, userId, value) {
111
+ userCache.set(userCacheKey(teamId, userId), {
112
+ value,
113
+ expiresAt: Date.now() + USER_CACHE_TTL_MS
114
+ });
115
+ }
116
+ async function lookupSlackUser(teamId, userId) {
117
+ if (!teamId || !userId) {
118
+ return null;
119
+ }
120
+ const cached = readFromCache(teamId, userId);
121
+ if (cached) {
122
+ return cached;
123
+ }
124
+ const token = getSlackBotToken();
125
+ if (!token) {
126
+ return null;
127
+ }
128
+ try {
129
+ const response = await fetch(
130
+ `https://slack.com/api/users.info?user=${encodeURIComponent(userId)}`,
131
+ {
132
+ headers: {
133
+ authorization: `Bearer ${token}`
134
+ }
135
+ }
136
+ );
137
+ if (!response.ok) {
138
+ logWarn("slack.user.lookup.failed", {
139
+ "enduser.id": userId,
140
+ "app.slack.team_id": teamId,
141
+ "http.response.status_code": response.status
142
+ });
143
+ return null;
144
+ }
145
+ const parsed = slackUserInfoSchema.safeParse(await response.json());
146
+ if (!parsed.success) {
147
+ return null;
148
+ }
149
+ const payload = parsed.data;
150
+ const userName = payload.user.name?.trim() || void 0;
151
+ const fullName = payload.user.profile?.real_name?.trim() || void 0;
152
+ const result = {
153
+ userName,
154
+ fullName,
155
+ email: payload.user.profile?.email?.trim() || void 0
156
+ };
157
+ writeToCache(teamId, userId, result);
158
+ return result;
159
+ } catch (error) {
160
+ logWarn("slack.user.lookup.failed", {
161
+ "enduser.id": userId,
162
+ "app.slack.team_id": teamId,
163
+ "exception.message": error instanceof Error ? error.message : String(error)
164
+ });
165
+ return null;
166
+ }
167
+ }
168
+
73
169
  // src/chat/api-turns/work.ts
74
170
  import { createHash } from "crypto";
75
- import { z } from "zod";
171
+ import { z as z2 } from "zod";
76
172
  import {
77
173
  createWebSource,
78
174
  localDestinationSchema
79
175
  } from "@sentry/junior-plugin-api";
80
- var apiTurnMailboxMetadataSchema = z.object({
81
- authorEmail: z.string().email(),
82
- authorFullName: z.string().min(1).optional(),
83
- authorUserId: z.string().min(1),
84
- authorUserName: z.string().min(1).optional(),
85
- kind: z.literal("api_turn"),
86
- messageId: z.string().min(1)
176
+ var apiTurnMailboxMetadataSchema = z2.object({
177
+ authorEmail: z2.string().email(),
178
+ authorFullName: z2.string().min(1).optional(),
179
+ authorUserId: z2.string().min(1),
180
+ authorUserName: z2.string().min(1).optional(),
181
+ kind: z2.literal("api_turn"),
182
+ messageId: z2.string().min(1)
87
183
  }).strict();
88
184
  function normalizeEmail(email) {
89
185
  return email.trim().toLowerCase();
@@ -438,6 +534,27 @@ function createApiTurnWorker(options) {
438
534
  startedAtMs = userMessage.createdAtMs;
439
535
  inputMessageIds = [userMessageId];
440
536
  } else {
537
+ const authParked = (await listTurnSummaries(context.conversationId)).filter(
538
+ (summary) => summary.surface === "api" && !summary.dispatchId && summary.state === "paused" && summary.resumeReason === "auth"
539
+ );
540
+ for (const parked of authParked) {
541
+ await abandonTurnRecord({
542
+ conversationId: context.conversationId,
543
+ turnId: parked.turnId,
544
+ errorMessage: "Auth-parked session superseded by a new user message"
545
+ });
546
+ markTurnClosed({
547
+ conversation,
548
+ nowMs: Date.now(),
549
+ sessionId: parked.turnId
550
+ });
551
+ }
552
+ if (authParked.length > 0) {
553
+ await deleteWebAuthorization({
554
+ actorId: actor.userId,
555
+ conversationId: context.conversationId
556
+ });
557
+ }
441
558
  upsertConversationMessage(conversation, {
442
559
  id: userMessageId,
443
560
  role: "user",
@@ -535,7 +652,10 @@ function createApiTurnWorker(options) {
535
652
  publishExternally: false,
536
653
  source,
537
654
  surface: "api",
538
- disabledFeatures: ["interactive-auth"],
655
+ authorization: createWebAuthorization({
656
+ actorId: actor.userId,
657
+ conversationId: context.conversationId
658
+ }),
539
659
  state: {
540
660
  pendingAuth: conversation.processing.pendingAuth,
541
661
  sandboxRef
@@ -550,14 +670,30 @@ function createApiTurnWorker(options) {
550
670
  conversation,
551
671
  sandboxRef
552
672
  });
673
+ },
674
+ recordPendingAuth: async (pendingAuth) => {
675
+ conversation.processing.pendingAuth = pendingAuth;
676
+ await persistThreadStateById(context.conversationId, {
677
+ conversation,
678
+ sandboxRef
679
+ });
553
680
  }
554
681
  }
555
682
  });
556
683
  if (outcome.status === "suspended") {
557
684
  return { status: "yielded" };
558
685
  }
559
- if (outcome.status !== "completed") {
560
- throw new Error(`API agent run ended with ${outcome.status}`);
686
+ if (outcome.status === "awaiting_auth") {
687
+ completeAuthPauseTurn({
688
+ conversation,
689
+ sessionId: turnId
690
+ });
691
+ await persistThreadStateById(context.conversationId, {
692
+ conversation,
693
+ sandboxRef
694
+ });
695
+ await acknowledge();
696
+ return { status: "completed" };
561
697
  }
562
698
  reply = outcome.result;
563
699
  modelFailureCaptureAttempted = reply.diagnostics.outcome !== "success";
@@ -789,6 +925,7 @@ function formatSlackConversationRedactedLabel(context) {
789
925
  export {
790
926
  readHealthReport,
791
927
  GET,
928
+ lookupSlackUser,
792
929
  conversationVisibilityFromSlackChannelType,
793
930
  resolveSlackChannelTypeFromMessage,
794
931
  resolveSlackConversationContext,