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,200 @@
1
+ // ============================================================
2
+ // SSE Stream Proxy - 流式响应透传与 Trace 记录
3
+ // ============================================================
4
+ /**
5
+ * Proxy an SSE stream from upstream to client, recording chunks for trace.
6
+ * 使用 start() 异步循环驱动,避免 pull() 回调的竞态问题。
7
+ */
8
+ export async function proxySSEStream(upstreamResponse, trace, collector, ws, requestStartTime) {
9
+ if (!upstreamResponse.body) {
10
+ throw new Error('Upstream response has no body');
11
+ }
12
+ // startTime 来自 handler,包含完整的请求发出时间,确保 TTFB 统计准确
13
+ const startTime = requestStartTime;
14
+ let ttfb = 0;
15
+ let firstChunk = true;
16
+ // Accumulate the full response from SSE chunks
17
+ let fullContent = '';
18
+ let reasoningContent = '';
19
+ const toolCallsMap = new Map();
20
+ let usage;
21
+ const reader = upstreamResponse.body.getReader();
22
+ const decoder = new TextDecoder();
23
+ // 用 start() 而不是 pull(),用一个 async 循环完整驱动读取,
24
+ // 彻底避免 pull() 竞态导致的 ERR_INVALID_STATE
25
+ const stream = new ReadableStream({
26
+ async start(controller) {
27
+ try {
28
+ while (true) {
29
+ let done;
30
+ let value;
31
+ try {
32
+ ({ done, value } = await reader.read());
33
+ }
34
+ catch (readErr) {
35
+ // 上游连接被关闭(客户端断开 / 超时)
36
+ const msg = readErr instanceof Error ? readErr.message : String(readErr);
37
+ if (!msg.includes('aborted') && !msg.includes('closed') && !msg.includes('disconnected')) {
38
+ console.error('[Stream] Reader error:', readErr);
39
+ }
40
+ break;
41
+ }
42
+ if (done)
43
+ break;
44
+ if (!value)
45
+ continue;
46
+ const chunk = decoder.decode(value, { stream: true });
47
+ // Record TTFB
48
+ if (firstChunk) {
49
+ ttfb = Date.now() - startTime;
50
+ firstChunk = false;
51
+ collector.markStreaming(trace.id);
52
+ }
53
+ // Record chunk for trace
54
+ collector.appendChunk(trace.id, chunk);
55
+ // Parse SSE data lines
56
+ const lines = chunk.split('\n');
57
+ for (const line of lines) {
58
+ if (!line.startsWith('data: '))
59
+ continue;
60
+ const data = line.slice(6).trim();
61
+ if (data === '[DONE]')
62
+ continue;
63
+ try {
64
+ const parsed = JSON.parse(data);
65
+ const delta = parsed.choices?.[0]?.delta;
66
+ if (delta) {
67
+ if (typeof delta.content === 'string')
68
+ fullContent += delta.content;
69
+ if (typeof delta.reasoning_content === 'string')
70
+ reasoningContent += delta.reasoning_content;
71
+ if (Array.isArray(delta.tool_calls)) {
72
+ for (const tc of delta.tool_calls) {
73
+ const idx = tc.index ?? 0;
74
+ if (tc.id && tc.function?.name) {
75
+ toolCallsMap.set(idx, { id: tc.id, name: tc.function.name, arguments: tc.function.arguments || '' });
76
+ }
77
+ else if (tc.function?.arguments) {
78
+ const existing = toolCallsMap.get(idx);
79
+ if (existing)
80
+ existing.arguments += tc.function.arguments;
81
+ }
82
+ }
83
+ }
84
+ }
85
+ // 提取 usage(含扩展字段)
86
+ if (parsed.usage && typeof parsed.usage === 'object') {
87
+ usage = extractUsage(parsed.usage);
88
+ }
89
+ }
90
+ catch { /* Not JSON, skip */ }
91
+ }
92
+ // Broadcast chunk
93
+ const chunkIndex = collector.get(trace.id)?.response?.chunks?.length ?? 0;
94
+ const rawChunk = {
95
+ index: Math.max(0, chunkIndex - 1),
96
+ timestamp: Date.now(),
97
+ data: chunk,
98
+ };
99
+ ws.broadcast({ type: 'trace:chunk', data: { id: trace.id, chunk: rawChunk } });
100
+ // Pass through to client
101
+ try {
102
+ controller.enqueue(value);
103
+ }
104
+ catch {
105
+ // Client disconnected — stop reading
106
+ break;
107
+ }
108
+ }
109
+ }
110
+ finally {
111
+ // 无论正常结束还是异常退出,都完成 trace 并关闭 controller
112
+ const totalDuration = Date.now() - startTime;
113
+ const toolCalls = Array.from(toolCallsMap.values());
114
+ const completeBody = buildCompleteBody(fullContent, reasoningContent, trace.model, toolCalls, usage);
115
+ collector.recordResponse(trace.id, upstreamResponse.status, Object.fromEntries(upstreamResponse.headers.entries()), completeBody);
116
+ collector.complete(trace.id, ttfb, usage);
117
+ ws.broadcast({ type: 'trace:complete', data: { id: trace.id, duration: totalDuration, usage } });
118
+ try {
119
+ controller.close();
120
+ }
121
+ catch { /* already closed */ }
122
+ reader.releaseLock();
123
+ }
124
+ },
125
+ cancel() {
126
+ reader.cancel().catch(() => { });
127
+ },
128
+ });
129
+ // Forward relevant headers from upstream
130
+ const responseHeaders = {};
131
+ for (const [k, v] of upstreamResponse.headers.entries()) {
132
+ if (['content-length', 'content-encoding', 'transfer-encoding'].includes(k.toLowerCase()))
133
+ continue;
134
+ responseHeaders[k] = v;
135
+ }
136
+ responseHeaders['content-type'] = 'text/event-stream';
137
+ responseHeaders['cache-control'] = 'no-cache';
138
+ responseHeaders['connection'] = 'keep-alive';
139
+ responseHeaders['x-accel-buffering'] = 'no';
140
+ return new Response(stream, {
141
+ status: upstreamResponse.status,
142
+ headers: responseHeaders,
143
+ });
144
+ }
145
+ /** 从 usage 对象提取全部字段(含各家扩展) */
146
+ function extractUsage(u) {
147
+ const base = {
148
+ promptTokens: u.prompt_tokens || 0,
149
+ completionTokens: u.completion_tokens || 0,
150
+ totalTokens: u.total_tokens || 0,
151
+ };
152
+ // OpenAI o1 / reasoning tokens
153
+ const compDetails = u.completion_tokens_details;
154
+ if (compDetails?.reasoning_tokens) {
155
+ base.reasoningTokens = compDetails.reasoning_tokens;
156
+ }
157
+ // OpenAI prompt cache
158
+ const promptDetails = u.prompt_tokens_details;
159
+ if (promptDetails?.cached_tokens) {
160
+ base.cachedTokens = promptDetails.cached_tokens;
161
+ }
162
+ // Anthropic cache
163
+ if (u.cache_read_input_tokens)
164
+ base.cacheReadTokens = u.cache_read_input_tokens;
165
+ if (u.cache_creation_input_tokens)
166
+ base.cacheWriteTokens = u.cache_creation_input_tokens;
167
+ // GLM/DeepSeek: completion_tokens_details.reasoning_tokens 或直接 reasoning_tokens
168
+ if (!base.reasoningTokens && u.reasoning_tokens) {
169
+ base.reasoningTokens = u.reasoning_tokens;
170
+ }
171
+ return base;
172
+ }
173
+ function buildCompleteBody(content, reasoningContent, model, toolCalls, usage) {
174
+ const message = {
175
+ role: 'assistant',
176
+ content: content || null,
177
+ };
178
+ if (reasoningContent)
179
+ message.reasoning_content = reasoningContent;
180
+ if (toolCalls.length > 0) {
181
+ message.tool_calls = toolCalls.map((tc) => ({
182
+ id: tc.id,
183
+ type: 'function',
184
+ function: { name: tc.name, arguments: tc.arguments },
185
+ }));
186
+ }
187
+ return {
188
+ id: `chatcmpl-${Date.now()}`,
189
+ object: 'chat.completion',
190
+ created: Math.floor(Date.now() / 1000),
191
+ model,
192
+ choices: [{ index: 0, message, finish_reason: toolCalls.length > 0 ? 'tool_calls' : 'stop' }],
193
+ usage: usage ? {
194
+ prompt_tokens: usage.promptTokens,
195
+ completion_tokens: usage.completionTokens,
196
+ total_tokens: usage.totalTokens,
197
+ } : undefined,
198
+ };
199
+ }
200
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../../src/server/proxy/stream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Context, Next } from 'hono';
2
+ /**
3
+ * Serve static files from a directory, with SPA fallback to index.html
4
+ */
5
+ export declare function serveStaticFiles(staticDir: string): (c: Context, next: Next) => Promise<void | Response>;
6
+ //# sourceMappingURL=static.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/server/static.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAmB1C;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,IAClC,GAAG,OAAO,EAAE,MAAM,IAAI,8BAqCrC"}
@@ -0,0 +1,58 @@
1
+ // ============================================================
2
+ // Static file serving middleware for Hono (Node.js)
3
+ // ============================================================
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ const MIME_TYPES = {
7
+ '.html': 'text/html',
8
+ '.js': 'application/javascript',
9
+ '.mjs': 'application/javascript',
10
+ '.css': 'text/css',
11
+ '.json': 'application/json',
12
+ '.png': 'image/png',
13
+ '.jpg': 'image/jpeg',
14
+ '.gif': 'image/gif',
15
+ '.svg': 'image/svg+xml',
16
+ '.ico': 'image/x-icon',
17
+ '.woff': 'font/woff',
18
+ '.woff2': 'font/woff2',
19
+ '.ttf': 'font/ttf',
20
+ '.webmanifest': 'application/manifest+json',
21
+ };
22
+ /**
23
+ * Serve static files from a directory, with SPA fallback to index.html
24
+ */
25
+ export function serveStaticFiles(staticDir) {
26
+ return async (c, next) => {
27
+ const urlPath = c.req.path;
28
+ // Skip API and proxy paths
29
+ if (urlPath.startsWith('/api') || urlPath.startsWith('/v1') || urlPath.startsWith('/ws')) {
30
+ return next();
31
+ }
32
+ // Try to serve the exact file
33
+ const filePath = path.join(staticDir, urlPath);
34
+ // Security: prevent path traversal — ensure resolved path stays within staticDir
35
+ const resolvedStatic = path.resolve(staticDir);
36
+ const resolvedFile = path.resolve(filePath);
37
+ if (resolvedFile.startsWith(resolvedStatic + path.sep) &&
38
+ fs.existsSync(resolvedFile) &&
39
+ fs.statSync(resolvedFile).isFile()) {
40
+ const ext = path.extname(filePath);
41
+ const mimeType = MIME_TYPES[ext] || 'application/octet-stream';
42
+ const content = fs.readFileSync(resolvedFile);
43
+ return new Response(content, {
44
+ headers: { 'Content-Type': mimeType },
45
+ });
46
+ }
47
+ // SPA fallback: serve index.html for any path that doesn't match a file
48
+ const indexHtml = path.join(staticDir, 'index.html');
49
+ if (fs.existsSync(indexHtml)) {
50
+ const content = fs.readFileSync(indexHtml);
51
+ return new Response(content, {
52
+ headers: { 'Content-Type': 'text/html' },
53
+ });
54
+ }
55
+ return next();
56
+ };
57
+ }
58
+ //# sourceMappingURL=static.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static.js","sourceRoot":"","sources":["../../src/server/static.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,oDAAoD;AACpD,+DAA+D;AAE/D,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,UAAU,GAA2B;IACzC,OAAO,EAAE,WAAW;IACpB,KAAK,EAAE,wBAAwB;IAC/B,MAAM,EAAE,wBAAwB;IAChC,MAAM,EAAE,UAAU;IAClB,OAAO,EAAE,kBAAkB;IAC3B,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,WAAW;IACpB,QAAQ,EAAE,YAAY;IACtB,MAAM,EAAE,UAAU;IAClB,cAAc,EAAE,2BAA2B;CAC5C,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,OAAO,KAAK,EAAE,CAAU,EAAE,IAAU,EAAE,EAAE;QACtC,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;QAE3B,2BAA2B;QAC3B,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACzF,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,8BAA8B;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC/C,iFAAiF;QACjF,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC5C,IACE,YAAY,CAAC,UAAU,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC;YAClD,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;YAC3B,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,EAClC,CAAC;YACD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAC;YAC/D,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;YAC9C,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE;gBAC3B,OAAO,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE;aACtC,CAAC,CAAC;QACL,CAAC;QAED,wEAAwE;QACxE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACrD,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YAC3C,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE;gBAC3B,OAAO,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE;aACzC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,59 @@
1
+ import type { TraceRecord, TraceStatus, TokenUsage } from '../types.js';
2
+ import { TraceWriter } from './writer.js';
3
+ export declare class TraceCollector {
4
+ private traces;
5
+ private writer;
6
+ private maxInMemory;
7
+ private onNewTrace?;
8
+ private onUpdateTrace?;
9
+ private pendingBroadcast;
10
+ constructor(traceDir: string, maxFileSize: number, maxInMemory: number);
11
+ /** 从 JSONL 文件加载历史记录(手动触发) */
12
+ loadFromDisk(): number;
13
+ /** 删除指定文件并清除其在内存中的记录 */
14
+ deleteFile(fileName: string): boolean;
15
+ /** Set callbacks for WebSocket broadcasting */
16
+ setCallbacks(onNew: (trace: TraceRecord) => void, onUpdate: (trace: Partial<TraceRecord> & {
17
+ id: string;
18
+ }) => void): void;
19
+ /** Create a new trace from an incoming request */
20
+ create(method: string, path: string, headers: Record<string, string>, body: Record<string, unknown>): TraceRecord;
21
+ /** Update trace with provider info */
22
+ setProvider(id: string, providerName: string): void;
23
+ /** Mark trace as streaming - 流式模式立即广播 trace:new */
24
+ markStreaming(id: string): void;
25
+ /** Record a streaming chunk */
26
+ appendChunk(id: string, chunkData: string): void;
27
+ /** Record response for non-streaming request */
28
+ recordResponse(id: string, status: number, headers: Record<string, string>, body: unknown): void;
29
+ /** Complete a trace with timing and usage */
30
+ complete(id: string, ttfb?: number, usage?: TokenUsage): void;
31
+ /** Mark a trace as error */
32
+ markError(id: string, code: string, message: string): void;
33
+ /**
34
+ * Enforce in-memory limit by evicting the oldest traces.
35
+ * C02: O(n) via Map insertion order (oldest first) instead of O(n log n) sort.
36
+ */
37
+ private enforceMemoryLimit;
38
+ /** Get a single trace by ID */
39
+ get(id: string): TraceRecord | undefined;
40
+ /** Get all in-memory traces as array, sorted by timestamp desc */
41
+ getAll(): TraceRecord[];
42
+ /** Search traces with filters */
43
+ search(filters: {
44
+ model?: string;
45
+ provider?: string;
46
+ status?: TraceStatus;
47
+ keyword?: string;
48
+ limit?: number;
49
+ offset?: number;
50
+ }): {
51
+ traces: TraceRecord[];
52
+ total: number;
53
+ };
54
+ /** Clear all in-memory traces */
55
+ clear(): void;
56
+ /** Get trace writer for direct file operations */
57
+ getWriter(): TraceWriter;
58
+ }
59
+ //# sourceMappingURL=collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../../src/server/trace/collector.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAA4C,MAAM,aAAa,CAAC;AAElH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAAC,CAA+B;IAClD,OAAO,CAAC,aAAa,CAAC,CAAyD;IAE/E,OAAO,CAAC,gBAAgB,CAA0B;gBAEtC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAKtE,6BAA6B;IAC7B,YAAY,IAAI,MAAM;IAgCtB,wBAAwB;IACxB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAYrC,+CAA+C;IAC/C,YAAY,CACV,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,EACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAC/D,IAAI;IAKP,kDAAkD;IAClD,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,WAAW;IAmCd,sCAAsC;IACtC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAMnD,mDAAmD;IACnD,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAa/B,+BAA+B;IAC/B,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAehD,gDAAgD;IAChD,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IA8BhG,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI;IAqB7D,4BAA4B;IAC5B,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAkB1D;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAU1B,+BAA+B;IAC/B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIxC,kEAAkE;IAClE,MAAM,IAAI,WAAW,EAAE;IAKvB,iCAAiC;IACjC,MAAM,CAAC,OAAO,EAAE;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG;QAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAqC5C,iCAAiC;IACjC,KAAK,IAAI,IAAI;IAIb,kDAAkD;IAClD,SAAS,IAAI,WAAW;CAGzB"}
@@ -0,0 +1,278 @@
1
+ // ============================================================
2
+ // Trace Collector - 创建/更新/完成 Trace,维护内存缓存
3
+ // ============================================================
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import { sanitizeHeaders } from './sanitizer.js';
6
+ import { TraceWriter } from './writer.js';
7
+ import path from 'node:path';
8
+ export class TraceCollector {
9
+ traces = new Map();
10
+ writer;
11
+ maxInMemory;
12
+ onNewTrace;
13
+ onUpdateTrace;
14
+ // 非流模式:延迟到 complete/markError 时才广播 trace:new
15
+ pendingBroadcast = new Set();
16
+ constructor(traceDir, maxFileSize, maxInMemory) {
17
+ this.writer = new TraceWriter(traceDir, maxFileSize);
18
+ this.maxInMemory = maxInMemory;
19
+ }
20
+ /** 从 JSONL 文件加载历史记录(手动触发) */
21
+ loadFromDisk() {
22
+ const files = this.writer.getTraceFiles();
23
+ if (files.length === 0)
24
+ return 0;
25
+ const allTraces = [];
26
+ // 从最新的文件往前读,凑够 maxInMemory 条
27
+ for (let i = files.length - 1; i >= 0 && allTraces.length < this.maxInMemory; i--) {
28
+ const need = this.maxInMemory - allTraces.length;
29
+ const records = this.writer.readTracesFromFile(files[i], need);
30
+ const fileName = path.basename(files[i]);
31
+ for (const r of records)
32
+ r.sourceFile = fileName;
33
+ allTraces.unshift(...records);
34
+ }
35
+ // 按时间正序插入 Map(保证 getAll 倒序正确)
36
+ const sorted = allTraces
37
+ .slice(-this.maxInMemory)
38
+ .sort((a, b) => a.timestamp.localeCompare(b.timestamp));
39
+ for (const trace of sorted) {
40
+ // 历史记录中未完成的重置为 error(进程已退出,不可能再完成)
41
+ if (trace.status === 'pending' || trace.status === 'streaming') {
42
+ trace.status = 'error';
43
+ if (!trace.error)
44
+ trace.error = { code: 'INTERRUPTED', message: '服务重启,请求中断' };
45
+ }
46
+ this.traces.set(trace.id, trace);
47
+ }
48
+ console.log(`📂 已加载历史记录:${sorted.length} 条(来自 ${files.length} 个文件)`);
49
+ return sorted.length;
50
+ }
51
+ /** 删除指定文件并清除其在内存中的记录 */
52
+ deleteFile(fileName) {
53
+ const files = this.writer.getTraceFiles();
54
+ const target = files.find(f => path.basename(f) === fileName);
55
+ if (!target)
56
+ return false;
57
+ // 清除该文件中的内存记录
58
+ for (const [id, trace] of this.traces.entries()) {
59
+ if (trace.sourceFile === fileName)
60
+ this.traces.delete(id);
61
+ }
62
+ this.writer.deleteFile(target);
63
+ return true;
64
+ }
65
+ /** Set callbacks for WebSocket broadcasting */
66
+ setCallbacks(onNew, onUpdate) {
67
+ this.onNewTrace = onNew;
68
+ this.onUpdateTrace = onUpdate;
69
+ }
70
+ /** Create a new trace from an incoming request */
71
+ create(method, path, headers, body) {
72
+ const id = uuidv4();
73
+ const trace = {
74
+ id,
75
+ timestamp: new Date().toISOString(),
76
+ provider: '',
77
+ model: body.model || '',
78
+ status: 'pending',
79
+ duration: 0,
80
+ ttfb: 0,
81
+ request: {
82
+ method,
83
+ path,
84
+ headers: sanitizeHeaders(headers),
85
+ body: {
86
+ ...body,
87
+ model: body.model || '',
88
+ },
89
+ },
90
+ response: {
91
+ status: 0,
92
+ headers: {},
93
+ body: null,
94
+ },
95
+ };
96
+ this.traces.set(id, trace);
97
+ this.enforceMemoryLimit();
98
+ // 非流模式延迟广播,markStreaming/complete/markError 时再决定
99
+ this.pendingBroadcast.add(id);
100
+ return trace;
101
+ }
102
+ /** Update trace with provider info */
103
+ setProvider(id, providerName) {
104
+ const trace = this.traces.get(id);
105
+ if (!trace)
106
+ return;
107
+ trace.provider = providerName;
108
+ }
109
+ /** Mark trace as streaming - 流式模式立即广播 trace:new */
110
+ markStreaming(id) {
111
+ const trace = this.traces.get(id);
112
+ if (!trace)
113
+ return;
114
+ trace.status = 'streaming';
115
+ // 流式:立即广播,后续 update 追加 chunks
116
+ if (this.pendingBroadcast.has(id)) {
117
+ this.pendingBroadcast.delete(id);
118
+ this.onNewTrace?.(trace);
119
+ }
120
+ else {
121
+ this.onUpdateTrace?.({ id, status: 'streaming' });
122
+ }
123
+ }
124
+ /** Record a streaming chunk */
125
+ appendChunk(id, chunkData) {
126
+ const trace = this.traces.get(id);
127
+ if (!trace)
128
+ return;
129
+ if (!trace.response.chunks) {
130
+ trace.response.chunks = [];
131
+ }
132
+ trace.response.chunks.push({
133
+ index: trace.response.chunks.length,
134
+ timestamp: Date.now(),
135
+ data: chunkData,
136
+ });
137
+ }
138
+ /** Record response for non-streaming request */
139
+ recordResponse(id, status, headers, body) {
140
+ const trace = this.traces.get(id);
141
+ if (!trace)
142
+ return;
143
+ trace.response = {
144
+ status,
145
+ headers: sanitizeHeaders(headers),
146
+ body,
147
+ chunks: trace.response.chunks, // preserve accumulated chunks
148
+ };
149
+ // Extract tool calls from response body
150
+ if (body && typeof body === 'object') {
151
+ const respObj = body;
152
+ if (respObj.choices && Array.isArray(respObj.choices)) {
153
+ const choice = respObj.choices[0];
154
+ const message = choice?.message;
155
+ if (message?.tool_calls && Array.isArray(message.tool_calls)) {
156
+ trace.toolCalls = message.tool_calls.map((tc) => ({
157
+ id: tc.id,
158
+ name: tc.function.name,
159
+ arguments: (() => {
160
+ try {
161
+ return JSON.parse(tc.function.arguments);
162
+ }
163
+ catch {
164
+ return tc.function.arguments;
165
+ }
166
+ })(),
167
+ }));
168
+ }
169
+ }
170
+ }
171
+ }
172
+ /** Complete a trace with timing and usage */
173
+ complete(id, ttfb, usage) {
174
+ const trace = this.traces.get(id);
175
+ if (!trace)
176
+ return;
177
+ trace.status = 'completed';
178
+ // B03: Use Date object arithmetic, not string comparison
179
+ trace.duration = Date.now() - new Date(trace.timestamp).getTime();
180
+ if (ttfb != null)
181
+ trace.ttfb = ttfb;
182
+ if (usage)
183
+ trace.usage = usage;
184
+ // Persist to JSONL
185
+ this.writer.write(trace);
186
+ // 非流模式:第一次广播带完整 trace;流式模式:发 update
187
+ if (this.pendingBroadcast.has(id)) {
188
+ this.pendingBroadcast.delete(id);
189
+ this.onNewTrace?.(trace);
190
+ }
191
+ else {
192
+ this.onUpdateTrace?.({ id, status: 'completed', duration: trace.duration, ttfb: trace.ttfb, usage, response: trace.response });
193
+ }
194
+ }
195
+ /** Mark a trace as error */
196
+ markError(id, code, message) {
197
+ const trace = this.traces.get(id);
198
+ if (!trace)
199
+ return;
200
+ trace.status = 'error';
201
+ trace.duration = Date.now() - new Date(trace.timestamp).getTime();
202
+ trace.error = { code, message };
203
+ // Persist even errors
204
+ this.writer.write(trace);
205
+ if (this.pendingBroadcast.has(id)) {
206
+ this.pendingBroadcast.delete(id);
207
+ this.onNewTrace?.(trace);
208
+ }
209
+ else {
210
+ this.onUpdateTrace?.({ id, status: 'error', error: trace.error });
211
+ }
212
+ }
213
+ /**
214
+ * Enforce in-memory limit by evicting the oldest traces.
215
+ * C02: O(n) via Map insertion order (oldest first) instead of O(n log n) sort.
216
+ */
217
+ enforceMemoryLimit() {
218
+ if (this.traces.size <= this.maxInMemory)
219
+ return;
220
+ const toRemove = this.traces.size - this.maxInMemory;
221
+ let removed = 0;
222
+ for (const key of this.traces.keys()) {
223
+ this.traces.delete(key);
224
+ if (++removed >= toRemove)
225
+ break;
226
+ }
227
+ }
228
+ /** Get a single trace by ID */
229
+ get(id) {
230
+ return this.traces.get(id);
231
+ }
232
+ /** Get all in-memory traces as array, sorted by timestamp desc */
233
+ getAll() {
234
+ return Array.from(this.traces.values())
235
+ .sort((a, b) => b.timestamp.localeCompare(a.timestamp));
236
+ }
237
+ /** Search traces with filters */
238
+ search(filters) {
239
+ let traces = this.getAll();
240
+ if (filters.model) {
241
+ traces = traces.filter((t) => t.model === filters.model);
242
+ }
243
+ if (filters.provider) {
244
+ traces = traces.filter((t) => t.provider === filters.provider);
245
+ }
246
+ if (filters.status) {
247
+ traces = traces.filter((t) => t.status === filters.status);
248
+ }
249
+ if (filters.keyword) {
250
+ const kw = filters.keyword.toLowerCase();
251
+ traces = traces.filter((t) => {
252
+ const msgs = t.request.body.messages;
253
+ if (msgs) {
254
+ return msgs.some((m) => typeof m.content === 'string' && m.content.toLowerCase().includes(kw));
255
+ }
256
+ // Also check prompt field
257
+ if (typeof t.request.body.prompt === 'string') {
258
+ return t.request.body.prompt.toLowerCase().includes(kw);
259
+ }
260
+ return false;
261
+ });
262
+ }
263
+ const total = traces.length;
264
+ const offset = filters.offset || 0;
265
+ const limit = filters.limit || 50;
266
+ traces = traces.slice(offset, offset + limit);
267
+ return { traces, total };
268
+ }
269
+ /** Clear all in-memory traces */
270
+ clear() {
271
+ this.traces.clear();
272
+ }
273
+ /** Get trace writer for direct file operations */
274
+ getWriter() {
275
+ return this.writer;
276
+ }
277
+ }
278
+ //# sourceMappingURL=collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector.js","sourceRoot":"","sources":["../../../src/server/trace/collector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Sanitize headers - mask sensitive values
3
+ */
4
+ export declare function sanitizeHeaders(headers: Record<string, string>): Record<string, string>;
5
+ //# sourceMappingURL=sanitizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitizer.d.ts","sourceRoot":"","sources":["../../../src/server/trace/sanitizer.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBvF"}