@sentry/junior 0.203.0 → 0.205.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 (174) hide show
  1. package/dist/agent-D4nu8MQV.js +17521 -0
  2. package/dist/agent-hooks-DXHpTJ4m.js +4042 -0
  3. package/dist/agent-runner-C04colea.js +678 -0
  4. package/dist/api/schema.d.ts +2736 -2639
  5. package/dist/api/schema.js +4 -169
  6. package/dist/api.d.ts +23 -17
  7. package/dist/api.js +3881 -5326
  8. package/dist/app-Cb776lL8.d.ts +247 -0
  9. package/dist/app.d.ts +4 -520
  10. package/dist/app.js +9524 -11875
  11. package/dist/auth-pause-state-C2P3guS1.js +168 -0
  12. package/dist/catalog-runtime-CXw3asJD.js +7 -0
  13. package/dist/checkpoint-CrViJ8Ps.js +2450 -0
  14. package/dist/cli/chat.d.ts +20 -0
  15. package/dist/cli/chat.js +229 -336
  16. package/dist/cli/check.d.ts +8 -0
  17. package/dist/cli/check.js +513 -806
  18. package/dist/cli/env.d.ts +13 -0
  19. package/dist/cli/env.js +63 -12
  20. package/dist/cli/init.d.ts +3 -0
  21. package/dist/cli/init.js +90 -159
  22. package/dist/cli/main.d.ts +6 -0
  23. package/dist/cli/main.js +43 -64
  24. package/dist/cli/plugins.d.ts +13 -0
  25. package/dist/cli/plugins.js +148 -227
  26. package/dist/cli/run.d.ts +16 -0
  27. package/dist/cli/run.js +52 -8
  28. package/dist/cli/snapshot-create.d.ts +4 -0
  29. package/dist/cli/snapshot-create.js +71 -125
  30. package/dist/cli/upgrade.d.ts +15 -0
  31. package/dist/cli/upgrade.js +232 -335
  32. package/dist/config-BOtJQ7Pc.js +941 -0
  33. package/dist/context-B45_WqVX.js +298 -0
  34. package/dist/conversation-privacy-BZRA6Pes.js +182 -0
  35. package/dist/conversation-work-C6y3T5Hx.js +51 -0
  36. package/dist/credential-sync-Bep34IB_.js +2661 -0
  37. package/dist/db-BeyXKJOI.d.ts +5 -0
  38. package/dist/destinations-BeBiJeEM.js +29 -0
  39. package/dist/execution-stats-B6lgWxCK.js +373 -0
  40. package/dist/executor-BlUhFL7_.js +721 -0
  41. package/dist/experimental-CIXf7Uye.js +46 -0
  42. package/dist/history-ClE4toxe.d.ts +32 -0
  43. package/dist/history-CqTuSAdI.js +441 -0
  44. package/dist/instrumentation.d.ts +3 -3
  45. package/dist/instrumentation.js +130 -176
  46. package/dist/job-queue-DLMqIK74.js +63 -0
  47. package/dist/logging-BMJzdDlP.js +1210 -0
  48. package/dist/model-profile-CZmVoGdX.js +49 -0
  49. package/dist/nitro.d.ts +31 -36
  50. package/dist/nitro.js +275 -456
  51. package/dist/oauth-callback-server-WwG5_Zgm.js +130 -0
  52. package/dist/oauth-relay-CdCnu80W.js +62 -0
  53. package/dist/package-discovery-7a9YqLhE.js +455 -0
  54. package/dist/pending-auth-CUbXq06G.js +185 -0
  55. package/dist/plugin-module-BKGOXca2.js +81 -0
  56. package/dist/plugins-BI9A1vKA.d.ts +95 -0
  57. package/dist/plugins-egKWjgue.js +99 -0
  58. package/dist/private-trace-result-BLvBjy_e.js +16 -0
  59. package/dist/profile-T0tXE4zu.js +861 -0
  60. package/dist/registry-BA0__8ai.js +1419 -0
  61. package/dist/reporting-schema-DosTN__Q.js +105 -0
  62. package/dist/resolve-bvD1ORdv.js +546 -0
  63. package/dist/rolldown-runtime-B4FMCO8f.js +28 -0
  64. package/dist/runner-BXYxfIUL.js +392 -0
  65. package/dist/sandbox-egress-signals-ngEPjSEW.js +46 -0
  66. package/dist/schema-Rn8-XEaN.js +1140 -0
  67. package/dist/sentry-CD3SdJl-.js +26 -0
  68. package/dist/skills-DJOlYdBs.js +316 -0
  69. package/dist/spawn-h0R1bTEo.js +29 -0
  70. package/dist/stats-3YZn-Swi.js +2648 -0
  71. package/dist/store-C5qxF2ac.d.ts +208 -0
  72. package/dist/task-queue-CoXwd2eq.js +136 -0
  73. package/dist/task-runner-B2_mJZj0.js +639 -0
  74. package/dist/thread-state-CqZ1m-es.js +431 -0
  75. package/dist/turn-execution-fI6PZ0iI.js +47 -0
  76. package/dist/turn-lifecycle-CcnwrOcp.js +54 -0
  77. package/dist/usage-B5SfMb3H.js +296 -0
  78. package/dist/usage-schema-CKaDkH_j.js +20 -0
  79. package/dist/validation-DfWcvhuS.js +40 -0
  80. package/dist/vercel-queue-DIkVcfK4.js +167 -0
  81. package/dist/vercel.d.ts +6 -6
  82. package/dist/vercel.js +14 -6
  83. package/dist/version-CnXZ614E.d.ts +5 -0
  84. package/dist/version-oD-oPrbO.js +8 -0
  85. package/dist/version.d.ts +2 -4
  86. package/dist/version.js +2 -6
  87. package/dist/web-authorization-Crbzlmzo.js +76 -0
  88. package/dist/web-input-BOuq3oKK.js +494 -0
  89. package/dist/work-B91LQKHr.js +509 -0
  90. package/dist/worker-BcRRTe6k.js +625 -0
  91. package/package.json +9 -9
  92. package/dist/agent-hooks-GB2VPTNA.js +0 -51
  93. package/dist/catalog-runtime-UBLIWD3O.js +0 -14
  94. package/dist/chunk-2LYHWMR4.js +0 -46
  95. package/dist/chunk-352OWAZH.js +0 -320
  96. package/dist/chunk-3Y47VMHV.js +0 -6
  97. package/dist/chunk-3YJSKOWF.js +0 -164
  98. package/dist/chunk-4KSSKTQ5.js +0 -229
  99. package/dist/chunk-4UO6FK4G.js +0 -64
  100. package/dist/chunk-5AHX53NQ.js +0 -717
  101. package/dist/chunk-5J3E5FWA.js +0 -700
  102. package/dist/chunk-5PDAG6O3.js +0 -206
  103. package/dist/chunk-6Y5B5PEX.js +0 -80
  104. package/dist/chunk-7GWQ5S5R.js +0 -2086
  105. package/dist/chunk-7H2VZTWN.js +0 -103
  106. package/dist/chunk-7NL7T6VU.js +0 -406
  107. package/dist/chunk-A5L27LE4.js +0 -387
  108. package/dist/chunk-ADIAWL34.js +0 -81
  109. package/dist/chunk-ASTEMBKJ.js +0 -519
  110. package/dist/chunk-CEMMLV5L.js +0 -98
  111. package/dist/chunk-CM5HNV2W.js +0 -131
  112. package/dist/chunk-CRTRBBRI.js +0 -105
  113. package/dist/chunk-DA2KGZZI.js +0 -13
  114. package/dist/chunk-DIB4GX3G.js +0 -8
  115. package/dist/chunk-DKIJ2RP5.js +0 -68
  116. package/dist/chunk-DWPN6SCH.js +0 -172
  117. package/dist/chunk-EDKUFGPL.js +0 -64
  118. package/dist/chunk-ENY6SKIU.js +0 -1228
  119. package/dist/chunk-F4MGCZOX.js +0 -2943
  120. package/dist/chunk-FA6POGLH.js +0 -70
  121. package/dist/chunk-FSUR7GTG.js +0 -20475
  122. package/dist/chunk-GKEOHJL5.js +0 -1856
  123. package/dist/chunk-GMCB6W5Y.js +0 -333
  124. package/dist/chunk-IE2VPG7O.js +0 -1135
  125. package/dist/chunk-IZ5B5IHQ.js +0 -3656
  126. package/dist/chunk-JAL3CH4G.js +0 -27
  127. package/dist/chunk-KIIEUXD3.js +0 -1764
  128. package/dist/chunk-KXU4NIL7.js +0 -692
  129. package/dist/chunk-MTM5IFCY.js +0 -1190
  130. package/dist/chunk-N7TMSOZH.js +0 -235
  131. package/dist/chunk-NCEBK6PH.js +0 -36
  132. package/dist/chunk-NHJU2ZAL.js +0 -56
  133. package/dist/chunk-P6KTRNVC.js +0 -321
  134. package/dist/chunk-PDO5BLNM.js +0 -22
  135. package/dist/chunk-PDRNLLFT.js +0 -3295
  136. package/dist/chunk-PEQXYSSE.js +0 -45
  137. package/dist/chunk-PKEX2AQX.js +0 -198
  138. package/dist/chunk-PSJCGIGO.js +0 -1163
  139. package/dist/chunk-PZUSUL55.js +0 -506
  140. package/dist/chunk-R45M4TUS.js +0 -37
  141. package/dist/chunk-RC745GGZ.js +0 -122
  142. package/dist/chunk-SP3QKZXJ.js +0 -820
  143. package/dist/chunk-TXKUKMVO.js +0 -417
  144. package/dist/chunk-UE4GPWSD.js +0 -931
  145. package/dist/chunk-UIE3R5XU.js +0 -17
  146. package/dist/chunk-UXPG6ZIN.js +0 -84
  147. package/dist/chunk-VFUK3X5B.js +0 -50
  148. package/dist/chunk-VNMJWREK.js +0 -787
  149. package/dist/chunk-VZ7CSOX2.js +0 -706
  150. package/dist/chunk-WCNQJKFT.js +0 -10
  151. package/dist/chunk-WDZR3QQM.js +0 -135
  152. package/dist/chunk-WLYVJCHV.js +0 -1433
  153. package/dist/chunk-WS7NAFTM.js +0 -1520
  154. package/dist/chunk-X6GDDWQH.js +0 -60
  155. package/dist/chunk-XPDEYNQI.js +0 -102
  156. package/dist/chunk-XRW44VGM.js +0 -58
  157. package/dist/chunk-Y2CM7HXH.js +0 -111
  158. package/dist/chunk-Y7X25LFY.js +0 -15
  159. package/dist/conversation-work-VIOQ5ZF3.js +0 -54
  160. package/dist/db-NGDJV7YH.js +0 -26
  161. package/dist/discovery-DWVDM7UK.js +0 -44
  162. package/dist/experimental-P5FZM4CU.js +0 -12
  163. package/dist/oauth-callback-server-YFY7YEGK.js +0 -243
  164. package/dist/oauth-relay-5XPVRPYB.js +0 -8
  165. package/dist/plugins-YTYJMMJF.js +0 -14
  166. package/dist/runner-ORTNSB2Q.js +0 -522
  167. package/dist/sandbox-egress-signals-FIL7EGPR.js +0 -73
  168. package/dist/sentry-MB3NL3IR.js +0 -42
  169. package/dist/skills-H376WQOH.js +0 -27
  170. package/dist/spawn-T43WHLOS.js +0 -42
  171. package/dist/task-runner-LBZWF32V.js +0 -36
  172. package/dist/validation-REJLRKI6.js +0 -17
  173. package/dist/work-3KJ3RE76.js +0 -51
  174. package/dist/worker-QFEBU72E.js +0 -24
