@sentry/junior 0.112.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.
- package/dist/{agent-hooks-6MVTPKP4.js → agent-hooks-BKEMWR3Z.js} +8 -8
- package/dist/api/conversations/cursor.d.ts +17 -0
- package/dist/api/conversations/detail.d.ts +16 -18
- package/dist/api/conversations/event-list.d.ts +91 -0
- package/dist/api/conversations/event-page.d.ts +18 -0
- package/dist/api/conversations/events.d.ts +5 -1
- package/dist/api/conversations/projection.d.ts +6 -1
- package/dist/api/schema/conversation.d.ts +132 -51
- package/dist/api/schema.d.ts +2 -2
- package/dist/api/schema.js +7 -1
- package/dist/api.js +444 -138
- package/dist/app.js +20 -20
- package/dist/{catalog-runtime-UEO25P2J.js → catalog-runtime-6XYOUVRZ.js} +5 -5
- package/dist/chat/pi/transcript.d.ts +2 -0
- package/dist/chat/services/provider-error.d.ts +39 -0
- package/dist/chat/services/provider-retry.d.ts +3 -6
- package/dist/chat/task-execution/state.d.ts +2 -2
- package/dist/chat/task-execution/store.d.ts +1 -1
- package/dist/{chunk-CSS7JHEM.js → chunk-36UJA3OD.js} +1 -1
- package/dist/{chunk-4EJO4HIC.js → chunk-3CTIAKSS.js} +1 -1
- package/dist/{chunk-66IP6WED.js → chunk-4VKFQPCW.js} +4 -4
- package/dist/{chunk-GJG67YFS.js → chunk-4WZ7YKDF.js} +2 -2
- package/dist/{chunk-SKEMI4IF.js → chunk-DXRPHBOU.js} +132 -23
- package/dist/{chunk-GR4IB6OQ.js → chunk-H5ON7XTE.js} +73 -28
- package/dist/{chunk-X3SP5RDW.js → chunk-HMRVILWZ.js} +1 -1
- package/dist/{chunk-2FJ6WEYV.js → chunk-K5BXPM74.js} +1 -1
- package/dist/{chunk-QIALGHRN.js → chunk-LLKDNPYV.js} +2 -2
- package/dist/{chunk-ZHP4KNF7.js → chunk-LR2SKL5Y.js} +1 -1
- package/dist/{chunk-AU2JVUDF.js → chunk-NP7TYFYR.js} +1 -1
- package/dist/{chunk-TZU3R5OC.js → chunk-OXE5ZUTS.js} +1 -1
- package/dist/{chunk-NDQL4ESR.js → chunk-QTS66GMR.js} +2 -2
- package/dist/{chunk-PK4ETCUQ.js → chunk-RCBUZGIT.js} +217 -199
- package/dist/{chunk-JE23YR3X.js → chunk-UKGNSJQQ.js} +50 -42
- package/dist/{chunk-AWNDKI5K.js → chunk-WBB22ANL.js} +20 -15
- package/dist/{chunk-VBSVNOLA.js → chunk-YJ44UT7D.js} +5 -5
- package/dist/{chunk-IV2O4HQJ.js → chunk-ZRSUCJGA.js} +1 -1
- package/dist/cli/chat.js +19 -19
- package/dist/cli/check.js +6 -6
- package/dist/cli/plugins.js +11 -11
- package/dist/cli/snapshot-warmup.js +8 -8
- package/dist/cli/upgrade.js +5 -5
- package/dist/{db-P5H5RVQV.js → db-2ASK6MV6.js} +5 -5
- package/dist/instrumentation.js +2 -2
- package/dist/nitro.js +2 -2
- package/dist/{runner-B4ZDUO3R.js → runner-L363K62Z.js} +12 -13
- package/dist/{skills-GWTOZ3XV.js → skills-VCPG3NOO.js} +6 -6
- package/dist/{validation-QFIC6XH6.js → validation-GY7AJBLC.js} +6 -6
- package/dist/version.js +1 -1
- package/package.json +6 -6
|
@@ -12,7 +12,203 @@ import {
|
|
|
12
12
|
normalizeGenAiFinishReason,
|
|
13
13
|
serializeGenAiAttribute,
|
|
14
14
|
withSpan
|
|
15
|
-
} from "./chunk-
|
|
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
|
|
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,
|
|
@@ -24,6 +24,13 @@ var conversationSurfaceSchema = z2.enum([
|
|
|
24
24
|
]);
|
|
25
25
|
var conversationUsageSchema = usageSchema;
|
|
26
26
|
var conversationParamsSchema = z2.object({ conversationId: z2.string().min(1) }).strict();
|
|
27
|
+
var conversationDetailQuerySchema = z2.object({
|
|
28
|
+
limit: z2.coerce.number().int().min(1).max(1e3).default(500)
|
|
29
|
+
}).strict();
|
|
30
|
+
var conversationEventsQuerySchema = z2.object({
|
|
31
|
+
before: z2.string().min(1),
|
|
32
|
+
limit: z2.coerce.number().int().min(1).max(1e3).default(500)
|
|
33
|
+
}).strict();
|
|
27
34
|
var conversationFeedQuerySchema = z2.object({
|
|
28
35
|
actorEmail: z2.string().trim().email().transform((value) => value.toLowerCase()).optional()
|
|
29
36
|
}).strict();
|
|
@@ -74,26 +81,26 @@ var conversationReportMessageHandledEventDataSchema = z2.object({
|
|
|
74
81
|
type: z2.literal("message_handled"),
|
|
75
82
|
messageId: z2.string().min(1)
|
|
76
83
|
}).strict();
|
|
77
|
-
var conversationReportToolStartedEventDataSchema = z2.object({
|
|
78
|
-
type: z2.literal("tool_started"),
|
|
79
|
-
toolCallId: z2.string().min(1),
|
|
80
|
-
name: z2.string().min(1)
|
|
81
|
-
}).strict();
|
|
82
84
|
var conversationReportToolCallSchema = z2.object({
|
|
83
85
|
toolCallId: z2.string().min(1),
|
|
84
86
|
name: z2.string().min(1),
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
status: z2.enum(["running", "completed", "error"]),
|
|
88
|
+
startedAt: z2.string().datetime().optional(),
|
|
89
|
+
startedSeq: z2.number().int().nonnegative().optional(),
|
|
90
|
+
input: z2.unknown().optional(),
|
|
91
|
+
output: z2.unknown().optional()
|
|
92
|
+
}).strict().superRefine((call, context) => {
|
|
93
|
+
if (call.startedAt === void 0 !== (call.startedSeq === void 0)) {
|
|
94
|
+
context.addIssue({
|
|
95
|
+
code: "custom",
|
|
96
|
+
message: "tool start sequence and timestamp must be provided together"
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
});
|
|
87
100
|
var conversationReportToolCallsEventDataSchema = z2.object({
|
|
88
101
|
type: z2.literal("tool_calls"),
|
|
89
102
|
calls: z2.array(conversationReportToolCallSchema).min(1)
|
|
90
103
|
}).strict();
|
|
91
|
-
var conversationReportToolResultEventDataSchema = z2.object({
|
|
92
|
-
type: z2.literal("tool_result"),
|
|
93
|
-
toolCallId: z2.string().min(1),
|
|
94
|
-
outcome: z2.enum(["completed", "error"]),
|
|
95
|
-
output: z2.unknown().optional()
|
|
96
|
-
}).strict();
|
|
97
104
|
var conversationReportTurnLifecycleEventDataSchema = z2.discriminatedUnion(
|
|
98
105
|
"state",
|
|
99
106
|
[
|
|
@@ -118,28 +125,23 @@ var conversationReportHandoffEventDataSchema = z2.object({
|
|
|
118
125
|
reasoningLevel: z2.string().min(1).optional(),
|
|
119
126
|
triggeringToolCallId: z2.string().min(1).optional()
|
|
120
127
|
}).strict();
|
|
121
|
-
var
|
|
122
|
-
type: z2.literal("
|
|
128
|
+
var conversationReportSubagentEventDataSchema = z2.object({
|
|
129
|
+
type: z2.literal("subagent"),
|
|
130
|
+
startedSeq: z2.number().int().nonnegative(),
|
|
131
|
+
startedAt: z2.string().datetime(),
|
|
123
132
|
childConversationId: z2.string().min(1),
|
|
124
133
|
subagentKind: z2.string().min(1),
|
|
125
|
-
parentToolCallId: z2.string().min(1).optional()
|
|
126
|
-
|
|
127
|
-
var conversationReportSubagentEndedEventDataSchema = z2.object({
|
|
128
|
-
type: z2.literal("subagent_ended"),
|
|
129
|
-
startedSeq: z2.number().int().nonnegative(),
|
|
130
|
-
outcome: z2.enum(["success", "error", "aborted"])
|
|
134
|
+
parentToolCallId: z2.string().min(1).optional(),
|
|
135
|
+
status: z2.enum(["running", "completed", "error", "aborted"])
|
|
131
136
|
}).strict();
|
|
132
137
|
var conversationReportEventDataSchema = z2.discriminatedUnion("type", [
|
|
133
138
|
conversationReportMessageEventDataSchema,
|
|
134
139
|
conversationReportMessageHandledEventDataSchema,
|
|
135
|
-
conversationReportToolStartedEventDataSchema,
|
|
136
140
|
conversationReportToolCallsEventDataSchema,
|
|
137
|
-
conversationReportToolResultEventDataSchema,
|
|
138
141
|
conversationReportTurnLifecycleEventDataSchema,
|
|
139
142
|
conversationReportCompactionEventDataSchema,
|
|
140
143
|
conversationReportHandoffEventDataSchema,
|
|
141
|
-
|
|
142
|
-
conversationReportSubagentEndedEventDataSchema
|
|
144
|
+
conversationReportSubagentEventDataSchema
|
|
143
145
|
]);
|
|
144
146
|
var conversationReportEventSchema = z2.object({
|
|
145
147
|
seq: z2.number().int().nonnegative(),
|
|
@@ -161,13 +163,7 @@ var conversationModelUsageSchema = z2.object({
|
|
|
161
163
|
modelId: z2.string(),
|
|
162
164
|
usage: conversationUsageSchema
|
|
163
165
|
}).strict();
|
|
164
|
-
|
|
165
|
-
modelUsage: z2.array(conversationModelUsageSchema).optional(),
|
|
166
|
-
events: z2.array(conversationReportEventSchema),
|
|
167
|
-
eventHistory: conversationEventHistorySchema,
|
|
168
|
-
generatedAt: z2.string(),
|
|
169
|
-
sentryConversationUrl: z2.string().optional()
|
|
170
|
-
}).strict().superRefine((report, context) => {
|
|
166
|
+
function validateConversationEvents(report, context) {
|
|
171
167
|
if (report.eventHistory.status === "expired" && report.events.length > 0) {
|
|
172
168
|
context.addIssue({
|
|
173
169
|
code: "custom",
|
|
@@ -201,22 +197,31 @@ var conversationDetailReportSchema = conversationSummaryReportSchema.extend({
|
|
|
201
197
|
});
|
|
202
198
|
}
|
|
203
199
|
}
|
|
204
|
-
if (report.eventHistory.status === "redacted" && event.data.type === "tool_calls" && event.data.calls.some(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
path: ["events", index, "data"],
|
|
208
|
-
message: "redacted event history must redact tool inputs"
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
if (report.eventHistory.status === "redacted" && event.data.type === "tool_result" && event.data.output !== void 0) {
|
|
200
|
+
if (report.eventHistory.status === "redacted" && event.data.type === "tool_calls" && event.data.calls.some(
|
|
201
|
+
(call) => call.input !== void 0 || call.output !== void 0
|
|
202
|
+
)) {
|
|
212
203
|
context.addIssue({
|
|
213
204
|
code: "custom",
|
|
214
205
|
path: ["events", index, "data"],
|
|
215
|
-
message: "redacted event history must redact tool
|
|
206
|
+
message: "redacted event history must redact tool payloads"
|
|
216
207
|
});
|
|
217
208
|
}
|
|
218
209
|
}
|
|
219
|
-
}
|
|
210
|
+
}
|
|
211
|
+
var conversationDetailReportSchema = conversationSummaryReportSchema.extend({
|
|
212
|
+
modelUsage: z2.array(conversationModelUsageSchema).optional(),
|
|
213
|
+
events: z2.array(conversationReportEventSchema),
|
|
214
|
+
eventHistory: conversationEventHistorySchema,
|
|
215
|
+
previousCursor: z2.string().min(1).optional(),
|
|
216
|
+
generatedAt: z2.string(),
|
|
217
|
+
sentryConversationUrl: z2.string().optional()
|
|
218
|
+
}).strict().superRefine(validateConversationEvents);
|
|
219
|
+
var conversationEventPageSchema = z2.object({
|
|
220
|
+
events: z2.array(conversationReportEventSchema),
|
|
221
|
+
eventHistory: conversationEventHistorySchema,
|
|
222
|
+
previousCursor: z2.string().min(1).optional(),
|
|
223
|
+
generatedAt: z2.string()
|
|
224
|
+
}).strict().superRefine(validateConversationEvents);
|
|
220
225
|
var conversationFeedSchema = z2.object({
|
|
221
226
|
conversations: z2.array(conversationSummaryReportSchema),
|
|
222
227
|
source: z2.literal("conversation_index"),
|
|
@@ -378,6 +383,8 @@ var actorProfileReportSchema = z5.object({
|
|
|
378
383
|
export {
|
|
379
384
|
apiErrorSchema,
|
|
380
385
|
conversationParamsSchema,
|
|
386
|
+
conversationDetailQuerySchema,
|
|
387
|
+
conversationEventsQuerySchema,
|
|
381
388
|
conversationFeedQuerySchema,
|
|
382
389
|
archiveConversationBodySchema,
|
|
383
390
|
archiveConversationResponseSchema,
|
|
@@ -386,6 +393,7 @@ export {
|
|
|
386
393
|
conversationReportEventSchema,
|
|
387
394
|
conversationEventHistorySchema,
|
|
388
395
|
conversationDetailReportSchema,
|
|
396
|
+
conversationEventPageSchema,
|
|
389
397
|
conversationFeedSchema,
|
|
390
398
|
conversationStatsReportSchema,
|
|
391
399
|
dailyConversationActivitySchema,
|