@sentry/junior 0.75.0 → 0.76.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/junior.mjs +4 -66
- package/dist/agent-hooks-ZOE7RIED.js +37 -0
- package/dist/api-reference.d.ts +2 -0
- package/dist/app.js +364 -135
- package/dist/build/virtual-config.d.ts +2 -2
- package/dist/chat/agent-dispatch/runner.d.ts +2 -0
- package/dist/chat/config.d.ts +1 -0
- package/dist/chat/credentials/state-adapter-token-store.d.ts +2 -0
- package/dist/chat/credentials/user-token-store.d.ts +17 -12
- package/dist/chat/db.d.ts +8 -0
- package/dist/chat/mcp/auth-store.d.ts +2 -1
- package/dist/chat/mcp/oauth.d.ts +2 -1
- package/dist/chat/oauth-flow.d.ts +3 -1
- package/dist/chat/pi/client.d.ts +15 -7
- package/dist/chat/plugins/agent-hooks.d.ts +7 -0
- package/dist/chat/plugins/auth/oauth-request.d.ts +11 -7
- package/dist/chat/plugins/model.d.ts +9 -0
- package/dist/chat/plugins/prompt.d.ts +5 -0
- package/dist/chat/plugins/task-callback.d.ts +5 -0
- package/dist/chat/plugins/task-message.d.ts +23 -0
- package/dist/chat/plugins/task-queue.d.ts +5 -0
- package/dist/chat/plugins/task-runner.d.ts +12 -0
- package/dist/chat/plugins/task-signing.d.ts +31 -0
- package/dist/chat/prompt.d.ts +4 -0
- package/dist/chat/requester.d.ts +6 -5
- package/dist/chat/respond-helpers.d.ts +2 -0
- package/dist/chat/respond.d.ts +4 -2
- package/dist/chat/runtime/agent-continue-runner.d.ts +4 -0
- package/dist/chat/runtime/reply-executor.d.ts +5 -1
- package/dist/chat/runtime/slack-resume.d.ts +10 -2
- package/dist/chat/sentry.d.ts +1 -0
- package/dist/chat/services/mcp-auth-orchestration.d.ts +2 -1
- package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
- package/dist/chat/services/subscribed-decision.d.ts +2 -2
- package/dist/chat/services/turn-session-record.d.ts +11 -7
- package/dist/chat/slack/footer.d.ts +1 -1
- package/dist/chat/state/turn-session.d.ts +8 -5
- package/dist/chat/tools/agent-tools.d.ts +8 -1
- package/dist/chat/tools/slack/context.d.ts +2 -2
- package/dist/chat/tools/types.d.ts +4 -4
- package/dist/chat/vercel-queue-client.d.ts +3 -0
- package/dist/{chunk-C3AM4Z4J.js → chunk-2ECJXSVQ.js} +5 -5
- package/dist/{chunk-OJODNL2P.js → chunk-4SCWV7TJ.js} +2 -2
- package/dist/chunk-4UO6FK4G.js +64 -0
- package/dist/{chunk-BNJIEFQC.js → chunk-56TBVRJG.js} +2 -2
- package/dist/{chunk-OK4KKR7B.js → chunk-EJN6G5A2.js} +28 -12
- package/dist/{chunk-TQ74BATR.js → chunk-FFGXUXMD.js} +435 -111
- package/dist/{chunk-XJHDZUGD.js → chunk-JBASI5VV.js} +4 -4
- package/dist/chunk-KNFROR7R.js +127 -0
- package/dist/{chunk-VNTLUFTY.js → chunk-KOIMO7S3.js} +126 -87
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/{chunk-NPVUAXUE.js → chunk-NFTMTIP3.js} +303 -33
- package/dist/chunk-NYKJ3KON.js +1082 -0
- package/dist/{chunk-SJHUF3DP.js → chunk-OJ53FYVG.js} +2 -10
- package/dist/{chunk-62FUNJYS.js → chunk-Q6XFTRV5.js} +54 -3
- package/dist/{chunk-UJ7OTHPO.js → chunk-R6Z5XWY3.js} +12 -670
- package/dist/chunk-RV5RYIJW.js +56 -0
- package/dist/{chunk-EE6PJWY4.js → chunk-SG5WAA7H.js} +7 -5
- package/dist/chunk-ST6YNAXG.js +54 -0
- package/dist/{chunk-FCZO7LAR.js → chunk-T77LUIX3.js} +139 -153
- package/dist/{chunk-EIYL7I4S.js → chunk-VALUBQ7R.js} +22 -30
- package/dist/{chunk-OZSPLAQ4.js → chunk-XBBC6W45.js} +1 -1
- package/dist/{chunk-ZNNTSPNF.js → chunk-Y5OFBCBZ.js} +1 -1
- package/dist/{chunk-74HO27II.js → chunk-Z4CIQ3EB.js} +5 -1
- package/dist/{chunk-2RWFUS5F.js → chunk-ZLMBNBUG.js} +101 -44
- package/dist/{chunk-JEELK46E.js → chunk-ZQB37HUX.js} +11 -11
- package/dist/cli/chat.js +52 -23
- package/dist/cli/check.js +7 -7
- package/dist/cli/env.js +4 -53
- package/dist/cli/init.js +6 -1
- package/dist/cli/main.js +84 -0
- package/dist/cli/plugins.js +244 -0
- package/dist/cli/run.js +5 -52
- package/dist/cli/snapshot-warmup.js +9 -9
- package/dist/cli/upgrade.js +167 -48
- package/dist/db-7A7PFRGL.js +17 -0
- package/dist/deployment.d.ts +1 -0
- package/dist/instrumentation.js +14 -18
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +43 -22
- package/dist/plugins-PZMDS7AT.js +15 -0
- package/dist/plugins.d.ts +4 -2
- package/dist/{registry-NLZFIW23.js → registry-OIPAJU2O.js} +6 -6
- package/dist/reporting.js +34 -26
- package/dist/{runner-LUQZ5G67.js → runner-7Z4D6AKV.js} +76 -23
- package/dist/sentry-4CP5NNQ5.js +31 -0
- package/dist/validation-SLA6IGF7.js +15 -0
- package/dist/vercel.js +1 -1
- package/package.json +8 -7
- package/dist/agent-hooks-2HEB4C3Q.js +0 -33
- package/dist/chat/conversations/configured.d.ts +0 -7
- package/dist/chat/conversations/state.d.ts +0 -4
- package/dist/chat/plugins/db.d.ts +0 -31
- package/dist/chunk-2KG3PWR4.js +0 -17
- package/dist/chunk-D7NFH5GD.js +0 -570
- package/dist/chunk-MCMROINU.js +0 -12
- package/dist/chunk-WBZ4M5N5.js +0 -59
- package/dist/db-A3ILH67H.js +0 -20
- package/dist/plugins-OMJKLRJ2.js +0 -13
- 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
|
|
120
|
-
return pluginSet?.registrations.filter(
|
|
121
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
|
558
|
-
return
|
|
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 =
|
|
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":
|
|
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
|
-
|
|
656
|
+
const apiKey = getGatewayApiKey();
|
|
657
|
+
const provider = createGatewayProvider(apiKey ? { apiKey } : {});
|
|
754
658
|
try {
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
{
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
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
|
-
|
|
773
|
-
|
|
694
|
+
const providerError = createProviderError(error);
|
|
695
|
+
if (isProviderRetryError(providerError)) {
|
|
696
|
+
throw providerError;
|
|
774
697
|
}
|
|
775
698
|
logException(
|
|
776
|
-
|
|
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
|
|
709
|
+
throw providerError;
|
|
787
710
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
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":
|
|
731
|
+
"gen_ai.operation.name": GEN_AI_OPERATION_EMBEDDINGS,
|
|
798
732
|
"gen_ai.request.model": params.modelId,
|
|
799
|
-
"
|
|
800
|
-
|
|
801
|
-
|
|
733
|
+
"gen_ai.output.type": "embedding",
|
|
734
|
+
"server.address": GEN_AI_SERVER_ADDRESS,
|
|
735
|
+
"server.port": GEN_AI_SERVER_PORT
|
|
736
|
+
}
|
|
802
737
|
);
|
|
803
|
-
|
|
804
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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-
|
|
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
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
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
|
-
|
|
186
|
+
createSlackResumeRequester
|
|
195
187
|
};
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
isRecord,
|
|
3
3
|
toOptionalNumber,
|
|
4
4
|
toOptionalString
|
|
5
|
-
} from "./chunk-
|
|
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
|
};
|