llmpt 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/LICENSE +21 -0
  3. package/README.md +130 -0
  4. package/dist/index.d.ts +3 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +71 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/server/api/routes.d.ts +6 -0
  9. package/dist/server/api/routes.d.ts.map +1 -0
  10. package/dist/server/api/routes.js +128 -0
  11. package/dist/server/api/routes.js.map +1 -0
  12. package/dist/server/app.d.ts +14 -0
  13. package/dist/server/app.d.ts.map +1 -0
  14. package/dist/server/app.js +75 -0
  15. package/dist/server/app.js.map +1 -0
  16. package/dist/server/config/crypto.d.ts +14 -0
  17. package/dist/server/config/crypto.d.ts.map +1 -0
  18. package/dist/server/config/crypto.js +63 -0
  19. package/dist/server/config/crypto.js.map +1 -0
  20. package/dist/server/config/loader.d.ts +12 -0
  21. package/dist/server/config/loader.d.ts.map +1 -0
  22. package/dist/server/config/loader.js +142 -0
  23. package/dist/server/config/loader.js.map +1 -0
  24. package/dist/server/providers/anthropic.d.ts +9 -0
  25. package/dist/server/providers/anthropic.d.ts.map +1 -0
  26. package/dist/server/providers/anthropic.js +29 -0
  27. package/dist/server/providers/anthropic.js.map +1 -0
  28. package/dist/server/providers/base.d.ts +14 -0
  29. package/dist/server/providers/base.d.ts.map +1 -0
  30. package/dist/server/providers/base.js +15 -0
  31. package/dist/server/providers/base.js.map +1 -0
  32. package/dist/server/providers/ollama.d.ts +9 -0
  33. package/dist/server/providers/ollama.d.ts.map +1 -0
  34. package/dist/server/providers/ollama.js +24 -0
  35. package/dist/server/providers/ollama.js.map +1 -0
  36. package/dist/server/providers/openai.d.ts +9 -0
  37. package/dist/server/providers/openai.d.ts.map +1 -0
  38. package/dist/server/providers/openai.js +32 -0
  39. package/dist/server/providers/openai.js.map +1 -0
  40. package/dist/server/providers/registry.d.ts +23 -0
  41. package/dist/server/providers/registry.d.ts.map +1 -0
  42. package/dist/server/providers/registry.js +50 -0
  43. package/dist/server/providers/registry.js.map +1 -0
  44. package/dist/server/proxy/handler.d.ts +9 -0
  45. package/dist/server/proxy/handler.d.ts.map +1 -0
  46. package/dist/server/proxy/handler.js +101 -0
  47. package/dist/server/proxy/handler.js.map +1 -0
  48. package/dist/server/proxy/stream.d.ts +9 -0
  49. package/dist/server/proxy/stream.d.ts.map +1 -0
  50. package/dist/server/proxy/stream.js +200 -0
  51. package/dist/server/proxy/stream.js.map +1 -0
  52. package/dist/server/static.d.ts +6 -0
  53. package/dist/server/static.d.ts.map +1 -0
  54. package/dist/server/static.js +58 -0
  55. package/dist/server/static.js.map +1 -0
  56. package/dist/server/trace/collector.d.ts +59 -0
  57. package/dist/server/trace/collector.d.ts.map +1 -0
  58. package/dist/server/trace/collector.js +278 -0
  59. package/dist/server/trace/collector.js.map +1 -0
  60. package/dist/server/trace/sanitizer.d.ts +5 -0
  61. package/dist/server/trace/sanitizer.d.ts.map +1 -0
  62. package/dist/server/trace/sanitizer.js +45 -0
  63. package/dist/server/trace/sanitizer.js.map +1 -0
  64. package/dist/server/trace/writer.d.ts +26 -0
  65. package/dist/server/trace/writer.d.ts.map +1 -0
  66. package/dist/server/trace/writer.js +125 -0
  67. package/dist/server/trace/writer.js.map +1 -0
  68. package/dist/server/types.d.ts +167 -0
  69. package/dist/server/types.d.ts.map +1 -0
  70. package/dist/server/types.js +5 -0
  71. package/dist/server/types.js.map +1 -0
  72. package/dist/server/ws/server.d.ts +20 -0
  73. package/dist/server/ws/server.d.ts.map +1 -0
  74. package/dist/server/ws/server.js +78 -0
  75. package/dist/server/ws/server.js.map +1 -0
  76. package/dist/web/assets/index-BleB8LKa.js +21 -0
  77. package/dist/web/assets/index-DAsXJzMt.css +1 -0
  78. package/dist/web/assets/markdown-DsSlw-Z4.js +20 -0
  79. package/dist/web/assets/react-vendor-BnH7jZBV.js +21 -0
  80. package/dist/web/assets/rolldown-runtime-QTnfLwEv.js +1 -0
  81. package/dist/web/index.html +18 -0
  82. package/lpt.config.yaml +11 -0
  83. package/package.json +70 -0
