@tonyclaw/agent-inspector 2.0.39 → 2.0.41
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/nitro.json +1 -1
- package/.output/public/assets/CompareDrawer-DCg6S2cl.js +1 -0
- package/.output/public/assets/ProxyViewerContainer-DsU6QETm.js +115 -0
- package/.output/public/assets/{ReplayDialog-B58TbTtY.js → ReplayDialog-ClVgjSDE.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-d4P6JNiP.js → RequestAnatomy-BhqvLQp9.js} +1 -1
- package/.output/public/assets/ResponseView-BZAJoK6B.js +1 -0
- package/.output/public/assets/StreamingChunkSequence-CaORmoKX.js +1 -0
- package/.output/public/assets/_sessionId-BHqywvM3.js +1 -0
- package/.output/public/assets/index-B_LPYuM0.js +1 -0
- package/.output/public/assets/{main-DK9PoBjx.js → main-CI3HFEcV.js} +2 -2
- package/.output/server/{_sessionId-DjarbXpT.mjs → _sessionId-DQ0ljHQ8.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-C5Z6AlUk.mjs → CompareDrawer-nkVa9epn.mjs} +4 -3
- package/.output/server/_ssr/{ProxyViewerContainer-4pXsBywn.mjs → ProxyViewerContainer-CXA7iH3H.mjs} +140 -45
- package/.output/server/_ssr/{ReplayDialog-w1vc1p5e.mjs → ReplayDialog-CK71-ucq.mjs} +3 -3
- package/.output/server/_ssr/{RequestAnatomy-2HaBhsNV.mjs → RequestAnatomy-DDCUJJ3X.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-SO_Y_W85.mjs → ResponseView-C6ZA7V3B.mjs} +2 -2
- package/.output/server/_ssr/{StreamingChunkSequence-CXEa2DkO.mjs → StreamingChunkSequence-DW5v_o6G.mjs} +2 -2
- package/.output/server/_ssr/{index-DuCGt4a2.mjs → index-Ckex98yq.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-D0BaSzkZ.mjs → router-ChJIVv7-.mjs} +434 -6
- package/.output/server/{_tanstack-start-manifest_v-6N4SODyd.mjs → _tanstack-start-manifest_v-CJ4__weU.mjs} +1 -1
- package/.output/server/index.mjs +62 -62
- package/package.json +1 -1
- package/src/components/ProxyViewer.tsx +5 -2
- package/src/components/providers/ProviderCard.tsx +6 -3
- package/src/components/providers/ProviderForm.tsx +6 -3
- package/src/components/providers/ProvidersPanel.tsx +6 -1
- package/src/components/providers/SettingsDialog.tsx +5 -2
- package/src/components/proxy-viewer/CompareDrawer.tsx +3 -1
- package/src/components/proxy-viewer/LogEntry.tsx +23 -6
- package/src/components/proxy-viewer/LogEntryHeader.tsx +20 -0
- package/src/components/proxy-viewer/useCopyFeedback.ts +3 -1
- package/src/components/ui/json-viewer.tsx +7 -2
- package/src/contracts/log.ts +1 -0
- package/src/lib/clipboard.ts +67 -0
- package/src/proxy/logFinalizer.ts +58 -0
- package/src/proxy/logSearch.ts +1 -0
- package/src/proxy/toolSchemaWarnings.ts +515 -0
- package/.output/public/assets/CompareDrawer-Jfe6M6DQ.js +0 -1
- package/.output/public/assets/ProxyViewerContainer-CQKV0Bqq.js +0 -115
- package/.output/public/assets/ResponseView-Bum1a3tG.js +0 -1
- package/.output/public/assets/StreamingChunkSequence-CjBDp5E9.js +0 -1
- package/.output/public/assets/_sessionId-BupV2gtf.js +0 -1
- package/.output/public/assets/index-DHSww5em.js +0 -1
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
import type { ApiFormat } from "./schemas";
|
|
2
|
+
|
|
3
|
+
type JsonObject = Record<string, unknown>;
|
|
4
|
+
|
|
5
|
+
type ExpectedJsonType = "array" | "boolean" | "integer" | "null" | "number" | "object" | "string";
|
|
6
|
+
|
|
7
|
+
type ParsedJson = { ok: true; value: unknown } | { ok: false };
|
|
8
|
+
|
|
9
|
+
type ToolSchema = {
|
|
10
|
+
name: string;
|
|
11
|
+
schema: JsonObject | null;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type ToolCall = {
|
|
15
|
+
name: string | null;
|
|
16
|
+
arguments: unknown;
|
|
17
|
+
argumentIssue: string | null;
|
|
18
|
+
location: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type ToolSchemaWarningInput = {
|
|
22
|
+
rawRequestBody: string | null;
|
|
23
|
+
responseText: string | null;
|
|
24
|
+
apiFormat: ApiFormat;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function parseJson(raw: string | null): ParsedJson {
|
|
28
|
+
if (raw === null) return { ok: false };
|
|
29
|
+
try {
|
|
30
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
31
|
+
} catch {
|
|
32
|
+
return { ok: false };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function isRecord(value: unknown): value is JsonObject {
|
|
37
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readProperty(value: unknown, key: string): unknown {
|
|
41
|
+
if (!isRecord(value)) return undefined;
|
|
42
|
+
return Object.getOwnPropertyDescriptor(value, key)?.value;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function hasOwnProperty(value: JsonObject, key: string): boolean {
|
|
46
|
+
return Object.getOwnPropertyDescriptor(value, key) !== undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function readString(value: unknown, key: string): string | null {
|
|
50
|
+
const property = readProperty(value, key);
|
|
51
|
+
return typeof property === "string" ? property : null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function readArray(value: unknown, key: string): unknown[] {
|
|
55
|
+
const property = readProperty(value, key);
|
|
56
|
+
return Array.isArray(property) ? property : [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function readStringArray(value: unknown, key: string): string[] {
|
|
60
|
+
return readArray(value, key).filter((item): item is string => typeof item === "string");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function readObject(value: unknown, key: string): JsonObject | null {
|
|
64
|
+
const property = readProperty(value, key);
|
|
65
|
+
return isRecord(property) ? property : null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function normalizeExpectedType(typeName: string): ExpectedJsonType | null {
|
|
69
|
+
switch (typeName) {
|
|
70
|
+
case "array":
|
|
71
|
+
case "boolean":
|
|
72
|
+
case "integer":
|
|
73
|
+
case "null":
|
|
74
|
+
case "number":
|
|
75
|
+
case "object":
|
|
76
|
+
case "string":
|
|
77
|
+
return typeName;
|
|
78
|
+
default:
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function schemaTypes(schema: JsonObject): ExpectedJsonType[] {
|
|
84
|
+
const typeValue = readProperty(schema, "type");
|
|
85
|
+
const rawTypes = Array.isArray(typeValue) ? typeValue : [typeValue];
|
|
86
|
+
const types: ExpectedJsonType[] = [];
|
|
87
|
+
for (const rawType of rawTypes) {
|
|
88
|
+
if (typeof rawType !== "string") continue;
|
|
89
|
+
const normalized = normalizeExpectedType(rawType);
|
|
90
|
+
if (normalized !== null && !types.includes(normalized)) {
|
|
91
|
+
types.push(normalized);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return types;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function actualType(value: unknown): ExpectedJsonType | "undefined" | "unknown" {
|
|
98
|
+
if (value === null) return "null";
|
|
99
|
+
if (Array.isArray(value)) return "array";
|
|
100
|
+
|
|
101
|
+
switch (typeof value) {
|
|
102
|
+
case "boolean":
|
|
103
|
+
return "boolean";
|
|
104
|
+
case "number":
|
|
105
|
+
return Number.isInteger(value) ? "integer" : "number";
|
|
106
|
+
case "string":
|
|
107
|
+
return "string";
|
|
108
|
+
case "undefined":
|
|
109
|
+
return "undefined";
|
|
110
|
+
case "bigint":
|
|
111
|
+
case "function":
|
|
112
|
+
case "object":
|
|
113
|
+
case "symbol":
|
|
114
|
+
return isRecord(value) ? "object" : "unknown";
|
|
115
|
+
}
|
|
116
|
+
return "unknown";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function matchesExpectedType(value: unknown, expected: ExpectedJsonType): boolean {
|
|
120
|
+
switch (expected) {
|
|
121
|
+
case "array":
|
|
122
|
+
return Array.isArray(value);
|
|
123
|
+
case "boolean":
|
|
124
|
+
return typeof value === "boolean";
|
|
125
|
+
case "integer":
|
|
126
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
127
|
+
case "null":
|
|
128
|
+
return value === null;
|
|
129
|
+
case "number":
|
|
130
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
131
|
+
case "object":
|
|
132
|
+
return isRecord(value);
|
|
133
|
+
case "string":
|
|
134
|
+
return typeof value === "string";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function matchesAnyExpectedType(
|
|
139
|
+
value: unknown,
|
|
140
|
+
expectedTypes: readonly ExpectedJsonType[],
|
|
141
|
+
): boolean {
|
|
142
|
+
return expectedTypes.some((expected) => matchesExpectedType(value, expected));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function formatExpectedTypes(expectedTypes: readonly ExpectedJsonType[]): string {
|
|
146
|
+
return expectedTypes.join(" or ");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function pathLabel(path: string): string {
|
|
150
|
+
return path === "" ? "arguments" : `argument "${path}"`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function childPath(parent: string, key: string): string {
|
|
154
|
+
return parent === "" ? key : `${parent}.${key}`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function jsonString(value: unknown): string | null {
|
|
158
|
+
try {
|
|
159
|
+
const serialized = JSON.stringify(value);
|
|
160
|
+
return serialized === undefined ? null : serialized;
|
|
161
|
+
} catch {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function jsonValuesEqual(left: unknown, right: unknown): boolean {
|
|
167
|
+
const leftJson = jsonString(left);
|
|
168
|
+
const rightJson = jsonString(right);
|
|
169
|
+
return leftJson !== null && rightJson !== null && leftJson === rightJson;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function formatJsonValue(value: unknown): string {
|
|
173
|
+
const serialized = jsonString(value);
|
|
174
|
+
return serialized ?? String(value);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function enumMatches(value: unknown, enumValues: readonly unknown[]): boolean {
|
|
178
|
+
return enumValues.some((enumValue) => jsonValuesEqual(value, enumValue));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function schemaHasObjectKeywords(schema: JsonObject): boolean {
|
|
182
|
+
return (
|
|
183
|
+
readStringArray(schema, "required").length > 0 || readObject(schema, "properties") !== null
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function schemaAllowsObjectValidation(
|
|
188
|
+
schema: JsonObject,
|
|
189
|
+
expectedTypes: readonly ExpectedJsonType[],
|
|
190
|
+
): boolean {
|
|
191
|
+
if (expectedTypes.length === 0) return schemaHasObjectKeywords(schema);
|
|
192
|
+
return expectedTypes.includes("object");
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function schemaAllowsArrayValidation(
|
|
196
|
+
schema: JsonObject,
|
|
197
|
+
expectedTypes: readonly ExpectedJsonType[],
|
|
198
|
+
): boolean {
|
|
199
|
+
if (expectedTypes.length === 0) return readProperty(schema, "items") !== undefined;
|
|
200
|
+
return expectedTypes.includes("array");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function addTypeWarning(
|
|
204
|
+
warnings: string[],
|
|
205
|
+
toolName: string,
|
|
206
|
+
path: string,
|
|
207
|
+
expectedTypes: readonly ExpectedJsonType[],
|
|
208
|
+
value: unknown,
|
|
209
|
+
): void {
|
|
210
|
+
warnings.push(
|
|
211
|
+
`Tool call "${toolName}" ${pathLabel(path)} expected ${formatExpectedTypes(
|
|
212
|
+
expectedTypes,
|
|
213
|
+
)} but got ${actualType(value)}.`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function validateObjectSchema(
|
|
218
|
+
schema: JsonObject,
|
|
219
|
+
value: JsonObject,
|
|
220
|
+
toolName: string,
|
|
221
|
+
path: string,
|
|
222
|
+
warnings: string[],
|
|
223
|
+
): void {
|
|
224
|
+
for (const requiredName of readStringArray(schema, "required")) {
|
|
225
|
+
if (!hasOwnProperty(value, requiredName)) {
|
|
226
|
+
warnings.push(
|
|
227
|
+
`Tool call "${toolName}" is missing required ${pathLabel(childPath(path, requiredName))}.`,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const properties = readObject(schema, "properties");
|
|
233
|
+
if (properties === null) return;
|
|
234
|
+
for (const [propertyName, propertySchema] of Object.entries(properties)) {
|
|
235
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, propertyName);
|
|
236
|
+
if (descriptor === undefined) continue;
|
|
237
|
+
validateValueAgainstSchema(
|
|
238
|
+
propertySchema,
|
|
239
|
+
descriptor.value,
|
|
240
|
+
toolName,
|
|
241
|
+
childPath(path, propertyName),
|
|
242
|
+
warnings,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function validateArraySchema(
|
|
248
|
+
schema: JsonObject,
|
|
249
|
+
value: readonly unknown[],
|
|
250
|
+
toolName: string,
|
|
251
|
+
path: string,
|
|
252
|
+
warnings: string[],
|
|
253
|
+
): void {
|
|
254
|
+
const itemsSchema = readProperty(schema, "items");
|
|
255
|
+
if (itemsSchema === undefined) return;
|
|
256
|
+
let index = 0;
|
|
257
|
+
for (const item of value) {
|
|
258
|
+
validateValueAgainstSchema(itemsSchema, item, toolName, `${path}[${index}]`, warnings);
|
|
259
|
+
index++;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function validateEnum(
|
|
264
|
+
schema: JsonObject,
|
|
265
|
+
value: unknown,
|
|
266
|
+
toolName: string,
|
|
267
|
+
path: string,
|
|
268
|
+
warnings: string[],
|
|
269
|
+
): void {
|
|
270
|
+
const enumValue = readProperty(schema, "enum");
|
|
271
|
+
if (Array.isArray(enumValue) && enumValue.length > 0 && !enumMatches(value, enumValue)) {
|
|
272
|
+
warnings.push(
|
|
273
|
+
`Tool call "${toolName}" ${pathLabel(path)} expected one of ${formatJsonValue(
|
|
274
|
+
enumValue,
|
|
275
|
+
)} but got ${formatJsonValue(value)}.`,
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const constDescriptor = Object.getOwnPropertyDescriptor(schema, "const");
|
|
280
|
+
if (constDescriptor !== undefined && !jsonValuesEqual(value, constDescriptor.value)) {
|
|
281
|
+
warnings.push(
|
|
282
|
+
`Tool call "${toolName}" ${pathLabel(path)} expected ${formatJsonValue(
|
|
283
|
+
constDescriptor.value,
|
|
284
|
+
)} but got ${formatJsonValue(value)}.`,
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function validateValueAgainstSchema(
|
|
290
|
+
schema: unknown,
|
|
291
|
+
value: unknown,
|
|
292
|
+
toolName: string,
|
|
293
|
+
path: string,
|
|
294
|
+
warnings: string[],
|
|
295
|
+
): void {
|
|
296
|
+
if (!isRecord(schema)) return;
|
|
297
|
+
|
|
298
|
+
const expectedTypes = schemaTypes(schema);
|
|
299
|
+
if (expectedTypes.length > 0 && !matchesAnyExpectedType(value, expectedTypes)) {
|
|
300
|
+
addTypeWarning(warnings, toolName, path, expectedTypes, value);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
validateEnum(schema, value, toolName, path, warnings);
|
|
305
|
+
|
|
306
|
+
if (schemaAllowsObjectValidation(schema, expectedTypes)) {
|
|
307
|
+
if (isRecord(value)) {
|
|
308
|
+
validateObjectSchema(schema, value, toolName, path, warnings);
|
|
309
|
+
} else if (expectedTypes.length === 0) {
|
|
310
|
+
warnings.push(
|
|
311
|
+
`Tool call "${toolName}" ${pathLabel(path)} expected object but got ${actualType(value)}.`,
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (schemaAllowsArrayValidation(schema, expectedTypes)) {
|
|
317
|
+
if (Array.isArray(value)) {
|
|
318
|
+
validateArraySchema(schema, value, toolName, path, warnings);
|
|
319
|
+
} else if (expectedTypes.length === 0) {
|
|
320
|
+
warnings.push(
|
|
321
|
+
`Tool call "${toolName}" ${pathLabel(path)} expected array but got ${actualType(value)}.`,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function extractAnthropicToolSchemas(request: unknown): Map<string, ToolSchema> {
|
|
328
|
+
const tools = new Map<string, ToolSchema>();
|
|
329
|
+
for (const tool of readArray(request, "tools")) {
|
|
330
|
+
if (!isRecord(tool)) continue;
|
|
331
|
+
const name = readString(tool, "name");
|
|
332
|
+
if (name === null || name === "") continue;
|
|
333
|
+
tools.set(name, {
|
|
334
|
+
name,
|
|
335
|
+
schema: readObject(tool, "input_schema"),
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
return tools;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function extractOpenAIToolSchemas(request: unknown): Map<string, ToolSchema> {
|
|
342
|
+
const tools = new Map<string, ToolSchema>();
|
|
343
|
+
for (const tool of readArray(request, "tools")) {
|
|
344
|
+
const functionDefinition = readObject(tool, "function");
|
|
345
|
+
if (functionDefinition === null) continue;
|
|
346
|
+
const name = readString(functionDefinition, "name");
|
|
347
|
+
if (name === null || name === "") continue;
|
|
348
|
+
tools.set(name, {
|
|
349
|
+
name,
|
|
350
|
+
schema: readObject(functionDefinition, "parameters"),
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
return tools;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function mergeToolSchemas(
|
|
357
|
+
primary: Map<string, ToolSchema>,
|
|
358
|
+
secondary: Map<string, ToolSchema>,
|
|
359
|
+
): Map<string, ToolSchema> {
|
|
360
|
+
const merged = new Map(primary);
|
|
361
|
+
for (const [name, schema] of secondary) {
|
|
362
|
+
if (!merged.has(name)) merged.set(name, schema);
|
|
363
|
+
}
|
|
364
|
+
return merged;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function extractToolSchemas(request: unknown, apiFormat: ApiFormat): Map<string, ToolSchema> {
|
|
368
|
+
switch (apiFormat) {
|
|
369
|
+
case "anthropic":
|
|
370
|
+
return extractAnthropicToolSchemas(request);
|
|
371
|
+
case "openai":
|
|
372
|
+
return extractOpenAIToolSchemas(request);
|
|
373
|
+
case "unknown":
|
|
374
|
+
return mergeToolSchemas(
|
|
375
|
+
extractOpenAIToolSchemas(request),
|
|
376
|
+
extractAnthropicToolSchemas(request),
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function parseOpenAIArguments(argumentsValue: unknown): { value: unknown; issue: string | null } {
|
|
382
|
+
if (argumentsValue === undefined) {
|
|
383
|
+
return { value: {}, issue: "arguments field is missing" };
|
|
384
|
+
}
|
|
385
|
+
if (typeof argumentsValue !== "string") {
|
|
386
|
+
return { value: argumentsValue, issue: null };
|
|
387
|
+
}
|
|
388
|
+
try {
|
|
389
|
+
return { value: JSON.parse(argumentsValue), issue: null };
|
|
390
|
+
} catch {
|
|
391
|
+
return { value: {}, issue: "arguments are not valid JSON" };
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function extractOpenAIToolCalls(response: unknown): ToolCall[] {
|
|
396
|
+
const calls: ToolCall[] = [];
|
|
397
|
+
let choiceIndex = 0;
|
|
398
|
+
for (const choice of readArray(response, "choices")) {
|
|
399
|
+
const message = readObject(choice, "message");
|
|
400
|
+
if (message === null) {
|
|
401
|
+
choiceIndex++;
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
let callIndex = 0;
|
|
406
|
+
for (const call of readArray(message, "tool_calls")) {
|
|
407
|
+
const functionCall = readObject(call, "function");
|
|
408
|
+
const name = functionCall === null ? null : readString(functionCall, "name");
|
|
409
|
+
const parsedArguments =
|
|
410
|
+
functionCall === null
|
|
411
|
+
? { value: {}, issue: "function block is missing" }
|
|
412
|
+
: parseOpenAIArguments(readProperty(functionCall, "arguments"));
|
|
413
|
+
calls.push({
|
|
414
|
+
name,
|
|
415
|
+
arguments: parsedArguments.value,
|
|
416
|
+
argumentIssue: parsedArguments.issue,
|
|
417
|
+
location: `choices[${choiceIndex}].message.tool_calls[${callIndex}]`,
|
|
418
|
+
});
|
|
419
|
+
callIndex++;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const legacyFunctionCall = readObject(message, "function_call");
|
|
423
|
+
if (legacyFunctionCall !== null) {
|
|
424
|
+
const parsedArguments = parseOpenAIArguments(readProperty(legacyFunctionCall, "arguments"));
|
|
425
|
+
calls.push({
|
|
426
|
+
name: readString(legacyFunctionCall, "name"),
|
|
427
|
+
arguments: parsedArguments.value,
|
|
428
|
+
argumentIssue: parsedArguments.issue,
|
|
429
|
+
location: `choices[${choiceIndex}].message.function_call`,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
choiceIndex++;
|
|
433
|
+
}
|
|
434
|
+
return calls;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function extractAnthropicToolCalls(response: unknown): ToolCall[] {
|
|
438
|
+
const calls: ToolCall[] = [];
|
|
439
|
+
let contentIndex = 0;
|
|
440
|
+
for (const block of readArray(response, "content")) {
|
|
441
|
+
if (readString(block, "type") !== "tool_use") {
|
|
442
|
+
contentIndex++;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
calls.push({
|
|
446
|
+
name: readString(block, "name"),
|
|
447
|
+
arguments: readProperty(block, "input") ?? {},
|
|
448
|
+
argumentIssue: null,
|
|
449
|
+
location: `content[${contentIndex}]`,
|
|
450
|
+
});
|
|
451
|
+
contentIndex++;
|
|
452
|
+
}
|
|
453
|
+
return calls;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function extractToolCalls(response: unknown, apiFormat: ApiFormat): ToolCall[] {
|
|
457
|
+
switch (apiFormat) {
|
|
458
|
+
case "anthropic":
|
|
459
|
+
return extractAnthropicToolCalls(response);
|
|
460
|
+
case "openai":
|
|
461
|
+
return extractOpenAIToolCalls(response);
|
|
462
|
+
case "unknown":
|
|
463
|
+
return [...extractOpenAIToolCalls(response), ...extractAnthropicToolCalls(response)];
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function uniqueWarnings(warnings: readonly string[]): string[] {
|
|
468
|
+
const seen = new Set<string>();
|
|
469
|
+
const unique: string[] = [];
|
|
470
|
+
for (const warning of warnings) {
|
|
471
|
+
if (seen.has(warning)) continue;
|
|
472
|
+
seen.add(warning);
|
|
473
|
+
unique.push(warning);
|
|
474
|
+
}
|
|
475
|
+
return unique;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
export function analyzeToolSchemaWarnings(input: ToolSchemaWarningInput): string[] {
|
|
479
|
+
const request = parseJson(input.rawRequestBody);
|
|
480
|
+
const response = parseJson(input.responseText);
|
|
481
|
+
if (!request.ok || !response.ok) return [];
|
|
482
|
+
|
|
483
|
+
const toolSchemas = extractToolSchemas(request.value, input.apiFormat);
|
|
484
|
+
const toolCalls = extractToolCalls(response.value, input.apiFormat);
|
|
485
|
+
if (toolCalls.length === 0) return [];
|
|
486
|
+
|
|
487
|
+
const warnings: string[] = [];
|
|
488
|
+
for (const call of toolCalls) {
|
|
489
|
+
if (call.name === null || call.name === "") {
|
|
490
|
+
warnings.push(`Tool call at ${call.location} is missing a tool name.`);
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const schema = toolSchemas.get(call.name);
|
|
495
|
+
if (schema === undefined) {
|
|
496
|
+
warnings.push(
|
|
497
|
+
toolSchemas.size === 0
|
|
498
|
+
? `Tool call "${call.name}" was returned, but the request did not define any tools.`
|
|
499
|
+
: `Tool call "${call.name}" was returned, but it is not defined in the request tools.`,
|
|
500
|
+
);
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (call.argumentIssue !== null) {
|
|
505
|
+
warnings.push(`Tool call "${call.name}" ${call.argumentIssue}.`);
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (schema.schema !== null) {
|
|
510
|
+
validateValueAgainstSchema(schema.schema, call.arguments, schema.name, "", warnings);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return uniqueWarnings(warnings);
|
|
515
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as h,j as t}from"./main-DK9PoBjx.js";import{c as X,g as O,r as P,a as q,X as Y,b as x,B as Z,f as $,R as ee,C as te,M as _,d as J,e as M,h as V,J as N,i as re,j as ne}from"./ProxyViewerContainer-CQKV0Bqq.js";const se=[["line",{x1:"5",x2:"19",y1:"9",y2:"9",key:"1nwqeh"}],["line",{x1:"5",x2:"19",y1:"15",y2:"15",key:"g8yjpy"}]],ae=X("equal",se),oe="";function j(e){if(e.length===0)return oe;let r="";for(let n=0;n<e.length;n++){const s=e[n];s!==void 0&&(typeof s=="number"?r+=`[${s}]`:n===0?r+=s:r+=`.${s}`)}return r}function de(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function D(e){if(typeof e=="string")try{return C(JSON.parse(e))}catch{return{kind:"primitive",value:e}}return C(e)}function C(e){if(e===null)return{kind:"primitive",value:null};if(typeof e=="string")return{kind:"primitive",value:e};if(typeof e=="number")return{kind:"primitive",value:e};if(typeof e=="boolean")return{kind:"primitive",value:e};if(Array.isArray(e))return{kind:"array",value:e.map(r=>C(r))};if(de(e)){const r={};for(const n of Object.keys(e).sort())r[n]=C(e[n]);return{kind:"object",value:r}}return{kind:"primitive",value:null}}function ie(e,r){const n=[];return R([],e,r,n),n}function R(e,r,n,s){const d=j(e);if(E(r,n)){s.push({kind:"equal",path:d,value:r});return}if(r.kind!==n.kind){s.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="primitive"&&n.kind==="primitive"){s.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="object"&&n.kind==="object"){const o=Object.keys(r.value),a=Object.keys(n.value),m=new Set(a);for(const i of o){const f=r.value[i];if(f!==void 0)if(!m.has(i))s.push({kind:"removed",path:j([...e,i]),value:f});else{const p=n.value[i];if(p===void 0)continue;R([...e,i],f,p,s)}}for(const i of a){if(o.includes(i))continue;const f=n.value[i];f!==void 0&&s.push({kind:"added",path:j([...e,i]),value:f})}return}if(r.kind==="array"&&n.kind==="array"){const o=Math.min(r.value.length,n.value.length);for(let a=0;a<o;a++){const m=r.value[a],i=n.value[a];m===void 0||i===void 0||R([...e,a],m,i,s)}for(let a=o;a<n.value.length;a++){const m=n.value[a];m!==void 0&&s.push({kind:"added",path:j([...e,a]),value:m})}for(let a=o;a<r.value.length;a++){const m=r.value[a];m!==void 0&&s.push({kind:"removed",path:j([...e,a]),value:m})}}}function E(e,r){if(e.kind!==r.kind)return!1;if(e.kind==="primitive"&&r.kind==="primitive")return e.value===r.value;if(e.kind==="array"&&r.kind==="array"){if(e.value.length!==r.value.length)return!1;for(let n=0;n<e.value.length;n++){const s=e.value[n],d=r.value[n];if(s===void 0||d===void 0||!E(s,d))return!1}return!0}if(e.kind==="object"&&r.kind==="object"){const n=Object.keys(e.value),s=Object.keys(r.value);if(n.length!==s.length)return!1;for(const d of n){const o=e.value[d],a=r.value[d];if(o===void 0||a===void 0||!E(o,a))return!1}return!0}return!1}function v(e,r=80){let n;switch(e.kind){case"primitive":n=e.value===null?"null":JSON.stringify(e.value);break;case"array":n=`[… ${e.value.length} items]`;break;case"object":n=`{… ${Object.keys(e.value).length} keys}`;break}return n.length>r&&(n=`${n.slice(0,r-1)}…`),n}function w(e,r=2){return JSON.stringify(S(e),null,r)}function S(e){switch(e.kind){case"primitive":return e.value;case"array":return e.value.map(S);case"object":{const r={};for(const[n,s]of Object.entries(e.value))r[n]=S(s);return r}}}function K(e){if(e==="")return"";for(let r=e.length-1;r>=0;r--){const n=e[r];if(n==="."||n==="[")return e.substring(0,r)}return""}function L(e){return e.kind==="equal"&&(e.value.kind==="object"||e.value.kind==="array")}function le(e){const r=[];let n=0;for(;n<e.length;){const s=e[n];if(s!==void 0&&L(s)){const d=K(s.path);let o=n+1;for(;o<e.length;){const a=e[o];if(a===void 0||!L(a)||K(a.path)!==d)break;o++}if(o-n>1){const a=[];for(let m=n;m<o;m++){const i=e[m];i!==void 0&&i.kind==="equal"&&a.push(i)}r.push({kind:"equal-run",ops:a}),n=o;continue}}s!==void 0&&r.push({kind:"single",op:s}),n++}return r}const B={added:{icon:J,accent:"text-emerald-600 dark:text-emerald-400",bg:"bg-emerald-500/5 hover:bg-emerald-500/10",border:"border-l-emerald-500",label:"ADDED"},removed:{icon:_,accent:"text-rose-600 dark:text-rose-400",bg:"bg-rose-500/5 hover:bg-rose-500/10",border:"border-l-rose-500",label:"REMOVED"},changed:{icon:M,accent:"text-amber-600 dark:text-amber-400",bg:"bg-amber-500/5 hover:bg-amber-500/10",border:"border-l-amber-500",label:"CHANGED"},equal:{icon:ae,accent:"text-muted-foreground/70",bg:"bg-muted/20 hover:bg-muted/30",border:"border-l-muted-foreground/20",label:"EQUAL"}};function ce({ops:e,expanded:r,onToggle:n}){const s=e[0],d=e[e.length-1];if(s===void 0||d===void 0)return t.jsx("div",{className:"text-muted-foreground/40 text-xs",children:"—"});const o=s.path,a=d.path,m=e.length===1?o:`${o} … ${a}`,i=s.value.kind==="array"?`${e.length} equal arrays`:s.value.kind==="object"?`${e.length} equal objects`:"equal",f=B.equal;return t.jsxs("div",{className:x("border-l-4 rounded-sm",f.border,f.bg),children:[t.jsxs("button",{type:"button",onClick:n,className:"w-full text-left flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground cursor-pointer",children:[t.jsx(V,{className:x("size-3 transition-transform shrink-0",r&&"rotate-90")}),t.jsx(f.icon,{className:x("size-3 shrink-0",f.accent)}),t.jsx("span",{className:"font-mono truncate flex-1",title:`${o} … ${a}`,children:m}),t.jsx("span",{className:x("text-[10px] uppercase tracking-wider shrink-0",f.accent),children:f.label}),t.jsxs("span",{className:"text-muted-foreground/60 shrink-0",children:["(",i,")"]})]}),r&&t.jsx("div",{className:"ml-5 mt-1 mb-2 space-y-2 pr-2",children:e.map(p=>t.jsxs("div",{className:"border border-border/50 rounded p-2 bg-muted/20",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-1",children:p.path}),t.jsx(N,{text:w(p.value),defaultExpandDepth:0})]},p.path))})]})}function ue({op:e,idx:r,copiedPath:n,onCopyPath:s,expanded:d,onToggle:o}){const a=B[e.kind],m=a.icon,i=e.kind==="added"||e.kind==="removed"?e.value.kind==="object"||e.value.kind==="array":e.kind==="changed"?e.left.kind==="object"||e.left.kind==="array"||e.right.kind==="object"||e.right.kind==="array":!1,f=e.kind==="changed"?[{text:v(e.left,400),tone:"text-rose-700 dark:text-rose-300 line-through"},{text:v(e.right,400),tone:"text-emerald-700 dark:text-emerald-300"}]:e.kind==="removed"?[{text:v(e.value,400),tone:"text-rose-700 dark:text-rose-300 line-through"}]:e.kind==="added"?[{text:v(e.value,400),tone:"text-emerald-700 dark:text-emerald-300"}]:[{text:v(e.value,400),tone:"text-muted-foreground"}],p=n===e.path&&e.path!=="";return t.jsxs("div",{"data-diff-idx":r,"data-diff-kind":e.kind,className:x("border-l-4 rounded-sm px-3 py-2 my-0.5 transition-colors",a.border,a.bg),children:[t.jsxs("button",{type:"button",onClick:o,disabled:!i,className:x("w-full flex items-center gap-2 text-xs text-left rounded-sm",i?"cursor-pointer":"cursor-default"),"aria-expanded":i?d:void 0,"aria-label":i?d?`Collapse ${e.path||"root"}`:`Expand ${e.path||"root"}`:void 0,children:[i?t.jsx(V,{className:x("size-3 shrink-0 transition-transform",a.accent,d&&"rotate-90")}):t.jsx("span",{className:"size-3 shrink-0","aria-hidden":"true"}),t.jsx(m,{className:x("size-3.5 shrink-0",a.accent),strokeWidth:2.5}),t.jsx("span",{className:"font-mono truncate flex-1 min-w-0",title:e.path||"(root)",children:e.path===""?"(root)":e.path}),t.jsx("span",{className:x("text-[9px] font-bold uppercase tracking-wider shrink-0 px-1.5 py-0.5 rounded",a.accent,e.kind==="equal"?"bg-muted/40":"bg-background/60"),children:a.label}),e.path!==""&&t.jsx("span",{role:"button",tabIndex:0,onClick:b=>{b.stopPropagation(),s(e.path)},onKeyDown:b=>{(b.key==="Enter"||b.key===" ")&&(b.stopPropagation(),b.preventDefault(),s(e.path))},className:x("shrink-0 p-1 rounded transition-colors cursor-pointer inline-flex items-center justify-center",p?"text-emerald-500":"text-muted-foreground/50 hover:text-foreground hover:bg-muted"),"aria-label":p?"Copied":"Copy",title:p?"Copied!":"Copy",children:p?t.jsx(re,{className:"size-3"}):t.jsx(ne,{className:"size-3"})})]}),f.map((b,y)=>t.jsx("div",{className:x("font-mono text-xs mt-1 break-all pl-5",b.tone),children:b.text},y)),t.jsx("div",{className:"overflow-hidden transition-all duration-200",style:{maxHeight:d&&i?"2000px":"0"},"aria-hidden":!d,children:d&&i&&e.kind!=="equal"?t.jsx(me,{op:e}):null})]})}function me({op:e}){if(e.kind==="added"||e.kind==="removed")return t.jsx("div",{className:"pl-5 mt-2 border border-border/50 rounded p-2 bg-muted/20",children:t.jsx(N,{text:w(e.value),defaultExpandDepth:0})});const r=e.left.kind==="object"||e.left.kind==="array",n=e.right.kind==="object"||e.right.kind==="array";return!r&&!n?t.jsx("div",{className:"pl-5 mt-2 text-xs text-muted-foreground/70 italic",children:"Primitive values are shown inline above."}):t.jsxs("div",{className:"pl-5 mt-2 grid grid-cols-1 md:grid-cols-2 gap-2",children:[t.jsxs("div",{className:"border border-rose-500/30 rounded p-2 bg-rose-500/5",children:[t.jsx("div",{className:"text-[10px] uppercase tracking-wider text-rose-500 mb-1",children:"Old"}),t.jsx(N,{text:w(e.left),defaultExpandDepth:0})]}),t.jsxs("div",{className:"border border-emerald-500/30 rounded p-2 bg-emerald-500/5",children:[t.jsx("div",{className:"text-[10px] uppercase tracking-wider text-emerald-500 mb-1",children:"New"}),t.jsx(N,{text:w(e.right),defaultExpandDepth:0})]})]})}function xe({counts:e,onJumpTo:r}){const n=e.added+e.removed+e.changed;return t.jsxs("div",{className:"px-4 py-2 border-b border-border bg-muted/20 flex items-center gap-2 text-xs flex-wrap",children:[t.jsxs("span",{className:"text-muted-foreground font-medium",children:[n," ",n===1?"change":"changes"]}),t.jsxs("button",{type:"button",onClick:()=>r("removed"),disabled:e.removed===0,className:x("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.removed>0?"border-rose-500/40 text-rose-600 dark:text-rose-400 bg-rose-500/10 hover:bg-rose-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.removed>0?"Jump to first removed":"No removals",children:[t.jsx(_,{className:"size-3"}),e.removed," removed"]}),t.jsxs("button",{type:"button",onClick:()=>r("added"),disabled:e.added===0,className:x("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.added>0?"border-emerald-500/40 text-emerald-600 dark:text-emerald-400 bg-emerald-500/10 hover:bg-emerald-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.added>0?"Jump to first added":"No additions",children:[t.jsx(J,{className:"size-3"}),e.added," added"]}),t.jsxs("button",{type:"button",onClick:()=>r("changed"),disabled:e.changed===0,className:x("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.changed>0?"border-amber-500/40 text-amber-600 dark:text-amber-400 bg-amber-500/10 hover:bg-amber-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.changed>0?"Jump to first changed":"No changes",children:[t.jsx(M,{className:"size-3"}),e.changed," changed"]})]})}function fe({mode:e,onChange:r}){return t.jsxs("div",{className:"inline-flex rounded-md border border-border overflow-hidden",children:[t.jsxs("button",{type:"button",onClick:()=>r("unified"),"aria-pressed":e==="unified",className:x("flex items-center gap-1 px-2 py-1 text-xs transition-colors cursor-pointer",e==="unified"?"bg-muted text-foreground":"hover:bg-muted/50 text-muted-foreground"),title:"Unified view (single column, emphasized diffs)",children:[t.jsx(ee,{className:"size-3"}),"Unified"]}),t.jsxs("button",{type:"button",onClick:()=>r("split"),"aria-pressed":e==="split",className:x("flex items-center gap-1 px-2 py-1 text-xs transition-colors border-l border-border cursor-pointer",e==="split"?"bg-muted text-foreground":"hover:bg-muted/50 text-muted-foreground"),title:"Split view (path | left | right)",children:[t.jsx(te,{className:"size-3"}),"Split"]})]})}function A({log:e,side:r}){const n=q(e);return t.jsxs("div",{className:"flex-1 min-w-0 space-y-1 text-xs",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(Z,{variant:"outline",className:x("text-[10px] px-1.5 py-0 h-5 font-mono shrink-0",r==="left"?"border-rose-500/40 text-rose-400":"border-emerald-500/40 text-emerald-400"),children:r==="left"?"← Left":"Right →"}),t.jsxs("span",{className:"font-mono text-blue-400/80",children:["#",e.id]}),e.model!==null&&t.jsx("span",{className:"font-mono text-muted-foreground truncate",children:e.model})]}),t.jsxs("div",{className:"flex items-center gap-3 text-muted-foreground font-mono",children:[e.cacheCreationInputTokens!==null&&e.cacheCreationInputTokens>0&&t.jsxs("span",{className:"text-emerald-400",children:["KV Cache +",$(e.cacheCreationInputTokens)]}),e.cacheReadInputTokens!==null&&e.cacheReadInputTokens>0&&t.jsxs("span",{className:"text-purple-400",children:["KV Cache ~",$(e.cacheReadInputTokens)]}),t.jsx("span",{className:"truncate",title:e.timestamp,children:e.timestamp})]}),t.jsxs("div",{className:"text-muted-foreground/70 font-mono truncate",title:n,children:["session: ",n]})]})}function ve({left:e,right:r,onClose:n}){const s=h.useMemo(()=>{const l=O(P(e)).analyzeRequest(e.rawRequestBody),c=O(P(r)).analyzeRequest(r.rawRequestBody),u=D(l.comparisonValue),g=D(c.comparisonValue);return ie(u,g)},[e.apiFormat,e.path,e.rawRequestBody,r.apiFormat,r.path,r.rawRequestBody]),d=h.useMemo(()=>le(s),[s]),o=h.useMemo(()=>{let l=0,c=0,u=0;for(const g of d)if(g.kind==="single")switch(g.op.kind){case"added":l++;break;case"removed":c++;break;case"changed":u++;break}return{added:l,removed:c,changed:u}},[d]),[a,m]=h.useState(new Set),i=l=>{m(c=>{const u=new Set(c);return u.has(l)?u.delete(l):u.add(l),u})},[f,p]=h.useState(new Set),b=l=>{p(c=>{const u=new Set(c);return u.has(l)?u.delete(l):u.add(l),u})};h.useEffect(()=>{p(new Set)},[e.id,r.id]);const[y,F]=h.useState("unified"),T=h.useRef(null),[U,z]=h.useState(null),k=h.useRef(null),H=l=>{window.navigator.clipboard.writeText(l).then(()=>{z(l),k.current!==null&&clearTimeout(k.current),k.current=setTimeout(()=>z(null),1500)})};h.useEffect(()=>()=>{k.current!==null&&clearTimeout(k.current)},[]);const G=l=>{const c=d.findIndex(I=>I.kind==="single"&&I.op.kind===l);if(c===-1)return;const u=T.current;if(u===null)return;const g=u.querySelector(`[data-diff-idx="${c}"]`);g!==null&&g.scrollIntoView({behavior:"smooth",block:"center"})};h.useEffect(()=>{const l=u=>{u.key==="Escape"&&n()};document.addEventListener("keydown",l);const c=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{document.removeEventListener("keydown",l),document.body.style.overflow=c}},[n]);const Q=q(e)===q(r),W=s.length===1&&s[0]?.kind==="equal";return t.jsxs("div",{className:"fixed inset-0 z-50 flex justify-end",role:"dialog","aria-modal":"true","aria-label":"Compare two log requests",children:[t.jsx("button",{type:"button",onClick:n,"aria-label":"Close compare drawer",className:"absolute inset-0 bg-black/40 cursor-default",tabIndex:-1}),t.jsxs("div",{className:x("relative bg-background border-l border-border shadow-xl","w-full md:w-[70vw] max-w-[1100px] flex flex-col h-full"),onClick:l=>l.stopPropagation(),onKeyDown:l=>l.stopPropagation(),children:[t.jsxs("div",{className:"flex items-start gap-4 px-4 py-3 border-b border-border",children:[t.jsxs("div",{className:"flex-1 flex gap-4 min-w-0",children:[t.jsx(A,{log:e,side:"left"}),t.jsx(A,{log:r,side:"right"})]}),t.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[t.jsx(fe,{mode:y,onChange:F}),t.jsx("button",{type:"button",onClick:n,"aria-label":"Close",className:"p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted cursor-pointer",children:t.jsx(Y,{className:"size-4"})})]})]}),!Q&&t.jsx("div",{className:"px-4 py-1.5 text-xs text-amber-400 bg-amber-500/10 border-b border-border",children:"Heads up: the two selected logs are from different sessions."}),W?t.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto flex items-center justify-center text-muted-foreground text-sm",children:"The two Request payloads are identical."}):t.jsxs(t.Fragment,{children:[t.jsx(xe,{counts:o,onJumpTo:G}),t.jsx("div",{ref:T,className:"flex-1 min-h-0 overflow-y-auto",children:y==="unified"?t.jsx("div",{className:"px-3 py-2 space-y-0.5",children:d.map((l,c)=>{if(l.kind==="equal-run")return t.jsx(ce,{ops:l.ops,expanded:a.has(c),onToggle:()=>i(c)},`r${c}`);const u=l.op;return t.jsx(ue,{op:u,idx:c,copiedPath:U,onCopyPath:H,expanded:f.has(c),onToggle:()=>b(c)},`o${c}`)})}):t.jsx(pe,{grouped:d,left:e,right:r})})]})]})]})}function pe({grouped:e,left:r,right:n}){return t.jsxs("div",{className:"grid grid-cols-[200px_1fr_1fr] gap-x-2 gap-y-0.5 px-3 py-2 text-xs",children:[t.jsxs("div",{className:"grid grid-cols-[200px_1fr_1fr] gap-x-2 col-span-3 pb-2 mb-2 border-b border-border text-[10px] uppercase tracking-wider text-muted-foreground",children:[t.jsx("span",{children:"Path"}),t.jsxs("span",{children:["Left (Log #",r.id,")"]}),t.jsxs("span",{children:["Right (Log #",n.id,")"]})]}),e.map((s,d)=>{if(s.kind==="equal-run")return t.jsxs("div",{className:"col-span-3 px-2 py-1 text-xs text-muted-foreground/60",children:[s.ops.length," equal siblings collapsed — switch to Unified to expand"]},d);const o=s.op;return o.kind==="equal"?t.jsxs("div",{className:"col-span-3 grid grid-cols-[200px_1fr_1fr] gap-x-2 px-2 py-0.5 text-muted-foreground",children:[t.jsx("span",{className:"font-mono text-xs truncate",title:o.path,children:o.path}),t.jsx("span",{className:"font-mono text-xs break-all opacity-60",children:v(o.value,200)}),t.jsx("span",{className:"font-mono text-xs break-all opacity-60",children:v(o.value,200)})]},d):o.kind==="added"?t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-emerald-400/70 bg-emerald-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-0.5",children:o.path}),t.jsxs("div",{className:"font-mono break-all text-emerald-300/90",children:["+ ",v(o.value,400)]})]},d):o.kind==="removed"?t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-rose-400/70 bg-rose-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-0.5",children:o.path}),t.jsxs("div",{className:"font-mono break-all text-rose-300/90 line-through",children:["− ",v(o.value,400)]})]},d):t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-amber-400/70 bg-amber-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-1",children:o.path}),t.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[t.jsx("div",{className:"font-mono text-rose-300/90 break-all line-through",children:v(o.left,400)}),t.jsx("div",{className:"font-mono text-emerald-300/90 break-all",children:v(o.right,400)})]})]},d)})]})}export{ve as CompareDrawer};
|