@sentry/junior 0.111.0 → 0.113.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 (57) hide show
  1. package/dist/{agent-hooks-QQ2IWKOP.js → agent-hooks-BKEMWR3Z.js} +8 -8
  2. package/dist/api/conversations/cursor.d.ts +17 -0
  3. package/dist/api/conversations/detail.d.ts +16 -18
  4. package/dist/api/conversations/event-list.d.ts +91 -0
  5. package/dist/api/conversations/event-page.d.ts +18 -0
  6. package/dist/api/conversations/events.d.ts +5 -1
  7. package/dist/api/conversations/projection.d.ts +6 -1
  8. package/dist/api/people/profile.d.ts +1 -0
  9. package/dist/api/schema/conversation.d.ts +132 -51
  10. package/dist/api/schema/person.d.ts +2 -0
  11. package/dist/api/schema.d.ts +2 -2
  12. package/dist/api/schema.js +7 -1
  13. package/dist/api.js +445 -138
  14. package/dist/app.js +50 -27
  15. package/dist/{catalog-runtime-D22W6QEJ.js → catalog-runtime-6XYOUVRZ.js} +5 -5
  16. package/dist/chat/pi/transcript.d.ts +2 -0
  17. package/dist/chat/runtime/agent-run-outcome.d.ts +1 -0
  18. package/dist/chat/services/auth-pause-response.d.ts +1 -1
  19. package/dist/chat/services/auth-pause.d.ts +2 -1
  20. package/dist/chat/services/mcp-auth-orchestration.d.ts +1 -1
  21. package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
  22. package/dist/chat/services/provider-error.d.ts +39 -0
  23. package/dist/chat/services/provider-retry.d.ts +3 -6
  24. package/dist/chat/task-execution/state.d.ts +2 -2
  25. package/dist/chat/task-execution/store.d.ts +1 -1
  26. package/dist/chat/tools/resource-events.d.ts +3 -129
  27. package/dist/{chunk-J7APPQIJ.js → chunk-36UJA3OD.js} +1 -1
  28. package/dist/{chunk-Z2W4SJZ7.js → chunk-3CTIAKSS.js} +1 -1
  29. package/dist/{chunk-B45FPP2A.js → chunk-4VKFQPCW.js} +4 -4
  30. package/dist/{chunk-BTRNMS6A.js → chunk-4WZ7YKDF.js} +2 -2
  31. package/dist/{chunk-SL3ZKNLQ.js → chunk-DXRPHBOU.js} +132 -23
  32. package/dist/{chunk-OOLU34J4.js → chunk-H5ON7XTE.js} +125 -62
  33. package/dist/{chunk-PYKKM4MM.js → chunk-HMRVILWZ.js} +1 -1
  34. package/dist/{chunk-L6JPKANW.js → chunk-K5BXPM74.js} +1 -1
  35. package/dist/{chunk-ZRZ4SVWG.js → chunk-LLKDNPYV.js} +2 -2
  36. package/dist/{chunk-WSRBFHPX.js → chunk-LR2SKL5Y.js} +1 -1
  37. package/dist/{chunk-MPVES2IC.js → chunk-NP7TYFYR.js} +1 -1
  38. package/dist/{chunk-XQAYFRWT.js → chunk-OXE5ZUTS.js} +1 -1
  39. package/dist/{chunk-IFAHK54X.js → chunk-QTS66GMR.js} +2 -2
  40. package/dist/{chunk-NQLWOTY4.js → chunk-RCBUZGIT.js} +217 -199
  41. package/dist/{chunk-FPK7XY3F.js → chunk-UKGNSJQQ.js} +51 -42
  42. package/dist/{chunk-PZELBSHC.js → chunk-WBB22ANL.js} +20 -15
  43. package/dist/{chunk-QQIVLZW4.js → chunk-YJ44UT7D.js} +5 -5
  44. package/dist/{chunk-Z4G3WCP3.js → chunk-ZRSUCJGA.js} +1 -1
  45. package/dist/cli/chat.js +19 -19
  46. package/dist/cli/check.js +6 -6
  47. package/dist/cli/plugins.js +11 -11
  48. package/dist/cli/snapshot-warmup.js +8 -8
  49. package/dist/cli/upgrade.js +5 -5
  50. package/dist/{db-WXQOQESG.js → db-2ASK6MV6.js} +5 -5
  51. package/dist/instrumentation.js +2 -2
  52. package/dist/nitro.js +2 -2
  53. package/dist/{runner-4QY4XH4B.js → runner-L363K62Z.js} +12 -13
  54. package/dist/{skills-P5MU4EBX.js → skills-VCPG3NOO.js} +6 -6
  55. package/dist/{validation-PQF5OP6T.js → validation-GY7AJBLC.js} +6 -6
  56. package/dist/version.js +1 -1
  57. package/package.json +5 -5
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-2ZTTXTSZ.js";
4
4
  import {
5
5
  normalizeSlackConversationId
6
- } from "./chunk-IFAHK54X.js";
6
+ } from "./chunk-QTS66GMR.js";
7
7
  import {
8
8
  parseSlackThreadId
9
9
  } from "./chunk-6Y5L4BOM.js";
