@tonyclaw/agent-inspector 2.1.16 → 2.1.17
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/.output/cli.js +57 -13
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-Ccrrcx1j.js → CompareDrawer-B9sLBHw5.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-DbWjc_BE.js +106 -0
- package/.output/public/assets/{ReplayDialog-C7axhr-l.js → ReplayDialog-D9I9W9n3.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-WOptg8j_.js → RequestAnatomy-DGXK_Rii.js} +1 -1
- package/.output/public/assets/{ResponseView-CSAcxh_M.js → ResponseView-df_JzwsS.js} +2 -2
- package/.output/public/assets/{StreamingChunkSequence-DJS5KhPx.js → StreamingChunkSequence-i3DM5IKL.js} +1 -1
- package/.output/public/assets/_sessionId-CTpCHdFh.js +1 -0
- package/.output/public/assets/index-Blqvndcn.js +1 -0
- package/.output/public/assets/index-Cs79WRQj.css +1 -0
- package/.output/public/assets/{index-DMPNh46t.js → index-Dqc2r1ea.js} +1 -1
- package/.output/public/assets/{json-viewer-inX5QSa3.js → json-viewer-D3QWQlSB.js} +1 -1
- package/.output/public/assets/{main-aCAKYGSD.js → main-ZhxhOCmF.js} +2 -2
- package/.output/server/_libs/lucide-react.mjs +220 -202
- package/.output/server/{_sessionId-C0fhvQnn.mjs → _sessionId-YFrP0lZP.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-CO-Ti5sg.mjs → CompareDrawer-qC3adEeq.mjs} +3 -3
- package/.output/server/_ssr/{ProxyViewerContainer-N4J7uBCX.mjs → ProxyViewerContainer-DCZIJC2b.mjs} +1858 -1396
- package/.output/server/_ssr/{ReplayDialog-J1VxC0In.mjs → ReplayDialog-CvX4XYCi.mjs} +4 -4
- package/.output/server/_ssr/{RequestAnatomy-DBH-F3rq.mjs → RequestAnatomy-HQfrxjO1.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-DLFwV7Hd.mjs → ResponseView-QSlSD11e.mjs} +3 -3
- package/.output/server/_ssr/{StreamingChunkSequence-BywmuND0.mjs → StreamingChunkSequence-DTAiwlnI.mjs} +2 -2
- package/.output/server/_ssr/{index-CStymIc0.mjs → index-D_EzfXaN.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-DlQu0N1x.mjs → json-viewer-CrIX0e0Q.mjs} +3 -3
- package/.output/server/_ssr/{router-CQ4Zxhmr.mjs → router-__o2wrfO.mjs} +398 -95
- package/.output/server/{_tanstack-start-manifest_v-BHeJBGfo.mjs → _tanstack-start-manifest_v-DbqyLpsI.mjs} +1 -1
- package/.output/server/index.mjs +73 -73
- package/README.md +57 -2
- package/package.json +1 -1
- package/src/cli/startupOutput.ts +16 -0
- package/src/cli.ts +61 -15
- package/src/components/ProxyViewer.tsx +395 -64
- package/src/components/providers/ProviderCard.tsx +132 -31
- package/src/components/providers/ProviderForm.tsx +43 -11
- package/src/components/providers/ProvidersPanel.tsx +1 -1
- package/src/components/proxy-viewer/ConversationHeader.tsx +133 -112
- package/src/components/proxy-viewer/LogEntry.tsx +109 -26
- package/src/components/proxy-viewer/LogEntryHeader.tsx +339 -329
- package/src/components/proxy-viewer/ThreadConnector.tsx +102 -83
- package/src/components/proxy-viewer/TurnGroup.tsx +22 -63
- package/src/components/proxy-viewer/bodyHydration.ts +56 -0
- package/src/lib/providerTestContract.ts +56 -10
- package/src/lib/providerTestPrompt.ts +23 -1
- package/src/lib/upstreamUrl.ts +105 -1
- package/src/mcp/toolHandlers.ts +1 -1
- package/src/routes/api/providers.$providerId.test.log.ts +85 -10
- package/.output/public/assets/ProxyViewerContainer-DLqClc9A.js +0 -106
- package/.output/public/assets/_sessionId-DUSalzKH.js +0 -1
- package/.output/public/assets/index-BPpA21dY.css +0 -1
- package/.output/public/assets/index-Bt0Az2I2.js +0 -1
|
@@ -65,7 +65,7 @@ import "../_libs/immediate.mjs";
|
|
|
65
65
|
import "../_libs/setimmediate.mjs";
|
|
66
66
|
import "../_libs/pako.mjs";
|
|
67
67
|
const faviconSvg = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20role='img'%20aria-label='Agent%20Inspector'%3e%3cg%20fill='none'%20stroke='%23f59e0b'%20stroke-width='1.5'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M5%2013%20C5%209%208%207%2012%207%20C16%207%2019%209%2019%2013%20C19%2016%2016%2018%2012%2018%20C8%2018%205%2016%205%2013%20Z'%20/%3e%3cpath%20d='M5%2011%20C3.5%209.5%201.5%2010%202%2012.5%20C2.5%2014%204%2013.5%205%2012.5'%20/%3e%3cpath%20d='M19%2011%20C20.5%209.5%2022.5%2010%2022%2012.5%20C21.5%2014%2020%2013.5%2019%2012.5'%20/%3e%3cline%20x1='10'%20y1='7'%20x2='9.5'%20y2='5'%20/%3e%3cline%20x1='14'%20y1='7'%20x2='14.5'%20y2='5'%20/%3e%3cline%20x1='6.5'%20y1='16'%20x2='4.5'%20y2='19.5'%20/%3e%3cline%20x1='9'%20y1='17.5'%20x2='8'%20y2='20.5'%20/%3e%3cline%20x1='15'%20y1='17.5'%20x2='16'%20y2='20.5'%20/%3e%3cline%20x1='17.5'%20y1='16'%20x2='19.5'%20y2='19.5'%20/%3e%3c/g%3e%3ccircle%20cx='9.5'%20cy='4.5'%20r='0.9'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='14.5'%20cy='4.5'%20r='0.9'%20fill='%23f59e0b'%20/%3e%3c/svg%3e";
|
|
68
|
-
const appCss = "/assets/index-
|
|
68
|
+
const appCss = "/assets/index-Cs79WRQj.css";
|
|
69
69
|
const Route$D = createRootRoute({
|
|
70
70
|
head: () => ({
|
|
71
71
|
meta: [
|
|
@@ -108,7 +108,7 @@ function RootDocument({ children }) {
|
|
|
108
108
|
] })
|
|
109
109
|
] });
|
|
110
110
|
}
|
|
111
|
-
const $$splitComponentImporter$1 = () => import("./index-
|
|
111
|
+
const $$splitComponentImporter$1 = () => import("./index-D_EzfXaN.mjs");
|
|
112
112
|
const Route$C = createFileRoute("/")({
|
|
113
113
|
component: lazyRouteComponent($$splitComponentImporter$1, "component")
|
|
114
114
|
});
|
|
@@ -151,7 +151,7 @@ function decodeSessionIdFromPath(encoded) {
|
|
|
151
151
|
function getSessionPath(sessionId) {
|
|
152
152
|
return `/session/${encodeSessionIdForPath(sessionId)}`;
|
|
153
153
|
}
|
|
154
|
-
const $$splitComponentImporter = () => import("../_sessionId-
|
|
154
|
+
const $$splitComponentImporter = () => import("../_sessionId-YFrP0lZP.mjs");
|
|
155
155
|
const Route$B = createFileRoute("/session/$sessionId")({
|
|
156
156
|
component: lazyRouteComponent($$splitComponentImporter, "component"),
|
|
157
157
|
parseParams: (params) => ({
|
|
@@ -1061,7 +1061,7 @@ function objectFromUnknown$1(value) {
|
|
|
1061
1061
|
if (typeof value === "object" || typeof value === "function") return value;
|
|
1062
1062
|
return null;
|
|
1063
1063
|
}
|
|
1064
|
-
function readProperty$
|
|
1064
|
+
function readProperty$4(value, name) {
|
|
1065
1065
|
let current = objectFromUnknown$1(value);
|
|
1066
1066
|
while (current !== null) {
|
|
1067
1067
|
const desc = Object.getOwnPropertyDescriptor(current, name);
|
|
@@ -1075,7 +1075,7 @@ function readProperty$3(value, name) {
|
|
|
1075
1075
|
return void 0;
|
|
1076
1076
|
}
|
|
1077
1077
|
function readFunction$1(value, name) {
|
|
1078
|
-
const property = readProperty$
|
|
1078
|
+
const property = readProperty$4(value, name);
|
|
1079
1079
|
return typeof property === "function" ? property : null;
|
|
1080
1080
|
}
|
|
1081
1081
|
function callMethod$1(target, methodName, args) {
|
|
@@ -1117,7 +1117,7 @@ function execSql$1(db, sql) {
|
|
|
1117
1117
|
return result !== void 0;
|
|
1118
1118
|
}
|
|
1119
1119
|
function sqliteConstructorFromModule$1(moduleValue, exportName) {
|
|
1120
|
-
const exportedValue = readProperty$
|
|
1120
|
+
const exportedValue = readProperty$4(moduleValue, exportName);
|
|
1121
1121
|
if (typeof exportedValue === "function") {
|
|
1122
1122
|
return (path2) => Reflect.construct(exportedValue, [path2]);
|
|
1123
1123
|
}
|
|
@@ -1260,11 +1260,11 @@ function entryParams(entry) {
|
|
|
1260
1260
|
];
|
|
1261
1261
|
}
|
|
1262
1262
|
function readNumber$1(row, name) {
|
|
1263
|
-
const value = readProperty$
|
|
1263
|
+
const value = readProperty$4(row, name);
|
|
1264
1264
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1265
1265
|
}
|
|
1266
1266
|
function readString$2(row, name) {
|
|
1267
|
-
const value = readProperty$
|
|
1267
|
+
const value = readProperty$4(row, name);
|
|
1268
1268
|
return typeof value === "string" ? value : null;
|
|
1269
1269
|
}
|
|
1270
1270
|
function readBoolean(row, name) {
|
|
@@ -2019,9 +2019,9 @@ const DEFAULT_OPENAI_UPSTREAM$1 = "https://api.openai.com/v1";
|
|
|
2019
2019
|
const PROXY_IDENTITY = process.env["PROXY_IDENTITY"] ?? "inspector9527@Tony";
|
|
2020
2020
|
const PATH_V1_CHAT_COMPLETIONS$1 = "/v1/chat/completions";
|
|
2021
2021
|
const PATH_CHAT_COMPLETIONS = "/chat/completions";
|
|
2022
|
-
const PATH_V1_RESPONSES = "/v1/responses";
|
|
2022
|
+
const PATH_V1_RESPONSES$1 = "/v1/responses";
|
|
2023
2023
|
const PATH_RESPONSES = "/responses";
|
|
2024
|
-
const PATH_V1_MESSAGES = "/v1/messages";
|
|
2024
|
+
const PATH_V1_MESSAGES$1 = "/v1/messages";
|
|
2025
2025
|
const HEADER_CONTENT_TYPE = "content-type";
|
|
2026
2026
|
const HEADER_USER_AGENT = "user-agent";
|
|
2027
2027
|
const HEADER_X_PROXY_IDENTITY = "x-proxy-identity";
|
|
@@ -2075,10 +2075,10 @@ function formatForPath(path2) {
|
|
|
2075
2075
|
function apiFormatForPath(path2) {
|
|
2076
2076
|
return formatRegistry.getApiFormatByPath(path2) ?? "unknown";
|
|
2077
2077
|
}
|
|
2078
|
-
formatRegistry.registerPath(PATH_V1_MESSAGES, "anthropic");
|
|
2078
|
+
formatRegistry.registerPath(PATH_V1_MESSAGES$1, "anthropic");
|
|
2079
2079
|
formatRegistry.registerPath(PATH_V1_CHAT_COMPLETIONS$1, "openai");
|
|
2080
2080
|
formatRegistry.registerPath(PATH_CHAT_COMPLETIONS, "openai");
|
|
2081
|
-
formatRegistry.registerPath(PATH_V1_RESPONSES, "openai");
|
|
2081
|
+
formatRegistry.registerPath(PATH_V1_RESPONSES$1, "openai");
|
|
2082
2082
|
formatRegistry.registerPath(PATH_RESPONSES, "openai");
|
|
2083
2083
|
const SESSION_ARCHIVE_DIR = "sessions";
|
|
2084
2084
|
const SESSION_ARCHIVE_FILE = "session.sqlite";
|
|
@@ -2130,7 +2130,7 @@ function objectFromUnknown(value) {
|
|
|
2130
2130
|
if (typeof value === "object" || typeof value === "function") return value;
|
|
2131
2131
|
return null;
|
|
2132
2132
|
}
|
|
2133
|
-
function readProperty$
|
|
2133
|
+
function readProperty$3(value, name) {
|
|
2134
2134
|
let current = objectFromUnknown(value);
|
|
2135
2135
|
while (current !== null) {
|
|
2136
2136
|
const desc = Object.getOwnPropertyDescriptor(current, name);
|
|
@@ -2144,7 +2144,7 @@ function readProperty$2(value, name) {
|
|
|
2144
2144
|
return void 0;
|
|
2145
2145
|
}
|
|
2146
2146
|
function readFunction(value, name) {
|
|
2147
|
-
const property = readProperty$
|
|
2147
|
+
const property = readProperty$3(value, name);
|
|
2148
2148
|
return typeof property === "function" ? property : null;
|
|
2149
2149
|
}
|
|
2150
2150
|
function callMethod(target, methodName, args) {
|
|
@@ -2182,7 +2182,7 @@ function closeDatabase(db) {
|
|
|
2182
2182
|
callMethod(db, "close", []);
|
|
2183
2183
|
}
|
|
2184
2184
|
function sqliteConstructorFromModule(moduleValue, exportName) {
|
|
2185
|
-
const exportedValue = readProperty$
|
|
2185
|
+
const exportedValue = readProperty$3(moduleValue, exportName);
|
|
2186
2186
|
if (typeof exportedValue === "function") {
|
|
2187
2187
|
return (path2) => Reflect.construct(exportedValue, [path2]);
|
|
2188
2188
|
}
|
|
@@ -2273,11 +2273,11 @@ async function archiveSessionLog(log) {
|
|
|
2273
2273
|
}
|
|
2274
2274
|
}
|
|
2275
2275
|
function readString$1(row, name) {
|
|
2276
|
-
const value = readProperty$
|
|
2276
|
+
const value = readProperty$3(row, name);
|
|
2277
2277
|
return typeof value === "string" ? value : null;
|
|
2278
2278
|
}
|
|
2279
2279
|
function readNumber(row, name) {
|
|
2280
|
-
const value = readProperty$
|
|
2280
|
+
const value = readProperty$3(row, name);
|
|
2281
2281
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
2282
2282
|
}
|
|
2283
2283
|
function logFromJson(value) {
|
|
@@ -4090,24 +4090,24 @@ const anthropicProvider = {
|
|
|
4090
4090
|
};
|
|
4091
4091
|
registry.register(anthropicProvider);
|
|
4092
4092
|
const MAX_CHUNKS = 1e3;
|
|
4093
|
-
function readProperty$
|
|
4093
|
+
function readProperty$2(value, key) {
|
|
4094
4094
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
4095
4095
|
return Object.getOwnPropertyDescriptor(value, key)?.value;
|
|
4096
4096
|
}
|
|
4097
|
-
function readStringProperty$
|
|
4098
|
-
const property = readProperty$
|
|
4097
|
+
function readStringProperty$2(value, key) {
|
|
4098
|
+
const property = readProperty$2(value, key);
|
|
4099
4099
|
return typeof property === "string" ? property : null;
|
|
4100
4100
|
}
|
|
4101
4101
|
function readNumberProperty(value, key) {
|
|
4102
|
-
const property = readProperty$
|
|
4102
|
+
const property = readProperty$2(value, key);
|
|
4103
4103
|
return typeof property === "number" && Number.isFinite(property) ? property : null;
|
|
4104
4104
|
}
|
|
4105
4105
|
function readObjectProperty(value, key) {
|
|
4106
|
-
const property = readProperty$
|
|
4106
|
+
const property = readProperty$2(value, key);
|
|
4107
4107
|
return property !== null && typeof property === "object" && !Array.isArray(property) ? property : null;
|
|
4108
4108
|
}
|
|
4109
|
-
function readArrayProperty(value, key) {
|
|
4110
|
-
const property = readProperty$
|
|
4109
|
+
function readArrayProperty$1(value, key) {
|
|
4110
|
+
const property = readProperty$2(value, key);
|
|
4111
4111
|
return Array.isArray(property) ? property : [];
|
|
4112
4112
|
}
|
|
4113
4113
|
function parseSseEvents(raw) {
|
|
@@ -4175,7 +4175,7 @@ function collectChunk(chunks, chunkIndex, streamStartMs, type, parsed) {
|
|
|
4175
4175
|
}
|
|
4176
4176
|
function setErrorFromPayload(log, payload) {
|
|
4177
4177
|
const errorObject = readObjectProperty(payload, "error");
|
|
4178
|
-
const message = readStringProperty$
|
|
4178
|
+
const message = readStringProperty$2(errorObject, "message") ?? readStringProperty$2(payload, "message") ?? readStringProperty$2(payload, "error");
|
|
4179
4179
|
if (message !== null && message.length > 0) {
|
|
4180
4180
|
log.error = message;
|
|
4181
4181
|
}
|
|
@@ -4299,7 +4299,7 @@ function extractChatCompletionsStream(events, log, fallbackModel, collectChunks)
|
|
|
4299
4299
|
}
|
|
4300
4300
|
function parseResponsesResponse(value) {
|
|
4301
4301
|
const fromResponseProperty = OpenAIResponsesResponseSchema.safeParse(
|
|
4302
|
-
readProperty$
|
|
4302
|
+
readProperty$2(value, "response")
|
|
4303
4303
|
);
|
|
4304
4304
|
if (fromResponseProperty.success) return fromResponseProperty.data;
|
|
4305
4305
|
const direct = OpenAIResponsesResponseSchema.safeParse(value);
|
|
@@ -4311,10 +4311,10 @@ function responseTextFromOutput(response) {
|
|
|
4311
4311
|
}
|
|
4312
4312
|
const parts = [];
|
|
4313
4313
|
for (const outputItem of response.output ?? []) {
|
|
4314
|
-
const content = readArrayProperty(outputItem, "content");
|
|
4314
|
+
const content = readArrayProperty$1(outputItem, "content");
|
|
4315
4315
|
for (const contentPart of content) {
|
|
4316
|
-
const type = readStringProperty$
|
|
4317
|
-
const text = readStringProperty$
|
|
4316
|
+
const type = readStringProperty$2(contentPart, "type");
|
|
4317
|
+
const text = readStringProperty$2(contentPart, "text");
|
|
4318
4318
|
if ((type === "output_text" || type === "text") && text !== null && text.length > 0) {
|
|
4319
4319
|
parts.push(text);
|
|
4320
4320
|
}
|
|
@@ -4333,7 +4333,7 @@ function updateUsageFromResponse(response, log) {
|
|
|
4333
4333
|
return { inputTokens, outputTokens };
|
|
4334
4334
|
}
|
|
4335
4335
|
function functionCallKey(payload, fallbackIndex) {
|
|
4336
|
-
const itemId = readStringProperty$
|
|
4336
|
+
const itemId = readStringProperty$2(payload, "item_id");
|
|
4337
4337
|
if (itemId !== null && itemId.length > 0) return itemId;
|
|
4338
4338
|
const outputIndex = readNumberProperty(payload, "output_index");
|
|
4339
4339
|
if (outputIndex !== null) return String(outputIndex);
|
|
@@ -4350,13 +4350,13 @@ function ensureFunctionCall(calls, key) {
|
|
|
4350
4350
|
return created;
|
|
4351
4351
|
}
|
|
4352
4352
|
function updateFunctionCallFromItem(calls, key, item) {
|
|
4353
|
-
if (readStringProperty$
|
|
4353
|
+
if (readStringProperty$2(item, "type") !== "function_call") return;
|
|
4354
4354
|
const call = ensureFunctionCall(calls, key);
|
|
4355
|
-
const id = readStringProperty$
|
|
4356
|
-
const callId = readStringProperty$
|
|
4357
|
-
const name = readStringProperty$
|
|
4358
|
-
const args = readStringProperty$
|
|
4359
|
-
const status = readStringProperty$
|
|
4355
|
+
const id = readStringProperty$2(item, "id");
|
|
4356
|
+
const callId = readStringProperty$2(item, "call_id");
|
|
4357
|
+
const name = readStringProperty$2(item, "name");
|
|
4358
|
+
const args = readStringProperty$2(item, "arguments");
|
|
4359
|
+
const status = readStringProperty$2(item, "status");
|
|
4360
4360
|
if (id !== null) call.id = id;
|
|
4361
4361
|
if (callId !== null) call.call_id = callId;
|
|
4362
4362
|
if (name !== null) call.name = name;
|
|
@@ -4444,13 +4444,13 @@ function extractResponsesStream(events, log, fallbackModel, collectChunks) {
|
|
|
4444
4444
|
outputTokens = usage.outputTokens ?? outputTokens;
|
|
4445
4445
|
setErrorFromPayload(log, response);
|
|
4446
4446
|
}
|
|
4447
|
-
const delta = readStringProperty$
|
|
4447
|
+
const delta = readStringProperty$2(parsed, "delta");
|
|
4448
4448
|
switch (type) {
|
|
4449
4449
|
case "response.output_text.delta":
|
|
4450
4450
|
if (delta !== null) outputText += delta;
|
|
4451
4451
|
break;
|
|
4452
4452
|
case "response.output_text.done": {
|
|
4453
|
-
const text = readStringProperty$
|
|
4453
|
+
const text = readStringProperty$2(parsed, "text");
|
|
4454
4454
|
if (outputText.length === 0 && text !== null) outputText = text;
|
|
4455
4455
|
break;
|
|
4456
4456
|
}
|
|
@@ -4462,7 +4462,7 @@ function extractResponsesStream(events, log, fallbackModel, collectChunks) {
|
|
|
4462
4462
|
break;
|
|
4463
4463
|
}
|
|
4464
4464
|
case "response.function_call_arguments.done": {
|
|
4465
|
-
const args = readStringProperty$
|
|
4465
|
+
const args = readStringProperty$2(parsed, "arguments");
|
|
4466
4466
|
if (args !== null) {
|
|
4467
4467
|
const call = ensureFunctionCall(calls, functionCallKey(parsed, calls.size));
|
|
4468
4468
|
call.arguments = args;
|
|
@@ -4511,7 +4511,7 @@ function extractResponsesStream(events, log, fallbackModel, collectChunks) {
|
|
|
4511
4511
|
return JSON.stringify(normalizedResponse.data);
|
|
4512
4512
|
}
|
|
4513
4513
|
if (log.outputTokens === null) {
|
|
4514
|
-
const finalText = readStringProperty$
|
|
4514
|
+
const finalText = readStringProperty$2(normalized, "output_text") ?? outputText;
|
|
4515
4515
|
const estimatedOutputTokens = Math.ceil(finalText.length / 4);
|
|
4516
4516
|
log.outputTokens = estimatedOutputTokens;
|
|
4517
4517
|
}
|
|
@@ -6251,7 +6251,7 @@ function parseJson$1(raw) {
|
|
|
6251
6251
|
function isRecord$1(value) {
|
|
6252
6252
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6253
6253
|
}
|
|
6254
|
-
function readProperty(value, key) {
|
|
6254
|
+
function readProperty$1(value, key) {
|
|
6255
6255
|
if (!isRecord$1(value)) return void 0;
|
|
6256
6256
|
return Object.getOwnPropertyDescriptor(value, key)?.value;
|
|
6257
6257
|
}
|
|
@@ -6259,18 +6259,18 @@ function hasOwnProperty(value, key) {
|
|
|
6259
6259
|
return Object.getOwnPropertyDescriptor(value, key) !== void 0;
|
|
6260
6260
|
}
|
|
6261
6261
|
function readString(value, key) {
|
|
6262
|
-
const property = readProperty(value, key);
|
|
6262
|
+
const property = readProperty$1(value, key);
|
|
6263
6263
|
return typeof property === "string" ? property : null;
|
|
6264
6264
|
}
|
|
6265
6265
|
function readArray(value, key) {
|
|
6266
|
-
const property = readProperty(value, key);
|
|
6266
|
+
const property = readProperty$1(value, key);
|
|
6267
6267
|
return Array.isArray(property) ? property : [];
|
|
6268
6268
|
}
|
|
6269
6269
|
function readStringArray(value, key) {
|
|
6270
6270
|
return readArray(value, key).filter((item) => typeof item === "string");
|
|
6271
6271
|
}
|
|
6272
6272
|
function readObject(value, key) {
|
|
6273
|
-
const property = readProperty(value, key);
|
|
6273
|
+
const property = readProperty$1(value, key);
|
|
6274
6274
|
return isRecord$1(property) ? property : null;
|
|
6275
6275
|
}
|
|
6276
6276
|
function normalizeExpectedType(typeName) {
|
|
@@ -6288,7 +6288,7 @@ function normalizeExpectedType(typeName) {
|
|
|
6288
6288
|
}
|
|
6289
6289
|
}
|
|
6290
6290
|
function schemaTypes(schema) {
|
|
6291
|
-
const typeValue = readProperty(schema, "type");
|
|
6291
|
+
const typeValue = readProperty$1(schema, "type");
|
|
6292
6292
|
const rawTypes = Array.isArray(typeValue) ? typeValue : [typeValue];
|
|
6293
6293
|
const types = [];
|
|
6294
6294
|
for (const rawType of rawTypes) {
|
|
@@ -6378,7 +6378,7 @@ function schemaAllowsObjectValidation(schema, expectedTypes) {
|
|
|
6378
6378
|
return expectedTypes.includes("object");
|
|
6379
6379
|
}
|
|
6380
6380
|
function schemaAllowsArrayValidation(schema, expectedTypes) {
|
|
6381
|
-
if (expectedTypes.length === 0) return readProperty(schema, "items") !== void 0;
|
|
6381
|
+
if (expectedTypes.length === 0) return readProperty$1(schema, "items") !== void 0;
|
|
6382
6382
|
return expectedTypes.includes("array");
|
|
6383
6383
|
}
|
|
6384
6384
|
function addTypeWarning(warnings, toolName, path2, expectedTypes, value) {
|
|
@@ -6411,7 +6411,7 @@ function validateObjectSchema(schema, value, toolName, path2, warnings) {
|
|
|
6411
6411
|
}
|
|
6412
6412
|
}
|
|
6413
6413
|
function validateArraySchema(schema, value, toolName, path2, warnings) {
|
|
6414
|
-
const itemsSchema = readProperty(schema, "items");
|
|
6414
|
+
const itemsSchema = readProperty$1(schema, "items");
|
|
6415
6415
|
if (itemsSchema === void 0) return;
|
|
6416
6416
|
let index = 0;
|
|
6417
6417
|
for (const item of value) {
|
|
@@ -6420,7 +6420,7 @@ function validateArraySchema(schema, value, toolName, path2, warnings) {
|
|
|
6420
6420
|
}
|
|
6421
6421
|
}
|
|
6422
6422
|
function validateEnum(schema, value, toolName, path2, warnings) {
|
|
6423
|
-
const enumValue = readProperty(schema, "enum");
|
|
6423
|
+
const enumValue = readProperty$1(schema, "enum");
|
|
6424
6424
|
if (Array.isArray(enumValue) && enumValue.length > 0 && !enumMatches(value, enumValue)) {
|
|
6425
6425
|
warnings.push(
|
|
6426
6426
|
`Tool call "${toolName}" ${pathLabel(path2)} expected one of ${formatJsonValue(
|
|
@@ -6537,7 +6537,7 @@ function extractOpenAIToolCalls(response) {
|
|
|
6537
6537
|
for (const call of readArray(message, "tool_calls")) {
|
|
6538
6538
|
const functionCall = readObject(call, "function");
|
|
6539
6539
|
const name = functionCall === null ? null : readString(functionCall, "name");
|
|
6540
|
-
const parsedArguments = functionCall === null ? { value: {}, issue: "function block is missing" } : parseOpenAIArguments(readProperty(functionCall, "arguments"));
|
|
6540
|
+
const parsedArguments = functionCall === null ? { value: {}, issue: "function block is missing" } : parseOpenAIArguments(readProperty$1(functionCall, "arguments"));
|
|
6541
6541
|
calls.push({
|
|
6542
6542
|
name,
|
|
6543
6543
|
arguments: parsedArguments.value,
|
|
@@ -6548,7 +6548,7 @@ function extractOpenAIToolCalls(response) {
|
|
|
6548
6548
|
}
|
|
6549
6549
|
const legacyFunctionCall = readObject(message, "function_call");
|
|
6550
6550
|
if (legacyFunctionCall !== null) {
|
|
6551
|
-
const parsedArguments = parseOpenAIArguments(readProperty(legacyFunctionCall, "arguments"));
|
|
6551
|
+
const parsedArguments = parseOpenAIArguments(readProperty$1(legacyFunctionCall, "arguments"));
|
|
6552
6552
|
calls.push({
|
|
6553
6553
|
name: readString(legacyFunctionCall, "name"),
|
|
6554
6554
|
arguments: parsedArguments.value,
|
|
@@ -6564,7 +6564,7 @@ function extractOpenAIToolCalls(response) {
|
|
|
6564
6564
|
outputIndex++;
|
|
6565
6565
|
continue;
|
|
6566
6566
|
}
|
|
6567
|
-
const parsedArguments = parseOpenAIArguments(readProperty(item, "arguments"));
|
|
6567
|
+
const parsedArguments = parseOpenAIArguments(readProperty$1(item, "arguments"));
|
|
6568
6568
|
calls.push({
|
|
6569
6569
|
name: readString(item, "name"),
|
|
6570
6570
|
arguments: parsedArguments.value,
|
|
@@ -6585,7 +6585,7 @@ function extractAnthropicToolCalls(response) {
|
|
|
6585
6585
|
}
|
|
6586
6586
|
calls.push({
|
|
6587
6587
|
name: readString(block, "name"),
|
|
6588
|
-
arguments: readProperty(block, "input") ?? {},
|
|
6588
|
+
arguments: readProperty$1(block, "input") ?? {},
|
|
6589
6589
|
argumentIssue: null,
|
|
6590
6590
|
location: `content[${contentIndex}]`
|
|
6591
6591
|
});
|
|
@@ -7154,9 +7154,11 @@ class RawStreamCapture {
|
|
|
7154
7154
|
}
|
|
7155
7155
|
}
|
|
7156
7156
|
const PATH_V1_CHAT_COMPLETIONS = "/v1/chat/completions";
|
|
7157
|
+
const PATH_V1_RESPONSES = "/v1/responses";
|
|
7158
|
+
const PATH_V1_MESSAGES = "/v1/messages";
|
|
7157
7159
|
function buildUpstreamUrl(upstreamBase, normalizedPath) {
|
|
7158
7160
|
const base = upstreamBase.endsWith("/") ? upstreamBase.slice(0, -1) : upstreamBase;
|
|
7159
|
-
const endpointPath = normalizedPath
|
|
7161
|
+
const endpointPath = endpointPathFor(normalizedPath);
|
|
7160
7162
|
const queryIndex = normalizedPath.indexOf("?");
|
|
7161
7163
|
const search = queryIndex >= 0 ? normalizedPath.slice(queryIndex) : "";
|
|
7162
7164
|
if (endpointPath !== "" && base.endsWith(endpointPath)) {
|
|
@@ -7170,9 +7172,78 @@ function buildUpstreamUrl(upstreamBase, normalizedPath) {
|
|
|
7170
7172
|
}
|
|
7171
7173
|
return base + normalizedPath;
|
|
7172
7174
|
}
|
|
7175
|
+
function previewUpstreamUrl(upstreamBase, normalizedPath, options = {}) {
|
|
7176
|
+
const base = upstreamBase.trim().replace(/\/+$/, "");
|
|
7177
|
+
const endpointPath = endpointPathFor(normalizedPath);
|
|
7178
|
+
const finalUrl = buildUpstreamUrl(base, normalizedPath);
|
|
7179
|
+
const diagnostics = [];
|
|
7180
|
+
const exactEndpoint = endpointPath !== "" && base.endsWith(endpointPath);
|
|
7181
|
+
if (exactEndpoint) {
|
|
7182
|
+
diagnostics.push({
|
|
7183
|
+
severity: "info",
|
|
7184
|
+
message: "This already includes the exact endpoint; no duplicate suffix will be appended."
|
|
7185
|
+
});
|
|
7186
|
+
} else if (isZhipuVersionedOpenAIBase(base) && isVersionedChatCompletionsPath(normalizedPath)) {
|
|
7187
|
+
diagnostics.push({
|
|
7188
|
+
severity: "info",
|
|
7189
|
+
message: "Zhipu bases already include the API version; only /chat/completions is appended."
|
|
7190
|
+
});
|
|
7191
|
+
} else if (base.endsWith("/v1") && normalizedPath.startsWith("/v1/")) {
|
|
7192
|
+
diagnostics.push({
|
|
7193
|
+
severity: "info",
|
|
7194
|
+
message: "Base URL already ends with /v1; the suffix will not repeat /v1."
|
|
7195
|
+
});
|
|
7196
|
+
}
|
|
7197
|
+
if (isResponsesPath(endpointPath) && baseEndsWithChatEndpoint(base)) {
|
|
7198
|
+
diagnostics.push({
|
|
7199
|
+
severity: "warning",
|
|
7200
|
+
message: "This looks like a Chat Completions endpoint, so Responses would append after it."
|
|
7201
|
+
});
|
|
7202
|
+
}
|
|
7203
|
+
if (isChatCompletionsPath(endpointPath) && baseEndsWithResponsesEndpoint(base)) {
|
|
7204
|
+
diagnostics.push({
|
|
7205
|
+
severity: "warning",
|
|
7206
|
+
message: "This looks like a Responses endpoint, so Chat Completions would append after it."
|
|
7207
|
+
});
|
|
7208
|
+
}
|
|
7209
|
+
if (isResponsesPath(endpointPath) && isLikelyDeepSeekBase(base, options.providerName)) {
|
|
7210
|
+
diagnostics.push({
|
|
7211
|
+
severity: "warning",
|
|
7212
|
+
message: "DeepSeek's official API does not currently expose OpenAI Responses."
|
|
7213
|
+
});
|
|
7214
|
+
}
|
|
7215
|
+
return { finalUrl, diagnostics };
|
|
7216
|
+
}
|
|
7217
|
+
function endpointPathFor(normalizedPath) {
|
|
7218
|
+
return normalizedPath.split("?")[0] ?? normalizedPath;
|
|
7219
|
+
}
|
|
7173
7220
|
function isVersionedChatCompletionsPath(normalizedPath) {
|
|
7174
7221
|
return normalizedPath === PATH_V1_CHAT_COMPLETIONS || normalizedPath.startsWith(`${PATH_V1_CHAT_COMPLETIONS}?`) || normalizedPath.startsWith(`${PATH_V1_CHAT_COMPLETIONS}/`);
|
|
7175
7222
|
}
|
|
7223
|
+
function isChatCompletionsPath(endpointPath) {
|
|
7224
|
+
return endpointPath === PATH_V1_CHAT_COMPLETIONS || endpointPath.startsWith(`${PATH_V1_CHAT_COMPLETIONS}/`);
|
|
7225
|
+
}
|
|
7226
|
+
function isResponsesPath(endpointPath) {
|
|
7227
|
+
return endpointPath === PATH_V1_RESPONSES || endpointPath.startsWith(`${PATH_V1_RESPONSES}/`);
|
|
7228
|
+
}
|
|
7229
|
+
function baseEndsWithChatEndpoint(base) {
|
|
7230
|
+
const normalized = base.toLowerCase();
|
|
7231
|
+
return normalized.endsWith("/chat/completions");
|
|
7232
|
+
}
|
|
7233
|
+
function baseEndsWithResponsesEndpoint(base) {
|
|
7234
|
+
const normalized = base.toLowerCase();
|
|
7235
|
+
return normalized.endsWith("/responses");
|
|
7236
|
+
}
|
|
7237
|
+
function isLikelyDeepSeekBase(base, providerName) {
|
|
7238
|
+
const provider = providerName?.toLowerCase();
|
|
7239
|
+
if (provider !== void 0 && provider.includes("deepseek")) return true;
|
|
7240
|
+
try {
|
|
7241
|
+
const parsed = new URL(base);
|
|
7242
|
+
return parsed.hostname.toLowerCase().includes("deepseek");
|
|
7243
|
+
} catch {
|
|
7244
|
+
return base.toLowerCase().includes("deepseek");
|
|
7245
|
+
}
|
|
7246
|
+
}
|
|
7176
7247
|
function isZhipuVersionedOpenAIBase(base) {
|
|
7177
7248
|
try {
|
|
7178
7249
|
const parsed = new URL(base);
|
|
@@ -7185,7 +7256,7 @@ function isZhipuVersionedOpenAIBase(base) {
|
|
|
7185
7256
|
function describeApiRoute(apiPath) {
|
|
7186
7257
|
const endpointPath = apiPath.split("?")[0] ?? "";
|
|
7187
7258
|
const isChatCompletions = endpointPath === PATH_CHAT_COMPLETIONS || endpointPath === PATH_V1_CHAT_COMPLETIONS$1;
|
|
7188
|
-
const isResponses = endpointPath === PATH_RESPONSES || endpointPath === PATH_V1_RESPONSES;
|
|
7259
|
+
const isResponses = endpointPath === PATH_RESPONSES || endpointPath === PATH_V1_RESPONSES$1;
|
|
7189
7260
|
const isOpenAI = isChatCompletions || isResponses;
|
|
7190
7261
|
const normalizedPath = isOpenAI && !apiPath.startsWith("/v1/") ? `/v1${apiPath}` : apiPath;
|
|
7191
7262
|
return { apiPath, endpointPath, isChatCompletions, isResponses, isOpenAI, normalizedPath };
|
|
@@ -7255,7 +7326,7 @@ function parseRequestPath(req, url) {
|
|
|
7255
7326
|
const route = describeApiRoute(getProxyApiPath(url));
|
|
7256
7327
|
const isPost = req.method === "POST";
|
|
7257
7328
|
const isChatCompletions = isPost && route.isChatCompletions;
|
|
7258
|
-
const isMessages = isPost && (route.endpointPath === PATH_V1_MESSAGES || route.isChatCompletions);
|
|
7329
|
+
const isMessages = isPost && (route.endpointPath === PATH_V1_MESSAGES$1 || route.isChatCompletions);
|
|
7259
7330
|
return {
|
|
7260
7331
|
apiPath: route.apiPath,
|
|
7261
7332
|
isMessages,
|
|
@@ -9016,7 +9087,7 @@ const Route$w = createFileRoute("/api/models")({
|
|
|
9016
9087
|
}
|
|
9017
9088
|
}
|
|
9018
9089
|
});
|
|
9019
|
-
const version = "2.1.
|
|
9090
|
+
const version = "2.1.17";
|
|
9020
9091
|
const packageJson = {
|
|
9021
9092
|
version
|
|
9022
9093
|
};
|
|
@@ -10224,7 +10295,7 @@ function providerDiagnosticHints(result) {
|
|
|
10224
10295
|
}
|
|
10225
10296
|
if (text.includes("nonstream") || text.includes("non-stream")) {
|
|
10226
10297
|
hints.push(
|
|
10227
|
-
"The failure mentions non-streaming. Compare the
|
|
10298
|
+
"The failure mentions non-streaming. Compare the Anthropic, OpenAI Chat, and OpenAI Responses non-streaming path and payload with the streaming request."
|
|
10228
10299
|
);
|
|
10229
10300
|
}
|
|
10230
10301
|
return [...new Set(hints)];
|
|
@@ -13229,7 +13300,7 @@ function parseJsonlLogs(text) {
|
|
|
13229
13300
|
}
|
|
13230
13301
|
return { logs, skipped };
|
|
13231
13302
|
}
|
|
13232
|
-
function readStringProperty(value, name) {
|
|
13303
|
+
function readStringProperty$1(value, name) {
|
|
13233
13304
|
const property = readRecordProperty(value, name);
|
|
13234
13305
|
return typeof property === "string" ? property : null;
|
|
13235
13306
|
}
|
|
@@ -13238,7 +13309,7 @@ function hasProperty(value, name) {
|
|
|
13238
13309
|
return Object.getOwnPropertyDescriptor(value, name) !== void 0;
|
|
13239
13310
|
}
|
|
13240
13311
|
function modelFromRequestText(requestText) {
|
|
13241
|
-
return readStringProperty(parseJson(requestText), "model");
|
|
13312
|
+
return readStringProperty$1(parseJson(requestText), "model");
|
|
13242
13313
|
}
|
|
13243
13314
|
function inferApiFormatFromBody(path2, model, requestText) {
|
|
13244
13315
|
const pathFormat = apiFormatForPath(path2);
|
|
@@ -14424,7 +14495,15 @@ function buildProviderTestUserPrompt(mode) {
|
|
|
14424
14495
|
function buildProviderTestMessages(mode) {
|
|
14425
14496
|
return [{ role: "user", content: buildProviderTestUserPrompt(mode) }];
|
|
14426
14497
|
}
|
|
14427
|
-
function buildProviderTestRequestBody(model, mode) {
|
|
14498
|
+
function buildProviderTestRequestBody(model, mode, apiShape = "chat") {
|
|
14499
|
+
if (apiShape === "responses") {
|
|
14500
|
+
return {
|
|
14501
|
+
model,
|
|
14502
|
+
input: buildProviderTestUserPrompt(mode),
|
|
14503
|
+
max_output_tokens: maxTokensForMode(mode),
|
|
14504
|
+
stream: mode === "streaming"
|
|
14505
|
+
};
|
|
14506
|
+
}
|
|
14428
14507
|
const base = {
|
|
14429
14508
|
model,
|
|
14430
14509
|
messages: buildProviderTestMessages(mode),
|
|
@@ -14671,6 +14750,50 @@ const OpenAIResponseSchema = object({
|
|
|
14671
14750
|
})
|
|
14672
14751
|
)
|
|
14673
14752
|
});
|
|
14753
|
+
function isOpenAIProtocol(protocol) {
|
|
14754
|
+
return protocol === "openaiChat" || protocol === "openaiResponses";
|
|
14755
|
+
}
|
|
14756
|
+
function providerTestApiShape(protocol) {
|
|
14757
|
+
switch (protocol) {
|
|
14758
|
+
case "anthropic":
|
|
14759
|
+
case "openaiChat":
|
|
14760
|
+
return "chat";
|
|
14761
|
+
case "openaiResponses":
|
|
14762
|
+
return "responses";
|
|
14763
|
+
}
|
|
14764
|
+
}
|
|
14765
|
+
function buildProviderTestBodyText(model, mode, protocol) {
|
|
14766
|
+
return JSON.stringify(buildProviderTestRequestBody(model, mode, providerTestApiShape(protocol)));
|
|
14767
|
+
}
|
|
14768
|
+
function readProperty(value, key) {
|
|
14769
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
14770
|
+
return Object.getOwnPropertyDescriptor(value, key)?.value;
|
|
14771
|
+
}
|
|
14772
|
+
function readStringProperty(value, key) {
|
|
14773
|
+
const property = readProperty(value, key);
|
|
14774
|
+
return typeof property === "string" ? property : null;
|
|
14775
|
+
}
|
|
14776
|
+
function readArrayProperty(value, key) {
|
|
14777
|
+
const property = readProperty(value, key);
|
|
14778
|
+
return Array.isArray(property) ? property : [];
|
|
14779
|
+
}
|
|
14780
|
+
function responseTextFromOpenAIResponses(response) {
|
|
14781
|
+
if (response.output_text !== void 0 && response.output_text.length > 0) {
|
|
14782
|
+
return response.output_text;
|
|
14783
|
+
}
|
|
14784
|
+
const parts = [];
|
|
14785
|
+
for (const outputItem of response.output ?? []) {
|
|
14786
|
+
const content = readArrayProperty(outputItem, "content");
|
|
14787
|
+
for (const contentPart of content) {
|
|
14788
|
+
const type = readStringProperty(contentPart, "type");
|
|
14789
|
+
const text = readStringProperty(contentPart, "text");
|
|
14790
|
+
if ((type === "output_text" || type === "text") && text !== null && text.length > 0) {
|
|
14791
|
+
parts.push(text);
|
|
14792
|
+
}
|
|
14793
|
+
}
|
|
14794
|
+
}
|
|
14795
|
+
return parts.length > 0 ? parts.join("\n") : null;
|
|
14796
|
+
}
|
|
14674
14797
|
function getProviderTestTimeoutMs() {
|
|
14675
14798
|
return getConfig().providerTestTimeoutSeconds * 1e3;
|
|
14676
14799
|
}
|
|
@@ -14684,9 +14807,9 @@ function buildTestRequestHeaders(provider) {
|
|
|
14684
14807
|
});
|
|
14685
14808
|
return result;
|
|
14686
14809
|
}
|
|
14687
|
-
async function testEndpoint(baseUrl, provider, path2, model,
|
|
14810
|
+
async function testEndpoint(baseUrl, provider, path2, model, protocol) {
|
|
14688
14811
|
const startTime = Date.now();
|
|
14689
|
-
const body =
|
|
14812
|
+
const body = buildProviderTestBodyText(model, "non-streaming", protocol);
|
|
14690
14813
|
const requestHeaders = buildTestRequestHeaders(provider);
|
|
14691
14814
|
let requestUrl = baseUrl;
|
|
14692
14815
|
const controller = new AbortController();
|
|
@@ -14719,7 +14842,7 @@ async function testEndpoint(baseUrl, provider, path2, model, isOpenAI) {
|
|
|
14719
14842
|
const responseText = await response.text();
|
|
14720
14843
|
const safeRequestHeaders = redactHeaders(requestHeaders);
|
|
14721
14844
|
try {
|
|
14722
|
-
if (
|
|
14845
|
+
if (protocol === "openaiChat") {
|
|
14723
14846
|
const json = OpenAIResponseSchema.parse(JSON.parse(responseText));
|
|
14724
14847
|
const responseModel = json.model ?? model;
|
|
14725
14848
|
const inputTokens = json.usage?.prompt_tokens;
|
|
@@ -14735,7 +14858,25 @@ async function testEndpoint(baseUrl, provider, path2, model, isOpenAI) {
|
|
|
14735
14858
|
rawResponse: responseText,
|
|
14736
14859
|
requestHeaders: safeRequestHeaders
|
|
14737
14860
|
};
|
|
14738
|
-
}
|
|
14861
|
+
}
|
|
14862
|
+
if (protocol === "openaiResponses") {
|
|
14863
|
+
const json = OpenAIResponsesResponseSchema.parse(JSON.parse(responseText));
|
|
14864
|
+
const responseModel = json.model ?? model;
|
|
14865
|
+
const inputTokens = json.usage?.input_tokens ?? void 0;
|
|
14866
|
+
const outputTokens = json.usage?.output_tokens ?? void 0;
|
|
14867
|
+
const content = responseTextFromOpenAIResponses(json);
|
|
14868
|
+
return {
|
|
14869
|
+
success: true,
|
|
14870
|
+
model: responseModel,
|
|
14871
|
+
inputTokens,
|
|
14872
|
+
outputTokens,
|
|
14873
|
+
latencyMs,
|
|
14874
|
+
content: content !== null && content !== "" ? [{ type: "text", text: content }] : void 0,
|
|
14875
|
+
rawResponse: responseText,
|
|
14876
|
+
requestHeaders: safeRequestHeaders
|
|
14877
|
+
};
|
|
14878
|
+
}
|
|
14879
|
+
{
|
|
14739
14880
|
const json = AnthropicResponseSchema.parse(JSON.parse(responseText));
|
|
14740
14881
|
const responseModel = json.model ?? model;
|
|
14741
14882
|
const inputTokens = json.usage?.input_tokens;
|
|
@@ -14790,9 +14931,9 @@ async function testEndpoint(baseUrl, provider, path2, model, isOpenAI) {
|
|
|
14790
14931
|
clearTimeout(timeoutId);
|
|
14791
14932
|
}
|
|
14792
14933
|
}
|
|
14793
|
-
async function testStreamingEndpoint(baseUrl, provider, path2, model,
|
|
14934
|
+
async function testStreamingEndpoint(baseUrl, provider, path2, model, protocol) {
|
|
14794
14935
|
const startTime = Date.now();
|
|
14795
|
-
const body =
|
|
14936
|
+
const body = buildProviderTestBodyText(model, "streaming", protocol);
|
|
14796
14937
|
const requestHeaders = buildTestRequestHeaders(provider);
|
|
14797
14938
|
let requestUrl = baseUrl;
|
|
14798
14939
|
const controller = new AbortController();
|
|
@@ -14906,11 +15047,11 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
14906
15047
|
streaming: true,
|
|
14907
15048
|
userAgent: null,
|
|
14908
15049
|
origin: null,
|
|
14909
|
-
apiFormat: "anthropic",
|
|
15050
|
+
apiFormat: isOpenAIProtocol(protocol) ? "openai" : "anthropic",
|
|
14910
15051
|
isTest: true
|
|
14911
15052
|
};
|
|
14912
15053
|
let reconstructedJson;
|
|
14913
|
-
if (
|
|
15054
|
+
if (isOpenAIProtocol(protocol)) {
|
|
14914
15055
|
reconstructedJson = extractOpenAIStream(fullResponse, mockLog, model, true);
|
|
14915
15056
|
} else {
|
|
14916
15057
|
reconstructedJson = extractAnthropicStream(fullResponse, mockLog, model, true);
|
|
@@ -14923,7 +15064,7 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
14923
15064
|
let cacheCreationInputTokens;
|
|
14924
15065
|
let cacheReadInputTokens;
|
|
14925
15066
|
let responseModel;
|
|
14926
|
-
if (
|
|
15067
|
+
if (protocol === "openaiChat") {
|
|
14927
15068
|
const parsed = OpenAIResponseSchema.parse(JSON.parse(reconstructedJson));
|
|
14928
15069
|
responseModel = typeof parsed.model === "string" && parsed.model !== "" ? parsed.model : void 0;
|
|
14929
15070
|
inputTokens = parsed.usage?.prompt_tokens;
|
|
@@ -14932,6 +15073,15 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
14932
15073
|
if (textContent !== null && textContent !== "") {
|
|
14933
15074
|
content = [{ type: "text", text: textContent }];
|
|
14934
15075
|
}
|
|
15076
|
+
} else if (protocol === "openaiResponses") {
|
|
15077
|
+
const parsed = OpenAIResponsesResponseSchema.parse(JSON.parse(reconstructedJson));
|
|
15078
|
+
responseModel = typeof parsed.model === "string" && parsed.model !== "" ? parsed.model : void 0;
|
|
15079
|
+
inputTokens = parsed.usage?.input_tokens ?? void 0;
|
|
15080
|
+
outputTokens = parsed.usage?.output_tokens ?? void 0;
|
|
15081
|
+
const textContent = responseTextFromOpenAIResponses(parsed);
|
|
15082
|
+
if (textContent !== null && textContent !== "") {
|
|
15083
|
+
content = [{ type: "text", text: textContent }];
|
|
15084
|
+
}
|
|
14935
15085
|
} else {
|
|
14936
15086
|
const parsed = AnthropicResponseSchema.parse(JSON.parse(reconstructedJson));
|
|
14937
15087
|
responseModel = typeof parsed.model === "string" && parsed.model !== "" ? parsed.model : void 0;
|
|
@@ -15016,24 +15166,39 @@ const Route$a = createFileRoute("/api/providers/$providerId/test")({
|
|
|
15016
15166
|
const results = {
|
|
15017
15167
|
anthropic: { nonStreaming: { notConfigured: true }, streaming: { notConfigured: true } },
|
|
15018
15168
|
openai: { nonStreaming: { notConfigured: true }, streaming: { notConfigured: true } },
|
|
15169
|
+
openaiChat: {
|
|
15170
|
+
nonStreaming: { notConfigured: true },
|
|
15171
|
+
streaming: { notConfigured: true }
|
|
15172
|
+
},
|
|
15173
|
+
openaiResponses: {
|
|
15174
|
+
nonStreaming: { notConfigured: true },
|
|
15175
|
+
streaming: { notConfigured: true }
|
|
15176
|
+
},
|
|
15019
15177
|
models: {}
|
|
15020
15178
|
};
|
|
15021
15179
|
const anthropicUrl = provider.anthropicBaseUrl !== void 0 && provider.anthropicBaseUrl.length > 0 ? provider.anthropicBaseUrl : void 0;
|
|
15022
15180
|
const openaiUrl = provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl.length > 0 ? provider.openaiBaseUrl : void 0;
|
|
15181
|
+
const openaiResponsesUrl = provider.openaiResponsesBaseUrl !== void 0 && provider.openaiResponsesBaseUrl.length > 0 ? provider.openaiResponsesBaseUrl : void 0;
|
|
15023
15182
|
async function testOneModel(displayName) {
|
|
15024
15183
|
const usageModel = getModelUsageName(displayName, p.name);
|
|
15025
15184
|
const notConfigured = { notConfigured: true };
|
|
15185
|
+
const notConfiguredFormat = {
|
|
15186
|
+
nonStreaming: notConfigured,
|
|
15187
|
+
streaming: notConfigured
|
|
15188
|
+
};
|
|
15026
15189
|
const modelResults = {
|
|
15027
15190
|
anthropic: { nonStreaming: notConfigured, streaming: notConfigured },
|
|
15028
|
-
openai:
|
|
15191
|
+
openai: notConfiguredFormat,
|
|
15192
|
+
openaiChat: { nonStreaming: notConfigured, streaming: notConfigured },
|
|
15193
|
+
openaiResponses: { nonStreaming: notConfigured, streaming: notConfigured }
|
|
15029
15194
|
};
|
|
15030
15195
|
const tasks = [];
|
|
15031
15196
|
if (anthropicUrl !== void 0) {
|
|
15032
15197
|
tasks.push(
|
|
15033
|
-
testEndpoint(anthropicUrl, p, "/v1/messages", usageModel,
|
|
15198
|
+
testEndpoint(anthropicUrl, p, "/v1/messages", usageModel, "anthropic").then((r) => {
|
|
15034
15199
|
modelResults.anthropic.nonStreaming = r;
|
|
15035
15200
|
}),
|
|
15036
|
-
testStreamingEndpoint(anthropicUrl, p, "/v1/messages", usageModel,
|
|
15201
|
+
testStreamingEndpoint(anthropicUrl, p, "/v1/messages", usageModel, "anthropic").then(
|
|
15037
15202
|
(r) => {
|
|
15038
15203
|
modelResults.anthropic.streaming = r;
|
|
15039
15204
|
}
|
|
@@ -15042,14 +15207,44 @@ const Route$a = createFileRoute("/api/providers/$providerId/test")({
|
|
|
15042
15207
|
}
|
|
15043
15208
|
if (openaiUrl !== void 0) {
|
|
15044
15209
|
tasks.push(
|
|
15045
|
-
testEndpoint(openaiUrl, p, "/v1/chat/completions", usageModel,
|
|
15046
|
-
modelResults.openai.nonStreaming = r;
|
|
15047
|
-
}),
|
|
15048
|
-
testStreamingEndpoint(openaiUrl, p, "/v1/chat/completions", usageModel, true).then(
|
|
15210
|
+
testEndpoint(openaiUrl, p, "/v1/chat/completions", usageModel, "openaiChat").then(
|
|
15049
15211
|
(r) => {
|
|
15050
|
-
modelResults.openai.
|
|
15212
|
+
modelResults.openai.nonStreaming = r;
|
|
15213
|
+
modelResults.openaiChat.nonStreaming = r;
|
|
15051
15214
|
}
|
|
15052
|
-
)
|
|
15215
|
+
),
|
|
15216
|
+
testStreamingEndpoint(
|
|
15217
|
+
openaiUrl,
|
|
15218
|
+
p,
|
|
15219
|
+
"/v1/chat/completions",
|
|
15220
|
+
usageModel,
|
|
15221
|
+
"openaiChat"
|
|
15222
|
+
).then((r) => {
|
|
15223
|
+
modelResults.openai.streaming = r;
|
|
15224
|
+
modelResults.openaiChat.streaming = r;
|
|
15225
|
+
})
|
|
15226
|
+
);
|
|
15227
|
+
}
|
|
15228
|
+
if (openaiResponsesUrl !== void 0) {
|
|
15229
|
+
tasks.push(
|
|
15230
|
+
testEndpoint(
|
|
15231
|
+
openaiResponsesUrl,
|
|
15232
|
+
p,
|
|
15233
|
+
"/v1/responses",
|
|
15234
|
+
usageModel,
|
|
15235
|
+
"openaiResponses"
|
|
15236
|
+
).then((r) => {
|
|
15237
|
+
modelResults.openaiResponses.nonStreaming = r;
|
|
15238
|
+
}),
|
|
15239
|
+
testStreamingEndpoint(
|
|
15240
|
+
openaiResponsesUrl,
|
|
15241
|
+
p,
|
|
15242
|
+
"/v1/responses",
|
|
15243
|
+
usageModel,
|
|
15244
|
+
"openaiResponses"
|
|
15245
|
+
).then((r) => {
|
|
15246
|
+
modelResults.openaiResponses.streaming = r;
|
|
15247
|
+
})
|
|
15053
15248
|
);
|
|
15054
15249
|
}
|
|
15055
15250
|
await Promise.all(tasks);
|
|
@@ -15061,6 +15256,8 @@ const Route$a = createFileRoute("/api/providers/$providerId/test")({
|
|
|
15061
15256
|
if (firstResults !== void 0) {
|
|
15062
15257
|
results.anthropic = firstResults.anthropic;
|
|
15063
15258
|
results.openai = firstResults.openai;
|
|
15259
|
+
results.openaiChat = firstResults.openaiChat;
|
|
15260
|
+
results.openaiResponses = firstResults.openaiResponses;
|
|
15064
15261
|
}
|
|
15065
15262
|
results.testedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15066
15263
|
return Response.json(results);
|
|
@@ -15701,15 +15898,41 @@ const ProviderFormatTestResultsSchema = object({
|
|
|
15701
15898
|
nonStreaming: ProviderTestStateSchema,
|
|
15702
15899
|
streaming: ProviderTestStateSchema
|
|
15703
15900
|
});
|
|
15901
|
+
function createNotConfiguredProviderFormatTestResults() {
|
|
15902
|
+
return {
|
|
15903
|
+
nonStreaming: { notConfigured: true },
|
|
15904
|
+
streaming: { notConfigured: true }
|
|
15905
|
+
};
|
|
15906
|
+
}
|
|
15704
15907
|
const ModelTestResultsSchema = object({
|
|
15705
15908
|
anthropic: ProviderFormatTestResultsSchema,
|
|
15706
|
-
openai: ProviderFormatTestResultsSchema
|
|
15909
|
+
openai: ProviderFormatTestResultsSchema.optional(),
|
|
15910
|
+
openaiChat: ProviderFormatTestResultsSchema.optional(),
|
|
15911
|
+
openaiResponses: ProviderFormatTestResultsSchema.optional()
|
|
15912
|
+
}).transform((value) => {
|
|
15913
|
+
const openaiChat = value.openaiChat ?? value.openai ?? createNotConfiguredProviderFormatTestResults();
|
|
15914
|
+
return {
|
|
15915
|
+
...value,
|
|
15916
|
+
openai: value.openai ?? openaiChat,
|
|
15917
|
+
openaiChat,
|
|
15918
|
+
openaiResponses: value.openaiResponses ?? createNotConfiguredProviderFormatTestResults()
|
|
15919
|
+
};
|
|
15707
15920
|
});
|
|
15708
15921
|
const ProviderTestResultsSchema = object({
|
|
15709
15922
|
anthropic: ProviderFormatTestResultsSchema,
|
|
15710
|
-
openai: ProviderFormatTestResultsSchema,
|
|
15923
|
+
openai: ProviderFormatTestResultsSchema.optional(),
|
|
15924
|
+
openaiChat: ProviderFormatTestResultsSchema.optional(),
|
|
15925
|
+
openaiResponses: ProviderFormatTestResultsSchema.optional(),
|
|
15711
15926
|
models: record(string(), ModelTestResultsSchema).optional(),
|
|
15712
15927
|
testedAt: string().optional()
|
|
15928
|
+
}).transform((value) => {
|
|
15929
|
+
const openaiChat = value.openaiChat ?? value.openai ?? createNotConfiguredProviderFormatTestResults();
|
|
15930
|
+
return {
|
|
15931
|
+
...value,
|
|
15932
|
+
openai: value.openai ?? openaiChat,
|
|
15933
|
+
openaiChat,
|
|
15934
|
+
openaiResponses: value.openaiResponses ?? createNotConfiguredProviderFormatTestResults()
|
|
15935
|
+
};
|
|
15713
15936
|
});
|
|
15714
15937
|
function createPendingProviderTestResults() {
|
|
15715
15938
|
return {
|
|
@@ -15720,6 +15943,14 @@ function createPendingProviderTestResults() {
|
|
|
15720
15943
|
openai: {
|
|
15721
15944
|
nonStreaming: { testing: true },
|
|
15722
15945
|
streaming: { testing: true }
|
|
15946
|
+
},
|
|
15947
|
+
openaiChat: {
|
|
15948
|
+
nonStreaming: { testing: true },
|
|
15949
|
+
streaming: { testing: true }
|
|
15950
|
+
},
|
|
15951
|
+
openaiResponses: {
|
|
15952
|
+
nonStreaming: { testing: true },
|
|
15953
|
+
streaming: { testing: true }
|
|
15723
15954
|
}
|
|
15724
15955
|
};
|
|
15725
15956
|
}
|
|
@@ -15733,7 +15964,9 @@ function createFailedProviderTestResults(message, type) {
|
|
|
15733
15964
|
});
|
|
15734
15965
|
return {
|
|
15735
15966
|
anthropic: createFormatResult(),
|
|
15736
|
-
openai: createFormatResult()
|
|
15967
|
+
openai: createFormatResult(),
|
|
15968
|
+
openaiChat: createFormatResult(),
|
|
15969
|
+
openaiResponses: createFormatResult()
|
|
15737
15970
|
};
|
|
15738
15971
|
}
|
|
15739
15972
|
function hasSuccessField(result) {
|
|
@@ -15764,7 +15997,7 @@ function getResultTokensPerSecond(result) {
|
|
|
15764
15997
|
totalStreamMs: getResultTotalStreamMs(result)
|
|
15765
15998
|
});
|
|
15766
15999
|
}
|
|
15767
|
-
async function logModelResults(displayName, providerName, providerSessionId, anthropicUrl,
|
|
16000
|
+
async function logModelResults(displayName, providerName, providerSessionId, anthropicUrl, openaiChatUrl, openaiResponsesUrl, modelResults, captureFullDetails) {
|
|
15768
16001
|
const usageModel = getModelUsageName(displayName, providerName);
|
|
15769
16002
|
if (anthropicUrl !== void 0) {
|
|
15770
16003
|
const nsResult = modelResults.anthropic.nonStreaming;
|
|
@@ -15829,9 +16062,9 @@ async function logModelResults(displayName, providerName, providerSessionId, ant
|
|
|
15829
16062
|
});
|
|
15830
16063
|
}
|
|
15831
16064
|
}
|
|
15832
|
-
if (
|
|
15833
|
-
const nsResult = modelResults.
|
|
15834
|
-
const sResult = modelResults.
|
|
16065
|
+
if (openaiChatUrl !== void 0) {
|
|
16066
|
+
const nsResult = modelResults.openaiChat.nonStreaming;
|
|
16067
|
+
const sResult = modelResults.openaiChat.streaming;
|
|
15835
16068
|
if (hasSuccessField(nsResult) && hasSuccessField(sResult)) {
|
|
15836
16069
|
const nonStreamingResult = nsResult;
|
|
15837
16070
|
const streamingResult = sResult;
|
|
@@ -15892,6 +16125,71 @@ async function logModelResults(displayName, providerName, providerSessionId, ant
|
|
|
15892
16125
|
});
|
|
15893
16126
|
}
|
|
15894
16127
|
}
|
|
16128
|
+
if (openaiResponsesUrl !== void 0) {
|
|
16129
|
+
const nsResult = modelResults.openaiResponses.nonStreaming;
|
|
16130
|
+
const sResult = modelResults.openaiResponses.streaming;
|
|
16131
|
+
if (hasSuccessField(nsResult) && hasSuccessField(sResult)) {
|
|
16132
|
+
const nonStreamingResult = nsResult;
|
|
16133
|
+
const streamingResult = sResult;
|
|
16134
|
+
const requestBody = JSON.stringify(
|
|
16135
|
+
buildProviderTestRequestBody(usageModel, "non-streaming", "responses")
|
|
16136
|
+
);
|
|
16137
|
+
await addTestLogEntry({
|
|
16138
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16139
|
+
method: "POST",
|
|
16140
|
+
path: "/v1/responses",
|
|
16141
|
+
model: nonStreamingResult.model ?? displayName,
|
|
16142
|
+
sessionId: providerSessionId,
|
|
16143
|
+
rawRequestBody: requestBody,
|
|
16144
|
+
responseStatus: getResultResponseStatus(nonStreamingResult),
|
|
16145
|
+
responseText: getResultResponseText(nonStreamingResult),
|
|
16146
|
+
inputTokens: nonStreamingResult.inputTokens ?? null,
|
|
16147
|
+
outputTokens: nonStreamingResult.outputTokens ?? null,
|
|
16148
|
+
cacheCreationInputTokens: null,
|
|
16149
|
+
cacheReadInputTokens: nonStreamingResult.cacheReadInputTokens ?? null,
|
|
16150
|
+
elapsedMs: nonStreamingResult.latencyMs ?? 0,
|
|
16151
|
+
firstChunkMs: null,
|
|
16152
|
+
totalStreamMs: null,
|
|
16153
|
+
tokensPerSecond: null,
|
|
16154
|
+
streaming: false,
|
|
16155
|
+
userAgent: "provider-test",
|
|
16156
|
+
origin: null,
|
|
16157
|
+
apiFormat: "openai",
|
|
16158
|
+
isTest: true,
|
|
16159
|
+
providerName,
|
|
16160
|
+
headers: captureFullDetails ? getResultHeaders(nonStreamingResult) : void 0
|
|
16161
|
+
});
|
|
16162
|
+
const streamingRequestBody = JSON.stringify(
|
|
16163
|
+
buildProviderTestRequestBody(usageModel, "streaming", "responses")
|
|
16164
|
+
);
|
|
16165
|
+
await addTestLogEntry({
|
|
16166
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16167
|
+
method: "POST",
|
|
16168
|
+
path: "/v1/responses",
|
|
16169
|
+
model: streamingResult.model ?? displayName,
|
|
16170
|
+
sessionId: providerSessionId,
|
|
16171
|
+
rawRequestBody: streamingRequestBody,
|
|
16172
|
+
responseStatus: getResultResponseStatus(streamingResult),
|
|
16173
|
+
responseText: getResultResponseText(streamingResult),
|
|
16174
|
+
inputTokens: streamingResult.inputTokens ?? null,
|
|
16175
|
+
outputTokens: streamingResult.outputTokens ?? null,
|
|
16176
|
+
cacheCreationInputTokens: null,
|
|
16177
|
+
cacheReadInputTokens: streamingResult.cacheReadInputTokens ?? null,
|
|
16178
|
+
elapsedMs: getResultTotalStreamMs(streamingResult) ?? 0,
|
|
16179
|
+
firstChunkMs: getResultFirstChunkMs(streamingResult),
|
|
16180
|
+
totalStreamMs: getResultTotalStreamMs(streamingResult),
|
|
16181
|
+
tokensPerSecond: getResultTokensPerSecond(streamingResult),
|
|
16182
|
+
streaming: true,
|
|
16183
|
+
streamingChunks: captureFullDetails ? streamingResult.streamingChunks : void 0,
|
|
16184
|
+
userAgent: "provider-test",
|
|
16185
|
+
origin: null,
|
|
16186
|
+
apiFormat: "openai",
|
|
16187
|
+
isTest: true,
|
|
16188
|
+
providerName,
|
|
16189
|
+
headers: captureFullDetails ? getResultHeaders(streamingResult) : void 0
|
|
16190
|
+
});
|
|
16191
|
+
}
|
|
16192
|
+
}
|
|
15895
16193
|
}
|
|
15896
16194
|
const Route$2 = createFileRoute("/api/providers/$providerId/test/log")({
|
|
15897
16195
|
server: {
|
|
@@ -15918,7 +16216,8 @@ const Route$2 = createFileRoute("/api/providers/$providerId/test/log")({
|
|
|
15918
16216
|
const providerSessionId = buildProviderTestSessionId(params.providerId);
|
|
15919
16217
|
const captureFullDetails = getConfig().captureMode === "full";
|
|
15920
16218
|
const anthropicUrl = provider.anthropicBaseUrl !== void 0 && provider.anthropicBaseUrl.length > 0 ? provider.anthropicBaseUrl : void 0;
|
|
15921
|
-
const
|
|
16219
|
+
const openaiChatUrl = provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl.length > 0 ? provider.openaiBaseUrl : void 0;
|
|
16220
|
+
const openaiResponsesUrl = provider.openaiResponsesBaseUrl !== void 0 && provider.openaiResponsesBaseUrl.length > 0 ? provider.openaiResponsesBaseUrl : void 0;
|
|
15922
16221
|
const entries = [];
|
|
15923
16222
|
if (results.models !== void 0) {
|
|
15924
16223
|
for (const [modelName, modelResult] of Object.entries(results.models)) {
|
|
@@ -15928,7 +16227,8 @@ const Route$2 = createFileRoute("/api/providers/$providerId/test/log")({
|
|
|
15928
16227
|
provider.name,
|
|
15929
16228
|
providerSessionId,
|
|
15930
16229
|
anthropicUrl,
|
|
15931
|
-
|
|
16230
|
+
openaiChatUrl,
|
|
16231
|
+
openaiResponsesUrl,
|
|
15932
16232
|
modelResult,
|
|
15933
16233
|
captureFullDetails
|
|
15934
16234
|
)
|
|
@@ -16386,12 +16686,15 @@ const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
|
|
|
16386
16686
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
16387
16687
|
export {
|
|
16388
16688
|
AnthropicResponseSchema$1 as A,
|
|
16389
|
-
|
|
16689
|
+
createFailedProviderTestResults as B,
|
|
16390
16690
|
CapturedLogSchema as C,
|
|
16391
16691
|
DEFAULT_CAPTURE_MODE as D,
|
|
16392
|
-
|
|
16692
|
+
MAX_PROVIDER_TEST_TIMEOUT_SECONDS as E,
|
|
16693
|
+
resolveProviderContextWindow as F,
|
|
16393
16694
|
GroupEvidenceReadResponseSchema as G,
|
|
16695
|
+
isPlainRecord as H,
|
|
16394
16696
|
InspectorGroupsListResponseSchema as I,
|
|
16697
|
+
router as J,
|
|
16395
16698
|
KnowledgeCandidateSchema as K,
|
|
16396
16699
|
LogBodyChunkSchema as L,
|
|
16397
16700
|
MAX_SLOW_RESPONSE_THRESHOLD_SECONDS as M,
|
|
@@ -16419,10 +16722,10 @@ export {
|
|
|
16419
16722
|
findProviderModelMetadata as r,
|
|
16420
16723
|
safeGetOwnProperty as s,
|
|
16421
16724
|
maskApiKey as t,
|
|
16422
|
-
|
|
16423
|
-
|
|
16424
|
-
|
|
16425
|
-
|
|
16426
|
-
|
|
16427
|
-
|
|
16725
|
+
PATH_V1_MESSAGES as u,
|
|
16726
|
+
PATH_V1_CHAT_COMPLETIONS as v,
|
|
16727
|
+
PATH_V1_RESPONSES as w,
|
|
16728
|
+
previewUpstreamUrl as x,
|
|
16729
|
+
createPendingProviderTestResults as y,
|
|
16730
|
+
ProviderTestResultsSchema as z
|
|
16428
16731
|
};
|