@sentry/junior 0.75.0 → 0.76.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 (100) hide show
  1. package/README.md +1 -1
  2. package/bin/junior.mjs +4 -66
  3. package/dist/agent-hooks-ZOE7RIED.js +37 -0
  4. package/dist/api-reference.d.ts +2 -0
  5. package/dist/app.js +317 -118
  6. package/dist/build/virtual-config.d.ts +2 -2
  7. package/dist/chat/agent-dispatch/runner.d.ts +2 -0
  8. package/dist/chat/config.d.ts +1 -0
  9. package/dist/chat/credentials/state-adapter-token-store.d.ts +2 -0
  10. package/dist/chat/credentials/user-token-store.d.ts +17 -12
  11. package/dist/chat/db.d.ts +8 -0
  12. package/dist/chat/mcp/auth-store.d.ts +2 -1
  13. package/dist/chat/mcp/oauth.d.ts +2 -1
  14. package/dist/chat/oauth-flow.d.ts +3 -1
  15. package/dist/chat/pi/client.d.ts +15 -7
  16. package/dist/chat/plugins/agent-hooks.d.ts +7 -0
  17. package/dist/chat/plugins/auth/oauth-request.d.ts +11 -7
  18. package/dist/chat/plugins/model.d.ts +9 -0
  19. package/dist/chat/plugins/prompt.d.ts +5 -0
  20. package/dist/chat/plugins/task-callback.d.ts +5 -0
  21. package/dist/chat/plugins/task-message.d.ts +23 -0
  22. package/dist/chat/plugins/task-queue.d.ts +5 -0
  23. package/dist/chat/plugins/task-runner.d.ts +12 -0
  24. package/dist/chat/plugins/task-signing.d.ts +31 -0
  25. package/dist/chat/prompt.d.ts +4 -0
  26. package/dist/chat/requester.d.ts +6 -5
  27. package/dist/chat/respond-helpers.d.ts +2 -0
  28. package/dist/chat/respond.d.ts +4 -2
  29. package/dist/chat/runtime/agent-continue-runner.d.ts +4 -0
  30. package/dist/chat/runtime/reply-executor.d.ts +5 -1
  31. package/dist/chat/runtime/slack-resume.d.ts +10 -2
  32. package/dist/chat/sentry.d.ts +1 -0
  33. package/dist/chat/services/mcp-auth-orchestration.d.ts +2 -1
  34. package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
  35. package/dist/chat/services/subscribed-decision.d.ts +2 -2
  36. package/dist/chat/services/turn-session-record.d.ts +11 -7
  37. package/dist/chat/state/turn-session.d.ts +8 -5
  38. package/dist/chat/tools/agent-tools.d.ts +8 -1
  39. package/dist/chat/tools/slack/context.d.ts +2 -2
  40. package/dist/chat/tools/types.d.ts +4 -4
  41. package/dist/chat/vercel-queue-client.d.ts +3 -0
  42. package/dist/{chunk-C3AM4Z4J.js → chunk-2ECJXSVQ.js} +5 -5
  43. package/dist/{chunk-OJODNL2P.js → chunk-4SCWV7TJ.js} +2 -2
  44. package/dist/chunk-4UO6FK4G.js +64 -0
  45. package/dist/{chunk-BNJIEFQC.js → chunk-56TBVRJG.js} +2 -2
  46. package/dist/{chunk-OK4KKR7B.js → chunk-EJN6G5A2.js} +28 -12
  47. package/dist/{chunk-TQ74BATR.js → chunk-HHDUKWVG.js} +428 -111
  48. package/dist/{chunk-XJHDZUGD.js → chunk-JBASI5VV.js} +4 -4
  49. package/dist/chunk-KNFROR7R.js +127 -0
  50. package/dist/{chunk-VNTLUFTY.js → chunk-KOIMO7S3.js} +126 -87
  51. package/dist/chunk-MLKGABMK.js +9 -0
  52. package/dist/{chunk-NPVUAXUE.js → chunk-NFTMTIP3.js} +303 -33
  53. package/dist/chunk-NYKJ3KON.js +1082 -0
  54. package/dist/{chunk-SJHUF3DP.js → chunk-OJ53FYVG.js} +2 -10
  55. package/dist/{chunk-62FUNJYS.js → chunk-Q6XFTRV5.js} +54 -3
  56. package/dist/{chunk-UJ7OTHPO.js → chunk-R6Z5XWY3.js} +12 -670
  57. package/dist/chunk-RV5RYIJW.js +56 -0
  58. package/dist/{chunk-EE6PJWY4.js → chunk-SG5WAA7H.js} +7 -5
  59. package/dist/chunk-ST6YNAXG.js +54 -0
  60. package/dist/{chunk-FCZO7LAR.js → chunk-T77LUIX3.js} +139 -153
  61. package/dist/{chunk-EIYL7I4S.js → chunk-VALUBQ7R.js} +22 -30
  62. package/dist/{chunk-OZSPLAQ4.js → chunk-XBBC6W45.js} +1 -1
  63. package/dist/{chunk-ZNNTSPNF.js → chunk-Y5OFBCBZ.js} +1 -1
  64. package/dist/{chunk-74HO27II.js → chunk-Z4CIQ3EB.js} +5 -1
  65. package/dist/{chunk-2RWFUS5F.js → chunk-ZLMBNBUG.js} +101 -44
  66. package/dist/{chunk-JEELK46E.js → chunk-ZQB37HUX.js} +11 -11
  67. package/dist/cli/chat.js +52 -23
  68. package/dist/cli/check.js +7 -7
  69. package/dist/cli/env.js +4 -53
  70. package/dist/cli/init.js +6 -1
  71. package/dist/cli/main.js +84 -0
  72. package/dist/cli/plugins.js +244 -0
  73. package/dist/cli/run.js +5 -52
  74. package/dist/cli/snapshot-warmup.js +9 -9
  75. package/dist/cli/upgrade.js +167 -48
  76. package/dist/db-7A7PFRGL.js +17 -0
  77. package/dist/deployment.d.ts +1 -0
  78. package/dist/instrumentation.js +14 -18
  79. package/dist/nitro.d.ts +1 -1
  80. package/dist/nitro.js +43 -22
  81. package/dist/plugins-PZMDS7AT.js +15 -0
  82. package/dist/plugins.d.ts +4 -2
  83. package/dist/{registry-NLZFIW23.js → registry-OIPAJU2O.js} +6 -6
  84. package/dist/reporting.js +34 -26
  85. package/dist/{runner-LUQZ5G67.js → runner-KPLNHDCV.js} +76 -23
  86. package/dist/sentry-4CP5NNQ5.js +31 -0
  87. package/dist/validation-SLA6IGF7.js +15 -0
  88. package/dist/vercel.js +1 -1
  89. package/package.json +7 -6
  90. package/dist/agent-hooks-2HEB4C3Q.js +0 -33
  91. package/dist/chat/conversations/configured.d.ts +0 -7
  92. package/dist/chat/conversations/state.d.ts +0 -4
  93. package/dist/chat/plugins/db.d.ts +0 -31
  94. package/dist/chunk-2KG3PWR4.js +0 -17
  95. package/dist/chunk-D7NFH5GD.js +0 -570
  96. package/dist/chunk-MCMROINU.js +0 -12
  97. package/dist/chunk-WBZ4M5N5.js +0 -59
  98. package/dist/db-A3ILH67H.js +0 -20
  99. package/dist/plugins-OMJKLRJ2.js +0 -13
  100. package/dist/validation-VMCPP3YO.js +0 -15