@@ -8,13 +8,13 @@ import {
8
8
  import {
9
9
  getChatConfig,
10
10
  modelProfileSchema
11
- } from "./chunk-NQLWOTY4.js";
11
+ } from "./chunk-RCBUZGIT.js";
12
12
  import {
13
13
  juniorDestinations
14
14
  } from "./chunk-VFUK3X5B.js";
15
15
  import {
16
16
  normalizeIdentityEmail
17
- } from "./chunk-J7APPQIJ.js";
17
+ } from "./chunk-36UJA3OD.js";
18
18
  import {
19
19
  parseSlackChannelReferenceId,
20
20
  parseSlackTeamId
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createPluginCatalogRuntime
3
- } from "./chunk-XQAYFRWT.js";
3
+ } from "./chunk-OXE5ZUTS.js";
4
4
 
5
5
  // src/chat/plugins/catalog-runtime.ts
6
6
  var pluginCatalogRuntime = createPluginCatalogRuntime();
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  JUNIOR_VERSION
3
- } from "./chunk-Z4G3WCP3.js";
3
+ } from "./chunk-ZRSUCJGA.js";
4
4
 
5
5
  // src/deployment.ts
6
6
  var JUNIOR_HEARTBEAT_ROUTE = "/api/internal/heartbeat";
@@ -5,7 +5,7 @@ import {
5
5
  logInfo,
6
6
  logWarn,
7
7
  setSpanAttributes
8
- } from "./chunk-J7APPQIJ.js";
8
+ } from "./chunk-36UJA3OD.js";
9
9
  import {
10
10
  discoverInstalledPluginPackageContent,
11
11
  normalizePluginPackageNames
@@ -3,13 +3,13 @@ import {
3
3
  } from "./chunk-4ZNGQH7C.js";
4
4
  import {
5
5
  getSlackBotToken
6
- } from "./chunk-NQLWOTY4.js";
6
+ } from "./chunk-RCBUZGIT.js";
7
7
  import {
8
8
  logWarn,
9
9
  setSpanAttributes,
10
10
  setSpanStatus,
11
11
  withSpan
12
- } from "./chunk-J7APPQIJ.js";
12
+ } from "./chunk-36UJA3OD.js";
13
13
  import {
14
14
  parseSlackChannelReferenceId
15
15
  } from "./chunk-42WRQLJ6.js";