@@ -1,1228 +0,0 @@
1
- import {
2
- TURN_REASONING_LEVELS,
3
- modelProfileSchema,
4
- parseTurnReasoningLevel
5
- } from "./chunk-NHJU2ZAL.js";
6
- import {
7
- getCurrentConversationPrivacy,
8
- toCanonicalInputMessage,
9
- toCanonicalOutputMessage,
10
- toGenAiMessagesTraceAttributes
11
- } from "./chunk-PKEX2AQX.js";
12
- import {
13
- extractGenAiUsageAttributes,
14
- logException,
15
- logWarn,
16
- normalizeGenAiFinishReason,
17
- serializeGenAiAttribute,
18
- withSpan
19
- } from "./chunk-WS7NAFTM.js";
20
-
21
- // src/chat/services/provider-error.ts
22
- var ProviderError = class extends Error {
23
- code = "provider_error";
24
- kind;
25
- modelId;
26
- retryable;
27
- retryAfterMs;
28
- status;
29
- constructor(details) {
30
- super(
31
- `AI provider error: ${details.kind}`,
32
- details.cause !== void 0 ? { cause: details.cause } : {}
33
- );
34
- this.name = "ProviderError";
35
- this.kind = details.kind;
36
- this.modelId = details.modelId;
37
- this.retryable = details.retryable;
38
- this.retryAfterMs = details.retryAfterMs;
39
- this.status = details.status;
40
- }
41
- };
42
- var NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
43
- "ECONNREFUSED",
44
- "ECONNRESET",
45
- "ENOTFOUND",
46
- "EAI_AGAIN"
47
- ]);
48
- var TIMEOUT_ERROR_CODES = /* @__PURE__ */ new Set([
49
- "ETIMEDOUT",
50
- "ECONNABORTED",
51
- "ESOCKETTIMEDOUT"
52
- ]);
53
- var CONTENT_POLICY_PATTERN = /\b(?:content|safety)[ _-]?policy\b|\b(?:content|safety) (?:filter|violation)\b|\bmoderation (?:blocked|rejected|refused)\b/i;
54
- var QUOTA_PATTERN = /insufficient.?quota|quota exceeded|usage limit|available balance|out of budget|billing (?:limit|quota|error)|payment required/i;
55
- var AUTH_PATTERN = /unauthenticated|invalid.?api.?key|no api key|authentication (?:failed|error|required)|(?:invalid|missing|expired|revoked).{0,24}\bcredentials?\b|\bcredentials?\b.{0,24}(?:invalid|missing|expired|revoked)|\bno\b.{0,16}\bcredentials?\b/i;
56
- var PERMISSION_PATTERN = /permission denied|forbidden|not authorized|authorization (?:failed|required|denied)/i;
57
- var INVALID_REQUEST_PATTERN = /context.?length|context.?window|validation (?:error|failed)|bad request|unsupported model|invalid model|unknown (?:ai gateway )?model|mismatched api/i;
58
- var CAPACITY_PATTERN = /overloaded|at capacity|capacity exceeded/i;
59
- var TIMEOUT_PATTERN = /timed? out|timeout|gateway timeout/i;
60
- var NETWORK_PATTERN = /network.?error|connection (?:error|refused|lost|closed)|fetch failed|socket (?:hang up|closed)|stream ended before/i;
61
- var SERVER_PATTERN = /service(?: temporarily)?[ _-]?unavailable|server.?error|internal.?error|bad gateway|upstream (?:request )?failed/i;
62
- var TERMINAL_KINDS = /* @__PURE__ */ new Set([
63
- "auth",
64
- "permission",
65
- "invalid_request",
66
- "invalid_response",
67
- "quota",
68
- "content_policy"
69
- ]);
70
- var RETRYABLE_KINDS = /* @__PURE__ */ new Set([
71
- "rate_limit",
72
- "capacity",
73
- "timeout",
74
- "network",
75
- "server"
76
- ]);
77
- function providerMessage(error) {
78
- return (error instanceof Error ? error.message : String(error)).trim();
79
- }
80
- var PROVIDER_ERROR_SUMMARY_MAX_CHARS = 240;
81
- function summarizeProviderErrorMessage(message) {
82
- const normalized = message.trim().replace(/\s+/g, " ");
83
- if (!normalized) return void 0;
84
- const jsonStart = normalized.indexOf("{");
85
- const summary = (jsonStart >= 0 ? normalized.slice(0, jsonStart) : normalized).trim();
86
- if (!summary) return void 0;
87
- return summary.length > PROVIDER_ERROR_SUMMARY_MAX_CHARS ? `${summary.slice(0, PROVIDER_ERROR_SUMMARY_MAX_CHARS)}...` : summary;
88
- }
89
- function extractTransportKind(error, depth = 0) {
90
- if (!(error instanceof Error) || depth > 4) return void 0;
91
- const providerError = error;
92
- const code = typeof providerError.code === "string" ? providerError.code.toUpperCase() : void 0;
93
- if (code && TIMEOUT_ERROR_CODES.has(code)) return "timeout";
94
- if (code && NETWORK_ERROR_CODES.has(code)) return "network";
95
- return extractTransportKind(providerError.cause, depth + 1);
96
- }
97
- function extractStatus(error, message) {
98
- if (error instanceof Error) {
99
- const providerError = error;
100
- if (typeof providerError.status === "number") return providerError.status;
101
- if (typeof providerError.statusCode === "number") return providerError.statusCode;
102
- }
103
- const match = message.match(
104
- /^(?:Error:\s*)?([45]\d\d)\b|\bstatus(?:Code)?["'=:\s]+([45]\d\d)\b/i
105
- );
106
- const status = match?.[1] ?? match?.[2];
107
- return status ? Number(status) : void 0;
108
- }
109
- function extractRetryAfterMs(error, message) {
110
- const headers = error instanceof Error ? error.responseHeaders ?? error.response?.headers : void 0;
111
- const retryAfter = headers instanceof Headers ? headers.get("retry-after") : headers && typeof headers === "object" ? Object.entries(headers).find(
112
- ([name]) => name.toLowerCase() === "retry-after"
113
- )?.[1] : void 0;
114
- const raw = typeof retryAfter === "string" || typeof retryAfter === "number" ? String(retryAfter) : message.match(/"retry-after"\s*:\s*"?([^",}]+)"?/i)?.[1];
115
- if (!raw) return void 0;
116
- const seconds = Number(raw);
117
- if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
118
- const date = Date.parse(raw);
119
- return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
120
- }
121
- function classifyProviderError(status, message, transportKind) {
122
- if (CONTENT_POLICY_PATTERN.test(message)) return "content_policy";
123
- if (QUOTA_PATTERN.test(message)) return "quota";
124
- if (status === 401 || AUTH_PATTERN.test(message)) return "auth";
125
- if (status === 403 || PERMISSION_PATTERN.test(message)) return "permission";
126
- if (INVALID_REQUEST_PATTERN.test(message)) return "invalid_request";
127
- if (status === 429 || /rate.?limit|too many requests/i.test(message)) {
128
- return "rate_limit";
129
- }
130
- if (status === 408) return "timeout";
131
- if (CAPACITY_PATTERN.test(message)) return "capacity";
132
- if (transportKind === "timeout" || TIMEOUT_PATTERN.test(message))
133
- return "timeout";
134
- if (transportKind === "network" || NETWORK_PATTERN.test(message))
135
- return "network";
136
- if (status !== void 0 && status >= 500 || SERVER_PATTERN.test(message)) {
137
- return "server";
138
- }
139
- if (status !== void 0 && status >= 400) {
140
- return "invalid_request";
141
- }
142
- return "unknown";
143
- }
144
- function createProviderError(error, options = {}) {
145
- if (error instanceof ProviderError) return error;
146
- const message = providerMessage(error);
147
- const status = extractStatus(error, message);
148
- const kind = options.kind ?? classifyProviderError(status, message, extractTransportKind(error));
149
- const retryable = !TERMINAL_KINDS.has(kind) && (options.retryable ?? RETRYABLE_KINDS.has(kind));
150
- return new ProviderError({
151
- cause: error,
152
- kind,
153
- modelId: options.modelId,
154
- retryable,
155
- retryAfterMs: extractRetryAfterMs(error, message),
156
- status
157
- });
158
- }
159
- function isProviderRetryError(error) {
160
- return error instanceof ProviderError && error.retryable;
161
- }
162
- function findProviderError(error) {
163
- const visited = /* @__PURE__ */ new Set();
164
- let current = error;
165
- while (current instanceof Error && !visited.has(current)) {
166
- if (current instanceof ProviderError) {
167
- return current;
168
- }
169
- visited.add(current);
170
- current = current.cause;
171
- }
172
- return void 0;
173
- }
174
- function getProviderErrorUserMessage(error) {
175
- switch (error.kind) {
176
- case "capacity":
177
- return "The selected model is temporarily unavailable because it is at capacity. Please try again shortly.";
178
- case "rate_limit": {
179
- const seconds = error.retryAfterMs ? Math.max(1, Math.ceil(error.retryAfterMs / 1e3)) : void 0;
180
- return seconds ? `The model is rate-limited. Please try again in about ${seconds} seconds.` : "The model is rate-limited. Please try again shortly.";
181
- }
182
- case "timeout":
183
- case "network":
184
- case "server":
185
- return "The model provider had a temporary connection problem. Please try again.";
186
- case "auth":
187
- return "The model provider rejected Junior's credentials. This needs an administrator or configuration fix.";
188
- case "permission":
189
- return "The model provider denied access to this model or request. Ask an administrator to check model access, organization policy, and region availability.";
190
- case "quota":
191
- return "The model provider's usage quota has been exhausted. This needs an administrator or billing configuration fix.";
192
- case "content_policy":
193
- return "The model provider blocked this request under its content policy. Please revise the request and try again.";
194
- case "invalid_request":
195
- return "The model provider rejected this request as invalid. Please revise the request or ask an administrator to check the model configuration.";
196
- case "invalid_response":
197
- return "The model provider returned an invalid response. Please try again.";
198
- default:
199
- return "";
200
- }
201
- }
202
- function getProviderErrorAttributes(error) {
203
- const cause = error.cause;
204
- const causeMessage = cause instanceof Error ? cause.message : typeof cause === "string" ? cause : void 0;
205
- const summary = causeMessage ? summarizeProviderErrorMessage(causeMessage) : void 0;
206
- return {
207
- "app.ai.provider_error.kind": error.kind,
208
- "app.ai.provider_error.retryable": error.retryable,
209
- ...error.status !== void 0 ? { "app.ai.provider_error.status": error.status } : void 0,
210
- ...error.retryAfterMs !== void 0 ? { "app.ai.provider_error.retry_after_ms": error.retryAfterMs } : void 0,
211
- ...summary ? { "app.ai.provider_error.summary": summary } : void 0,
212
- ...error.modelId ? { "gen_ai.request.model": error.modelId } : void 0
213
- };
214
- }
215
-
216
- // src/chat/config.ts
217
- import { getModel as getModel2 } from "@earendil-works/pi-ai/compat";
218
-
219
- // src/chat/optional-string.ts
220
- function toOptionalTrimmed(value) {
221
- if (!value) {
222
- return void 0;
223
- }
224
- const trimmed = value.trim();
225
- return trimmed.length > 0 ? trimmed : void 0;
226
- }
227
-
228
- // src/chat/pi/sdk.ts
229
- import {
230
- calculateCost,
231
- completeSimple,
232
- getEnvApiKey,
233
- getModel,
234
- getModels,
235
- isRetryableAssistantError,
236
- registerApiProvider
237
- } from "@earendil-works/pi-ai/compat";
238
- import {
239
- stream,
240
- streamSimple
241
- } from "@earendil-works/pi-ai/api/anthropic-messages";
242
-
243
- // src/chat/pi/client.ts
244
- import { createGatewayProvider } from "@ai-sdk/gateway";
245
-
246
- // src/chat/pi/gateway-auth.ts
247
- import { getVercelOidcToken } from "@vercel/oidc";
248
- var MISSING_GATEWAY_CREDENTIALS_ERROR = "Missing AI gateway credentials (enable Vercel OIDC or set AI_GATEWAY_API_KEY)";
249
- async function resolveGatewayCredential() {
250
- try {
251
- const oidcToken = toOptionalTrimmed(await getVercelOidcToken());
252
- if (oidcToken) {
253
- return { mode: "oidc", token: oidcToken };
254
- }
255
- } catch {
256
- }
257
- const apiKey = toOptionalTrimmed(getEnvApiKey("vercel-ai-gateway"));
258
- if (apiKey) {
259
- return { mode: "api_key", token: apiKey };
260
- }
261
- return void 0;
262
- }
263
- async function getGatewayApiKey() {
264
- return (await resolveGatewayCredential())?.token;
265
- }
266
-
267
- // src/chat/pi/client.ts
268
- import {
269
- embedMany,
270
- generateObject,
271
- NoObjectGeneratedError
272
- } from "ai";
273
-
274
- // src/chat/xml.ts
275
- function escapeXml(value) {
276
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
277
- }
278
- function unescapeXml(value) {
279
- return value.replaceAll("&quot;", '"').replaceAll("&apos;", "'").replaceAll("&gt;", ">").replaceAll("&lt;", "<").replaceAll("&amp;", "&");
280
- }
281
-
282
- // src/chat/current-instruction.ts
283
- var CURRENT_INSTRUCTION_TAG = "current-instruction";
284
- var CURRENT_INSTRUCTION_OPEN_PREFIX = `<${CURRENT_INSTRUCTION_TAG}`;
285
- var CURRENT_INSTRUCTION_OPEN_BARE = `<${CURRENT_INSTRUCTION_TAG}>`;
286
- var CURRENT_INSTRUCTION_OPEN_ATTR_PREFIX = `<${CURRENT_INSTRUCTION_TAG} `;
287
- var CURRENT_INSTRUCTION_CLOSE = `
288
- </${CURRENT_INSTRUCTION_TAG}>`;
289
- function isCurrentInstructionOpeningTag(value) {
290
- return value === CURRENT_INSTRUCTION_OPEN_BARE || value.startsWith(CURRENT_INSTRUCTION_OPEN_ATTR_PREFIX) && value.endsWith(">");
291
- }
292
- function readCurrentInstructionBody(text) {
293
- const start = text.indexOf(CURRENT_INSTRUCTION_OPEN_PREFIX);
294
- if (start < 0) {
295
- return void 0;
296
- }
297
- const openingEnd = text.indexOf(">\n", start);
298
- if (openingEnd < 0) {
299
- return void 0;
300
- }
301
- const openingTag = text.slice(start, openingEnd + 1);
302
- if (!isCurrentInstructionOpeningTag(openingTag)) {
303
- return void 0;
304
- }
305
- const bodyStart = openingEnd + 2;
306
- const bodyEnd = text.indexOf(CURRENT_INSTRUCTION_CLOSE, bodyStart);
307
- if (bodyEnd < bodyStart) {
308
- return void 0;
309
- }
310
- return text.slice(bodyStart, bodyEnd);
311
- }
312
- function renderCurrentInstruction(instruction, attrs) {
313
- const renderedAttrs = [
314
- attrs?.authorId ? `author_id="${escapeXml(attrs.authorId)}"` : void 0,
315
- attrs?.authorName ? `author_name="${escapeXml(attrs.authorName)}"` : void 0,
316
- attrs?.slackTs ? `slack_ts="${escapeXml(attrs.slackTs)}"` : void 0
317
- ].filter((attr) => Boolean(attr)).join(" ");
318
- const openingTag = renderedAttrs ? `<${CURRENT_INSTRUCTION_TAG} ${renderedAttrs}>` : `<${CURRENT_INSTRUCTION_TAG}>`;
319
- return [
320
- openingTag,
321
- escapeXml(instruction),
322
- `</${CURRENT_INSTRUCTION_TAG}>`
323
- ].join("\n");
324
- }
325
- function unwrapCurrentInstruction(text) {
326
- const body = readCurrentInstructionBody(text);
327
- return body === void 0 ? void 0 : unescapeXml(body);
328
- }
329
-
330
- // src/chat/services/context-compaction-marker.ts
331
- var COMPACTION_SUMMARY_PREFIX = "Context compaction summary for future Junior turns:";
332
- var ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX = "Active-turn context checkpoint. If no newer user instruction follows this checkpoint, continue the same unfinished task now using the authoritative instructions above and this summary as internal continuation state. If a newer user instruction follows, treat this checkpoint as prior context and follow that newer instruction. Do not reply with a plan or summary solely because this checkpoint appeared:";
333
- var MODEL_HANDOFF_SUMMARY_PREFIX = "Model handoff checkpoint. Continue the outstanding request now using this summary as the complete prior context:";
334
- function isCompactionSummaryText(text) {
335
- const normalized = (unwrapCurrentInstruction(text) ?? text).trimStart();
336
- return normalized.startsWith(COMPACTION_SUMMARY_PREFIX) || normalized.startsWith(ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX) || normalized.startsWith(MODEL_HANDOFF_SUMMARY_PREFIX);
337
- }
338
- function hasCompactedConversationContext(messages) {
339
- return messages.some((message) => {
340
- const content = message.content;
341
- if (typeof content === "string") {
342
- return isCompactionSummaryText(content);
343
- }
344
- if (!Array.isArray(content)) {
345
- return false;
346
- }
347
- return content.some(
348
- (part) => part && typeof part === "object" && part.type === "text" && typeof part.text === "string" && isCompactionSummaryText(part.text)
349
- );
350
- });
351
- }
352
-
353
- // src/chat/pi/client.ts
354
- registerApiProvider({
355
- api: "anthropic-messages",
356
- stream,
357
- streamSimple
358
- });
359
- var GATEWAY_PROVIDER = "vercel-ai-gateway";
360
- var GEN_AI_PROVIDER_NAME = GATEWAY_PROVIDER;
361
- var GEN_AI_SERVER_ADDRESS = "ai-gateway.vercel.sh";
362
- var GEN_AI_SERVER_PORT = 443;
363
- var GEN_AI_OPERATION_CHAT = "chat";
364
- var GEN_AI_OPERATION_EMBEDDINGS = "embeddings";
365
- var EMBEDDING_INPUT_COST_USD_PER_MILLION_TOKENS = {
366
- "cohere/embed-v4.0": 0.12,
367
- "google/gemini-embedding-001": 0.15,
368
- "google/text-embedding-005": 0.025,
369
- "mistral/mistral-embed": 0.1,
370
- "openai/text-embedding-3-large": 0.13,
371
- "openai/text-embedding-3-small": 0.02,
372
- "openai/text-embedding-ada-002": 0.1,
373
- "voyage/voyage-3.5": 0.06,
374
- "voyage/voyage-3.5-lite": 0.02
375
- };
376
- function embeddingCostUsd(modelId, inputTokens) {
377
- const costPerMillionTokens = EMBEDDING_INPUT_COST_USD_PER_MILLION_TOKENS[modelId];
378
- return costPerMillionTokens === void 0 ? void 0 : inputTokens * costPerMillionTokens / 1e6;
379
- }
380
- function extractText(message) {
381
- return (message.content ?? []).filter((part) => part.type === "text" && typeof part.text === "string").map((part) => part.text ?? "").join("").trim();
382
- }
383
- function resolveGatewayModel(modelId) {
384
- const matched = getModels(GATEWAY_PROVIDER).find(
385
- (model) => model.id === modelId
386
- );
387
- if (!matched) {
388
- throw new Error(`Unknown AI Gateway model id: ${modelId}`);
389
- }
390
- return matched;
391
- }
392
- async function completeText(params) {
393
- const model = resolveGatewayModel(params.modelId);
394
- const credential = await resolveGatewayCredential();
395
- const apiKey = credential?.token;
396
- const authMode = credential?.mode ?? "api_key";
397
- const effectivePrivacy = getCurrentConversationPrivacy() ?? "private";
398
- const messageAttributeMode = params.messageAttributeMode ?? (effectivePrivacy === "public" ? "content" : "metadata");
399
- const requestMessagesAttribute = messageAttributeMode === "content" ? serializeGenAiAttribute(params.messages.map(toCanonicalInputMessage)) : void 0;
400
- const systemInstructionsAttribute = params.system && messageAttributeMode === "content" ? serializeGenAiAttribute([{ type: "text", content: params.system }]) : void 0;
401
- const baseAttributes = {
402
- "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
403
- "gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
404
- "gen_ai.request.model": params.modelId,
405
- "gen_ai.output.type": "text",
406
- ...params.promptName ? { "gen_ai.prompt.name": params.promptName } : void 0,
407
- "server.address": GEN_AI_SERVER_ADDRESS,
408
- "server.port": GEN_AI_SERVER_PORT,
409
- ...hasCompactedConversationContext(params.messages) ? { "gen_ai.conversation.compacted": true } : void 0,
410
- "app.conversation.privacy": effectivePrivacy,
411
- ...params.thinkingLevel ? { "gen_ai.request.reasoning.level": params.thinkingLevel } : void 0,
412
- ...params.temperature !== void 0 ? { "gen_ai.request.temperature": params.temperature } : void 0,
413
- ...params.maxTokens !== void 0 ? { "gen_ai.request.max_tokens": params.maxTokens } : void 0
414
- };
415
- const startAttributes = {
416
- ...baseAttributes,
417
- ...toGenAiMessagesTraceAttributes("gen_ai.input", params.messages),
418
- ...params.system ? { "gen_ai.system_instructions.content_chars": params.system.length } : void 0,
419
- ...systemInstructionsAttribute ? { "gen_ai.system_instructions": systemInstructionsAttribute } : void 0,
420
- ...requestMessagesAttribute ? { "gen_ai.input.messages": requestMessagesAttribute } : void 0,
421
- "gen_ai.provider.auth_mode": authMode
422
- };
423
- return withSpan(
424
- `${GEN_AI_OPERATION_CHAT} ${params.modelId}`,
425
- "gen_ai.chat",
426
- logContextFromMetadata(params.modelId, params.metadata),
427
- async (setSpanAttributes) => {
428
- let message;
429
- try {
430
- message = await completeSimple(
431
- model,
432
- {
433
- systemPrompt: params.system,
434
- messages: params.messages
435
- },
436
- {
437
- ...apiKey ? { apiKey } : void 0,
438
- temperature: params.temperature,
439
- maxTokens: params.maxTokens,
440
- reasoning: params.thinkingLevel,
441
- signal: params.signal,
442
- metadata: params.metadata
443
- }
444
- );
445
- } catch (error) {
446
- throw createProviderError(error, { modelId: params.modelId });
447
- }
448
- const outputText = extractText(message);
449
- const outputMessagesAttribute = serializeGenAiAttribute(
450
- messageAttributeMode === "content" ? [toCanonicalOutputMessage(message)] : void 0
451
- );
452
- const usageAttributes = extractGenAiUsageAttributes(message);
453
- const endAttributes = {
454
- ...baseAttributes,
455
- ...toGenAiMessagesTraceAttributes("gen_ai.output", [
456
- {
457
- role: "assistant",
458
- content: outputText ? [{ type: "text", text: outputText }] : []
459
- }
460
- ]),
461
- ...outputMessagesAttribute ? { "gen_ai.output.messages": outputMessagesAttribute } : void 0,
462
- ...usageAttributes,
463
- ...message.stopReason ? {
464
- "gen_ai.response.finish_reasons": [
465
- normalizeGenAiFinishReason(message.stopReason)
466
- ]
467
- } : void 0,
468
- ...message.model ? { "gen_ai.response.model": message.model } : void 0
469
- };
470
- setSpanAttributes(endAttributes);
471
- if (message.stopReason === "error") {
472
- const providerMessage2 = message.errorMessage?.trim() || "Unknown provider error";
473
- logWarn("ai.completion.provider_error", {
474
- ...baseAttributes,
475
- "exception.message": providerMessage2
476
- });
477
- throw createProviderError(providerMessage2, { modelId: params.modelId });
478
- }
479
- return {
480
- message,
481
- text: outputText
482
- };
483
- },
484
- startAttributes
485
- );
486
- }
487
- function logContextFromMetadata(modelId, metadata) {
488
- const conversationId = typeof metadata?.conversationId === "string" ? metadata.conversationId : typeof metadata?.threadId === "string" ? metadata.threadId : void 0;
489
- const messageConversationId = typeof metadata?.threadId === "string" ? metadata.threadId : void 0;
490
- const destinationName = typeof metadata?.channelId === "string" ? metadata.channelId : void 0;
491
- const runId = typeof metadata?.runId === "string" ? metadata.runId : void 0;
492
- return {
493
- modelId,
494
- ...conversationId ? { conversationId } : void 0,
495
- ...messageConversationId ? { messageConversationId } : void 0,
496
- ...destinationName ? { destinationName } : void 0,
497
- ...runId ? { runId } : void 0
498
- };
499
- }
500
- function objectCompletionCost(modelId, usage) {
501
- const cacheRead = usage.inputTokenDetails.cacheReadTokens;
502
- const cacheWrite = usage.inputTokenDetails.cacheWriteTokens;
503
- const input = usage.inputTokenDetails.noCacheTokens ?? (usage.inputTokens === void 0 ? void 0 : Math.max(0, usage.inputTokens - (cacheRead ?? 0) - (cacheWrite ?? 0)));
504
- if (input === void 0 && usage.outputTokens === void 0 && cacheRead === void 0 && cacheWrite === void 0) {
505
- return void 0;
506
- }
507
- return calculateCost(resolveGatewayModel(modelId), {
508
- input: input ?? 0,
509
- output: usage.outputTokens ?? 0,
510
- cacheRead: cacheRead ?? 0,
511
- cacheWrite: cacheWrite ?? 0,
512
- ...usage.outputTokenDetails.reasoningTokens !== void 0 ? { reasoning: usage.outputTokenDetails.reasoningTokens } : void 0,
513
- totalTokens: usage.totalTokens ?? (input ?? 0) + (usage.outputTokens ?? 0) + (cacheRead ?? 0) + (cacheWrite ?? 0),
514
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
515
- }).total;
516
- }
517
- function bestEffortObjectCompletionCost(modelId, usage) {
518
- try {
519
- return objectCompletionCost(modelId, usage);
520
- } catch (error) {
521
- logWarn("ai.completion.cost_estimate.failed", {
522
- "exception.message": error instanceof Error ? error.message : String(error),
523
- "gen_ai.request.model": modelId
524
- });
525
- return void 0;
526
- }
527
- }
528
- async function completeObject(params) {
529
- const credential = await resolveGatewayCredential();
530
- const provider = createGatewayProvider(
531
- credential ? { apiKey: credential.token } : {}
532
- );
533
- let result;
534
- try {
535
- result = await withSpan(
536
- `${GEN_AI_OPERATION_CHAT} ${params.modelId}`,
537
- "gen_ai.chat",
538
- logContextFromMetadata(params.modelId, params.metadata),
539
- async (setSpanAttributes) => {
540
- const result2 = await generateObject({
541
- model: provider.chat(params.modelId),
542
- schema: params.schema,
543
- prompt: params.prompt,
544
- ...params.system !== void 0 ? { system: params.system } : void 0,
545
- ...params.temperature !== void 0 ? { temperature: params.temperature } : void 0,
546
- ...params.maxTokens !== void 0 ? { maxOutputTokens: params.maxTokens } : void 0,
547
- ...params.recordTelemetryPayloads === false ? {
548
- experimental_telemetry: {
549
- isEnabled: true,
550
- recordInputs: false,
551
- recordOutputs: false
552
- }
553
- } : void 0,
554
- ...params.signal !== void 0 ? { abortSignal: params.signal } : void 0
555
- });
556
- setSpanAttributes({
557
- "gen_ai.response.finish_reasons": [result2.finishReason],
558
- ...extractGenAiUsageAttributes(result2.usage)
559
- });
560
- return result2;
561
- },
562
- {
563
- "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
564
- "gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
565
- "gen_ai.request.model": params.modelId,
566
- "gen_ai.output.type": "json",
567
- ...params.promptName ? { "gen_ai.prompt.name": params.promptName } : void 0,
568
- "server.address": GEN_AI_SERVER_ADDRESS,
569
- "server.port": GEN_AI_SERVER_PORT,
570
- "gen_ai.provider.auth_mode": credential?.mode ?? "api_key",
571
- ...params.thinkingLevel ? { "gen_ai.request.reasoning.level": params.thinkingLevel } : void 0,
572
- ...params.temperature !== void 0 ? { "gen_ai.request.temperature": params.temperature } : void 0,
573
- ...params.maxTokens !== void 0 ? { "gen_ai.request.max_tokens": params.maxTokens } : void 0
574
- }
575
- );
576
- } catch (error) {
577
- const providerError = createProviderError(error, {
578
- ...NoObjectGeneratedError.isInstance(error) ? { kind: "invalid_response" } : void 0,
579
- modelId: params.modelId
580
- });
581
- throw providerError;
582
- }
583
- const costUsd = bestEffortObjectCompletionCost(params.modelId, result.usage);
584
- return {
585
- object: result.object,
586
- ...costUsd !== void 0 ? { costUsd } : void 0
587
- };
588
- }
589
- async function embedTexts(params) {
590
- const texts = params.texts.map((text) => text.trim());
591
- if (texts.length === 0 || texts.some((text) => text.length === 0)) {
592
- throw new Error("Embedding text is required.");
593
- }
594
- const credential = await resolveGatewayCredential();
595
- const provider = createGatewayProvider(
596
- credential ? { apiKey: credential.token } : {}
597
- );
598
- try {
599
- const result = await withSpan(
600
- `${GEN_AI_OPERATION_EMBEDDINGS} ${params.modelId}`,
601
- "gen_ai.embeddings",
602
- logContextFromMetadata(params.modelId, params.metadata),
603
- async (setSpanAttributes) => {
604
- const result2 = await embedMany({
605
- model: provider.embeddingModel(params.modelId),
606
- values: texts,
607
- ...params.signal !== void 0 ? { abortSignal: params.signal } : void 0
608
- });
609
- const dimensions = result2.embeddings[0]?.length;
610
- if (result2.embeddings.length !== texts.length || !dimensions || !result2.embeddings.every(
611
- (embedding) => embedding.length === dimensions
612
- )) {
613
- throw createProviderError(
614
- "Embedding provider returned invalid vectors.",
615
- {
616
- kind: "invalid_response",
617
- modelId: params.modelId
618
- }
619
- );
620
- }
621
- const costUsd = embeddingCostUsd(params.modelId, result2.usage.tokens);
622
- setSpanAttributes({
623
- "gen_ai.embeddings.dimension.count": dimensions,
624
- ...extractGenAiUsageAttributes({
625
- inputTokens: result2.usage.tokens,
626
- ...costUsd !== void 0 ? { cost: { input: costUsd, total: costUsd } } : void 0
627
- })
628
- });
629
- return { costUsd, dimensions, result: result2 };
630
- },
631
- {
632
- "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
633
- "gen_ai.operation.name": GEN_AI_OPERATION_EMBEDDINGS,
634
- "gen_ai.request.model": params.modelId,
635
- "server.address": GEN_AI_SERVER_ADDRESS,
636
- "server.port": GEN_AI_SERVER_PORT,
637
- "gen_ai.provider.auth_mode": credential?.mode ?? "api_key"
638
- }
639
- );
640
- return {
641
- ...result.costUsd !== void 0 ? { costUsd: result.costUsd } : void 0,
642
- dimensions: result.dimensions,
643
- model: params.modelId,
644
- provider: GEN_AI_PROVIDER_NAME,
645
- vectors: result.result.embeddings
646
- };
647
- } catch (error) {
648
- const providerError = createProviderError(error, {
649
- modelId: params.modelId
650
- });
651
- if (isProviderRetryError(providerError)) {
652
- throw providerError;
653
- }
654
- logException(providerError, "ai.embeddings.failed", {
655
- "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
656
- "gen_ai.operation.name": GEN_AI_OPERATION_EMBEDDINGS,
657
- "gen_ai.request.model": params.modelId
658
- });
659
- throw providerError;
660
- }
661
- }
662
-
663
- // src/chat/slack/emoji.ts
664
- var SLACK_EMOJI_NAME_RE = /^(?:[a-z0-9_+-]+)(?:::(?:skin-tone-[2-6]))?$/;
665
- function normalizeSlackEmojiName(value) {
666
- const trimmed = value.trim().toLowerCase();
667
- if (!trimmed) {
668
- return null;
669
- }
670
- const normalized = trimmed.startsWith(":") && trimmed.endsWith(":") ? trimmed.slice(1, -1) : trimmed;
671
- return SLACK_EMOJI_NAME_RE.test(normalized) ? normalized : null;
672
- }
673
-
674
- // src/chat/config.ts
675
- var MIN_AGENT_TURN_TIMEOUT_MS = 10 * 1e3;
676
- var DEFAULT_AGENT_TURN_TIMEOUT_MS = 12 * 60 * 1e3;
677
- var MAX_SLICES_PER_TURN = 100;
678
- var MAX_TOOL_CALLS_PER_TURN = 150;
679
- var MAX_CONSECUTIVE_AUTOMATED_TURNS = 25;
680
- var DEFAULT_FUNCTION_MAX_DURATION_SECONDS = 300;
681
- var DEFAULT_SLACK_SLASH_COMMAND = "/jr";
682
- var DEFAULT_PROCESSING_REACTION_EMOJI = "eyes";
683
- var DEFAULT_COMPLETED_REACTION_EMOJI = "white_check_mark";
684
- var DEFAULT_MODEL_CONTEXT_WINDOW_TOKENS = 4e5;
685
- var DEFAULT_SQL_STATEMENT_TIMEOUT_MS = 3e4;
686
- var FUNCTION_TIMEOUT_BUFFER_SECONDS = 20;
687
- var CONVERSATION_WORK_SOFT_YIELD_BUFFER_SECONDS = 40;
688
- var DEFAULT_ASSISTANT_LOADING_MESSAGES = [
689
- "Consulting the orb",
690
- "Bribing the gremlins",
691
- "Shuffling the papers dramatically",
692
- "Summoning the right stack trace",
693
- "Negotiating with the mutex",
694
- "Poking the internet with a stick",
695
- "Asking the docs nicely",
696
- "Searching for the least cursed path",
697
- "Pretending this was obvious",
698
- "Waking up the test suite",
699
- "Untangling the spaghetti carefully",
700
- "Rattling the command line"
701
- ];
702
- function parseAgentTurnTimeoutMs(rawValue, maxTimeoutMs) {
703
- const value = Number.parseInt(rawValue ?? "", 10);
704
- if (Number.isNaN(value)) {
705
- return Math.max(
706
- MIN_AGENT_TURN_TIMEOUT_MS,
707
- Math.min(DEFAULT_AGENT_TURN_TIMEOUT_MS, maxTimeoutMs)
708
- );
709
- }
710
- return Math.max(MIN_AGENT_TURN_TIMEOUT_MS, Math.min(value, maxTimeoutMs));
711
- }
712
- function resolveFunctionMaxDurationSeconds(functionMaxDurationSeconds) {
713
- return functionMaxDurationSeconds ?? DEFAULT_FUNCTION_MAX_DURATION_SECONDS;
714
- }
715
- function resolveConversationWorkSoftYieldAfterMs(functionMaxDurationSeconds) {
716
- return Math.max(
717
- MIN_AGENT_TURN_TIMEOUT_MS,
718
- (functionMaxDurationSeconds - CONVERSATION_WORK_SOFT_YIELD_BUFFER_SECONDS) * 1e3
719
- );
720
- }
721
- function resolveMaxTurnTimeoutMs(functionMaxDurationSeconds) {
722
- const budgetSeconds = functionMaxDurationSeconds - FUNCTION_TIMEOUT_BUFFER_SECONDS;
723
- return Math.max(MIN_AGENT_TURN_TIMEOUT_MS, budgetSeconds * 1e3);
724
- }
725
- function parseLoadingMessages(rawValue) {
726
- const trimmed = rawValue?.trim();
727
- if (!trimmed) {
728
- return [...DEFAULT_ASSISTANT_LOADING_MESSAGES];
729
- }
730
- let parsed;
731
- try {
732
- parsed = JSON.parse(trimmed);
733
- } catch {
734
- throw new Error("JUNIOR_LOADING_MESSAGES must be a JSON array of strings");
735
- }
736
- if (!Array.isArray(parsed)) {
737
- throw new Error("JUNIOR_LOADING_MESSAGES must be a JSON array of strings");
738
- }
739
- return parsed.map((value, index) => {
740
- if (typeof value !== "string") {
741
- throw new Error(`JUNIOR_LOADING_MESSAGES[${index}] must be a string`);
742
- }
743
- return value.trim();
744
- });
745
- }
746
- function parseOptionalPositiveInteger(envName, rawValue) {
747
- const trimmed = toOptionalTrimmed(rawValue);
748
- if (trimmed === void 0) {
749
- return void 0;
750
- }
751
- const value = Number.parseInt(trimmed, 10);
752
- if (!Number.isSafeInteger(value) || value <= 0 || String(value) !== trimmed) {
753
- throw new Error(`${envName} must be a positive integer`);
754
- }
755
- return value;
756
- }
757
- function parseSlashCommand(rawValue) {
758
- const command = toOptionalTrimmed(rawValue) ?? DEFAULT_SLACK_SLASH_COMMAND;
759
- if (!command.startsWith("/") || /\s/.test(command)) {
760
- throw new Error(
761
- "JUNIOR_SLASH_COMMAND must start with / and contain no whitespace"
762
- );
763
- }
764
- return command;
765
- }
766
- function parseConversationWorkEnabled(rawValue) {
767
- const value = toOptionalTrimmed(rawValue)?.toLowerCase();
768
- if (value === void 0 || value === "true") {
769
- return true;
770
- }
771
- if (value === "false") {
772
- return false;
773
- }
774
- throw new Error("JUNIOR_CONVERSATION_WORK_ENABLED must be true or false");
775
- }
776
- function parseCrossActorMidRunMode(rawValue) {
777
- const value = toOptionalTrimmed(rawValue) ?? "follow_up";
778
- if (value === "follow_up" || value === "steer") {
779
- return value;
780
- }
781
- throw new Error("JUNIOR_CROSS_ACTOR_MID_RUN_MODE must be follow_up or steer");
782
- }
783
- var DEFAULT_MODEL_ID = getModel2("vercel-ai-gateway", "xai/grok-4.5").id;
784
- var DEFAULT_FAST_MODEL_ID = getModel2(
785
- "vercel-ai-gateway",
786
- "anthropic/claude-haiku-4.5"
787
- ).id;
788
- var DEFAULT_GUARDIAN_MODEL_ID = getModel2(
789
- "vercel-ai-gateway",
790
- "openai/gpt-5.6-luna"
791
- ).id;
792
- var DEFAULT_HANDOFF_MODEL_ID = getModel2(
793
- "vercel-ai-gateway",
794
- "openai/gpt-5.6-sol"
795
- ).id;
796
- var DEFAULT_WEB_SEARCH_MODEL_ID = getModel2(
797
- "vercel-ai-gateway",
798
- "openai/gpt-5.4"
799
- ).id;
800
- var DEFAULT_EMBEDDING_MODEL_ID = "openai/text-embedding-3-small";
801
- var DEFAULT_IMAGE_GENERATION_MODEL_ID = "google/gemini-3-pro-image";
802
- function validateGatewayModelId(raw) {
803
- const trimmed = toOptionalTrimmed(raw);
804
- if (trimmed === void 0) return void 0;
805
- resolveGatewayModel(trimmed);
806
- return trimmed;
807
- }
808
- function validateEmbeddingModelId(raw) {
809
- return toOptionalTrimmed(raw);
810
- }
811
- function requireModelId(configName, raw, validate) {
812
- const modelId = validate(raw);
813
- if (!modelId) {
814
- throw new Error(`${configName} must not be empty`);
815
- }
816
- return modelId;
817
- }
818
- var DEFAULT_STANDARD_PROFILE_DESCRIPTION = "Use for default assistant work: lookups, explanations, ordinary tool use, short answers, and light investigation of one source. Avoid for implementation, debugging, multi-file changes, architecture decisions, or research across several systems.";
819
- var DEFAULT_HANDOFF_PROFILE_DESCRIPTION = "Use for coding and difficult multi-step work: implementation, debugging, root-cause analysis, broad refactors, multi-file changes, architecture decisions, and research across several systems. Avoid for simple lookups, short answers, single-file reads, or ordinary tool use that the default profile can finish.";
820
- function parseOptionalProfileDescription(rawDescription, configName, profile) {
821
- if (rawDescription === void 0) {
822
- return void 0;
823
- }
824
- if (typeof rawDescription !== "string") {
825
- throw new Error(
826
- `${configName}.${profile}.description must be a string when set`
827
- );
828
- }
829
- const description = toOptionalTrimmed(rawDescription);
830
- if (!description) {
831
- throw new Error(
832
- `${configName}.${profile}.description must not be empty when set`
833
- );
834
- }
835
- return description;
836
- }
837
- function parseOptionalProfileReasoningLevel(rawReasoningLevel, configName, profile) {
838
- if (rawReasoningLevel === void 0) {
839
- return void 0;
840
- }
841
- try {
842
- return parseTurnReasoningLevel(rawReasoningLevel);
843
- } catch {
844
- throw new Error(
845
- `${configName}.${profile}.reasoningLevel must be one of ${TURN_REASONING_LEVELS.join(", ")}`
846
- );
847
- }
848
- }
849
- function parseProfileConfig(rawProfile, configName, profile) {
850
- if (typeof rawProfile === "string") {
851
- const modelId2 = validateGatewayModelId(rawProfile);
852
- if (!modelId2) {
853
- throw new Error(`${configName}.${profile} must not be empty`);
854
- }
855
- return { modelId: modelId2 };
856
- }
857
- if (!rawProfile || typeof rawProfile !== "object" || Array.isArray(rawProfile)) {
858
- throw new Error(
859
- `${configName}.${profile} must be a model id string or an object with modelId`
860
- );
861
- }
862
- const rawModelId = rawProfile.modelId;
863
- if (typeof rawModelId !== "string") {
864
- throw new Error(
865
- `${configName}.${profile}.modelId must be a model id string`
866
- );
867
- }
868
- const modelId = validateGatewayModelId(rawModelId);
869
- if (!modelId) {
870
- throw new Error(`${configName}.${profile}.modelId must not be empty`);
871
- }
872
- const description = parseOptionalProfileDescription(
873
- rawProfile.description,
874
- configName,
875
- profile
876
- );
877
- const reasoningLevel = parseOptionalProfileReasoningLevel(
878
- rawProfile.reasoningLevel,
879
- configName,
880
- profile
881
- );
882
- return {
883
- modelId,
884
- ...description ? { description } : void 0,
885
- ...reasoningLevel ? { reasoningLevel } : void 0
886
- };
887
- }
888
- function parseProfileMap(rawProfiles, configName) {
889
- if (!rawProfiles || typeof rawProfiles !== "object" || Array.isArray(rawProfiles)) {
890
- const objectType = configName === "AI_MODEL_PROFILES" ? "a JSON object" : "an object";
891
- throw new Error(`${configName} must be ${objectType}`);
892
- }
893
- const profiles = {};
894
- for (const [profile, rawProfile] of Object.entries(rawProfiles)) {
895
- if (!modelProfileSchema.safeParse(profile).success) {
896
- throw new Error(
897
- `${configName} profile "${profile}" must match ^[a-z][a-z0-9_-]*$`
898
- );
899
- }
900
- profiles[profile] = parseProfileConfig(rawProfile, configName, profile);
901
- }
902
- return profiles;
903
- }
904
- function parseProfiles(rawValue, standardModelId, handoffModelId) {
905
- const profiles = {
906
- standard: {
907
- modelId: standardModelId,
908
- description: DEFAULT_STANDARD_PROFILE_DESCRIPTION
909
- },
910
- handoff: {
911
- modelId: handoffModelId,
912
- description: DEFAULT_HANDOFF_PROFILE_DESCRIPTION,
913
- reasoningLevel: "high"
914
- }
915
- };
916
- const trimmed = toOptionalTrimmed(rawValue);
917
- if (trimmed === void 0) {
918
- return profiles;
919
- }
920
- let parsed;
921
- try {
922
- parsed = JSON.parse(trimmed);
923
- } catch {
924
- throw new Error("AI_MODEL_PROFILES must be a JSON object");
925
- }
926
- return {
927
- ...profiles,
928
- ...parseProfileMap(parsed, "AI_MODEL_PROFILES")
929
- };
930
- }
931
- function parseReactionEmoji(envName, rawValue, defaultEmoji) {
932
- const trimmed = toOptionalTrimmed(rawValue);
933
- if (trimmed === void 0) {
934
- return defaultEmoji;
935
- }
936
- const normalized = normalizeSlackEmojiName(trimmed);
937
- if (!normalized) {
938
- throw new Error(
939
- `${envName} must be a valid Slack emoji name (for example "eyes" or ":white_check_mark:")`
940
- );
941
- }
942
- return normalized;
943
- }
944
- function warnDeprecatedProfileEnv(env) {
945
- for (const envName of [
946
- "AI_MODEL",
947
- "AI_HANDOFF_MODEL",
948
- "AI_MODEL_PROFILES"
949
- ]) {
950
- if (toOptionalTrimmed(env[envName]) !== void 0) {
951
- logWarn("config.profile_env.deprecated", {
952
- "app.config.env_name": envName,
953
- "app.config.replacement": "createApp({ defaultProfile, profiles })"
954
- });
955
- }
956
- }
957
- }
958
- function readBotConfig(env, functionMaxDurationSeconds) {
959
- warnDeprecatedProfileEnv(env);
960
- const maxTurnTimeoutMs = resolveMaxTurnTimeoutMs(functionMaxDurationSeconds);
961
- const modelId = validateGatewayModelId(env.AI_MODEL) ?? DEFAULT_MODEL_ID;
962
- const reasoningLevel = toOptionalTrimmed(env.AI_REASONING_LEVEL);
963
- const fastModelId = validateGatewayModelId(env.AI_FAST_MODEL ?? env.AI_MODEL) ?? DEFAULT_FAST_MODEL_ID;
964
- const guardianModelId = validateGatewayModelId(env.AI_GUARDIAN_MODEL) ?? DEFAULT_GUARDIAN_MODEL_ID;
965
- const handoffModelId = validateGatewayModelId(env.AI_HANDOFF_MODEL) ?? DEFAULT_HANDOFF_MODEL_ID;
966
- return {
967
- userName: toOptionalTrimmed(env.JUNIOR_BOT_NAME) ?? "junior",
968
- defaultProfile: "standard",
969
- crossActorMidRunMode: parseCrossActorMidRunMode(
970
- env.JUNIOR_CROSS_ACTOR_MID_RUN_MODE
971
- ),
972
- profiles: parseProfiles(env.AI_MODEL_PROFILES, modelId, handoffModelId),
973
- contextWindowTokens: parseOptionalPositiveInteger(
974
- "AI_MODEL_CONTEXT_WINDOW_TOKENS",
975
- env.AI_MODEL_CONTEXT_WINDOW_TOKENS
976
- ) ?? DEFAULT_MODEL_CONTEXT_WINDOW_TOKENS,
977
- reasoningLevel: reasoningLevel === void 0 ? void 0 : parseTurnReasoningLevel(reasoningLevel),
978
- fastModelId,
979
- guardianModelId,
980
- imageGenerationModelId: toOptionalTrimmed(env.AI_IMAGE_MODEL) ?? DEFAULT_IMAGE_GENERATION_MODEL_ID,
981
- embeddingModelId: validateEmbeddingModelId(env.AI_EMBEDDING_MODEL) ?? DEFAULT_EMBEDDING_MODEL_ID,
982
- loadingMessages: parseLoadingMessages(env.JUNIOR_LOADING_MESSAGES),
983
- visionModelId: validateGatewayModelId(env.AI_VISION_MODEL),
984
- maxSlicesPerTurn: MAX_SLICES_PER_TURN,
985
- maxToolCallsPerTurn: MAX_TOOL_CALLS_PER_TURN,
986
- maxConsecutiveAutomatedTurns: MAX_CONSECUTIVE_AUTOMATED_TURNS,
987
- turnTimeoutMs: parseAgentTurnTimeoutMs(
988
- env.AGENT_TURN_TIMEOUT_MS,
989
- maxTurnTimeoutMs
990
- ),
991
- webSearchModelId: validateGatewayModelId(env.AI_WEB_SEARCH_MODEL) ?? DEFAULT_WEB_SEARCH_MODEL_ID
992
- };
993
- }
994
- function readDatabaseUrl(env) {
995
- const databaseUrl = toOptionalTrimmed(env.DATABASE_URL);
996
- if (!databaseUrl) {
997
- throw new Error("DATABASE_URL is required");
998
- }
999
- return databaseUrl;
1000
- }
1001
- function isLocalDatabaseUrl(databaseUrl) {
1002
- try {
1003
- const { hostname } = new URL(databaseUrl);
1004
- return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
1005
- } catch {
1006
- return false;
1007
- }
1008
- }
1009
- function readSqlDriver(env, databaseUrl) {
1010
- const value = toOptionalTrimmed(env.JUNIOR_DATABASE_DRIVER);
1011
- if (value === void 0) {
1012
- if (isLocalDatabaseUrl(databaseUrl)) {
1013
- return "postgres";
1014
- }
1015
- return "neon";
1016
- }
1017
- if (value === "neon" || value === "postgres") {
1018
- return value;
1019
- }
1020
- throw new Error("JUNIOR_DATABASE_DRIVER must be postgres or neon");
1021
- }
1022
- function readSqlStatementTimeoutMs(env) {
1023
- const rawValue = toOptionalTrimmed(env.JUNIOR_SQL_STATEMENT_TIMEOUT_MS);
1024
- if (rawValue === void 0) {
1025
- return DEFAULT_SQL_STATEMENT_TIMEOUT_MS;
1026
- }
1027
- const value = Number.parseInt(rawValue, 10);
1028
- if (!Number.isSafeInteger(value) || value < 0 || String(value) !== rawValue) {
1029
- throw new Error(
1030
- "JUNIOR_SQL_STATEMENT_TIMEOUT_MS must be a non-negative integer"
1031
- );
1032
- }
1033
- return value === 0 ? false : value;
1034
- }
1035
- function readChatConfig(env = process.env, functionMaxDurationSeconds = DEFAULT_FUNCTION_MAX_DURATION_SECONDS) {
1036
- const databaseUrl = readDatabaseUrl(env);
1037
- const resolvedFunctionMaxDurationSeconds = resolveFunctionMaxDurationSeconds(
1038
- functionMaxDurationSeconds
1039
- );
1040
- return {
1041
- bot: readBotConfig(env, resolvedFunctionMaxDurationSeconds),
1042
- functionMaxDurationSeconds: resolvedFunctionMaxDurationSeconds,
1043
- conversationWorkEnabled: parseConversationWorkEnabled(
1044
- env.JUNIOR_CONVERSATION_WORK_ENABLED
1045
- ),
1046
- conversationWorkSoftYieldAfterMs: resolveConversationWorkSoftYieldAfterMs(
1047
- resolvedFunctionMaxDurationSeconds
1048
- ),
1049
- sql: {
1050
- databaseUrl,
1051
- driver: readSqlDriver(env, databaseUrl),
1052
- statementTimeoutMs: readSqlStatementTimeoutMs(env)
1053
- },
1054
- slack: {
1055
- botToken: toOptionalTrimmed(env.SLACK_BOT_TOKEN) ?? toOptionalTrimmed(env.SLACK_BOT_USER_TOKEN),
1056
- clientId: toOptionalTrimmed(env.SLACK_CLIENT_ID),
1057
- clientSecret: toOptionalTrimmed(env.SLACK_CLIENT_SECRET),
1058
- completedReactionEmoji: DEFAULT_COMPLETED_REACTION_EMOJI,
1059
- processingReactionEmoji: DEFAULT_PROCESSING_REACTION_EMOJI,
1060
- signingSecret: toOptionalTrimmed(env.SLACK_SIGNING_SECRET),
1061
- slashCommand: parseSlashCommand(env.JUNIOR_SLASH_COMMAND)
1062
- },
1063
- state: {
1064
- adapter: env.JUNIOR_STATE_ADAPTER?.trim().toLowerCase() === "memory" ? "memory" : "redis",
1065
- keyPrefix: toOptionalTrimmed(env.JUNIOR_STATE_KEY_PREFIX),
1066
- redisUrl: toOptionalTrimmed(env.REDIS_URL)
1067
- }
1068
- };
1069
- }
1070
- var chatConfig = readChatConfig(process.env);
1071
- function configureFunctionMaxDurationSeconds(functionMaxDurationSeconds) {
1072
- const resolved = resolveFunctionMaxDurationSeconds(
1073
- functionMaxDurationSeconds
1074
- );
1075
- chatConfig.functionMaxDurationSeconds = resolved;
1076
- chatConfig.conversationWorkSoftYieldAfterMs = resolveConversationWorkSoftYieldAfterMs(resolved);
1077
- chatConfig.bot.turnTimeoutMs = parseAgentTurnTimeoutMs(
1078
- process.env.AGENT_TURN_TIMEOUT_MS,
1079
- resolveMaxTurnTimeoutMs(resolved)
1080
- );
1081
- }
1082
- function getChatConfig() {
1083
- return chatConfig;
1084
- }
1085
- var botConfig = chatConfig.bot;
1086
- function getSlackBotToken() {
1087
- return chatConfig.slack.botToken;
1088
- }
1089
- function getSlackSigningSecret() {
1090
- return chatConfig.slack.signingSecret;
1091
- }
1092
- function getSlackClientId() {
1093
- return chatConfig.slack.clientId;
1094
- }
1095
- function getSlackClientSecret() {
1096
- return chatConfig.slack.clientSecret;
1097
- }
1098
- function getRuntimeMetadata() {
1099
- return {
1100
- version: toOptionalTrimmed(process.env.VERCEL_GIT_COMMIT_SHA)
1101
- };
1102
- }
1103
- function setBotModelConfig(config) {
1104
- if (config.embeddingModelId !== void 0) {
1105
- botConfig.embeddingModelId = requireModelId(
1106
- "embeddingModelId",
1107
- config.embeddingModelId,
1108
- validateEmbeddingModelId
1109
- );
1110
- }
1111
- if (config.fastModelId !== void 0) {
1112
- botConfig.fastModelId = requireModelId(
1113
- "fastModelId",
1114
- config.fastModelId,
1115
- validateGatewayModelId
1116
- );
1117
- }
1118
- if (config.guardianModelId !== void 0) {
1119
- botConfig.guardianModelId = requireModelId(
1120
- "guardianModelId",
1121
- config.guardianModelId,
1122
- validateGatewayModelId
1123
- );
1124
- }
1125
- if (config.imageGenerationModelId !== void 0) {
1126
- botConfig.imageGenerationModelId = requireModelId(
1127
- "imageGenerationModelId",
1128
- config.imageGenerationModelId,
1129
- validateEmbeddingModelId
1130
- );
1131
- }
1132
- if (config.visionModelId !== void 0) {
1133
- botConfig.visionModelId = requireModelId(
1134
- "visionModelId",
1135
- config.visionModelId,
1136
- validateGatewayModelId
1137
- );
1138
- }
1139
- if (config.webSearchModelId !== void 0) {
1140
- botConfig.webSearchModelId = requireModelId(
1141
- "webSearchModelId",
1142
- config.webSearchModelId,
1143
- validateGatewayModelId
1144
- );
1145
- }
1146
- }
1147
- function setProfiles(profiles, defaultProfile) {
1148
- if (!profiles || !defaultProfile) {
1149
- throw new Error("profiles and defaultProfile must be configured together");
1150
- }
1151
- const configuredProfiles = parseProfileMap(profiles, "profiles");
1152
- const selectedDefault = defaultProfile;
1153
- if (!modelProfileSchema.safeParse(selectedDefault).success) {
1154
- throw new Error(
1155
- `defaultProfile "${selectedDefault}" must match ^[a-z][a-z0-9_-]*$`
1156
- );
1157
- }
1158
- if (!Object.hasOwn(configuredProfiles, selectedDefault)) {
1159
- throw new Error(`defaultProfile "${selectedDefault}" is not configured`);
1160
- }
1161
- botConfig.profiles = configuredProfiles;
1162
- botConfig.defaultProfile = selectedDefault;
1163
- }
1164
- function getSlackReactionConfig() {
1165
- return {
1166
- completedReactionEmoji: chatConfig.slack.completedReactionEmoji,
1167
- processingReactionEmoji: chatConfig.slack.processingReactionEmoji
1168
- };
1169
- }
1170
- function setSlackReactionConfig(overrides) {
1171
- if (overrides.processingReactionEmoji !== void 0) {
1172
- chatConfig.slack.processingReactionEmoji = parseReactionEmoji(
1173
- "processingReactionEmoji",
1174
- overrides.processingReactionEmoji,
1175
- chatConfig.slack.processingReactionEmoji
1176
- );
1177
- }
1178
- if (overrides.completedReactionEmoji !== void 0) {
1179
- chatConfig.slack.completedReactionEmoji = parseReactionEmoji(
1180
- "completedReactionEmoji",
1181
- overrides.completedReactionEmoji,
1182
- chatConfig.slack.completedReactionEmoji
1183
- );
1184
- }
1185
- }
1186
-
1187
- export {
1188
- toOptionalTrimmed,
1189
- MISSING_GATEWAY_CREDENTIALS_ERROR,
1190
- resolveGatewayCredential,
1191
- getGatewayApiKey,
1192
- ProviderError,
1193
- createProviderError,
1194
- isProviderRetryError,
1195
- findProviderError,
1196
- getProviderErrorUserMessage,
1197
- getProviderErrorAttributes,
1198
- escapeXml,
1199
- renderCurrentInstruction,
1200
- unwrapCurrentInstruction,
1201
- COMPACTION_SUMMARY_PREFIX,
1202
- ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX,
1203
- MODEL_HANDOFF_SUMMARY_PREFIX,
1204
- isCompactionSummaryText,
1205
- hasCompactedConversationContext,
1206
- GEN_AI_PROVIDER_NAME,
1207
- GEN_AI_SERVER_ADDRESS,
1208
- GEN_AI_SERVER_PORT,
1209
- resolveGatewayModel,
1210
- completeText,
1211
- completeObject,
1212
- embedTexts,
1213
- normalizeSlackEmojiName,
1214
- DEFAULT_SQL_STATEMENT_TIMEOUT_MS,
1215
- FUNCTION_TIMEOUT_BUFFER_SECONDS,
1216
- configureFunctionMaxDurationSeconds,
1217
- getChatConfig,
1218
- botConfig,
1219
- getSlackBotToken,
1220
- getSlackSigningSecret,
1221
- getSlackClientId,
1222
- getSlackClientSecret,
1223
- getRuntimeMetadata,
1224
- setBotModelConfig,
1225
- setProfiles,
1226
- getSlackReactionConfig,
1227
- setSlackReactionConfig
1228
- };