@@ -0,0 +1,56 @@
1
+ // src/cli/env.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ function envFileNames(nodeEnv) {
5
+ return [
6
+ `.env.${nodeEnv}.local`,
7
+ ...nodeEnv === "test" ? [] : [".env.local"],
8
+ `.env.${nodeEnv}`,
9
+ ".env",
10
+ ".env.example"
11
+ ];
12
+ }
13
+ function hasEnvRootMarker(dir) {
14
+ return fs.existsSync(path.join(dir, "package.json")) || fs.existsSync(path.join(dir, "pnpm-workspace.yaml"));
15
+ }
16
+ function resolveCliEnvRoots(cwd) {
17
+ const roots = [];
18
+ const seen = /* @__PURE__ */ new Set();
19
+ const addRoot = (candidate) => {
20
+ const resolved = path.resolve(candidate);
21
+ if (seen.has(resolved)) {
22
+ return;
23
+ }
24
+ seen.add(resolved);
25
+ roots.push(resolved);
26
+ };
27
+ let current = path.resolve(cwd);
28
+ addRoot(current);
29
+ while (true) {
30
+ if (hasEnvRootMarker(current)) {
31
+ addRoot(current);
32
+ }
33
+ const parent = path.dirname(current);
34
+ if (parent === current) {
35
+ break;
36
+ }
37
+ current = parent;
38
+ }
39
+ return roots;
40
+ }
41
+ function loadCliEnvFiles(cwd = process.cwd()) {
42
+ const nodeEnv = process.env.NODE_ENV ?? "development";
43
+ for (const root of resolveCliEnvRoots(cwd)) {
44
+ for (const envFile of envFileNames(nodeEnv)) {
45
+ const absolutePath = path.join(root, envFile);
46
+ if (!fs.existsSync(absolutePath)) {
47
+ continue;
48
+ }
49
+ process.loadEnvFile(absolutePath);
50
+ }
51
+ }
52
+ }
53
+
54
+ export {
55
+ loadCliEnvFiles
56
+ };
@@ -116,15 +116,17 @@ function pluginCatalogConfigFromEnv(env = process.env) {
116
116
  const packages = readEnvPluginPackages(env);
117
117
  return packages ? { packages } : void 0;
118
118
  }