@@ -12,7 +12,203 @@ import {
12
12
  normalizeGenAiFinishReason,
13
13
  serializeGenAiAttribute,
14
14
  withSpan
15
- } from "./chunk-J7APPQIJ.js";
15
+ } from "./chunk-36UJA3OD.js";
16
+
17
+ // src/chat/config.ts
18
+ import { getModel as getModel2 } from "@earendil-works/pi-ai/compat";
19
+
20
+ // src/chat/optional-string.ts
21
+ function toOptionalTrimmed(value) {
22
+ if (!value) {
23
+ return void 0;
24
+ }
25
+ const trimmed = value.trim();
26
+ return trimmed.length > 0 ? trimmed : void 0;
27
+ }
28
+
29
+ // src/chat/pi/sdk.ts
30
+ import {
31
+ completeSimple,
32
+ getEnvApiKey,
33
+ getModel,
34
+ getModels,
35
+ isRetryableAssistantError,
36
+ registerApiProvider
37
+ } from "@earendil-works/pi-ai/compat";
38
+ import {
39
+ stream,
40
+ streamSimple
41
+ } from "@earendil-works/pi-ai/api/anthropic-messages";
42
+
43
+ // src/chat/pi/client.ts
44
+ import { createGatewayProvider } from "@ai-sdk/gateway";
45
+ import { embedMany, generateObject } from "ai";
46
+
47
+ // src/chat/services/provider-error.ts
48
+ var ProviderError = class extends Error {
49
+ code = "provider_error";
50
+ kind;
51
+ modelId;
52
+ retryable;
53
+ retryAfterMs;
54
+ status;
55
+ constructor(details) {
56
+ super(`AI provider error: ${details.kind}`);
57
+ this.name = "ProviderError";
58
+ this.kind = details.kind;
59
+ this.modelId = details.modelId;
60
+ this.retryable = details.retryable;
61
+ this.retryAfterMs = details.retryAfterMs;
62
+ this.status = details.status;
63
+ }
64
+ };
65
+ var NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
66
+ "ECONNREFUSED",
67
+ "ECONNRESET",
68
+ "ENOTFOUND",
69
+ "EAI_AGAIN"
70
+ ]);
71
+ var TIMEOUT_ERROR_CODES = /* @__PURE__ */ new Set([
72
+ "ETIMEDOUT",
73
+ "ECONNABORTED",
74
+ "ESOCKETTIMEDOUT"
75
+ ]);
76
+ var CONTENT_POLICY_PATTERN = /\b(?:content|safety)[ _-]?policy\b|\b(?:content|safety) (?:filter|violation)\b|\bmoderation (?:blocked|rejected|refused)\b/i;
77
+ var QUOTA_PATTERN = /insufficient.?quota|quota exceeded|usage limit|available balance|out of budget|billing (?:limit|quota|error)|payment required/i;
78
+ 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;
79
+ var PERMISSION_PATTERN = /permission denied|forbidden|not authorized|authorization (?:failed|required|denied)/i;
80
+ var INVALID_REQUEST_PATTERN = /context.?length|context.?window|validation (?:error|failed)|bad request|unsupported model|invalid model|unknown (?:ai gateway )?model|mismatched api/i;
81
+ var CAPACITY_PATTERN = /overloaded|at capacity|capacity exceeded/i;
82
+ var TIMEOUT_PATTERN = /timed? out|timeout|gateway timeout/i;
83
+ var NETWORK_PATTERN = /network.?error|connection (?:error|refused|lost|closed)|fetch failed|socket (?:hang up|closed)|stream ended before/i;
84
+ var SERVER_PATTERN = /service(?: temporarily)?[ _-]?unavailable|server.?error|internal.?error|bad gateway|upstream (?:request )?failed/i;
85
+ var TERMINAL_KINDS = /* @__PURE__ */ new Set([
86
+ "auth",
87
+ "permission",
88
+ "invalid_request",
89
+ "invalid_response",
90
+ "quota",
91
+ "content_policy"
92
+ ]);
93
+ var RETRYABLE_KINDS = /* @__PURE__ */ new Set([
94
+ "rate_limit",
95
+ "capacity",
96
+ "timeout",
97
+ "network",
98
+ "server"
99
+ ]);
100
+ function providerMessage(error) {
101
+ return (error instanceof Error ? error.message : String(error)).trim();
102
+ }
103
+ function extractTransportKind(error, depth = 0) {
104
+ if (!(error instanceof Error) || depth > 4) return void 0;
105
+ const shaped = error;
106
+ const code = typeof shaped.code === "string" ? shaped.code.toUpperCase() : void 0;
107
+ if (code && TIMEOUT_ERROR_CODES.has(code)) return "timeout";
108
+ if (code && NETWORK_ERROR_CODES.has(code)) return "network";
109
+ return extractTransportKind(shaped.cause, depth + 1);
110
+ }
111
+ function extractStatus(error, message) {
112
+ if (error instanceof Error) {
113
+ const shaped = error;
114
+ if (typeof shaped.status === "number") return shaped.status;
115
+ if (typeof shaped.statusCode === "number") return shaped.statusCode;
116
+ }
117
+ const match = message.match(
118
+ /^(?:Error:\s*)?([45]\d\d)\b|\bstatus(?:Code)?["'=:\s]+([45]\d\d)\b/i
119
+ );
120
+ const status = match?.[1] ?? match?.[2];
121
+ return status ? Number(status) : void 0;
122
+ }
123
+ function extractRetryAfterMs(error, message) {
124
+ const headers = error instanceof Error ? error.responseHeaders ?? error.response?.headers : void 0;
125
+ const retryAfter = headers instanceof Headers ? headers.get("retry-after") : headers && typeof headers === "object" ? Object.entries(headers).find(
126
+ ([name]) => name.toLowerCase() === "retry-after"
127
+ )?.[1] : void 0;
128
+ const raw = typeof retryAfter === "string" || typeof retryAfter === "number" ? String(retryAfter) : message.match(/"retry-after"\s*:\s*"?([^",}]+)"?/i)?.[1];
129
+ if (!raw) return void 0;
130
+ const seconds = Number(raw);
131
+ if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
132
+ const date = Date.parse(raw);
133
+ return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
134
+ }
135
+ function classifyProviderError(status, message, transportKind) {
136
+ if (CONTENT_POLICY_PATTERN.test(message)) return "content_policy";
137
+ if (QUOTA_PATTERN.test(message)) return "quota";
138
+ if (status === 401 || AUTH_PATTERN.test(message)) return "auth";
139
+ if (status === 403 || PERMISSION_PATTERN.test(message)) return "permission";
140
+ if (INVALID_REQUEST_PATTERN.test(message)) return "invalid_request";
141
+ if (status === 429 || /rate.?limit|too many requests/i.test(message)) {
142
+ return "rate_limit";
143
+ }
144
+ if (status === 408) return "timeout";
145
+ if (CAPACITY_PATTERN.test(message)) return "capacity";
146
+ if (transportKind === "timeout" || TIMEOUT_PATTERN.test(message))
147
+ return "timeout";
148
+ if (transportKind === "network" || NETWORK_PATTERN.test(message))
149
+ return "network";
150
+ if (status !== void 0 && status >= 500 || SERVER_PATTERN.test(message)) {
151
+ return "server";
152
+ }
153
+ if (status !== void 0 && status >= 400) {
154
+ return "invalid_request";
155
+ }
156
+ return "unknown";
157
+ }
158
+ function createProviderError(error, options = {}) {
159
+ if (error instanceof ProviderError) return error;
160
+ const message = providerMessage(error);
161
+ const status = extractStatus(error, message);
162
+ const kind = options.kind ?? classifyProviderError(status, message, extractTransportKind(error));
163
+ const retryable = !TERMINAL_KINDS.has(kind) && (options.retryable ?? RETRYABLE_KINDS.has(kind));
164
+ return new ProviderError({
165
+ kind,
166
+ modelId: options.modelId,
167
+ retryable,
168
+ retryAfterMs: extractRetryAfterMs(error, message),
169
+ status
170
+ });
171
+ }
172
+ function isProviderRetryError(error) {
173
+ return error instanceof ProviderError && error.retryable;
174
+ }
175
+ function getProviderErrorUserMessage(error) {
176
+ switch (error.kind) {
177
+ case "capacity":
178
+ return "The selected model is temporarily unavailable because it is at capacity. Please try again shortly.";
179
+ case "rate_limit": {
180
+ const seconds = error.retryAfterMs ? Math.max(1, Math.ceil(error.retryAfterMs / 1e3)) : void 0;
181
+ return seconds ? `The model is rate-limited. Please try again in about ${seconds} seconds.` : "The model is rate-limited. Please try again shortly.";
182
+ }
183
+ case "timeout":
184
+ case "network":
185
+ case "server":
186
+ return "The model provider had a temporary connection problem. Please try again.";
187
+ case "auth":
188
+ return "The model provider rejected Junior's credentials. This needs an administrator or configuration fix.";
189
+ case "permission":
190
+ return "The model provider denied access to this model or request. Ask an administrator to check model access, organization policy, and region availability.";
191
+ case "quota":
192
+ return "The model provider's usage quota has been exhausted. This needs an administrator or billing configuration fix.";
193
+ case "content_policy":
194
+ return "The model provider blocked this request under its content policy. Please revise the request and try again.";
195
+ case "invalid_request":
196
+ return "The model provider rejected this request as invalid. Please revise the request or ask an administrator to check the model configuration.";
197
+ case "invalid_response":
198
+ return "The model provider returned an invalid response. Please try again.";
199
+ default:
200
+ return "";
201
+ }
202
+ }
203
+ function getProviderErrorAttributes(error) {
204
+ return {
205
+ "app.ai.provider_error.kind": error.kind,
206
+ "app.ai.provider_error.retryable": error.retryable,
207
+ ...error.status !== void 0 ? { "app.ai.provider_error.status": error.status } : {},
208
+ ...error.retryAfterMs !== void 0 ? { "app.ai.provider_error.retry_after_ms": error.retryAfterMs } : {},
209
+ ...error.modelId ? { "gen_ai.request.model": error.modelId } : {}
210
+ };
211
+ }
16
212
 
