@sentry/junior 0.74.1 → 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.
- 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 +3 -1
- package/dist/app.js +5516 -5422
- package/dist/build/copy-build-content.d.ts +1 -1
- package/dist/build/virtual-config.d.ts +2 -2
- package/dist/chat/agent-dispatch/context.d.ts +2 -3
- package/dist/chat/agent-dispatch/runner.d.ts +2 -0
- package/dist/chat/agent-dispatch/types.d.ts +2 -1
- package/dist/chat/config.d.ts +3 -0
- package/dist/chat/credentials/state-adapter-token-store.d.ts +2 -0
- package/dist/chat/credentials/subject.d.ts +3 -3
- 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 +20 -13
- package/dist/chat/plugins/auth/oauth-request.d.ts +11 -7
- package/dist/chat/plugins/credential-hooks.d.ts +6 -6
- package/dist/chat/plugins/logging.d.ts +2 -2
- package/dist/chat/plugins/model.d.ts +9 -0
- package/dist/chat/plugins/package-discovery.d.ts +2 -1
- package/dist/chat/plugins/prompt.d.ts +5 -0
- package/dist/chat/plugins/registry.d.ts +4 -0
- package/dist/chat/plugins/state.d.ts +3 -5
- 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/plugins/types.d.ts +1 -0
- package/dist/chat/plugins/validation.d.ts +5 -0
- package/dist/chat/prompt.d.ts +15 -1
- package/dist/chat/requester.d.ts +6 -5
- package/dist/chat/respond-helpers.d.ts +2 -0
- package/dist/chat/respond.d.ts +13 -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/runtime/slack-runtime.d.ts +6 -1
- package/dist/chat/sandbox/egress-credentials.d.ts +8 -8
- package/dist/chat/sandbox/sandbox.d.ts +2 -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/sql/db.d.ts +3 -0
- package/dist/chat/sql/executor.d.ts +7 -0
- package/dist/chat/sql/neon.d.ts +2 -4
- package/dist/chat/sql/postgres.d.ts +6 -0
- package/dist/chat/state/turn-session.d.ts +8 -5
- package/dist/chat/task-execution/state.d.ts +7 -2
- package/dist/chat/task-execution/worker.d.ts +1 -1
- package/dist/chat/tools/agent-tools.d.ts +9 -2
- package/dist/chat/tools/slack/context.d.ts +2 -2
- package/dist/chat/tools/types.d.ts +7 -4
- package/dist/chat/vercel-queue-client.d.ts +3 -0
- package/dist/{chunk-YOHFWWBV.js → chunk-2ECJXSVQ.js} +5 -107
- package/dist/{chunk-OR6NQJ5E.js → chunk-4SCWV7TJ.js} +3 -3
- package/dist/chunk-4UO6FK4G.js +64 -0
- package/dist/chunk-56TBVRJG.js +115 -0
- package/dist/{chunk-3BYAPS6B.js → chunk-EJN6G5A2.js} +17 -11
- package/dist/{chunk-SQGMG7OD.js → chunk-HHDUKWVG.js} +508 -149
- package/dist/{chunk-6UP2Z2RZ.js → chunk-JBASI5VV.js} +7 -7
- package/dist/chunk-KNFROR7R.js +127 -0
- package/dist/{chunk-HYHKTFG2.js → chunk-KOIMO7S3.js} +186 -910
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/chunk-NFTMTIP3.js +964 -0
- package/dist/chunk-NYKJ3KON.js +1082 -0
- package/dist/{chunk-SJHUF3DP.js → chunk-OJ53FYVG.js} +2 -10
- package/dist/{chunk-KVZL5NZS.js → chunk-Q3XNY442.js} +17 -7
- package/dist/{chunk-YRDS7VKO.js → chunk-Q6XFTRV5.js} +2 -2
- package/dist/chunk-R6Z5XWY3.js +1076 -0
- package/dist/chunk-RV5RYIJW.js +56 -0
- package/dist/chunk-SG5WAA7H.js +132 -0
- package/dist/chunk-ST6YNAXG.js +54 -0
- package/dist/{chunk-GM7HTXYC.js → chunk-T77LUIX3.js} +148 -151
- package/dist/{chunk-CYUI7JU5.js → chunk-VALUBQ7R.js} +22 -30
- package/dist/chunk-XBBC6W45.js +71 -0
- package/dist/chunk-Y2CM7HXH.js +111 -0
- package/dist/{chunk-F6HWCPOC.js → chunk-Y5OFBCBZ.js} +1 -1
- package/dist/{chunk-M4FLLXXD.js → chunk-Z4CIQ3EB.js} +5 -1
- package/dist/{chunk-7Q5YOUUT.js → chunk-ZLMBNBUG.js} +146 -52
- package/dist/{chunk-2LUZA3LY.js → chunk-ZQB37HUX.js} +11 -11
- package/dist/cli/chat.js +87 -8
- package/dist/cli/check.js +8 -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 +12 -11
- package/dist/cli/upgrade.js +385 -26
- package/dist/db-7A7PFRGL.js +17 -0
- package/dist/deployment.d.ts +1 -0
- package/dist/handlers/sandbox-egress-route.d.ts +4 -0
- package/dist/handlers/slack-webhook.d.ts +4 -0
- package/dist/handlers/webhooks.d.ts +6 -13
- package/dist/instrumentation.js +14 -18
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +67 -101
- package/dist/plugin-module.d.ts +21 -0
- package/dist/plugins-PZMDS7AT.js +15 -0
- package/dist/plugins.d.ts +9 -5
- package/dist/registry-OIPAJU2O.js +46 -0
- package/dist/reporting/conversations.d.ts +3 -3
- package/dist/reporting.d.ts +6 -5
- package/dist/reporting.js +42 -28
- package/dist/{runner-27NP2TEO.js → runner-KPLNHDCV.js} +77 -19
- package/dist/sentry-4CP5NNQ5.js +31 -0
- package/dist/validation-SLA6IGF7.js +15 -0
- package/dist/vercel.js +1 -1
- package/package.json +14 -11
- package/dist/chat/conversations/configured.d.ts +0 -5
- package/dist/chat/conversations/state.d.ts +0 -4
- package/dist/chunk-2KG3PWR4.js +0 -17
- package/dist/chunk-JL2SLRAT.js +0 -1970
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// src/plugins.ts
|
|
2
|
+
function cloneManifests(manifests) {
|
|
3
|
+
return manifests ? structuredClone(manifests) : void 0;
|
|
4
|
+
}
|
|
5
|
+
function cloneInlineManifests(registrations) {
|
|
6
|
+
const inlineManifests = registrations.flatMap(
|
|
7
|
+
(plugin) => plugin.manifest ? [
|
|
8
|
+
{
|
|
9
|
+
manifest: {
|
|
10
|
+
...structuredClone(plugin.manifest),
|
|
11
|
+
capabilities: plugin.manifest.capabilities?.map(
|
|
12
|
+
(capability) => capability.includes(".") ? capability : `${plugin.manifest.name}.${capability}`
|
|
13
|
+
) ?? [],
|
|
14
|
+
configKeys: plugin.manifest.configKeys?.map(
|
|
15
|
+
(key) => key.includes(".") ? key : `${plugin.manifest.name}.${key}`
|
|
16
|
+
) ?? [],
|
|
17
|
+
...plugin.manifest.target ? {
|
|
18
|
+
target: {
|
|
19
|
+
...plugin.manifest.target,
|
|
20
|
+
configKey: plugin.manifest.target.configKey.includes(".") ? plugin.manifest.target.configKey : `${plugin.manifest.name}.${plugin.manifest.target.configKey}`
|
|
21
|
+
}
|
|
22
|
+
} : {}
|
|
23
|
+
},
|
|
24
|
+
...plugin.packageName ? { packageName: plugin.packageName } : {}
|
|
25
|
+
}
|
|
26
|
+
] : []
|
|
27
|
+
);
|
|
28
|
+
return inlineManifests.length > 0 ? inlineManifests : void 0;
|
|
29
|
+
}
|
|
30
|
+
function assertUniquePluginNames(registrations) {
|
|
31
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32
|
+
for (const plugin of registrations) {
|
|
33
|
+
const name = plugin.manifest.name;
|
|
34
|
+
if (seen.has(name)) {
|
|
35
|
+
throw new Error(`Duplicate plugin registration name "${name}"`);
|
|
36
|
+
}
|
|
37
|
+
seen.add(name);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function assertUniquePackageNames(packageNames) {
|
|
41
|
+
const seen = /* @__PURE__ */ new Set();
|
|
42
|
+
for (const packageName of packageNames) {
|
|
43
|
+
if (seen.has(packageName)) {
|
|
44
|
+
throw new Error(`Duplicate plugin package name "${packageName}"`);
|
|
45
|
+
}
|
|
46
|
+
seen.add(packageName);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function normalizePluginInput(input) {
|
|
50
|
+
if (typeof input === "string") {
|
|
51
|
+
return { packageName: input };
|
|
52
|
+
}
|
|
53
|
+
return { registration: input };
|
|
54
|
+
}
|
|
55
|
+
function defineJuniorPlugins(inputs, options = {}) {
|
|
56
|
+
const normalized = inputs.map(normalizePluginInput);
|
|
57
|
+
const packageNames = normalized.flatMap(
|
|
58
|
+
(input) => input.packageName ? [input.packageName] : []
|
|
59
|
+
);
|
|
60
|
+
const registrations = normalized.flatMap(
|
|
61
|
+
(input) => input.registration ? [input.registration] : []
|
|
62
|
+
);
|
|
63
|
+
assertUniquePackageNames(packageNames);
|
|
64
|
+
assertUniquePluginNames(registrations);
|
|
65
|
+
const manifests = cloneManifests(options.manifests);
|
|
66
|
+
return {
|
|
67
|
+
packageNames,
|
|
68
|
+
registrations: registrations.map((plugin) => ({ ...plugin })),
|
|
69
|
+
...manifests ? { manifests } : {}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function pluginCatalogConfigFromPluginSet(pluginSet) {
|
|
73
|
+
if (!pluginSet) {
|
|
74
|
+
return void 0;
|
|
75
|
+
}
|
|
76
|
+
const packages = [
|
|
77
|
+
.../* @__PURE__ */ new Set([
|
|
78
|
+
...pluginSet.packageNames,
|
|
79
|
+
...pluginSet.registrations.flatMap(
|
|
80
|
+
(plugin) => plugin.packageName ? [plugin.packageName] : []
|
|
81
|
+
)
|
|
82
|
+
])
|
|
83
|
+
];
|
|
84
|
+
const manifests = cloneManifests(pluginSet.manifests);
|
|
85
|
+
const inlineManifests = cloneInlineManifests(pluginSet.registrations);
|
|
86
|
+
if (packages.length === 0 && !manifests && !inlineManifests) {
|
|
87
|
+
return void 0;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
...inlineManifests ? { inlineManifests } : {},
|
|
91
|
+
...packages.length > 0 ? { packages } : {},
|
|
92
|
+
...manifests ? { manifests } : {}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function readEnvPluginPackages(env = process.env) {
|
|
96
|
+
const value = env.JUNIOR_PLUGIN_PACKAGES;
|
|
97
|
+
if (!value) {
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
100
|
+
let parsed;
|
|
101
|
+
try {
|
|
102
|
+
parsed = JSON.parse(value);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
throw new Error("JUNIOR_PLUGIN_PACKAGES must be valid JSON", {
|
|
105
|
+
cause: error
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
if (!Array.isArray(parsed) || parsed.some((item) => typeof item !== "string" || !item.trim())) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
"JUNIOR_PLUGIN_PACKAGES must be a JSON array of package names"
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return parsed;
|
|
114
|
+
}
|
|
115
|
+
function pluginCatalogConfigFromEnv(env = process.env) {
|
|
116
|
+
const packages = readEnvPluginPackages(env);
|
|
117
|
+
return packages ? { packages } : void 0;
|
|
118
|
+
}
|
|
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) ?? [];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
defineJuniorPlugins,
|
|
128
|
+
pluginCatalogConfigFromPluginSet,
|
|
129
|
+
pluginCatalogConfigFromEnv,
|
|
130
|
+
pluginRuntimeRegistrationsFromPluginSet,
|
|
131
|
+
pluginCliRegistrationsFromPluginSet
|
|
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,12 +954,38 @@ function readBotConfig(env) {
|
|
|
983
954
|
function readJuniorDatabaseUrl(env) {
|
|
984
955
|
return toOptionalTrimmed(env.JUNIOR_DATABASE_URL) ?? toOptionalTrimmed(env.DATABASE_URL);
|
|
985
956
|
}
|
|
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) {
|
|
969
|
+
const value = toOptionalTrimmed(env.JUNIOR_DATABASE_DRIVER);
|
|
970
|
+
if (value === void 0) {
|
|
971
|
+
if (isLocalDatabaseUrl(databaseUrl)) {
|
|
972
|
+
return "postgres";
|
|
973
|
+
}
|
|
974
|
+
return "neon";
|
|
975
|
+
}
|
|
976
|
+
if (value === "neon" || value === "postgres") {
|
|
977
|
+
return value;
|
|
978
|
+
}
|
|
979
|
+
throw new Error("JUNIOR_DATABASE_DRIVER must be postgres or neon");
|
|
980
|
+
}
|
|
986
981
|
function readChatConfig(env = process.env) {
|
|
982
|
+
const databaseUrl = readJuniorDatabaseUrl(env);
|
|
987
983
|
return {
|
|
988
984
|
bot: readBotConfig(env),
|
|
989
985
|
functionMaxDurationSeconds: resolveFunctionMaxDurationSeconds(env),
|
|
990
986
|
sql: {
|
|
991
|
-
databaseUrl
|
|
987
|
+
databaseUrl,
|
|
988
|
+
driver: readSqlDriver(env, databaseUrl)
|
|
992
989
|
},
|
|
993
990
|
slack: {
|
|
994
991
|
botToken: toOptionalTrimmed(env.SLACK_BOT_TOKEN) ?? toOptionalTrimmed(env.SLACK_BOT_USER_TOKEN),
|
|
@@ -1076,7 +1073,6 @@ export {
|
|
|
1076
1073
|
isToolResultError,
|
|
1077
1074
|
isAssistantMessage,
|
|
1078
1075
|
getPiMessageRole,
|
|
1079
|
-
prependMissingRuntimeTurnContext,
|
|
1080
1076
|
hasRuntimeTurnContext,
|
|
1081
1077
|
stripRuntimeTurnContext,
|
|
1082
1078
|
extractAssistantText,
|
|
@@ -1090,10 +1086,11 @@ export {
|
|
|
1090
1086
|
GEN_AI_SERVER_PORT,
|
|
1091
1087
|
MISSING_GATEWAY_CREDENTIALS_ERROR,
|
|
1092
1088
|
getGatewayApiKey,
|
|
1093
|
-
|
|
1089
|
+
getPiGatewayApiKey,
|
|
1094
1090
|
resolveGatewayModel,
|
|
1095
1091
|
completeText,
|
|
1096
1092
|
completeObject,
|
|
1093
|
+
embedTexts,
|
|
1097
1094
|
normalizeSlackEmojiName,
|
|
1098
1095
|
FUNCTION_TIMEOUT_BUFFER_SECONDS,
|
|
1099
1096
|
getChatConfig,
|