119
- function pluginHookRegistrationsFromPluginSet(pluginSet) {
120
- return pluginSet?.registrations.filter(
121
- (plugin) => plugin.database || plugin.hooks
122
- ) ?? [];
119
+ function pluginRuntimeRegistrationsFromPluginSet(pluginSet) {
120
+ return pluginSet?.registrations.filter((plugin) => plugin.hooks || plugin.tasks) ?? [];
121
+ }
122
+ function pluginCliRegistrationsFromPluginSet(pluginSet) {
123
+ return pluginSet?.registrations.filter((plugin) => plugin.cli) ?? [];
123
124
  }
124
125
 
125
126
  export {
126
127
  defineJuniorPlugins,
127
128
  pluginCatalogConfigFromPluginSet,
128
129
  pluginCatalogConfigFromEnv,
129
- pluginHookRegistrationsFromPluginSet
130
+ pluginRuntimeRegistrationsFromPluginSet,
131
+ pluginCliRegistrationsFromPluginSet
130
132
  };
@@ -0,0 +1,54 @@
1
+ import {
2
+ __export
3
+ } from "./chunk-MLKGABMK.js";
4
+
5
+ // src/chat/sentry.ts
6
+ var sentry_exports = {};
7
+ __export(sentry_exports, {
8
+ captureException: () => captureException,
9
+ continueTrace: () => continueTrace,
10
+ flush: () => flush,
11
+ getClient: () => getClient,
12
+ getGlobalScope: () => getGlobalScope,
13
+ init: () => init,
14
+ setTag: () => setTag,
15
+ setUser: () => setUser,
16
+ startInactiveSpan: () => startInactiveSpan,
17
+ startSpan: () => startSpan,
18
+ vercelAIIntegration: () => vercelAIIntegration,
19
+ withActiveSpan: () => withActiveSpan,
20
+ withScope: () => withScope
21
+ });
22
+ import {
23
+ captureException,
24
+ continueTrace,
25
+ flush,
26
+ getClient,
27
+ getGlobalScope,
28
+ init,
29
+ setTag,
30
+ setUser,
31
+ startInactiveSpan,
32
+ startSpan,
33
+ vercelAIIntegration,
34
+ withActiveSpan,
35
+ withScope
36
+ } from "@sentry/node";
37
+ export * from "@sentry/node";
38
+
39
+ export {
40
+ sentry_exports,
41
+ captureException,
42
+ continueTrace,
43
+ flush,
44
+ getClient,
45
+ getGlobalScope,
46
+ init,
47
+ setTag,
48
+ setUser,
49
+ startInactiveSpan,
50
+ startSpan,
51
+ vercelAIIntegration,
52
+ withActiveSpan,
53
+ withScope
54
+ };
@@ -6,7 +6,7 @@ import {
6
6
  setSpanAttributes,
7
7
  toOptionalString,
8
8
  withSpan
9
- } from "./chunk-OK4KKR7B.js";
9
+ } from "./chunk-EJN6G5A2.js";
10
10
 
11
11
  // src/chat/turn-context-tag.ts
12
12
  var TURN_CONTEXT_TAG = "runtime-turn-context";