17
213
  // src/chat/xml.ts
18
214
  function escapeXml(value) {
@@ -70,184 +266,6 @@ function unwrapCurrentInstruction(text) {
70
266
  return body === void 0 ? void 0 : unescapeXml(body);
71
267
  }
72
268
 
73
- // src/chat/turn-context-tag.ts
74
- var TURN_CONTEXT_TAG = "runtime-turn-context";
75
-
76
- // src/chat/pi/transcript.ts
77
- var RUNTIME_TURN_CONTEXT_START = `<${TURN_CONTEXT_TAG}>`;
78
- function userMessageContent(message) {
79
- const record = message;
80
- return record.role === "user" && Array.isArray(record.content) ? record.content : void 0;
81
- }
82
- function isRuntimeTurnContextPart(part) {
83
- return part !== null && typeof part === "object" && part.type === "text" && typeof part.text === "string" && part.text.startsWith(RUNTIME_TURN_CONTEXT_START);
84
- }
85
- var EMBEDDED_THREAD_CONTEXT_TAGS = [
86
- "recent-thread-messages",
87
- "thread-compactions",
88
- "thread-transcript",
89
- "thread-background"
90
- ];
91
- var EMBEDDED_THREAD_CONTEXT_PATTERN = new RegExp(
92
- `<(${EMBEDDED_THREAD_CONTEXT_TAGS.join("|")})(?:\\s[^>]*)?>[\\s\\S]*?</\\1>`,
93
- "g"
94
- );
95
- function isAssistantMessage(value) {
96
- return typeof value === "object" && value !== null && value.role === "assistant";
97
- }
98
- function isToolResultMessage(value) {
99
- return typeof value === "object" && value !== null && value.role === "toolResult";
100
- }
101
- function isToolResultError(result) {
102
- if (!result || typeof result !== "object") return false;
103
- return Boolean(result.isError);
104
- }
105
- function normalizeToolNameFromResult(result) {
106
- if (!result || typeof result !== "object") return void 0;
107
- const record = result;
108
- if (typeof record.toolName === "string" && record.toolName.length > 0) {
109
- return record.toolName;
110
- }
111
- if (typeof record.name === "string" && record.name.length > 0) {
112
- return record.name;
113
- }
114
- return void 0;
115
- }
116
- function getPiMessageRole(value) {
117
- if (!value || typeof value !== "object") {
118
- return void 0;
119
- }
120
- const role = value.role;
121
- return typeof role === "string" ? role : void 0;
122
- }
123
- function extractAssistantText(message) {
124
- const content = message.content ?? [];
125
- return content.filter(
126
- (part) => part.type === "text" && typeof part.text === "string"
127
- ).map((part) => part.text).join("\n");
128
- }
129
- function getTerminalAssistantMessages(messages) {
130
- let lastNonAssistantIndex = -1;
131
- for (let index = messages.length - 1; index >= 0; index -= 1) {
132
- if (!isAssistantMessage(messages[index])) {
133
- lastNonAssistantIndex = index;
134
- break;
135
- }
136
- }
137
- return messages.slice(lastNonAssistantIndex + 1).filter(isAssistantMessage);
138
- }
139
- function trimTrailingAssistantMessages(messages) {
140
- let end = messages.length;
141
- while (end > 0 && getPiMessageRole(messages[end - 1]) === "assistant") {
142
- end -= 1;
143
- }
144
- return end === messages.length ? [...messages] : messages.slice(0, end);
145
- }
146
- function hasRuntimeTurnContext(messages) {
147
- return messages.some(
148
- (message) => userMessageContent(message)?.some(isRuntimeTurnContextPart)
149
- );
150
- }
151
- function retainRuntimeTurnContext(messages) {
152
- return messages.flatMap((message) => {
153
- const runtimeContent = userMessageContent(message)?.filter(isRuntimeTurnContextPart) ?? [];
154
- return runtimeContent.length > 0 ? [{ ...message, content: runtimeContent }] : [];
155
- });
156
- }
157
- function instructionTextForProjection(text) {
158
- const withoutContext = text.replace(EMBEDDED_THREAD_CONTEXT_PATTERN, "").trim();
159
- return unwrapCurrentInstruction(withoutContext) ?? withoutContext;
160
- }
161
- function stripRuntimeTurnContext(messages) {
162
- return messages.flatMap((message) => {
163
- const content = userMessageContent(message);
164
- if (!content) return [message];
165
- const nextContent = content.filter(
166
- (part) => !isRuntimeTurnContextPart(part)
167
- );
168
- if (nextContent.length === content.length) return [message];
169
- if (nextContent.length === 0) return [];
170
- return [{ ...message, content: nextContent }];
171
- });
172
- }
173
-
174
- // src/chat/config.ts
175
- import { getModel as getModel2 } from "@earendil-works/pi-ai/compat";
176
-
177
- // src/chat/optional-string.ts
178
- function toOptionalTrimmed(value) {
179
- if (!value) {
180
- return void 0;
181
- }
182
- const trimmed = value.trim();
183
- return trimmed.length > 0 ? trimmed : void 0;
184
- }
185
-
186
- // src/chat/pi/sdk.ts
187
- import {
188
- completeSimple,
189
- getEnvApiKey,
190
- getModel,
191
- getModels,
192
- isRetryableAssistantError,
193
- registerApiProvider
194
- } from "@earendil-works/pi-ai/compat";
195
- import {
196
- stream,
197
- streamSimple
198
- } from "@earendil-works/pi-ai/api/anthropic-messages";
199
-
200
- // src/chat/pi/client.ts
201
- import { createGatewayProvider } from "@ai-sdk/gateway";
202
- import { embedMany, generateObject } from "ai";
203
-
204
- // src/chat/services/provider-retry.ts
205
- var PROVIDER_RETRY_DELAYS_MS = [2e3, 4e3, 8e3];
206
- var PROVIDER_ERROR_PREFIX = "AI provider error:";
207
- var PROVIDER_RETRY_ERROR_NAME = "ProviderRetryError";
208
- var NON_RETRYABLE_PROVIDER_ERROR_PATTERNS = [
209
- /invalid.?api.?key|no api key|authentication|authorization|permission|forbidden|(?:invalid|missing|expired|revoked).{0,24}\bcredentials?\b|\bcredentials?\b.{0,24}(?:invalid|missing|expired|revoked)|\bno\b.{0,16}\bcredentials?\b/i,
210
- /context.?length|context.?window/i,
211
- /content.?policy|validation|bad request|\b(?:400|401|403)\b/i,
212
- /unsupported model|invalid model|unknown ai gateway model|unknown model|mismatched api/i,
213
- /usage limit|monthly usage limit|available balance|insufficient.?quota|out of budget|quota exceeded|billing/i
214
- ];
215
- function providerMessage(error) {
216
- return (error instanceof Error ? error.message : String(error)).trim();
217
- }
218
- function createProviderError(error) {
219
- const message = providerMessage(error);
220
- const displayMessage = `${PROVIDER_ERROR_PREFIX} ${message || "Unknown provider error"}`;
221
- const providerError = new Error(displayMessage, { cause: error });
222
- if (message && isRetryableProviderFailure(message)) {
223
- providerError.name = PROVIDER_RETRY_ERROR_NAME;
224
- }
225
- return providerError;
226
- }
227
- function isProviderRetryError(error) {
228
- return error instanceof Error && error.name === PROVIDER_RETRY_ERROR_NAME;
229
- }
230
- function isRetryableProviderFailure(errorMessage) {
231
- return !NON_RETRYABLE_PROVIDER_ERROR_PATTERNS.some(
232
- (pattern) => pattern.test(errorMessage)
233
- );
234
- }
235
- function nextProviderRetry(args) {
236
- const delayMs = PROVIDER_RETRY_DELAYS_MS[args.attempt];
237
- if (delayMs === void 0 || !args.retryableFailure) {
238
- return void 0;
239
- }
240
- const messages = trimTrailingAssistantMessages(args.messages);
241
- if (messages.length === args.messages.length) {
242
- return void 0;
243
- }
244
- const tailRole = getPiMessageRole(messages.at(-1));
245
- if (tailRole !== "user" && tailRole !== "toolResult") {
246
- return void 0;
247
- }
248
- return { delayMs, messages };
249
- }
250
-
251
269
  // src/chat/services/context-compaction-marker.ts
252
270
  var COMPACTION_SUMMARY_PREFIX = "Context compaction summary for future Junior turns:";
253
271
  var MODEL_HANDOFF_SUMMARY_PREFIX = "Model handoff checkpoint. Continue the outstanding request now using this summary as the complete prior context:";
@@ -357,7 +375,7 @@ async function completeText(params) {
357
375
  }
358
376
  );