@@ -0,0 +1,45 @@
1
+ // ============================================================
2
+ // Trace Sanitizer - 敏感信息脱敏
3
+ // ============================================================
4
+ const SENSITIVE_HEADERS = [
5
+ 'authorization',
6
+ 'x-api-key',
7
+ 'api-key',
8
+ 'cookie',
9
+ 'set-cookie',
10
+ ];
11
+ /**
12
+ * Sanitize headers - mask sensitive values
13
+ */
14
+ export function sanitizeHeaders(headers) {
15
+ const sanitized = {};
16
+ for (const [key, value] of Object.entries(headers)) {
17
+ const lowerKey = key.toLowerCase();
18
+ if (SENSITIVE_HEADERS.includes(lowerKey)) {
19
+ if (lowerKey === 'authorization') {
20
+ // Mask: Bearer sk-1234...5678
21
+ sanitized[key] = maskAuthHeader(value);
22
+ }
23
+ else {
24
+ sanitized[key] = '***REDACTED***';
25
+ }
26
+ }
27
+ else {
28
+ sanitized[key] = value;
29
+ }
30
+ }
31
+ return sanitized;
32
+ }
33
+ function maskAuthHeader(value) {
34
+ if (value.startsWith('Bearer ')) {
35
+ const token = value.slice(7);
36
+ return `Bearer ${maskKey(token)}`;
37
+ }
38
+ return '***REDACTED***';
39
+ }
40
+ function maskKey(key) {
41
+ if (key.length <= 8)
42
+ return '***';
43
+ return `${key.slice(0, 4)}...${key.slice(-4)}`;
44
+ }
45
+ //# sourceMappingURL=sanitizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitizer.js","sourceRoot":"","sources":["../../../src/server/trace/sanitizer.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,2BAA2B;AAC3B,+DAA+D;AAE/D,MAAM,iBAAiB,GAAG;IACxB,eAAe;IACf,WAAW;IACX,SAAS;IACT,QAAQ;IACR,YAAY;CACb,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,OAA+B;IAC7D,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QACnC,IAAI,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzC,IAAI,QAAQ,KAAK,eAAe,EAAE,CAAC;gBACjC,8BAA8B;gBAC9B,SAAS,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACN,SAAS,CAAC,GAAG,CAAC,GAAG,gBAAgB,CAAC;YACpC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7B,OAAO,UAAU,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,SAAS,OAAO,CAAC,GAAW;IAC1B,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAClC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACjD,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { TraceRecord } from '../types.js';
2
+ export declare class TraceWriter {
3
+ private traceDir;
4
+ private maxFileSize;
5
+ private currentFile;
6
+ private currentSize;
7
+ private writeQueue;
8
+ private flushing;
9
+ constructor(traceDir: string, maxFileSize: number);
10
+ private ensureDir;
11
+ private getCurrentFile;
12
+ /** Write a trace record to JSONL file (async, non-blocking) */
13
+ write(trace: TraceRecord): void;
14
+ private flush;
15
+ /** Get list of trace files */
16
+ getTraceFiles(): string[];
17
+ /** Read traces from file(s) */
18
+ readTracesFromFile(file: string, limit?: number): TraceRecord[];
19
+ /** Delete a single trace file */
20
+ deleteFile(filePath: string): void;
21
+ /** Delete all trace files (permanent clear) */
22
+ deleteAllFiles(): void;
23
+ /** Clean up old trace files beyond maxAge */
24
+ cleanup(maxAge: number): void;
25
+ }
26
+ //# sourceMappingURL=writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../../src/server/trace/writer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAMjD,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,cAAc;IAStB,+DAA+D;IAC/D,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAK/B,OAAO,CAAC,KAAK;IA0Bb,8BAA8B;IAC9B,aAAa,IAAI,MAAM,EAAE;IAQzB,+BAA+B;IAC/B,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE;IAe/D,iCAAiC;IACjC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQlC,+CAA+C;IAC/C,cAAc,IAAI,IAAI;IAUtB,6CAA6C;IAC7C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAY9B"}
@@ -0,0 +1,125 @@
1
+ // ============================================================
2
+ // Trace Writer - JSONL 持久化
3
+ // ============================================================
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ export class TraceWriter {
7
+ traceDir;
8
+ maxFileSize;
9
+ currentFile = null;
10
+ currentSize = 0;
11
+ writeQueue = [];
12
+ flushing = false;
13
+ constructor(traceDir, maxFileSize) {
14
+ this.traceDir = traceDir;
15
+ this.maxFileSize = maxFileSize;
16
+ this.ensureDir();
17
+ }
18
+ ensureDir() {
19
+ if (!fs.existsSync(this.traceDir)) {
20
+ fs.mkdirSync(this.traceDir, { recursive: true });
21
+ }
22
+ }
23
+ getCurrentFile() {
24
+ if (!this.currentFile || this.currentSize > this.maxFileSize) {
25
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
26
+ this.currentFile = path.join(this.traceDir, `traces-${timestamp}.jsonl`);
27
+ this.currentSize = 0;
28
+ }
29
+ return this.currentFile;
30
+ }
31
+ /** Write a trace record to JSONL file (async, non-blocking) */
32
+ write(trace) {
33
+ this.writeQueue.push(trace);
34
+ this.flush();
35
+ }
36
+ flush() {
37
+ if (this.flushing || this.writeQueue.length === 0)
38
+ return;
39
+ this.flushing = true;
40
+ const batch = this.writeQueue.splice(0, this.writeQueue.length);
41
+ const file = this.getCurrentFile();
42
+ const lines = batch.map((t) => JSON.stringify(t)).join('\n') + '\n';
43
+ const size = Buffer.byteLength(lines, 'utf-8');
44
+ fs.appendFile(file, lines, (err) => {
45
+ if (err) {
46
+ console.error('Failed to write trace:', err);
47
+ // Re-queue the failed batch
48
+ this.writeQueue.unshift(...batch);
49
+ }
50
+ else {
51
+ this.currentSize += size;
52
+ }
53
+ this.flushing = false;
54
+ // If more items queued, flush again
55
+ if (this.writeQueue.length > 0) {
56
+ this.flush();
57
+ }
58
+ });
59
+ }
60
+ /** Get list of trace files */
61
+ getTraceFiles() {
62
+ this.ensureDir();
63
+ return fs.readdirSync(this.traceDir)
64
+ .filter((f) => f.endsWith('.jsonl'))
65
+ .sort()
66
+ .map((f) => path.join(this.traceDir, f));
67
+ }
68
+ /** Read traces from file(s) */
69
+ readTracesFromFile(file, limit) {
70
+ if (!fs.existsSync(file))
71
+ return [];
72
+ const content = fs.readFileSync(file, 'utf-8');
73
+ const lines = content.trim().split('\n');
74
+ const traces = lines
75
+ .filter((l) => l.trim())
76
+ .flatMap((l) => {
77
+ try {
78
+ return [JSON.parse(l)];
79
+ }
80
+ catch {
81
+ return [];
82
+ } // skip malformed lines
83
+ });
84
+ if (limit)
85
+ return traces.slice(-limit);
86
+ return traces;
87
+ }
88
+ /** Delete a single trace file */
89
+ deleteFile(filePath) {
90
+ try {
91
+ fs.unlinkSync(filePath);
92
+ }
93
+ catch { }
94
+ if (this.currentFile === filePath) {
95
+ this.currentFile = null;
96
+ this.currentSize = 0;
97
+ }
98
+ }
99
+ /** Delete all trace files (permanent clear) */
100
+ deleteAllFiles() {
101
+ const files = this.getTraceFiles();
102
+ for (const file of files) {
103
+ try {
104
+ fs.unlinkSync(file);
105
+ }
106
+ catch { }
107
+ }
108
+ // Reset current file pointer so next write starts fresh
109
+ this.currentFile = null;
110
+ this.currentSize = 0;
111
+ }
112
+ /** Clean up old trace files beyond maxAge */
113
+ cleanup(maxAge) {
114
+ const now = Date.now();
115
+ const files = this.getTraceFiles();
116
+ for (const file of files) {
117
+ const stat = fs.statSync(file);
118
+ const age = (now - stat.mtimeMs) / 1000;
119
+ if (age > maxAge) {
120
+ fs.unlinkSync(file);
121
+ }
122
+ }
123
+ }
124
+ }
125
+ //# sourceMappingURL=writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../../src/server/trace/writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,167 @@
1
+ export interface ContentPart {
2
+ type: string;
3
+ text?: string;
4
+ thinking?: string;
5
+ signature?: string;
6
+ image_url?: {
7
+ url: string;
8
+ };
9
+ id?: string;
10
+ name?: string;
11
+ input?: unknown;
12
+ tool_use_id?: string;
13
+ }
14
+ export interface ChatMessage {
15
+ role: 'system' | 'user' | 'assistant' | 'tool';
16
+ content: string | ContentPart[];
17
+ name?: string;
18
+ tool_call_id?: string;
19
+ tool_calls?: ToolCallInMessage[];
20
+ }
21
+ export interface ToolCallInMessage {
22
+ id: string;
23
+ type: 'function';
24
+ function: {
25
+ name: string;
26
+ arguments: string;
27
+ };
28
+ }
29
+ export interface ToolDefinition {
30
+ type: 'function';
31
+ function: {
32
+ name: string;
33
+ description?: string;
34
+ parameters?: Record<string, unknown>;
35
+ };
36
+ }
37
+ export interface ToolCallRecord {
38
+ id: string;
39
+ name: string;
40
+ arguments: Record<string, unknown>;
41
+ result?: unknown;
42
+ }
43
+ export type ProviderType = 'openai' | 'anthropic' | 'ollama';
44
+ export interface ProviderConfig {
45
+ baseUrl: string;
46
+ apiKey?: string;
47
+ headers?: Record<string, string>;
48
+ }
49
+ export interface ProvidersConfig {
50
+ openai?: ProviderConfig;
51
+ anthropic?: ProviderConfig;
52
+ ollama?: ProviderConfig;
53
+ }
54
+ export interface TokenUsage {
55
+ promptTokens: number;
56
+ completionTokens: number;
57
+ totalTokens: number;
58
+ reasoningTokens?: number;
59
+ cacheReadTokens?: number;
60
+ cacheWriteTokens?: number;
61
+ cachedTokens?: number;
62
+ }
63
+ export interface RawChunk {
64
+ index: number;
65
+ timestamp: number;
66
+ data: string;
67
+ }
68
+ export type TraceStatus = 'pending' | 'streaming' | 'completed' | 'error';
69
+ export interface TraceRecord {
70
+ id: string;
71
+ timestamp: string;
72
+ provider: string;
73
+ model: string;
74
+ status: TraceStatus;
75
+ duration: number;
76
+ ttfb: number;
77
+ sourceFile?: string;
78
+ request: {
79
+ method: string;
80
+ path: string;
81
+ headers: Record<string, string>;
82
+ body: {
83
+ model: string;
84
+ messages?: ChatMessage[];
85
+ prompt?: string;
86
+ tools?: ToolDefinition[];
87
+ stream?: boolean;
88
+ temperature?: number;
89
+ max_tokens?: number;
90
+ [key: string]: unknown;
91
+ };
92
+ };
93
+ response: {
94
+ status: number;
95
+ headers: Record<string, string>;
96
+ body: unknown;
97
+ chunks?: RawChunk[];
98
+ };
99
+ toolCalls?: ToolCallRecord[];
100
+ usage?: TokenUsage;
101
+ error?: {
102
+ code: string;
103
+ message: string;
104
+ };
105
+ }
106
+ export interface ProxyConfig {
107
+ port: number;
108
+ logLevel: 'debug' | 'info' | 'warn' | 'error';
109
+ }
110
+ export interface TraceConfig {
111
+ dir: string;
112
+ maxFileSize: number;
113
+ maxAge: number;
114
+ maxInMemory: number;
115
+ }
116
+ export interface DashboardConfig {
117
+ autoOpen: boolean;
118
+ }
119
+ export interface AppConfig {
120
+ proxy: ProxyConfig;
121
+ providers: ProvidersConfig;
122
+ trace: TraceConfig;
123
+ dashboard: DashboardConfig;
124
+ }
125
+ export type WSEvent = {
126
+ type: 'trace:new';
127
+ data: TraceRecord;
128
+ } | {
129
+ type: 'trace:update';
130
+ data: Partial<TraceRecord> & {
131
+ id: string;
132
+ };
133
+ } | {
134
+ type: 'trace:chunk';
135
+ data: {
136
+ id: string;
137
+ chunk: RawChunk;
138
+ };
139
+ } | {
140
+ type: 'trace:complete';
141
+ data: {
142
+ id: string;
143
+ duration: number;
144
+ usage?: TokenUsage;
145
+ };
146
+ } | {
147
+ type: 'status';
148
+ data: {
149
+ proxy: boolean;
150
+ connections: number;
151
+ };
152
+ };
153
+ export interface TraceListResponse {
154
+ traces: TraceRecord[];
155
+ total: number;
156
+ page: number;
157
+ pageSize: number;
158
+ }
159
+ export interface StatsResponse {
160
+ totalCalls: number;
161
+ totalTokens: number;
162
+ avgDuration: number;
163
+ callsByModel: Record<string, number>;
164
+ callsByProvider: Record<string, number>;
165
+ recentCalls: TraceRecord[];
166
+ }
167
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ // ============================================================
2
+ // LPT Core Types - 所有模块共享的类型定义
3
+ // ============================================================
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+BAA+B;AAC/B,+DAA+D"}
@@ -0,0 +1,20 @@
1
+ import type { WSEvent } from '../types.js';
2
+ export declare class WSServer {
3
+ private wss;
4
+ private clients;
5
+ private pendingBroadcasts;
6
+ /** Attach WebSocket server to an existing HTTP server */
7
+ attachToServer(server: import('node:http').Server, path?: string): void;
8
+ /** C01: Shared connection handler */
9
+ private handleConnection;
10
+ /** Broadcast an event to all connected clients */
11
+ broadcast(event: WSEvent): void;
12
+ private broadcastDirect;
13
+ /** Send an event to a specific client */
14
+ private sendTo;
15
+ /** Stop the WebSocket server */
16
+ stop(): void;
17
+ /** Get number of connected clients */
18
+ get connectionCount(): number;
19
+ }
20
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/server/ws/server.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,qBAAa,QAAQ;IACnB,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,iBAAiB,CAAiB;IAE1C,yDAAyD;IACzD,cAAc,CAAC,MAAM,EAAE,OAAO,WAAW,EAAE,MAAM,EAAE,IAAI,GAAE,MAAc,GAAG,IAAI;IAM9E,qCAAqC;IACrC,OAAO,CAAC,gBAAgB;IAuBxB,kDAAkD;IAClD,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAY/B,OAAO,CAAC,eAAe;IASvB,yCAAyC;IACzC,OAAO,CAAC,MAAM;IAMd,gCAAgC;IAChC,IAAI,IAAI,IAAI;IAWZ,sCAAsC;IACtC,IAAI,eAAe,IAAI,MAAM,CAE5B;CACF"}
@@ -0,0 +1,78 @@
1
+ // ============================================================
2
+ // WebSocket Manager - Integrated with HTTP server
3
+ // C01: Merged duplicate connection handler into shared helper
4
+ // ============================================================
5
+ import { WebSocketServer, WebSocket } from 'ws';
6
+ const MAX_PENDING_EVENTS = 100; // B04: cap the pending broadcast buffer
7
+ export class WSServer {
8
+ wss = null;
9
+ clients = new Set();
10
+ pendingBroadcasts = [];
11
+ /** Attach WebSocket server to an existing HTTP server */
12
+ attachToServer(server, path = '/ws') {
13
+ this.wss = new WebSocketServer({ server, path });
14
+ this.wss.on('connection', (ws) => this.handleConnection(ws));
15
+ console.log(`[WS] WebSocket 已挂载,路径: ${path}`);
16
+ }
17
+ /** C01: Shared connection handler */
18
+ handleConnection(ws) {
19
+ this.clients.add(ws);
20
+ console.log(`[WS] 客户端已连接(当前连接数: ${this.clients.size})`);
21
+ // Send initial status
22
+ this.sendTo(ws, { type: 'status', data: { proxy: true, connections: this.clients.size } });
23
+ // Flush any buffered events to this new client
24
+ for (const event of this.pendingBroadcasts) {
25
+ this.sendTo(ws, event);
26
+ }
27
+ ws.on('close', () => {
28
+ this.clients.delete(ws);
29
+ console.log(`[WS] 客户端已断开(当前连接数: ${this.clients.size})`);
30
+ });
31
+ ws.on('error', (err) => {
32
+ console.error('[WS] 客户端错误:', err.message);
33
+ this.clients.delete(ws);
34
+ });
35
+ }
36
+ /** Broadcast an event to all connected clients */
37
+ broadcast(event) {
38
+ if (this.clients.size === 0) {
39
+ // B04: Cap the pending broadcast buffer
40
+ if (this.pendingBroadcasts.length >= MAX_PENDING_EVENTS) {
41
+ this.pendingBroadcasts.shift(); // drop oldest
42
+ }
43
+ this.pendingBroadcasts.push(event);
44
+ return;
45
+ }
46
+ this.broadcastDirect(event);
47
+ }
48
+ broadcastDirect(event) {
49
+ const message = JSON.stringify(event);
50
+ for (const client of this.clients) {
51
+ if (client.readyState === WebSocket.OPEN) {
52
+ client.send(message);
53
+ }
54
+ }
55
+ }
56
+ /** Send an event to a specific client */
57
+ sendTo(ws, event) {
58
+ if (ws.readyState === WebSocket.OPEN) {
59
+ ws.send(JSON.stringify(event));
60
+ }
61
+ }
62
+ /** Stop the WebSocket server */
63
+ stop() {
64
+ if (this.wss) {
65
+ for (const client of this.clients) {
66
+ client.close();
67
+ }
68
+ this.clients.clear();
69
+ this.wss.close();
70
+ this.wss = null;
71
+ }
72
+ }
73
+ /** Get number of connected clients */
74
+ get connectionCount() {
75
+ return this.clients.size;
76
+ }
77
+ }
78
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/server/ws/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import{r as e}from"./rolldown-runtime-QTnfLwEv.js";import{C as t,D as n,E as r,O as i,S as a,T as o,_ as s,a as c,b as l,c as u,d,f,g as p,h as m,i as h,k as g,l as _,m as v,n as y,o as b,p as x,r as ee,s as te,t as S,u as ne,v as re,w as C,x as ie,y as ae}from"./react-vendor-BnH7jZBV.js";import{_ as w,a as T,b as E,c as D,d as O,f as k,g as A,h as j,i as M,l as oe,m as N,n as P,o as se,p as F,r as I,s as ce,t as le,u as L,v as R,y as z}from"./markdown-DsSlw-Z4.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var B=e(g(),1),V=e(i(),1),H=`/api`;async function U(e,t){let n=await fetch(`${H}${e}`,t);if(!n.ok)throw Error(`API error: ${n.status}`);return n.json()}var W={getTraces:e=>{let t=new URLSearchParams;e?.model&&t.set(`model`,e.model),e?.provider&&t.set(`provider`,e.provider),e?.status&&t.set(`status`,e.status),e?.keyword&&t.set(`keyword`,e.keyword),e?.limit&&t.set(`limit`,String(e.limit)),e?.offset&&t.set(`offset`,String(e.offset));let n=t.toString();return U(`/traces${n?`?`+n:``}`)},getTrace:e=>U(`/traces/${e}`),reloadTraces:()=>U(`/traces/reload`,{method:`POST`}),getTraceFiles:()=>U(`/traces/files`),deleteTraceFile:e=>U(`/traces/file/${encodeURIComponent(e)}`,{method:`DELETE`}),deleteTraces:(e=!1)=>U(`/traces${e?`?files=true`:``}`,{method:`DELETE`}),getProviders:()=>U(`/providers`),getStats:()=>U(`/stats`),getConfig:()=>U(`/config`)};function ue({url:e,onEvent:t,reconnectInterval:n=3e3}){let r=(0,B.useRef)(null),[i,a]=(0,B.useState)(!1),o=(0,B.useRef)(),s=(0,B.useRef)(t);s.current=t;let c=(0,B.useCallback)(()=>{try{let t=new WebSocket(e);t.onopen=()=>{a(!0),console.log(`[WS] Connected`)},t.onclose=()=>{a(!1),console.log(`[WS] Disconnected, reconnecting...`),o.current=setTimeout(c,n)},t.onerror=e=>{console.error(`[WS] Error:`,e),t.close()},t.onmessage=e=>{try{let t=JSON.parse(e.data);s.current?.(t)}catch{}},r.current=t}catch{o.current=setTimeout(c,n)}},[e,n]);return(0,B.useEffect)(()=>(c(),()=>{clearTimeout(o.current),r.current?.close()}),[c]),{connected:i,send:(0,B.useCallback)(e=>{r.current?.readyState===WebSocket.OPEN&&r.current.send(JSON.stringify(e))},[])}}var G=x();function K({content:e,children:t,placement:n=`top`,delay:r=300}){let[i,a]=(0,B.useState)(!1),{refs:o,floatingStyles:s,context:l}=h({open:i,onOpenChange:a,placement:n,whileElementsMounted:f,middleware:[ne(4),_({padding:8}),d({padding:8})]}),{getReferenceProps:p,getFloatingProps:m}=te([b(l,{move:!1,delay:{open:r,close:0}}),c(l),ee(l),u(l,{role:`tooltip`})]);return(0,G.jsxs)(G.Fragment,{children:[B.cloneElement(t,p({ref:o.setReference,...t.props})),i&&e!=null&&e!==``&&(0,G.jsx)(y,{children:(0,G.jsx)(`div`,{ref:o.setFloating,style:{...s,zIndex:9999,pointerEvents:`none`},...m(),children:(0,G.jsx)(`div`,{style:{background:`var(--bg-card)`,color:`var(--text-secondary)`,border:`1px solid var(--border)`,padding:`5px 9px`,borderRadius:`6px`,fontSize:`11.5px`,fontFamily:`var(--sans)`,fontWeight:400,lineHeight:1.5,letterSpacing:`0.01em`,maxWidth:`260px`,boxShadow:`var(--shadow-md)`},children:e})})})]})}function de({traces:e,activeId:t,onSelect:n,loading:r,onDeleteFile:i}){let[s,c]=(0,B.useState)(`time`),[l,u]=(0,B.useState)(new Set);if(r)return(0,G.jsxs)(`div`,{className:`flex items-center justify-center flex-1 gap-2 text-sm`,style:{color:`var(--text-tertiary)`},children:[(0,G.jsx)(a,{size:14,className:`animate-spin`}),` 加载中…`]});if(e.length===0)return(0,G.jsx)(`div`,{className:`flex items-center justify-center flex-1 text-sm`,style:{color:`var(--text-tertiary)`},children:`暂无请求`});let d=[...e].sort((e,t)=>{if(s===`model`)return(e.model||``).localeCompare(t.model||``);if(s===`status`){let n=e=>e===`streaming`?0:e===`error`?1:e===`pending`?2:3;return n(e.status)-n(t.status)}return 0}),f=d.findIndex(e=>e.id===t),m=d.length>1&&f>=0?Math.round(f/(d.length-1)*100):0,h=[];if(s===`time`){let e=[];for(let t of d)t.sourceFile&&!e.includes(t.sourceFile)&&e.push(t.sourceFile);let t=d.map((e,t)=>({trace:e,globalIdx:t+1})).filter(e=>!e.trace.sourceFile);t.length>0&&h.push({key:`__session__`,label:`当前会话`,fileName:null,items:t});for(let t of e){let e=d.map((e,t)=>({trace:e,globalIdx:t+1})).filter(e=>e.trace.sourceFile===t);if(e.length>0){let n=t.match(/traces-(\d{4}-\d{2}-\d{2})T(\d{2}-\d{2}-\d{2})/),r=n?`${n[1]} ${n[2].replace(/-/g,`:`)}`:t.replace(`.jsonl`,``);h.push({key:t,label:r,fileName:t,items:e})}}}else h.push({key:`__all__`,label:``,fileName:null,items:d.map((e,t)=>({trace:e,globalIdx:t+1}))});let g=e=>{u(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})};return(0,G.jsxs)(`div`,{className:`flex flex-col flex-1 overflow-hidden`,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-1.5 border-b flex-shrink-0`,style:{borderColor:`var(--border-light)`},children:[(0,G.jsx)(`span`,{className:`text-[10px]`,style:{color:`var(--text-tertiary)`},children:`排序`}),(0,G.jsx)(`div`,{className:`sidebar-sort-segment`,children:[`time`,`model`,`status`].map(e=>(0,G.jsx)(K,{content:e===`time`?`按请求时间(最新在前)`:e===`model`?`按模型名称字母`:`按状态(接收中→错误→完成)`,placement:`bottom`,delay:400,children:(0,G.jsx)(`button`,{className:`sidebar-sort-btn${s===e?` active`:``}`,onClick:()=>c(e),children:e===`time`?`时间`:e===`model`?`模型`:`状态`})},e))}),f>=0&&(0,G.jsxs)(`span`,{className:`ml-auto text-[10px]`,style:{color:`var(--text-tertiary)`},children:[f+1,`/`,d.length]})]}),f>=0&&(0,G.jsx)(`div`,{style:{height:`2px`,background:`var(--border)`},children:(0,G.jsx)(`div`,{style:{width:`${m}%`,height:`100%`,background:`var(--blue)`,transition:`width .2s`}})}),(0,G.jsx)(`div`,{className:`flex-1 overflow-y-auto sidebar-scroll`,children:h.map(e=>{let r=l.has(e.key),a=h.length>1,s=e.fileName!==null;return(0,G.jsxs)(B.Fragment,{children:[a&&(0,G.jsxs)(`div`,{className:`file-group-header${s?` history`:` session`}`,onClick:()=>g(e.key),children:[(0,G.jsx)(o,{size:12,className:`file-group-chevron flex-shrink-0`,style:{transform:r?`rotate(-90deg)`:`rotate(0deg)`}}),(0,G.jsx)(`span`,{className:`file-group-label`,children:e.label}),(0,G.jsx)(`span`,{className:`file-group-count`,children:e.items.length}),(()=>{let t=e.items.reduce((e,{trace:t})=>e+(t.usage?.promptTokens||0),0),n=e.items.reduce((e,{trace:t})=>e+(t.usage?.completionTokens||0),0),r=e.items.reduce((e,{trace:t})=>e+(t.usage?.reasoningTokens||0),0),i=e.items.reduce((e,{trace:t})=>e+(t.usage?.cacheReadTokens||0),0),a=e.items.reduce((e,{trace:t})=>e+(t.usage?.cacheWriteTokens||0),0),o=e.items.reduce((e,{trace:t})=>e+(t.usage?.cachedTokens||0),0),s=t+n;if(s===0)return null;let c=e=>e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e),l=e=>e.toLocaleString();return(0,G.jsx)(K,{content:(0,G.jsxs)(`div`,{style:{display:`grid`,gridTemplateColumns:`auto auto`,gap:`1px 10px`,fontSize:`11px`},children:[(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`输入`}),(0,G.jsx)(`span`,{style:{color:`var(--blue)`,fontWeight:600,textAlign:`right`,fontFamily:`var(--mono)`},children:l(t)}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`输出`}),(0,G.jsx)(`span`,{style:{color:`var(--green)`,fontWeight:600,textAlign:`right`,fontFamily:`var(--mono)`},children:l(n)}),r>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`推理`}),(0,G.jsx)(`span`,{style:{color:`var(--indigo)`,fontWeight:600,textAlign:`right`,fontFamily:`var(--mono)`},children:l(r)})]}),i+o>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`缓存命中`}),(0,G.jsx)(`span`,{style:{color:`var(--cyan)`,fontWeight:600,textAlign:`right`,fontFamily:`var(--mono)`},children:l(i+o)})]}),a>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`缓存写入`}),(0,G.jsx)(`span`,{style:{color:`var(--cyan)`,fontWeight:600,textAlign:`right`,fontFamily:`var(--mono)`},children:l(a)})]}),(0,G.jsx)(`span`,{style:{color:`var(--text-secondary)`,fontWeight:600,borderTop:`1px solid var(--border-light)`,paddingTop:`2px`,marginTop:`1px`},children:`合计`}),(0,G.jsx)(`span`,{style:{color:`var(--text)`,fontWeight:700,textAlign:`right`,fontFamily:`var(--mono)`,borderTop:`1px solid var(--border-light)`,paddingTop:`2px`,marginTop:`1px`},children:l(s)})]}),placement:`bottom`,delay:200,children:(0,G.jsx)(`span`,{className:`file-group-tokens`,onClick:e=>e.stopPropagation(),children:c(s)})})})(),e.fileName&&i&&(0,G.jsx)(K,{content:`删除:${e.fileName}`,placement:`bottom`,children:(0,G.jsx)(`button`,{className:`file-group-delete`,onClick:t=>{t.stopPropagation(),i(e.fileName)},children:(0,G.jsx)(p,{size:11})})})]}),!r&&e.items.map(({trace:e,globalIdx:r})=>(0,G.jsx)(fe,{trace:e,isActive:e.id===t,onClick:()=>n(e.id),turnNumber:r},e.id))]},e.key)})})]})}function q(e){let t=(e||``).toLowerCase();return t.includes(`opus`)?{bg:`var(--purple-bg)`,fg:`var(--purple)`}:t.includes(`sonnet`)?{bg:`var(--blue-bg)`,fg:`var(--blue)`}:t.includes(`haiku`)||t.includes(`gpt-4`)?{bg:`var(--green-bg)`,fg:`var(--green)`}:t.includes(`gpt-3`)?{bg:`var(--amber-bg)`,fg:`var(--amber)`}:t.includes(`glm`)||t.includes(`zhipu`)||t.includes(`deepseek`)?{bg:`var(--blue-bg)`,fg:`var(--blue)`}:t.includes(`qwen`)?{bg:`var(--purple-bg)`,fg:`var(--purple)`}:t.includes(`llama`)?{bg:`var(--orange-bg)`,fg:`var(--orange)`}:t.includes(`mistral`)?{bg:`var(--amber-bg)`,fg:`var(--amber)`}:{bg:`var(--bg-code)`,fg:`var(--text-tertiary)`}}function fe({trace:e,isActive:t,onClick:n,turnNumber:r}){let i=new Date(e.timestamp).toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`,second:`2-digit`}),o=e.duration>0?e.duration>=1e3?`${(e.duration/1e3).toFixed(1)}s`:`${e.duration}ms`:e.status===`streaming`?`...`:`-`,s=e.usage?.promptTokens||0,c=e.usage?.completionTokens||0,l=e.usage?.totalTokens||0,u=pe(e),d=q(e.model),f=(e.model||`unknown`).split(`/`).pop()||`unknown`,p=e.status===`streaming`,m=e.status===`error`,h=e.status===`pending`,g=m?`var(--red)`:p?`var(--blue)`:e.status===`completed`?`var(--green)`:`var(--amber)`;return(0,G.jsxs)(`div`,{onClick:n,className:`sidebar-item px-3 py-2 cursor-pointer border-b transition-colors`,style:{background:t?`var(--bg-active)`:`transparent`,borderColor:`var(--border-light)`},children:[(0,G.jsxs)(`div`,{className:`flex items-baseline gap-1.5`,children:[(0,G.jsxs)(`span`,{className:`font-mono flex-shrink-0 text-center`,style:{color:`var(--text-tertiary)`,fontSize:`11px`,fontWeight:700,minWidth:`20px`},children:[`#`,r]}),u?(0,G.jsx)(`span`,{className:`text-xs truncate flex-1`,style:{color:`var(--text)`},children:u}):(0,G.jsx)(`span`,{className:`text-xs truncate flex-1`,style:{color:`var(--text-tertiary)`,fontStyle:`italic`},children:`No content`}),(0,G.jsx)(`span`,{className:`text-[10px] flex-shrink-0 font-mono`,style:{color:`var(--text-tertiary)`},children:i})]}),(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5 mt-0.5`,children:[(0,G.jsx)(`div`,{className:`flex items-center justify-center flex-shrink-0`,style:{minWidth:`20px`},children:p?(0,G.jsx)(a,{size:12,className:`animate-spin`,style:{color:`var(--blue)`}}):m?(0,G.jsx)(v,{size:14,strokeWidth:2.8,style:{color:`var(--red)`}}):h?(0,G.jsx)(`span`,{className:`rounded-full`,style:{width:`9px`,height:`9px`,background:`var(--amber)`,display:`inline-block`}}):(0,G.jsx)(`span`,{className:`rounded-full`,style:{width:`9px`,height:`9px`,background:g,display:`inline-block`}})}),(0,G.jsx)(K,{content:e.model,placement:`right`,delay:500,children:(0,G.jsx)(`span`,{className:`text-[10px] font-mono px-1.5 py-0.5 rounded-full truncate max-w-[90px]`,style:{background:d.bg,color:d.fg,lineHeight:`1.3`},children:f})}),(0,G.jsxs)(`div`,{className:`ml-auto flex items-center gap-1.5 flex-shrink-0 font-mono`,style:{color:`var(--text-tertiary)`,fontSize:`10px`},children:[l>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`span`,{style:{color:`var(--blue)`,fontWeight:600},children:[`↑`,s]}),(0,G.jsxs)(`span`,{style:{color:`var(--green)`,fontWeight:600},children:[`↓`,c]})]}),(0,G.jsxs)(`span`,{className:`flex items-center gap-0.5`,children:[(0,G.jsx)(C,{size:9}),o]})]})]})]})}function pe(e){let t=e.request.body.messages;if(t){let e=[...t].reverse().find(e=>e.role===`user`);if(e)return(typeof e.content==`string`?e.content:Array.isArray(e.content)?e.content.filter(e=>typeof e==`object`&&e.type===`text`).map(e=>e.text||``).join(` `):``).replace(/\s+/g,` `).trim().slice(0,100)}return e.request.body.prompt?String(e.request.body.prompt).replace(/\s+/g,` `).trim().slice(0,100):``}R.registerLanguage(`javascript`,w),R.registerLanguage(`js`,w),R.registerLanguage(`jsx`,w),R.registerLanguage(`typescript`,A),R.registerLanguage(`ts`,A),R.registerLanguage(`tsx`,A),R.registerLanguage(`python`,j),R.registerLanguage(`py`,j),R.registerLanguage(`bash`,N),R.registerLanguage(`sh`,N),R.registerLanguage(`shell`,N),R.registerLanguage(`json`,F),R.registerLanguage(`css`,k),R.registerLanguage(`xml`,O),R.registerLanguage(`html`,O),R.registerLanguage(`markdown`,L),R.registerLanguage(`md`,L),R.registerLanguage(`sql`,oe),R.registerLanguage(`go`,D),R.registerLanguage(`rust`,ce),R.registerLanguage(`java`,se),R.registerLanguage(`cpp`,T),R.registerLanguage(`c`,T),R.registerLanguage(`csharp`,M),R.registerLanguage(`yaml`,I),R.registerLanguage(`yml`,I),R.registerLanguage(`diff`,P),R.registerLanguage(`plaintext`,le);function me({inline:e,className:n,children:i,node:a,...o}){let[s,c]=(0,B.useState)(!1),l=String(i??``).replace(/\n$/,``),u=/language-(\w+)/.exec(n??``)?.[1]??``,d=e??(!n?.startsWith(`language-`)&&!l.includes(`
2
+ `)),f=(0,B.useCallback)(async()=>{try{await navigator.clipboard.writeText(l),c(!0),setTimeout(()=>c(!1),1500)}catch{}},[l]);if(d)return(0,G.jsx)(`code`,{className:n,...o,children:i});let p=``;try{p=u&&R.getLanguage(u)?R.highlight(l,{language:u,ignoreIllegals:!0}).value:R.highlightAuto(l).value}catch{p=l.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}return(0,G.jsxs)(`div`,{className:`md-code-wrapper`,children:[(0,G.jsxs)(`div`,{className:`md-code-header`,children:[u&&(0,G.jsx)(`span`,{className:`md-code-lang`,children:u}),(0,G.jsxs)(`button`,{className:`md-code-copy${s?` copied`:``}`,onClick:f,title:`复制代码`,children:[s?(0,G.jsx)(r,{size:11}):(0,G.jsx)(t,{size:11}),(0,G.jsx)(`span`,{children:s?`已复制`:`复制`})]})]}),(0,G.jsx)(`pre`,{className:`hljs md-code-pre`,children:(0,G.jsx)(`code`,{className:`hljs${u?` language-${u}`:``}`,dangerouslySetInnerHTML:{__html:z.sanitize(p)}})})]})}function he({text:e,isStreaming:t,className:n}){return e?(0,G.jsx)(`div`,{className:[`md-prose`,t?`streaming-cursor`:``,n??``].filter(Boolean).join(` `),children:(0,G.jsx)(S,{remarkPlugins:[E],components:{code:me,a:({href:e,children:t,...n})=>(0,G.jsx)(`a`,{href:e,target:`_blank`,rel:`noopener noreferrer`,...n,children:t})},children:e})}):null}var ge={};function _e({trace:e}){let t=e.response.status||0,n=t>=400||e.status===`error`,r=e.status===`streaming`,i=(0,B.useRef)(null);(0,B.useEffect)(()=>{r&&i.current&&(i.current.scrollTop=i.current.scrollHeight)},[e.response,r]);let a=e.request.body.messages||[],o=Me(e),s=a.filter(e=>e.role!==`system`&&e.role!==`developer`),c=Ne(e),l=Array.isArray(c)?c.filter(e=>e.type===`thinking`).map(e=>e.thinking||``).join(`
3
+
4
+ `):``,u=Array.isArray(c)?(()=>{let e=c.filter(e=>e.type!==`thinking`);return e.length===0?null:e.length===1&&e[0].type===`text`?e[0].text||null:e})():c,d=e.request.body.tools||[],f=e.toolCalls||[],p=e.usage;return(0,G.jsxs)(`div`,{ref:i,className:`detail-content`,children:[n&&(0,G.jsxs)(`div`,{className:`error-banner`,children:[(0,G.jsx)(`span`,{className:`eb-icon`,children:`⚠`}),(0,G.jsx)(`span`,{className:`eb-code`,children:t>=400?`HTTP ${t}`:e.error?.code||`Error`}),(0,G.jsx)(`span`,{className:`eb-sep`,children:`·`}),(0,G.jsx)(`span`,{className:`eb-message`,children:e.error?.message||`Unknown error`})]}),(0,G.jsx)(ve,{usage:p,duration:e.duration,ttfb:e.ttfb,isStreaming:r}),o&&(0,G.jsx)(Y,{title:`System Prompt`,defaultOpen:!1,copyText:o,badge:`system`,children:(0,G.jsx)(Se,{text:o})}),s.length>0&&(0,G.jsx)(Y,{title:`Messages`,defaultOpen:!0,badge:`${s.length}`,copyText:s.map(e=>{let t=typeof e.content==`string`?e.content:Array.isArray(e.content)?e.content.map(e=>e.text||e.thinking||``).join(`
5
+ `):``;return`[${e.role.toUpperCase()}]\n${t}`}).join(`
6
+
7
+ ---
8
+
9
+ `),children:(0,G.jsx)(`div`,{className:`messages-list`,children:s.map((e,t)=>(0,G.jsx)(ye,{message:e},t))})}),(0,G.jsxs)(Y,{title:`Response`,defaultOpen:!0,badge:t?`${t}`:r?`live`:void 0,copyText:(u?typeof u==`string`?u:u.map(e=>e.text||``).join(`
10
+
11
+ `):``)||void 0,children:[l&&(0,G.jsx)(Te,{content:l}),u?(0,G.jsx)(ye,{message:{role:`assistant`,content:u},isStreaming:r}):e.error?(0,G.jsxs)(`div`,{className:`msg system`,style:{marginBottom:0},children:[(0,G.jsx)(`span`,{className:`msg-role`,style:{background:`var(--red)`,color:`#fff`},children:`ERROR`}),(0,G.jsxs)(`div`,{className:`content-block`,children:[`[`,e.error.code,`] `,e.error.message]})]}):(0,G.jsx)(`div`,{style:{color:`var(--text-tertiary)`,fontSize:`13px`,padding:`4px 0`},children:r?(0,G.jsxs)(`span`,{style:{display:`inline-flex`,alignItems:`center`,gap:`8px`,color:`var(--text-tertiary)`,fontSize:`12px`},children:[`接收中 `,(0,G.jsxs)(`span`,{className:`streaming-dots`,children:[(0,G.jsx)(`span`,{}),(0,G.jsx)(`span`,{}),(0,G.jsx)(`span`,{})]})]}):`No response content`})]}),f.length>0&&(0,G.jsx)(Y,{title:`Tool Calls`,defaultOpen:!0,badge:`${f.length}`,copyText:f.map(e=>`${e.name}(${JSON.stringify(e.arguments,null,2)})`).join(`
12
+
13
+ `),children:(0,G.jsx)(`div`,{style:{display:`grid`,gap:`4px`},children:f.map((e,t)=>(0,G.jsx)(Ee,{toolCall:e},t))})}),d.length>0&&(0,G.jsx)(Y,{title:`Tools Definition`,defaultOpen:!1,badge:`${d.length}`,copyText:JSON.stringify(d,null,2),children:(0,G.jsx)(De,{tools:d})}),(0,G.jsx)(Y,{title:`Raw JSON`,defaultOpen:!1,copyText:JSON.stringify(e,null,2),children:(0,G.jsx)(Q,{data:e})})]})}function J(e){return e>=1e3?`${(e/1e3).toFixed(2)}s`:`${e}ms`}function ve({usage:e,duration:t,ttfb:n,isStreaming:r}){let i=(e?.cachedTokens||0)+(e?.cacheReadTokens||0)+(e?.cacheWriteTokens||0)>0;return(0,G.jsx)(`div`,{className:`token-usage-bar`,children:(0,G.jsx)(`div`,{className:`token-bar`,children:r?(0,G.jsxs)(`span`,{style:{display:`inline-flex`,alignItems:`center`,gap:`6px`,fontSize:`11px`,color:`var(--text-tertiary)`},children:[`接收中 `,(0,G.jsxs)(`span`,{className:`streaming-dots`,children:[(0,G.jsx)(`span`,{}),(0,G.jsx)(`span`,{}),(0,G.jsx)(`span`,{})]})]}):e?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{className:`tok-group`,children:(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-label`,children:`合计`}),(0,G.jsx)(`span`,{className:`tok-val`,style:{color:`var(--text)`,fontSize:`12px`},children:e.totalTokens.toLocaleString()})]})}),(0,G.jsxs)(`span`,{className:`tok-group`,children:[(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-arrow`,style:{color:`var(--blue)`},children:`↑`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.promptTokens.toLocaleString()})]}),(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-arrow`,style:{color:`var(--green)`},children:`↓`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.completionTokens.toLocaleString()})]}),(e.reasoningTokens||0)>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-dot`,style:{background:`var(--indigo)`}}),(0,G.jsx)(`span`,{className:`tok-label`,children:`推理`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.reasoningTokens.toLocaleString()})]})]}),i&&(0,G.jsxs)(`span`,{className:`tok-group`,children:[(e.cachedTokens||0)>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-dot`,style:{background:`var(--cyan)`}}),(0,G.jsx)(`span`,{className:`tok-label`,children:`缓存命中`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.cachedTokens.toLocaleString()})]}),(e.cacheReadTokens||0)>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-dot`,style:{background:`var(--cyan)`}}),(0,G.jsx)(`span`,{className:`tok-label`,children:`缓存读`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.cacheReadTokens.toLocaleString()})]}),(e.cacheWriteTokens||0)>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-dot`,style:{background:`var(--amber)`}}),(0,G.jsx)(`span`,{className:`tok-label`,children:`缓存写`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.cacheWriteTokens.toLocaleString()})]})]}),(0,G.jsxs)(`span`,{className:`tok-group`,children:[n>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-label`,children:`首字`}),(0,G.jsx)(`span`,{className:`tok-val`,children:J(n)})]}),t>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-label`,children:`耗时`}),(0,G.jsx)(`span`,{className:`tok-val`,children:J(t)})]}),t>0&&(e.completionTokens||0)>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-label`,children:`速度`}),(0,G.jsxs)(`span`,{className:`tok-val`,children:[Math.round(e.completionTokens/(t/1e3)),` tok/s`]})]})]})]}):(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`,fontSize:`11px`},children:`无 token 数据`})})})}function Y({title:e,defaultOpen:t,badge:n,copyText:r,children:i}){let[a,o]=(0,B.useState)(ge[e]??t);return(0,G.jsxs)(`div`,{className:`section`,children:[(0,G.jsxs)(`div`,{className:`section-header`,onClick:()=>{let t=!a;o(t),ge[e]=t},children:[(0,G.jsx)(`span`,{className:`chevron${a?` open`:``}`,children:`▶`}),(0,G.jsx)(`span`,{className:`title`,children:e}),n&&(0,G.jsx)(`span`,{className:`badge`,children:n}),r!==void 0&&r!==``&&(0,G.jsx)(Z,{getText:()=>r,className:`copy-btn`,stopPropagation:!0})]}),a&&(0,G.jsx)(`div`,{className:`section-body open`,children:i})]})}function ye({message:e,isStreaming:t}){let n=e.role,r=e.content,i=n===`assistant`,a=typeof r==`string`,[o,s]=(0,B.useState)(i?`markdown`:`raw`),c=()=>typeof r==`string`?r:Array.isArray(r)?r.map(e=>e.text||e.thinking||``).filter(Boolean).join(`
14
+
15
+ `):``,l=n===`user`?`user`:n===`assistant`?`assistant`:n===`system`||n===`developer`?`system`:n===`tool`?`tool_result`:``,u=e.tool_calls;e.tool_call_id;let d=a?r.trim().length>0:Array.isArray(r)&&r.length>0,f=a&&r.trim().length>0,[p,m]=(0,B.useState)(n===`tool`);return(0,G.jsxs)(`div`,{className:`msg ${l}`,children:[(0,G.jsxs)(`div`,{className:`msg-header-row`,children:[(0,G.jsxs)(`span`,{className:`msg-role msg-role-toggle`,onClick:()=>m(e=>!e),title:p?`展开`:`收起`,children:[(0,G.jsx)(`span`,{className:`msg-collapse-arrow${p?``:` open`}`,children:`▶`}),n.toUpperCase()]}),f&&(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginLeft:`8px`,marginTop:0,display:p?`none`:void 0},children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${o===`raw`?` active`:``}`,onClick:()=>s(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${o===`markdown`?` active`:``}`,onClick:()=>s(`markdown`),children:`渲染`})]}),(0,G.jsx)(`span`,{style:{marginLeft:`auto`},children:(0,G.jsx)(Z,{getText:c})})]}),!p&&(0,G.jsxs)(G.Fragment,{children:[a?(0,G.jsx)(Ce,{text:r,mode:o}):Array.isArray(r)?(0,G.jsx)(`div`,{children:r.map((e,n)=>(0,G.jsx)(xe,{block:e,isStreaming:t&&n===r.length-1},n))}):r?(0,G.jsx)(Q,{data:r}):null,u&&u.length>0&&(0,G.jsx)(`div`,{className:`msg-tool-calls`,children:u.map(e=>(0,G.jsx)(be,{toolCall:e},e.id))})]}),p&&(d||u&&u.length>0)&&(0,G.jsx)(`div`,{className:`msg-collapsed-hint`,children:[d?a?`${r.slice(0,60).replace(/\n/g,` `)}…`:`${r.length} 块`:``,u?.length?`${u.length} tool_call`:``].filter(Boolean).join(` · `)})]})}function be({toolCall:e}){let[t,n]=(0,B.useState)(!1),r=e.function.arguments;try{r=JSON.parse(e.function.arguments)}catch{}let i=typeof r==`object`&&r?Object.keys(r).length:0;return(0,G.jsxs)(`div`,{className:`tool-block`,children:[(0,G.jsxs)(`div`,{className:`tool-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsx)(`span`,{className:`tb-arrow${t?` open`:``}`,children:`▶`}),(0,G.jsx)(`span`,{className:`tb-name`,children:e.function.name}),!t&&i>0&&(0,G.jsxs)(`span`,{className:`tb-desc`,children:[`(`,i,` args)`]})]}),t&&(0,G.jsx)(`div`,{className:`tool-block-body open`,children:typeof r==`object`?(0,G.jsx)(Q,{data:r}):(0,G.jsx)(`pre`,{className:`text-raw`,children:String(r)})})]})}function xe({block:e,isStreaming:t}){let[n,r]=(0,B.useState)(`markdown`);if(e.type===`text`||e.type===`input_text`||e.type===`output_text`){let i=e.text||``;return(0,G.jsxs)(`div`,{className:`content-block`,children:[(0,G.jsx)(`div`,{className:`msg-header-row`,style:{marginBottom:`4px`},children:(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginTop:0},children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${n===`raw`?` active`:``}`,onClick:()=>r(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${n===`markdown`?` active`:``}`,onClick:()=>r(`markdown`),children:`渲染`})]})}),(0,G.jsx)(X,{text:i,mode:n,isStreaming:t})]})}return e.type===`thinking`?(0,G.jsx)(we,{content:e.thinking||``}):e.type===`tool_use`?(0,G.jsxs)(`div`,{className:`content-block block-framed`,children:[(0,G.jsxs)(`span`,{className:`tool-use-label`,children:[`⚙ `,e.name||`tool_use`]}),(0,G.jsx)(Q,{data:e.input})]}):e.type===`tool_result`?(0,G.jsxs)(`div`,{className:`content-block block-framed`,style:{borderColor:`var(--purple)`,background:`var(--purple-bg)`},children:[(0,G.jsxs)(`span`,{className:`tool-use-label`,style:{color:`var(--purple)`,background:`color-mix(in srgb, var(--purple) 15%, transparent)`},children:[`↩ tool_result: `,e.tool_use_id||``]}),(0,G.jsx)(`div`,{className:`content-block-text`,children:typeof e.text==`string`?e.text:(0,G.jsx)(Q,{data:e.text})})]}):(0,G.jsx)(Q,{data:e})}function X({text:e,mode:t,isStreaming:n,sans:r,compact:i,className:a}){return e?(0,G.jsxs)(`div`,{className:`text-pane${a?` `+a:``}`,children:[(0,G.jsx)(`pre`,{className:`text-raw${r?` sans`:``}`,style:{display:t===`raw`?void 0:`none`},children:e}),(0,G.jsx)(`div`,{style:{display:t===`markdown`?void 0:`none`},children:i?(0,G.jsx)(`div`,{className:`text-raw sans`,style:{whiteSpace:`pre-wrap`},children:e}):(0,G.jsx)(he,{text:e,isStreaming:n})})]}):null}function Se({text:e}){let[t,n]=(0,B.useState)(`raw`);return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginBottom:`6px`},children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${t===`raw`?` active`:``}`,onClick:()=>n(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${t===`markdown`?` active`:``}`,onClick:()=>n(`markdown`),children:`渲染`})]}),(0,G.jsx)(X,{text:e,mode:t,sans:!0})]})}function Ce({text:e,mode:t}){return e?(0,G.jsx)(X,{text:e,mode:t}):null}function we({content:e}){let[t,n]=(0,B.useState)(!1),[r,i]=(0,B.useState)(`raw`),a=e.slice(0,80).replace(/\n/g,` `);return(0,G.jsxs)(`div`,{className:`thinking-block content-block`,children:[(0,G.jsxs)(`div`,{className:`thinking-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsxs)(`span`,{className:`thinking-label`,children:[(0,G.jsx)(`span`,{className:`thinking-arrow`,children:t?`▼`:`▶`}),(0,G.jsx)(`span`,{children:`Thinking`})]}),t?(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginTop:0,marginLeft:`4px`},onClick:e=>e.stopPropagation(),children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`raw`?` active`:``}`,onClick:()=>i(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`markdown`?` active`:``}`,onClick:()=>i(`markdown`),children:`渲染`})]}):(0,G.jsxs)(`span`,{className:`thinking-preview`,children:[a,`…`]}),(0,G.jsx)(Z,{getText:()=>e,stopPropagation:!0,className:`copy-btn`})]}),t&&(0,G.jsx)(X,{text:e,mode:r,sans:!0})]})}function Te({content:e}){let[t,n]=(0,B.useState)(!1),[r,i]=(0,B.useState)(`raw`),a=e.slice(0,80).replace(/\n/g,` `);return(0,G.jsxs)(`div`,{className:`thinking-block content-block`,style:{marginBottom:`8px`},children:[(0,G.jsxs)(`div`,{className:`thinking-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsxs)(`span`,{className:`thinking-label`,children:[(0,G.jsx)(`span`,{className:`thinking-arrow`,children:t?`▼`:`▶`}),(0,G.jsx)(`span`,{children:`Thinking`})]}),t?(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginTop:0,marginLeft:`4px`},onClick:e=>e.stopPropagation(),children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`raw`?` active`:``}`,onClick:()=>i(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`markdown`?` active`:``}`,onClick:()=>i(`markdown`),children:`渲染`})]}):(0,G.jsxs)(`span`,{className:`thinking-preview`,children:[a,`…`]}),(0,G.jsx)(Z,{getText:()=>e,stopPropagation:!0,className:`copy-btn`})]}),t&&(0,G.jsx)(X,{text:e,mode:r,sans:!0})]})}function Ee({toolCall:e}){let[t,n]=(0,B.useState)(!1),r=typeof e.arguments==`object`?Object.keys(e.arguments||{}).length:0;return(0,G.jsxs)(`div`,{className:`tool-block`,children:[(0,G.jsxs)(`div`,{className:`tool-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsx)(`span`,{className:`tb-arrow${t?` open`:``}`,children:`▶`}),(0,G.jsx)(`span`,{className:`tb-name`,children:e.name}),!t&&r>0&&(0,G.jsxs)(`span`,{className:`tb-desc`,children:[`(`,r,` args)`]})]}),t&&(0,G.jsxs)(`div`,{className:`tool-block-body open`,children:[(0,G.jsx)(Q,{data:e.arguments}),e.result!==void 0&&(0,G.jsxs)(`div`,{style:{marginTop:`10px`,paddingTop:`10px`,borderTop:`1px solid var(--border-light)`},children:[(0,G.jsx)(`div`,{style:{fontSize:`11px`,fontWeight:600,color:`var(--orange)`,marginBottom:`6px`,textTransform:`uppercase`},children:`Result`}),(0,G.jsx)(Q,{data:e.result})]})]})]})}function De({tools:e}){return(0,G.jsx)(`div`,{style:{display:`grid`,gap:`4px`},children:e.map((e,t)=>(0,G.jsx)(Oe,{tool:e},t))})}function Oe({tool:e}){let[t,n]=(0,B.useState)(!1),r=e.function||e,i=r.name||e.name||`unknown`,a=r.description||e.description||``,o=r.parameters||e.input_schema||e.parameters,s=o?.required||[],c=o?.properties||{};return(0,G.jsxs)(`div`,{className:`tool-block`,children:[(0,G.jsxs)(`div`,{className:`tool-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsx)(`span`,{className:`tb-arrow${t?` open`:``}`,children:`▶`}),(0,G.jsx)(`span`,{className:`tb-name`,children:i}),(0,G.jsx)(`span`,{className:`tb-desc`,children:a})]}),t&&(0,G.jsxs)(`div`,{className:`tool-block-body open`,children:[a&&(0,G.jsx)(`div`,{className:`tb-full-desc`,children:a}),Object.keys(c).length>0?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`tb-params-title`,children:`Parameters`}),Object.entries(c).map(([e,t])=>(0,G.jsxs)(`div`,{className:`tb-param`,children:[(0,G.jsxs)(`div`,{className:`tb-param-row1`,children:[(0,G.jsx)(`span`,{className:`tb-pname`,children:e}),t.type&&(0,G.jsx)(`span`,{className:`tb-ptype`,children:t.type}),s.includes(e)&&(0,G.jsx)(`span`,{className:`tb-prequired`,children:`required`})]}),t.description&&(0,G.jsx)(`div`,{className:`tb-pdesc`,children:t.description})]},e))]}):o?(0,G.jsx)(Q,{data:o}):null]})]})}function Z({getText:e,className:n=`copy-btn`,stopPropagation:i=!1}){let[a,o]=(0,B.useState)(!1);return(0,G.jsx)(`button`,{className:`${n}${a?` copied`:``}`,onClick:async t=>{i&&t.stopPropagation();try{await navigator.clipboard.writeText(e()),o(!0),setTimeout(()=>o(!1),1500)}catch{}},"data-tip":`复制`,children:a?(0,G.jsx)(r,{size:10}):(0,G.jsx)(t,{size:10})})}var ke=0;function Q({data:e}){return ke=0,(0,G.jsx)(`div`,{className:`json-view`,children:$(e,0)})}var Ae=new Set([`chunks`,`headers`,`tools`]);function $(e,t,n){if(t>50)return(0,G.jsx)(`span`,{className:`json-punct`,children:`…`});if(e===null)return(0,G.jsx)(`span`,{className:`jnull`,children:`null`});if(e===void 0)return(0,G.jsx)(`span`,{className:`jnull`,children:`undefined`});if(typeof e==`boolean`)return(0,G.jsx)(`span`,{className:`jb`,children:String(e)});if(typeof e==`number`)return(0,G.jsx)(`span`,{className:`jn`,children:e});if(typeof e==`string`)return(0,G.jsxs)(`span`,{className:`js`,children:[`"`,e.length>300?e.slice(0,300)+`…`:e,`"`]});if(typeof e!=`object`)return(0,G.jsx)(`span`,{children:String(e)});let r=Array.isArray(e),i=r?e.map((e,t)=>[t,e]):Object.entries(e),a=i.length;if(a===0)return(0,G.jsx)(`span`,{className:`json-punct`,children:r?`[]`:`{}`});if(a<=3&&t<2&&i.every(([,e])=>typeof e!=`object`||!e)){let e=i.map(([e,n],i)=>(0,G.jsxs)(`span`,{children:[!r&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`span`,{className:`jk`,children:[`"`,String(e),`"`]}),(0,G.jsx)(`span`,{className:`json-punct`,children:`: `})]}),$(n,t+1),i<a-1&&(0,G.jsx)(`span`,{className:`json-punct`,children:`, `})]},String(e)));return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{className:`json-punct`,children:r?`[`:`{`}),e,(0,G.jsx)(`span`,{className:`json-punct`,children:r?`]`:`}`})]})}let o=`jt`+ ke++,s=`${a} ${r?`item`:`key`}${a===1?``:`s`}`,c=n!==void 0&&Ae.has(n),l=i.map(([e,n])=>(0,G.jsxs)(`div`,{className:`jt-line`,children:[!r&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`span`,{className:`jk`,children:[`"`,String(e),`"`]}),(0,G.jsx)(`span`,{className:`json-punct`,children:`: `})]}),$(n,t+1,String(e))]},String(e)));return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{className:`jt-toggle${c?``:` jt-open`}`,onClick:e=>je(e,o),style:{cursor:`pointer`},children:c?`▶`:`▼`}),(0,G.jsx)(`span`,{className:`json-punct`,children:r?`[`:`{`}),(0,G.jsxs)(`span`,{className:`jt-summary${c?` jt-show`:``}`,id:`${o}s`,children:[`… `,s]}),(0,G.jsx)(`div`,{className:`jt-children${c?``:` jt-open`}`,id:o,children:l}),(0,G.jsx)(`div`,{className:`jt-close${c?` jt-hidden`:``}`,id:`${o}c`,children:(0,G.jsx)(`span`,{className:`json-punct`,children:r?`]`:`}`})})]})}function je(e,t){e.stopPropagation();let n=document.getElementById(t),r=document.getElementById(t+`s`),i=document.getElementById(t+`c`),a=e.currentTarget;n&&(n.classList.contains(`jt-open`)?(n.classList.remove(`jt-open`),a.classList.remove(`jt-open`),a.textContent=`▶`,r?.classList.add(`jt-show`),i?.classList.add(`jt-hidden`)):(n.classList.add(`jt-open`),a.classList.add(`jt-open`),a.textContent=`▼`,r?.classList.remove(`jt-show`),i?.classList.remove(`jt-hidden`)))}function Me(e){let t=e.request.body,n=[];if(typeof t.system==`string`&&t.system.trim())n.push(t.system);else if(Array.isArray(t.system)){let e=t.system.map(e=>typeof e==`string`?e:e?.type===`text`&&e.text||``).filter(Boolean).join(`
16
+
17
+ `);e.trim()&&n.push(e)}let r=e.request.body.messages||[];for(let e of r)if(e.role===`system`||e.role===`developer`){let t=typeof e.content==`string`?e.content:Array.isArray(e.content)?e.content.map(e=>e.text||``).filter(Boolean).join(`
18
+
19
+ `):``;t.trim()&&n.push(t)}return n.length?n.join(`
20
+
21
+ `):null}function Ne(e){let t=e.response.body;if(!t)return null;if(t.choices&&Array.isArray(t.choices)&&t.choices.length>0){let e=t.choices[0].message;if(e){let t=e.content,n=e.reasoning_content,r=[];if(n&&r.push({type:`thinking`,thinking:n}),typeof t==`string`&&t.trim()?r.push({type:`text`,text:t}):Array.isArray(t)?r.push(...t):t!=null&&r.push({type:`text`,text:JSON.stringify(t)}),r.length===1&&r[0].type===`text`)return r[0].text||null;if(r.length>0)return r}return null}if(t.content&&Array.isArray(t.content)){let e=t.content;return e.length===1&&e[0].type===`text`?e[0].text||null:e}return typeof t.text==`string`?t.text:null}function Pe({onClose:e}){let[t,n]=(0,B.useState)([]),[r,i]=(0,B.useState)(!0),[a,o]=(0,B.useState)(null);(0,B.useEffect)(()=>{Promise.all([W.getProviders().then(n).catch(()=>{}),W.getConfig().then(e=>o(e.proxy?.port??null)).catch(()=>{})]).finally(()=>i(!1))},[]);let s=a??(window.location.port?Number(window.location.port):void 0);return(0,G.jsxs)(`div`,{className:`p-5 space-y-5`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`h2`,{className:`text-base font-semibold`,children:`设置`}),(0,G.jsx)(`button`,{onClick:e,style:{color:`var(--text-tertiary)`},children:(0,G.jsx)(v,{size:16})})]}),(0,G.jsxs)(`div`,{className:`rounded-lg p-3`,style:{background:`var(--bg)`,border:`1px solid var(--border)`},children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium mb-2`,children:`代理服务器`}),(0,G.jsxs)(`div`,{className:`grid grid-cols-2 gap-x-4 gap-y-1.5 text-xs`,children:[(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`监听端口`}),(0,G.jsx)(`span`,{className:`font-mono`,style:{color:`var(--blue)`},children:s}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`OpenAI Base URL`}),(0,G.jsxs)(`span`,{className:`font-mono`,style:{color:`var(--blue)`},children:[`http://localhost:`,s,`/v1`]}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`Anthropic Base URL`}),(0,G.jsxs)(`span`,{className:`font-mono`,style:{color:`var(--blue)`},children:[`http://localhost:`,s]})]})]}),(0,G.jsxs)(`div`,{className:`rounded-lg p-3`,style:{background:`var(--bg)`,border:`1px solid var(--border)`},children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium mb-1`,children:`上游服务商`}),(0,G.jsxs)(`p`,{className:`text-[11px] mb-3`,style:{color:`var(--text-tertiary)`},children:[`修改请编辑项目根目录的 `,(0,G.jsx)(`code`,{className:`font-mono px-1 py-0.5 rounded`,style:{background:`var(--bg-code)`},children:`.env`}),` 文件后重启服务`]}),r?(0,G.jsx)(`div`,{className:`text-sm`,style:{color:`var(--text-tertiary)`},children:`加载中…`}):t.length===0?(0,G.jsxs)(`div`,{className:`text-sm italic`,style:{color:`var(--text-tertiary)`},children:[`未检测到已配置的 Provider。请在 `,(0,G.jsx)(`code`,{className:`font-mono`,children:`.env`}),` 中设置 `,(0,G.jsx)(`code`,{className:`font-mono`,children:`OPENAI_API_KEY`}),` 等变量。`]}):(0,G.jsx)(`div`,{className:`space-y-1.5`,children:t.map(e=>(0,G.jsxs)(`div`,{className:`flex items-center gap-3 px-3 py-2 rounded`,style:{border:`1px solid var(--border)`},children:[(0,G.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full flex-shrink-0`,style:{background:`var(--green)`}}),(0,G.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,G.jsx)(`div`,{className:`text-sm font-medium capitalize`,children:e.type}),(0,G.jsx)(`div`,{className:`text-[11px] font-mono truncate`,style:{color:`var(--text-tertiary)`},children:e.baseUrl})]}),e.apiKey&&(0,G.jsx)(`span`,{className:`text-[11px] font-mono flex-shrink-0`,style:{color:`var(--text-tertiary)`},children:e.apiKey})]},e.type))})]})]})}function Fe({open:e,title:t,message:n,confirmText:r=`确认`,cancelText:i=`取消`,danger:a=!1,onConfirm:o,onCancel:s}){let c=(0,B.useRef)(null);return(0,B.useEffect)(()=>{e&&c.current?.focus()},[e]),(0,B.useEffect)(()=>{if(!e)return;let t=e=>{e.key===`Escape`&&s(),e.key===`Enter`&&o()};return window.addEventListener(`keydown`,t),()=>window.removeEventListener(`keydown`,t)},[e,o,s]),e?(0,G.jsx)(`div`,{className:`confirm-overlay`,onClick:s,children:(0,G.jsxs)(`div`,{className:`confirm-dialog`,onClick:e=>e.stopPropagation(),children:[(0,G.jsx)(`div`,{className:`confirm-icon-row`,children:(0,G.jsx)(`span`,{className:`confirm-icon${a?` danger`:``}`,children:(0,G.jsx)(m,{size:20})})}),(0,G.jsx)(`div`,{className:`confirm-title`,children:t}),(0,G.jsx)(`div`,{className:`confirm-message`,children:n}),(0,G.jsxs)(`div`,{className:`confirm-actions`,children:[(0,G.jsx)(`button`,{className:`confirm-btn cancel`,onClick:s,children:i}),(0,G.jsx)(`button`,{ref:c,className:`confirm-btn ok${a?` danger`:``}`,onClick:o,children:r})]})]})}):null}function Ie(){try{let e=localStorage.getItem(`lpt-theme`);if(e===`dark`||e===`light`)return e}catch{}return window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}function Le(e){document.documentElement.setAttribute(`data-theme`,e);try{localStorage.setItem(`lpt-theme`,e)}catch{}}function Re(){let[e,t]=(0,B.useState)([]),[r,i]=(0,B.useState)(null),[a,c]=(0,B.useState)(null),[u,d]=(0,B.useState)(``),[f,m]=(0,B.useState)(`all`),[h,g]=(0,B.useState)(!1),[_,y]=(0,B.useState)({open:!1,title:``,message:``,onConfirm:()=>{}}),b=(e,t,n)=>{y({open:!0,title:e,message:t,onConfirm:n})},x=()=>y(e=>({...e,open:!1})),[ee,te]=(0,B.useState)(!0),[S,ne]=(0,B.useState)(Ie),[C,w]=(0,B.useState)(320),T=(0,B.useRef)(!1),E=(0,B.useRef)(0),D=(0,B.useRef)(0),[O,k]=(0,B.useState)(!1),A=(0,B.useRef)(null),[j,M]=(0,B.useState)(!1);(0,B.useEffect)(()=>{Le(S)},[S]),(0,B.useEffect)(()=>{if(!O)return;let e=e=>{A.current&&!A.current.contains(e.target)&&k(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[O]);let oe=()=>ne(e=>e===`light`?`dark`:`light`),N=e.find(e=>e.id===a)||null,P=(0,B.useCallback)(async()=>{try{let[e,n]=await Promise.all([W.getTraces({keyword:u||void 0,limit:200}),W.getStats()]);t(e.traces),i(n)}catch{}finally{te(!1)}},[u]),se=(0,B.useCallback)(e=>{if(e.type===`trace:new`){let n=e.data;u||t(e=>[n,...e]),i(e=>e&&{...e,totalCalls:e.totalCalls+1})}else if(e.type===`trace:update`||e.type===`trace:complete`){let n=e.data;t(e=>e.map(e=>e.id===n.id?{...e,...n}:e)),e.type===`trace:complete`&&W.getStats().then(i).catch(()=>{})}},[u]),{connected:F}=ue({url:`ws://${window.location.host}/ws`,onEvent:se});(0,B.useEffect)(()=>{P()},[P]);let I=e=>{T.current=!0,E.current=e.clientX,D.current=C,document.body.style.userSelect=`none`,document.body.style.cursor=`col-resize`;let t=e=>{if(!T.current)return;let t=e.clientX-E.current;w(Math.max(240,Math.min(600,D.current+t)))},n=()=>{T.current=!1,document.body.style.userSelect=``,document.body.style.cursor=``,document.removeEventListener(`mousemove`,t),document.removeEventListener(`mouseup`,n)};document.addEventListener(`mousemove`,t),document.addEventListener(`mouseup`,n)},ce=r?.totalTokens??0,le=r?.totalCalls??0,L=r?.avgDuration??0,R=e.reduce((e,t)=>e+(t.usage?.promptTokens||0),0),z=e.reduce((e,t)=>e+(t.usage?.completionTokens||0),0),V=f===`all`?e:e.filter(e=>e.status===f),H={};for(let t of e)t.model&&(H[t.model]=(H[t.model]||0)+1);let U=Object.entries(H).sort((e,t)=>t[1]-e[1]).slice(0,4),[q,fe]=(0,B.useState)(null),pe=q?V.filter(e=>e.model===q):V,me=e.filter(e=>e.status===`error`).length;return(0,G.jsxs)(`div`,{className:`flex flex-col h-screen overflow-hidden`,style:{background:`var(--bg)`,color:`var(--text)`},children:[(0,G.jsxs)(`header`,{className:`flex items-center gap-3 px-4 flex-shrink-0`,style:{background:`var(--bg-card)`,borderBottom:`1px solid var(--border)`,height:`52px`,zIndex:10},children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,G.jsx)(n,{size:18,style:{color:`var(--blue)`}}),(0,G.jsx)(`span`,{className:`text-sm font-semibold tracking-tight`,children:`LPT`})]}),(0,G.jsx)(`div`,{className:`w-px h-5 flex-shrink-0`,style:{background:`var(--border)`}}),(0,G.jsxs)(`div`,{className:`flex items-center gap-3 text-[11px] flex-shrink-0`,style:{color:`var(--text-tertiary)`},children:[(0,G.jsxs)(`span`,{children:[`请求 `,(0,G.jsx)(`b`,{className:`font-mono`,style:{color:`var(--text-secondary)`},children:le})]}),(0,G.jsxs)(`span`,{children:[`Tokens `,(0,G.jsx)(`b`,{className:`font-mono`,style:{color:`var(--text-secondary)`},children:ce.toLocaleString()})]}),R>0&&(0,G.jsxs)(`span`,{className:`flex items-center gap-0.5 font-mono`,style:{color:`var(--blue)`},children:[`↑`,(0,G.jsx)(`b`,{children:R.toLocaleString()})]}),z>0&&(0,G.jsxs)(`span`,{className:`flex items-center gap-0.5 font-mono`,style:{color:`var(--green)`},children:[`↓`,(0,G.jsx)(`b`,{children:z.toLocaleString()})]}),L>0&&(0,G.jsxs)(`span`,{children:[`均 `,L,`ms`]})]}),U.length>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`w-px h-5 flex-shrink-0`,style:{background:`var(--border)`}}),(0,G.jsx)(`div`,{className:`flex items-center gap-1.5 overflow-hidden flex-1`,children:U.map(([e,t])=>(0,G.jsxs)(`button`,{onClick:()=>fe(t=>t===e?null:e),className:`filter-chip${q===e?` active`:``}`,children:[e.split(`/`).pop()||e,(0,G.jsx)(`span`,{className:`chip-count`,children:t})]},e))})]}),(0,G.jsxs)(`div`,{className:`ml-auto flex items-center gap-2 flex-shrink-0`,children:[(0,G.jsxs)(`span`,{className:`text-[11px] flex items-center gap-1`,style:{color:F?`var(--green)`:`var(--red)`},children:[(0,G.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full`,style:{background:F?`var(--green)`:`var(--red)`}}),F?`实时`:`离线`]}),(0,G.jsx)(K,{content:`从磁盘加载历史记录`,children:(0,G.jsxs)(`button`,{onClick:async()=>{M(!0),await W.reloadTraces().catch(()=>{}),await P(),M(!1)},className:`flex items-center gap-1 text-[11px] px-2 py-1 rounded border transition-colors`,style:{borderColor:`var(--border)`,color:j?`var(--blue)`:`var(--text-tertiary)`},disabled:j,children:[(0,G.jsx)(l,{size:12,style:{animation:j?`spin 1s linear infinite`:`none`}}),`加载记录`]})}),(0,G.jsxs)(`div`,{ref:A,className:`clear-split-btn`,style:{position:`relative`},children:[(0,G.jsx)(K,{content:`清空当前会话`,children:(0,G.jsxs)(`button`,{onClick:()=>{W.deleteTraces(!1).then(()=>{t([]),P()}),k(!1)},className:`clear-split-main`,children:[(0,G.jsx)(p,{size:12}),` 清空`]})}),(0,G.jsx)(`button`,{onClick:()=>k(e=>!e),className:`clear-split-arrow`,"aria-label":`更多清空选项`,children:(0,G.jsx)(o,{size:11})}),O&&(0,G.jsxs)(`div`,{className:`clear-dropdown`,children:[(0,G.jsx)(`div`,{className:`clear-dropdown-label`,children:`选择清空方式`}),(0,G.jsxs)(`button`,{className:`clear-dropdown-item`,onClick:()=>{W.deleteTraces(!1).then(()=>{t([]),P()}),k(!1)},children:[(0,G.jsx)(p,{size:12}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`div`,{className:`clear-dropdown-item-title`,children:`清空当前会话`}),(0,G.jsx)(`div`,{className:`clear-dropdown-item-desc`,children:`仅清内存,文件保留,重启可恢复`})]})]}),(0,G.jsxs)(`button`,{className:`clear-dropdown-item danger`,onClick:()=>{k(!1),b(`永久删除所有文件`,`将永久删除所有 Trace 文件,无法恢复,确认吗?`,()=>{W.deleteTraces(!0).then(()=>{t([]),P()})})},children:[(0,G.jsx)(p,{size:12}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`div`,{className:`clear-dropdown-item-title`,children:`永久删除所有文件`}),(0,G.jsx)(`div`,{className:`clear-dropdown-item-desc`,children:`删除磁盘 JSONL,重启不恢复`})]})]})]})]}),(0,G.jsx)(K,{content:S===`dark`?`浅色模式`:`深色模式`,children:(0,G.jsx)(`button`,{onClick:oe,className:`flex items-center justify-center w-7 h-7 rounded border transition-colors`,style:{borderColor:`var(--border)`,color:`var(--text-tertiary)`},children:S===`dark`?(0,G.jsx)(s,{size:13}):(0,G.jsx)(ie,{size:13})})}),(0,G.jsx)(K,{content:`Provider 与代理设置`,children:(0,G.jsxs)(`button`,{onClick:()=>g(!h),className:`flex items-center gap-1 text-[11px] px-2 py-1 rounded border transition-colors`,style:{borderColor:h?`var(--blue)`:`var(--border)`,color:h?`var(--blue)`:`var(--text-tertiary)`,background:h?`var(--blue-bg)`:`transparent`},children:[(0,G.jsx)(re,{size:12}),` 设置`]})})]})]}),(0,G.jsxs)(`div`,{className:`flex flex-1 overflow-hidden relative`,children:[h&&(0,G.jsx)(`div`,{className:`absolute inset-0 z-20 flex`,style:{background:`rgba(0,0,0,0.15)`},onClick:()=>g(!1),children:(0,G.jsx)(`div`,{className:`ml-auto h-full overflow-auto`,style:{width:`420px`,background:`var(--bg-card)`,borderLeft:`1px solid var(--border)`},onClick:e=>e.stopPropagation(),children:(0,G.jsx)(Pe,{onClose:()=>g(!1)})})}),(0,G.jsxs)(`div`,{className:`flex flex-col flex-shrink-0`,style:{width:`${C}px`,borderRight:`1px solid var(--border)`,background:`var(--bg-card)`},children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-2 border-b flex-shrink-0`,style:{borderColor:`var(--border)`},children:[(0,G.jsx)(ae,{size:13,style:{color:`var(--text-tertiary)`}}),(0,G.jsx)(`input`,{type:`text`,placeholder:`搜索消息、模型…`,value:u,onChange:e=>d(e.target.value),className:`flex-1 text-xs bg-transparent outline-none`,style:{color:`var(--text)`}}),u&&(0,G.jsx)(`button`,{onClick:()=>d(``),style:{color:`var(--text-tertiary)`},children:(0,G.jsx)(v,{size:11})}),(0,G.jsx)(`div`,{className:`flex items-center gap-1 flex-shrink-0`,children:[`all`,`error`].map(t=>(0,G.jsx)(K,{content:t===`all`?`显示全部请求`:`只看报错的请求`,placement:`bottom`,delay:400,children:(0,G.jsx)(`button`,{onClick:()=>m(t),className:`filter-chip${f===t?` active`:``}`,style:{fontSize:`10px`,padding:`2px 7px`},children:t===`all`?`全部 ${e.length}`:`✕ ${me}`})},t))})]}),(0,G.jsx)(de,{traces:pe,activeId:a,onSelect:e=>{c(e)},loading:ee,onDeleteFile:n=>{b(`删除记录文件`,`删除 ${n}?此操作不可恢复。`,async()=>{await W.deleteTraceFile(n).catch(()=>{}),t(e=>e.filter(e=>e.sourceFile!==n)),a&&e.find(e=>e.id===a)?.sourceFile===n&&c(null)})}})]}),(0,G.jsx)(`div`,{className:`resize-handle`,onMouseDown:I,style:{background:`var(--border-light)`}}),(0,G.jsx)(`div`,{className:`flex-1 overflow-auto detail-scroll`,style:{background:`var(--bg)`},children:N?(0,G.jsx)(_e,{trace:N},N.id):(0,G.jsx)(ze,{hasTraces:e.length>0})})]}),(0,G.jsx)(Fe,{open:_.open,title:_.title,message:_.message,confirmText:`确认删除`,danger:!0,onConfirm:()=>{x(),_.onConfirm()},onCancel:x})]})}function ze({hasTraces:e}){let t=window.location.port,r=t?`http://localhost:${t}`:window.location.origin;return e?(0,G.jsx)(`div`,{className:`flex items-center justify-center h-full text-sm`,style:{color:`var(--text-tertiary)`},children:`选择左侧一条请求查看详情`}):(0,G.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-5`,style:{padding:`40px`},children:[(0,G.jsx)(n,{size:28,style:{color:`var(--border)`}}),(0,G.jsxs)(`div`,{style:{textAlign:`center`},children:[(0,G.jsx)(`div`,{style:{fontSize:`15px`,fontWeight:600,color:`var(--text)`,marginBottom:`6px`},children:`等待第一条请求…`}),(0,G.jsx)(`div`,{style:{fontSize:`12px`,color:`var(--text-tertiary)`,lineHeight:1.7},children:`设置以下环境变量,所有兼容 OpenAI 接口的工具都会被自动拦截`})]}),(0,G.jsxs)(`div`,{style:{background:`var(--bg-code)`,border:`1px solid var(--border)`,borderRadius:`8px`,padding:`14px 18px`,fontFamily:`var(--mono)`,fontSize:`13px`,lineHeight:2,minWidth:`340px`},children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{style:{color:`var(--amber)`},children:`export `}),(0,G.jsx)(`span`,{style:{color:`var(--blue)`},children:`OPENAI_BASE_URL`}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`=`}),(0,G.jsxs)(`span`,{style:{color:`var(--green)`},children:[`"`,r,`/v1"`]})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{style:{color:`var(--amber)`},children:`export `}),(0,G.jsx)(`span`,{style:{color:`var(--blue)`},children:`OPENAI_API_KEY`}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`=`}),(0,G.jsx)(`span`,{style:{color:`var(--green)`},children:`"any-key"`}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`,fontStyle:`italic`,fontSize:`11px`},children:` # 代理不验证 key`})]})]}),(0,G.jsxs)(`div`,{style:{fontSize:`11px`,color:`var(--text-tertiary)`,lineHeight:1.7,textAlign:`center`,maxWidth:`320px`},children:[`上游 API 地址在 `,(0,G.jsx)(`span`,{style:{color:`var(--blue)`},children:`设置`}),` 中配置。 记录内容包括流式输出、工具调用与思考过程。`]})]})}V.createRoot(document.getElementById(`root`)).render((0,G.jsx)(B.StrictMode,{children:(0,G.jsx)(Re,{})}));