@@ -166,47 +166,6 @@ function getUserMessageContent(message) {
166
166
  function isRuntimeTurnContextPart(part, marker) {
167
167
  return part !== null && typeof part === "object" && part.type === "text" && typeof part.text === "string" && part.text.startsWith(marker);
168
168
  }
169
- function prependRuntimeTurnContext(message, turnContextPrompt) {
170
- const content = getUserMessageContent(message);
171
- if (!content) {
172
- return void 0;
173
- }
174
- const contextIndex = content.findIndex(
175
- (part) => isRuntimeTurnContextPart(part, RUNTIME_TURN_CONTEXT_START)
176
- );
177
- if (contextIndex >= 0) {
178
- return void 0;
179
- }
180
- return {
181
- ...message,
182
- content: [{ type: "text", text: turnContextPrompt }, ...content]
183
- };
184
- }
185
- function prependMissingRuntimeTurnContext(messages, turnContextPrompt) {
186
- if (hasRuntimeTurnContext(messages)) {
187
- return messages;
188
- }
189
- for (let index = messages.length - 1; index >= 0; index -= 1) {
190
- const updated = prependRuntimeTurnContext(
191
- messages[index],
192
- turnContextPrompt
193
- );
194
- if (!updated) {
195
- continue;
196
- }
197
- const nextMessages = [...messages];
198
- nextMessages[index] = updated;
199
- return nextMessages;
200
- }
201
- return [
202
- ...messages,
203
- {
204
- role: "user",
205
- content: [{ type: "text", text: turnContextPrompt }],
206
- timestamp: Date.now()
207
- }
208
- ];
209
- }
210
169
  function hasRuntimeTurnContext(messages) {
211
170
  return messages.some(
212
171
  (message) => getUserMessageContent(message)?.some(
@@ -287,6 +246,8 @@ import {
287
246
  getModels,
288
247
  registerApiProvider
289
248
  } from "@earendil-works/pi-ai";
249
+ import { createGatewayProvider } from "@ai-sdk/gateway";
250
+ import { embedMany, generateObject } from "ai";
290
251
  import {
291
252
  streamAnthropic,
292
253
  streamSimpleAnthropic
@@ -550,76 +511,17 @@ var GEN_AI_PROVIDER_NAME = GATEWAY_PROVIDER;
550
511
  var GEN_AI_SERVER_ADDRESS = "ai-gateway.vercel.sh";
551
512
  var GEN_AI_SERVER_PORT = 443;
552
513
  var GEN_AI_OPERATION_CHAT = "chat";
514
+ var GEN_AI_OPERATION_EMBEDDINGS = "embeddings";
553
515
  var MISSING_GATEWAY_CREDENTIALS_ERROR = "Missing AI gateway credentials (AI_GATEWAY_API_KEY or VERCEL_OIDC_TOKEN)";
554
516
  function getGatewayApiKey() {
555
517
  return toOptionalTrimmed(getEnvApiKey("vercel-ai-gateway")) ?? toOptionalTrimmed(process.env.VERCEL_OIDC_TOKEN);
556
518
  }
557
- function getPiGatewayApiKeyOverride() {
558
- return toOptionalTrimmed(process.env.VERCEL_OIDC_TOKEN);
519
+ function getPiGatewayApiKey() {
520
+ return getGatewayApiKey();
559
521
  }
560
522
  function extractText(message) {
561
523
  return (message.content ?? []).filter((part) => part.type === "text" && typeof part.text === "string").map((part) => part.text ?? "").join("").trim();
562
524
  }
563
- function parseJsonCandidate2(text) {
564
- const trimmed = text.trim();
565
- if (!trimmed) return void 0;
566
- try {
567
- return JSON.parse(trimmed);
568
- } catch {
569
- const fencedBlocks = [
570
- ...trimmed.matchAll(/```(?:json)?\s*([\s\S]*?)\s*```/gi)
571
- ];
572
- for (const block of fencedBlocks) {
573
- try {
574
- return JSON.parse(block[1]);
575
- } catch {
576
- }
577
- }
578
- const openBraceIndex = trimmed.indexOf("{");
579
- if (openBraceIndex >= 0) {
580
- let depth = 0;
581
- let inString = false;
582
- let escaped = false;
583
- for (let index = openBraceIndex; index < trimmed.length; index += 1) {
584
- const char = trimmed[index];
585
- if (inString) {
586
- if (escaped) {
587
- escaped = false;
588
- continue;
589
- }
590
- if (char === "\\") {
591
- escaped = true;
592
- continue;
593
- }
594
- if (char === '"') {
595
- inString = false;
596
- }
597
- continue;
598
- }
599
- if (char === '"') {
600
- inString = true;
601
- continue;
602
- }
603
- if (char === "{") {
604
- depth += 1;
605
- continue;
606
- }
607
- if (char === "}") {
608
- depth -= 1;
609
- if (depth === 0) {
610
- const slice = trimmed.slice(openBraceIndex, index + 1);
611
- try {
612
- return JSON.parse(slice);
613
- } catch {
614
- break;
615
- }
616
- }
617
- }
618
- }
619
- }
620
- return void 0;
621
- }
622
- }
623
525
  function resolveGatewayModel(modelId) {
624
526
  const matched = getModels(GATEWAY_PROVIDER).find(
625
527
  (model) => model.id === modelId
@@ -631,7 +533,8 @@ function resolveGatewayModel(modelId) {
631
533
  }
632
534
  async function completeText(params) {
633
535
  const model = resolveGatewayModel(params.modelId);
634
- const apiKey = getPiGatewayApiKeyOverride();
536
+ const apiKey = getPiGatewayApiKey();
537
+ const authMode = toOptionalTrimmed(process.env.AI_GATEWAY_API_KEY) ? "api_key" : toOptionalTrimmed(process.env.VERCEL_OIDC_TOKEN) ? "oidc" : "api_key";
635
538
  const privacy = resolveConversationPrivacy({
636
539
  channelId: typeof params.metadata?.channelId === "string" ? params.metadata.channelId : void 0,
637
540
  conversationId: typeof params.metadata?.conversationId === "string" ? params.metadata.conversationId : typeof params.metadata?.threadId === "string" ? params.metadata.threadId : void 0
@@ -660,7 +563,7 @@ async function completeText(params) {
660
563
  ...params.system ? { "app.ai.system_instructions.content_chars": params.system.length } : {},
661
564
  ...systemInstructionsAttribute ? { "gen_ai.system_instructions": systemInstructionsAttribute } : {},
662
565
  ...requestMessagesAttribute ? { "gen_ai.input.messages": requestMessagesAttribute } : {},
663
- "app.ai.auth_mode": apiKey ? "oidc" : "api_key"
566
+ "app.ai.auth_mode": authMode
664
567
  };
665
568
  return withSpan(
666
569
  `${GEN_AI_OPERATION_CHAT} ${params.modelId}`,
@@ -750,30 +653,50 @@ function logContextFromMetadata(modelId, metadata) {
750
653
  };
751
654
  }
752
655
  async function completeObject(params) {
753
- let text = "";
656
+ const apiKey = getGatewayApiKey();
657
+ const provider = createGatewayProvider(apiKey ? { apiKey } : {});
754
658
  try {
755
- ({ text } = await completeText({
756
- modelId: params.modelId,
757
- system: params.system,
758
- thinkingLevel: params.thinkingLevel,
759
- temperature: params.temperature,
760
- maxTokens: params.maxTokens,
761
- signal: params.signal,
762
- metadata: params.metadata,
763
- messages: [
764
- {
765
- role: "user",
766
- content: params.prompt,
767
- timestamp: Date.now()
768
- }
769
- ]
770
- }));
659
+ const result = await withSpan(
660
+ `${GEN_AI_OPERATION_CHAT} ${params.modelId}`,
661
+ "gen_ai.chat",
662
+ logContextFromMetadata(params.modelId, params.metadata),
663
+ async () => await generateObject({
664
+ model: provider.chat(params.modelId),
665
+ schema: params.schema,
666
+ prompt: params.prompt,
667
+ ...params.system !== void 0 ? { system: params.system } : {},
668
+ ...params.temperature !== void 0 ? { temperature: params.temperature } : {},
669
+ ...params.maxTokens !== void 0 ? { maxOutputTokens: params.maxTokens } : {},
670
+ ...params.signal !== void 0 ? { abortSignal: params.signal } : {}
671
+ }),
672
+ {
673
+ "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
674
+ "gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
675
+ "gen_ai.request.model": params.modelId,
676
+ "gen_ai.output.type": "json",
677
+ "server.address": GEN_AI_SERVER_ADDRESS,
678
+ "server.port": GEN_AI_SERVER_PORT,
679
+ ...params.thinkingLevel ? { "app.ai.reasoning_effort": params.thinkingLevel } : {}
680
+ }
681
+ );
682
+ setSpanAttributes({
683
+ "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
684
+ "gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
685
+ "gen_ai.request.model": params.modelId,
686
+ "gen_ai.output.type": "json",
687
+ "server.address": GEN_AI_SERVER_ADDRESS,
688
+ "server.port": GEN_AI_SERVER_PORT,
689
+ "gen_ai.response.finish_reasons": [result.finishReason],
690
+ ...extractGenAiUsageAttributes(result.usage)
691
+ });
692
+ return { object: result.object };
771
693
  } catch (error) {
772
- if (isProviderRetryError(error)) {
773
- throw error;
694
+ const providerError = createProviderError(error);
695
+ if (isProviderRetryError(providerError)) {
696
+ throw providerError;
774
697
  }
775
698
  logException(
776
- error,
699
+ providerError,
777
700
  "ai_completion_failed",
778
701
  {},
779
702
  {
@@ -783,31 +706,72 @@ async function completeObject(params) {
783
706
  },
784
707
  "AI object completion failed"
785
708
  );
786
- throw error;
709
+ throw providerError;
787
710
  }
788
- const candidate = parseJsonCandidate2(text);
789
- const parsed = params.schema.safeParse(candidate);
790
- if (!parsed.success) {
791
- const preview = text.length > 400 ? `${text.slice(0, 400)}...` : text;
792
- logWarn(
793
- "ai_completion_schema_parse_failed",
794
- {},
711
+ }
712
+ async function embedTexts(params) {
713
+ const texts = params.texts.map((text) => text.trim());
714
+ if (texts.length === 0 || texts.some((text) => text.length === 0)) {
715
+ throw new Error("Embedding text is required.");
716
+ }
717
+ const apiKey = getGatewayApiKey();
718
+ const provider = createGatewayProvider(apiKey ? { apiKey } : {});
719
+ try {
720
+ const result = await withSpan(
721
+ `${GEN_AI_OPERATION_EMBEDDINGS} ${params.modelId}`,
722
+ "gen_ai.embeddings",
723
+ logContextFromMetadata(params.modelId, params.metadata),
724
+ async () => await embedMany({
725
+ model: provider.embeddingModel(params.modelId),
726
+ values: texts,
727
+ ...params.signal !== void 0 ? { abortSignal: params.signal } : {}
728
+ }),
795
729
  {
796
730
  "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
797
- "gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
731
+ "gen_ai.operation.name": GEN_AI_OPERATION_EMBEDDINGS,
798
732
  "gen_ai.request.model": params.modelId,
799
- "app.ai.response_preview": preview
800
- },
801
- "AI object completion schema parse failed"
733
+ "gen_ai.output.type": "embedding",
734
+ "server.address": GEN_AI_SERVER_ADDRESS,
735
+ "server.port": GEN_AI_SERVER_PORT
736
+ }
802
737
  );
803
- throw new Error(
804
- `Model did not return valid JSON for schema: ${parsed.error.message}. Raw response: ${preview}`
738
+ const dimensions = result.embeddings[0]?.length;
739
+ if (result.embeddings.length !== texts.length || !dimensions || !result.embeddings.every((embedding) => embedding.length === dimensions)) {
740
+ throw new Error("Embedding provider returned invalid vectors.");
741
+ }
742
+ setSpanAttributes({
743
+ "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
744
+ "gen_ai.operation.name": GEN_AI_OPERATION_EMBEDDINGS,
745
+ "gen_ai.request.model": params.modelId,
746
+ "gen_ai.output.type": "embedding",
747
+ "server.address": GEN_AI_SERVER_ADDRESS,
748
+ "server.port": GEN_AI_SERVER_PORT,
749
+ ...extractGenAiUsageAttributes(result.usage)
750
+ });
751
+ return {
752
+ dimensions,
753
+ model: params.modelId,
754
+ provider: GEN_AI_PROVIDER_NAME,
755
+ vectors: result.embeddings
756
+ };
757
+ } catch (error) {
758
+ const providerError = createProviderError(error);
759
+ if (isProviderRetryError(providerError)) {
760
+ throw providerError;
761
+ }
762
+ logException(
763
+ providerError,
764
+ "ai_embeddings_failed",
765
+ {},
766
+ {
767
+ "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
768
+ "gen_ai.operation.name": GEN_AI_OPERATION_EMBEDDINGS,
769
+ "gen_ai.request.model": params.modelId
770
+ },
771
+ "AI embeddings failed"
805
772
  );
773
+ throw providerError;
806
774
  }
807
- return {
808
- object: parsed.data,
809
- text
810
- };
811
775
  }
812
776
 
813
777
  // src/chat/slack/emoji.ts
@@ -926,7 +890,7 @@ function parseSlashCommand(rawValue) {
926
890
  }
927
891
  return command;
928
892
  }
929
- var DEFAULT_MODEL_ID = getModel("vercel-ai-gateway", "openai/gpt-5.4").id;
893
+ var DEFAULT_MODEL_ID = getModel("vercel-ai-gateway", "openai/gpt-5.5").id;
930
894
  var DEFAULT_FAST_MODEL_ID = getModel(
931
895
  "vercel-ai-gateway",
932
896
  "openai/gpt-5.4-mini"
@@ -935,12 +899,16 @@ var DEFAULT_ADVISOR_MODEL_ID = getModel(
935
899
  "vercel-ai-gateway",
936
900
  "openai/gpt-5.5"
937
901
  ).id;
902
+ var DEFAULT_EMBEDDING_MODEL_ID = "openai/text-embedding-3-small";
938
903
  function validateGatewayModelId(raw) {
939
904
  const trimmed = toOptionalTrimmed(raw);
940
905
  if (trimmed === void 0) return void 0;
941
906
  resolveGatewayModel(trimmed);
942
907
  return trimmed;
943
908
  }
909
+ function validateEmbeddingModelId(raw) {
910
+ return toOptionalTrimmed(raw);
911
+ }
944
912
  function readAdvisorConfig(env) {
945
913
  return {
946
914
  modelId: validateGatewayModelId(env.AI_ADVISOR_MODEL) ?? DEFAULT_ADVISOR_MODEL_ID,
@@ -963,14 +931,17 @@ function parseReactionEmoji(envName, rawValue, defaultEmoji) {
963
931
  function readBotConfig(env) {
964
932
  const functionMaxDurationSeconds = resolveFunctionMaxDurationSeconds(env);
965
933
  const maxTurnTimeoutMs = resolveMaxTurnTimeoutMs(functionMaxDurationSeconds);
934
+ const modelId = validateGatewayModelId(env.AI_MODEL) ?? DEFAULT_MODEL_ID;
935
+ const fastModelId = validateGatewayModelId(env.AI_FAST_MODEL ?? env.AI_MODEL) ?? DEFAULT_FAST_MODEL_ID;
966
936
  return {
967
- userName: env.JUNIOR_BOT_NAME ?? "junior",
968
- modelId: validateGatewayModelId(env.AI_MODEL) ?? DEFAULT_MODEL_ID,
937
+ userName: toOptionalTrimmed(env.JUNIOR_BOT_NAME) ?? "junior",
938
+ modelId,
969
939
  modelContextWindowTokens: parseOptionalPositiveInteger(
970
940
  "AI_MODEL_CONTEXT_WINDOW_TOKENS",
971
941
  env.AI_MODEL_CONTEXT_WINDOW_TOKENS
972
942
  ),
973
- fastModelId: validateGatewayModelId(env.AI_FAST_MODEL ?? env.AI_MODEL) ?? DEFAULT_FAST_MODEL_ID,
943
+ fastModelId,
944
+ embeddingModelId: validateEmbeddingModelId(env.AI_EMBEDDING_MODEL) ?? DEFAULT_EMBEDDING_MODEL_ID,
974
945
  loadingMessages: parseLoadingMessages(env.JUNIOR_LOADING_MESSAGES),
975
946
  visionModelId: validateGatewayModelId(env.AI_VISION_MODEL),
976
947
  turnTimeoutMs: parseAgentTurnTimeoutMs(
@@ -983,9 +954,23 @@ function readBotConfig(env) {
983
954
  function readJuniorDatabaseUrl(env) {
984
955
  return toOptionalTrimmed(env.JUNIOR_DATABASE_URL) ?? toOptionalTrimmed(env.DATABASE_URL);
985
956
  }
986
- function readSqlDriver(env) {
957
+ function isLocalDatabaseUrl(databaseUrl) {
958
+ if (!databaseUrl) {
959
+ return false;
960
+ }
961
+ try {
962
+ const { hostname } = new URL(databaseUrl);
963
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
964
+ } catch {
965
+ return false;
966
+ }
967
+ }
968
+ function readSqlDriver(env, databaseUrl) {
987
969
  const value = toOptionalTrimmed(env.JUNIOR_DATABASE_DRIVER);
988
970
  if (value === void 0) {
971
+ if (isLocalDatabaseUrl(databaseUrl)) {
972
+ return "postgres";
973
+ }
989
974
  return "neon";
990
975
  }
991
976
  if (value === "neon" || value === "postgres") {
@@ -994,12 +979,13 @@ function readSqlDriver(env) {
994
979
  throw new Error("JUNIOR_DATABASE_DRIVER must be postgres or neon");
995
980
  }
996
981
  function readChatConfig(env = process.env) {
982
+ const databaseUrl = readJuniorDatabaseUrl(env);
997
983
  return {
998
984
  bot: readBotConfig(env),
999
985
  functionMaxDurationSeconds: resolveFunctionMaxDurationSeconds(env),
1000
986
  sql: {
1001
- databaseUrl: readJuniorDatabaseUrl(env),
1002
- driver: readSqlDriver(env)
987
+ databaseUrl,
988
+ driver: readSqlDriver(env, databaseUrl)
1003
989
  },
1004
990
  slack: {
1005
991
  botToken: toOptionalTrimmed(env.SLACK_BOT_TOKEN) ?? toOptionalTrimmed(env.SLACK_BOT_USER_TOKEN),
@@ -1087,7 +1073,6 @@ export {
1087
1073
  isToolResultError,
1088
1074
  isAssistantMessage,
1089
1075
  getPiMessageRole,
1090
- prependMissingRuntimeTurnContext,
1091
1076
  hasRuntimeTurnContext,
1092
1077
  stripRuntimeTurnContext,
1093
1078
  extractAssistantText,
@@ -1101,10 +1086,11 @@ export {
1101
1086
  GEN_AI_SERVER_PORT,
1102
1087
  MISSING_GATEWAY_CREDENTIALS_ERROR,
1103
1088
  getGatewayApiKey,
1104
- getPiGatewayApiKeyOverride,
1089
+ getPiGatewayApiKey,
1105
1090
  resolveGatewayModel,
1106
1091
  completeText,
1107
1092
  completeObject,
1093
+ embedTexts,
1108
1094
  normalizeSlackEmojiName,
1109
1095
  FUNCTION_TIMEOUT_BUFFER_SECONDS,
1110
1096
  getChatConfig,
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  isSlackTeamId
3
- } from "./chunk-MCMROINU.js";
3
+ } from "./chunk-EJN6G5A2.js";
4
4
 
5
5
  // src/chat/requester.ts
6
6
  import { z } from "zod";
7
+ import { requesterSchema } from "@sentry/junior-plugin-api";
7
8
  var SLACK_USER_ID_PATTERN = /^[UW][A-Z0-9]{5,}$/;
8
9
  var EMAIL_PATTERN = /^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/;
9
10
  var exactStoredStringSchema = z.string().min(1).refine((value) => value === value.trim());
@@ -15,6 +16,10 @@ var storedSlackRequesterSchema = z.object({
15
16
  slackUserName: exactStoredStringSchema.optional(),
16
17
  teamId: exactStoredStringSchema.optional()
17
18
  }).strict();
19
+ function parseRequester(value) {
20
+ const result = requesterSchema.safeParse(value);
21
+ return result.success ? result.data : void 0;
22
+ }
18
23
  function clean(value) {
19
24
  const trimmed = value?.trim();
20
25
  return trimmed ? trimmed : void 0;
@@ -151,45 +156,32 @@ function toStoredSlackRequester(requester) {
151
156
  teamId: requester.teamId
152
157
  };
153
158
  }
154
- function createRequesterFromStoredSlackRequester(args) {
155
- const actorUserId = parseActorUserId(args.userId);
156
- const actorTeamId = parseSlackTeamId(args.teamId);
157
- if (!actorTeamId || !actorUserId) {
159
+ function createSlackResumeRequester(args) {
160
+ if (!args.requester) {
161
+ throw new Error("Stored Slack requester is required for resume");
162
+ }
163
+ if (args.requester.platform !== "slack" || args.requester.teamId !== args.teamId || args.requester.userId !== args.userId) {
164
+ throw new Error("Stored Slack requester did not match resume actor");
165
+ }
166
+ const requester = createRequester(args.requester, {
167
+ platform: "slack",
168
+ teamId: args.teamId,
169
+ userId: args.userId
170
+ });
171
+ if (!requester || requester.platform !== "slack") {
158
172
  throw new Error("Slack requester requires team and user ids");
159
173
  }
160
- const storedUserId = args.requester?.slackUserId === void 0 ? void 0 : parseActorUserId(args.requester.slackUserId);
161
- const storedTeamId = args.requester?.teamId === void 0 ? void 0 : parseSlackTeamId(args.requester.teamId);
162
- if (args.requester?.slackUserId !== void 0 && !storedUserId) {
163
- throw new Error("Stored Slack requester requires a user id");
164
- }
165
- if (args.requester?.teamId !== void 0 && !storedTeamId) {
166
- throw new Error("Stored Slack requester requires a team id");
167
- }
168
- if (storedUserId && storedUserId !== actorUserId) {
169
- throw new Error("Stored Slack requester must match actor user id");
170
- }
171
- if (storedTeamId && storedTeamId !== actorTeamId) {
172
- throw new Error("Stored Slack requester must match actor team id");
173
- }
174
- const canUseStoredProfile = Boolean(storedUserId);
175
- return createSlackRequester(
176
- actorTeamId,
177
- actorUserId,
178
- canUseStoredProfile ? {
179
- email: args.requester?.email,
180
- fullName: args.requester?.fullName,
181
- userName: args.requester?.slackUserName
182
- } : void 0
183
- );
174
+ return requester;
184
175
  }
185
176
 
186
177
  export {
187
178
  storedSlackRequesterSchema,
179
+ parseRequester,
188
180
  parseActorUserId,
189
181
  isActorUserId,
190
182
  createRequester,
191
183
  createSlackRequester,
192
184
  parseStoredSlackRequester,
193
185
  toStoredSlackRequester,
194
- createRequesterFromStoredSlackRequester
186
+ createSlackResumeRequester
195
187
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getPluginProviders
3
- } from "./chunk-2RWFUS5F.js";
3
+ } from "./chunk-ZLMBNBUG.js";
4
4
 
5
5
  // src/chat/plugins/validation.ts
6
6
  function validatePluginRegistrations(registrations) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getChatConfig
3
- } from "./chunk-FCZO7LAR.js";
3
+ } from "./chunk-T77LUIX3.js";
4
4
 
5
5
  // src/chat/state/adapter.ts
6
6
  import { createMemoryState } from "@chat-adapter/state-memory";
@@ -2,7 +2,7 @@ import {
2
2
  isRecord,
3
3
  toOptionalNumber,
4
4
  toOptionalString
5
- } from "./chunk-OK4KKR7B.js";
5
+ } from "./chunk-EJN6G5A2.js";
6
6
 
7
7
  // src/chat/state/conversation.ts
8
8
  function coerceRole(value) {
@@ -206,7 +206,11 @@ function buildConversationStatePatch(conversation) {
206
206
  };
207
207
  }
208
208
 
209
+ // src/chat/state/ttl.ts
210
+ var JUNIOR_THREAD_STATE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
211
+
209
212
  export {
213
+ JUNIOR_THREAD_STATE_TTL_MS,
210
214
  coerceThreadConversationState,
211
215
  buildConversationStatePatch
212
216
  };