359
377
  } catch (error) {
360
- throw createProviderError(error);
378
+ throw createProviderError(error, { modelId: params.modelId });
361
379
  }
362
380
  const outputText = extractText(message);
363
381
  const outputMessagesAttribute = serializeGenAiAttribute(
@@ -393,7 +411,7 @@ async function completeText(params) {
393
411
  },
394
412
  "AI completion returned provider error"
395
413
  );
396
- throw createProviderError(providerMessage2);
414
+ throw createProviderError(providerMessage2, { modelId: params.modelId });
397
415
  }
398
416
  return {
399
417
  message,
@@ -454,7 +472,9 @@ async function completeObject(params) {
454
472
  );
455
473
  return { object: result.object };
456
474
  } catch (error) {
457
- const providerError = createProviderError(error);
475
+ const providerError = createProviderError(error, {
476
+ modelId: params.modelId
477
+ });
458
478
  if (isProviderRetryError(providerError)) {
459
479
  throw providerError;
460
480
  }
@@ -494,7 +514,13 @@ async function embedTexts(params) {
494
514
  if (result2.embeddings.length !== texts.length || !dimensions || !result2.embeddings.every(
495
515
  (embedding) => embedding.length === dimensions
496
516
  )) {
497
- throw new Error("Embedding provider returned invalid vectors.");
517
+ throw createProviderError(
518
+ "Embedding provider returned invalid vectors.",
519
+ {
520
+ kind: "invalid_response",
521
+ modelId: params.modelId
522
+ }
523
+ );
498
524
  }
499
525
  setSpanAttributes({
500
526
  "gen_ai.embeddings.dimension.count": dimensions,
@@ -517,7 +543,9 @@ async function embedTexts(params) {
517
543
  vectors: result.result.embeddings
518
544
  };
519
545
  } catch (error) {
520
- const providerError = createProviderError(error);
546
+ const providerError = createProviderError(error, {
547
+ modelId: params.modelId
548
+ });
521
549
  if (isProviderRetryError(providerError)) {
522
550
  throw providerError;
523
551
  }
@@ -895,24 +923,14 @@ function setSlackReactionConfig(overrides) {
895
923
 
896
924
  export {
897
925
  toOptionalTrimmed,
926
+ ProviderError,
927
+ createProviderError,
928
+ isProviderRetryError,
929
+ getProviderErrorUserMessage,
930
+ getProviderErrorAttributes,
898
931
  escapeXml,
899
932
  renderCurrentInstruction,
900
933
  unwrapCurrentInstruction,
901
- TURN_CONTEXT_TAG,
902
- isAssistantMessage,
903
- isToolResultMessage,
904
- isToolResultError,
905
- normalizeToolNameFromResult,
906
- getPiMessageRole,
907
- extractAssistantText,
908
- getTerminalAssistantMessages,
909
- trimTrailingAssistantMessages,
910
- hasRuntimeTurnContext,
911
- retainRuntimeTurnContext,
912
- instructionTextForProjection,
913
- stripRuntimeTurnContext,
914
- isProviderRetryError,
915
- nextProviderRetry,
916
934
  COMPACTION_SUMMARY_PREFIX,
917
935
  MODEL_HANDOFF_SUMMARY_PREFIX,
918
936
  isCompactionSummaryText,