llm-simple-router 0.6.7 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/constants.d.ts +1 -1
- package/dist/admin/constants.js +2 -2
- package/dist/admin/logs.d.ts +2 -0
- package/dist/admin/logs.js +17 -1
- package/dist/admin/providers.d.ts +2 -2
- package/dist/admin/providers.js +29 -16
- package/dist/admin/proxy-enhancement.d.ts +2 -0
- package/dist/admin/proxy-enhancement.js +4 -10
- package/dist/admin/retry-rules.d.ts +2 -2
- package/dist/admin/retry-rules.js +4 -8
- package/dist/admin/routes.d.ts +4 -4
- package/dist/admin/routes.js +6 -6
- package/dist/admin/settings-import-export.d.ts +2 -4
- package/dist/admin/settings-import-export.js +9 -19
- package/dist/admin/settings.d.ts +1 -0
- package/dist/admin/settings.js +29 -1
- package/dist/admin/upgrade.js +1 -1
- package/dist/{constants.d.ts → core/constants.d.ts} +4 -1
- package/dist/{constants.js → core/constants.js} +21 -1
- package/dist/core/container.d.ts +31 -0
- package/dist/core/container.js +41 -0
- package/dist/core/errors.d.ts +26 -0
- package/dist/core/errors.js +42 -0
- package/dist/core/registry.d.ts +43 -0
- package/dist/core/registry.js +3 -0
- package/dist/core/types.d.ts +105 -0
- package/dist/core/types.js +3 -0
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/logs.d.ts +11 -24
- package/dist/db/logs.js +37 -38
- package/dist/db/metrics.js +1 -1
- package/dist/db/migrations/033_add_pipeline_snapshot.sql +1 -0
- package/dist/db/migrations/034_drop_redundant_log_columns.sql +13 -0
- package/dist/db/settings.d.ts +2 -0
- package/dist/db/settings.js +9 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.js +191 -108
- package/dist/metrics/metrics-extractor.d.ts +1 -24
- package/dist/metrics/metrics-extractor.js +1 -1
- package/dist/metrics/sse-metrics-transform.d.ts +1 -1
- package/dist/middleware/admin-auth.js +4 -0
- package/dist/middleware/auth.js +1 -2
- package/dist/monitor/request-tracker.d.ts +3 -4
- package/dist/monitor/request-tracker.js +6 -16
- package/dist/monitor/runtime-collector.js +1 -1
- package/dist/monitor/types.d.ts +8 -0
- package/dist/proxy/adaptive-controller.d.ts +4 -1
- package/dist/proxy/adaptive-controller.js +5 -0
- package/dist/proxy/enhancement/enhancement-handler.d.ts +19 -3
- package/dist/proxy/enhancement/enhancement-handler.js +80 -28
- package/dist/proxy/enhancement/index.d.ts +1 -0
- package/dist/proxy/handler/anthropic.d.ts +7 -0
- package/dist/proxy/{anthropic.js → handler/anthropic.js} +8 -7
- package/dist/proxy/handler/openai.d.ts +7 -0
- package/dist/proxy/{openai.js → handler/openai.js} +10 -9
- package/dist/proxy/handler/proxy-handler-utils.d.ts +9 -0
- package/dist/proxy/handler/proxy-handler-utils.js +63 -0
- package/dist/proxy/handler/proxy-handler.d.ts +13 -0
- package/dist/proxy/{proxy-handler.js → handler/proxy-handler.js} +104 -120
- package/dist/proxy/log-detail-policy.d.ts +12 -0
- package/dist/proxy/log-detail-policy.js +21 -0
- package/dist/proxy/log-helpers.d.ts +8 -0
- package/dist/proxy/log-helpers.js +16 -4
- package/dist/proxy/loop-prevention/tool-loop-guard.d.ts +1 -1
- package/dist/proxy/loop-prevention/tool-loop-guard.js +9 -12
- package/dist/proxy/{orchestrator.d.ts → orchestration/orchestrator.d.ts} +6 -4
- package/dist/proxy/{orchestrator.js → orchestration/orchestrator.js} +2 -1
- package/dist/proxy/{resilience.d.ts → orchestration/resilience.d.ts} +2 -14
- package/dist/proxy/{resilience.js → orchestration/resilience.js} +2 -2
- package/dist/proxy/{retry-rules.d.ts → orchestration/retry-rules.d.ts} +1 -1
- package/dist/proxy/{retry-rules.js → orchestration/retry-rules.js} +1 -1
- package/dist/proxy/{scope.d.ts → orchestration/scope.d.ts} +3 -3
- package/dist/proxy/{semaphore.d.ts → orchestration/semaphore.d.ts} +7 -15
- package/dist/proxy/{semaphore.js → orchestration/semaphore.js} +12 -26
- package/dist/proxy/patch/index.d.ts +8 -2
- package/dist/proxy/patch/index.js +5 -2
- package/dist/proxy/pipeline-snapshot.d.ts +37 -0
- package/dist/proxy/pipeline-snapshot.js +15 -0
- package/dist/proxy/proxy-core.d.ts +1 -1
- package/dist/proxy/proxy-core.js +1 -1
- package/dist/proxy/proxy-logging.d.ts +10 -2
- package/dist/proxy/proxy-logging.js +23 -9
- package/dist/proxy/response-transform.d.ts +7 -0
- package/dist/proxy/response-transform.js +15 -0
- package/dist/proxy/{enhancement-config.js → routing/enhancement-config.js} +1 -1
- package/dist/proxy/{mapping-resolver.d.ts → routing/mapping-resolver.d.ts} +1 -1
- package/dist/proxy/{mapping-resolver.js → routing/mapping-resolver.js} +1 -1
- package/dist/proxy/{model-state.js → routing/model-state.js} +1 -1
- package/dist/proxy/{overflow.d.ts → routing/overflow.d.ts} +1 -1
- package/dist/proxy/{overflow.js → routing/overflow.js} +3 -3
- package/dist/proxy/{usage-window-tracker.js → routing/usage-window-tracker.js} +3 -3
- package/dist/proxy/{transport.d.ts → transport/http.d.ts} +2 -2
- package/dist/proxy/{transport.js → transport/http.js} +3 -3
- package/dist/proxy/{stream-proxy.d.ts → transport/stream.d.ts} +4 -4
- package/dist/proxy/{stream-proxy.js → transport/stream.js} +25 -7
- package/dist/proxy/{transport-fn.d.ts → transport/transport-fn.d.ts} +5 -5
- package/dist/proxy/{transport-fn.js → transport/transport-fn.js} +11 -9
- package/dist/proxy/types.d.ts +3 -64
- package/dist/proxy/types.js +5 -34
- package/dist/storage/log-file-compressor.d.ts +15 -0
- package/dist/storage/log-file-compressor.js +83 -0
- package/dist/storage/log-file-writer.d.ts +21 -0
- package/dist/storage/log-file-writer.js +103 -0
- package/dist/storage/types.d.ts +16 -0
- package/dist/storage/types.js +5 -0
- package/frontend-dist/assets/{CardContent-jQcfCC7J.js → CardContent-B_EIvwon.js} +1 -1
- package/frontend-dist/assets/{CardTitle-BrCTvULL.js → CardTitle-DHU-obrV.js} +1 -1
- package/frontend-dist/assets/{CascadingModelSelect-BFh67j5d.js → CascadingModelSelect-BFbt3-xP.js} +1 -1
- package/frontend-dist/assets/{Checkbox-Bbt7JpdE.js → Checkbox-CNGgDj55.js} +1 -1
- package/frontend-dist/assets/{CollapsibleTrigger-DMnEA0qC.js → CollapsibleTrigger-BIBFqVyy.js} +1 -1
- package/frontend-dist/assets/{Collection-CVk3TPHc.js → Collection-CYT_tSZn.js} +1 -1
- package/frontend-dist/assets/{Dashboard-Coftbg4B.js → Dashboard-DHzoPggK.js} +1 -1
- package/frontend-dist/assets/{DialogTitle-BbOAZzPQ.js → DialogTitle-C1gk4GN_.js} +1 -1
- package/frontend-dist/assets/{Input-DdHY9q0w.js → Input-CXpbIxXJ.js} +1 -1
- package/frontend-dist/assets/{Label-DRQv_Dr_.js → Label-BbOaRyGK.js} +1 -1
- package/frontend-dist/assets/{Login-SV3ctFnJ.js → Login-Cc2ocWjt.js} +1 -1
- package/frontend-dist/assets/{Logs-BG45kX6E.js → Logs-DMMr-_-8.js} +1 -1
- package/frontend-dist/assets/{ModelMappings-DEaBnRU3.js → ModelMappings-Cg8svYGw.js} +1 -1
- package/frontend-dist/assets/{Monitor-ZHOt11n-.js → Monitor-ps-VVzq3.js} +1 -1
- package/frontend-dist/assets/{PopoverTrigger-z-Z3EjBk.js → PopoverTrigger-BA1XOIO0.js} +1 -1
- package/frontend-dist/assets/{PopperContent-DPC-6a3n.js → PopperContent--3HCLUEp.js} +1 -1
- package/frontend-dist/assets/{Providers-DpY6pAcg.js → Providers-Bjhhw2O4.js} +1 -1
- package/frontend-dist/assets/{ProxyEnhancement-D6KBDXMp.js → ProxyEnhancement-BhlZ3pYo.js} +1 -1
- package/frontend-dist/assets/{RetryRules-DWI7_WLZ.js → RetryRules-BxCAMxNM.js} +1 -1
- package/frontend-dist/assets/{RouterKeys-CZ1657eX.js → RouterKeys-N-5AHCZf.js} +1 -1
- package/frontend-dist/assets/{RovingFocusItem-BREE2YEV.js → RovingFocusItem-BXHXOE-y.js} +1 -1
- package/frontend-dist/assets/{Schedules-BVPsBRPi.js → Schedules-oxUdLakf.js} +1 -1
- package/frontend-dist/assets/{SelectValue-H8hwQwbk.js → SelectValue-RQZKO7OV.js} +1 -1
- package/frontend-dist/assets/Settings-BlIRQ9y-.js +6 -0
- package/frontend-dist/assets/{Setup-yOYNKkOG.js → Setup-CmpQtMiu.js} +1 -1
- package/frontend-dist/assets/{Switch-CojD3rTH.js → Switch-B3sVDDC7.js} +1 -1
- package/frontend-dist/assets/{TableHeader-awoHTsWN.js → TableHeader-Bpen86Ix.js} +1 -1
- package/frontend-dist/assets/{TabsTrigger-DTKSFj85.js → TabsTrigger-VNURbZR2.js} +1 -1
- package/frontend-dist/assets/{Teleport-DehYAXud.js → Teleport-CsHgwC1b.js} +1 -1
- package/frontend-dist/assets/{TooltipTrigger-C2dl_dml.js → TooltipTrigger-BHwxX9h-.js} +1 -1
- package/frontend-dist/assets/{UnifiedRequestDialog-C8A-uSTR.js → UnifiedRequestDialog-3rdh4fhf.js} +2 -2
- package/frontend-dist/assets/{VisuallyHidden-C8oaGi2S.js → VisuallyHidden-DCZ9DkoD.js} +1 -1
- package/frontend-dist/assets/{VisuallyHiddenInput-BMc813t2.js → VisuallyHiddenInput-BxgnyBWj.js} +1 -1
- package/frontend-dist/assets/{alert-dialog-C8TZQmU6.js → alert-dialog-LaLkz7c6.js} +1 -1
- package/frontend-dist/assets/arrow-down-BpGORRs9.js +1 -0
- package/frontend-dist/assets/{badge-BVh2WpA5.js → badge-BYEw6ni_.js} +1 -1
- package/frontend-dist/assets/{button-N59D1BGa.js → button-C5VcfpgV.js} +2 -2
- package/frontend-dist/assets/check-Bqx_fTQX.js +1 -0
- package/frontend-dist/assets/{copy-DTOecxa9.js → copy-CmWRpuG-.js} +1 -1
- package/frontend-dist/assets/{dialog-kA7AUNoc.js → dialog-BEKceMtO.js} +1 -1
- package/frontend-dist/assets/{file-text-DzZCFO7y.js → file-text-C_jIlYPS.js} +1 -1
- package/frontend-dist/assets/{index-DVTeNVaa.js → index-C2aljBfM.js} +1 -1
- package/frontend-dist/assets/{lib-ClDokUbt.js → lib-Cj3cGvin.js} +1 -1
- package/frontend-dist/assets/loader-circle-BLhRyZzy.js +1 -0
- package/frontend-dist/assets/{useClipboard-DU1ne-Jw.js → useClipboard-ZCpnVKiU.js} +1 -1
- package/frontend-dist/assets/{useFocusGuards-Btmdbg_F.js → useFocusGuards-BjqTo_uk.js} +1 -1
- package/frontend-dist/assets/useFormControl-D7vjbPSC.js +1 -0
- package/frontend-dist/assets/{useLogRetention--EGNWXig.js → useLogRetention-BZZvG6jh.js} +1 -1
- package/frontend-dist/assets/useNonce-BuusARRu.js +1 -0
- package/frontend-dist/assets/x-CUQFnWz8.js +1 -0
- package/frontend-dist/index.html +19 -19
- package/package.json +1 -1
- package/dist/proxy/anthropic.d.ts +0 -19
- package/dist/proxy/openai.d.ts +0 -19
- package/dist/proxy/proxy-handler.d.ts +0 -19
- package/dist/proxy/strategy/types.d.ts +0 -21
- package/dist/proxy/strategy/types.js +0 -1
- package/frontend-dist/assets/Settings-DHYaYRgU.js +0 -6
- package/frontend-dist/assets/arrow-down-D-cQXxau.js +0 -1
- package/frontend-dist/assets/check-dDgrw3T3.js +0 -1
- package/frontend-dist/assets/loader-circle-DVHRL-38.js +0 -1
- package/frontend-dist/assets/useFormControl-C5Kjziuj.js +0 -1
- package/frontend-dist/assets/useNonce-Cp31yRzV.js +0 -1
- package/frontend-dist/assets/x-DMktsI_w.js +0 -1
- /package/dist/{config.d.ts → config/index.d.ts} +0 -0
- /package/dist/{config.js → config/index.js} +0 -0
- /package/dist/proxy/{scope.js → orchestration/scope.js} +0 -0
- /package/dist/proxy/{enhancement-config.d.ts → routing/enhancement-config.d.ts} +0 -0
- /package/dist/proxy/{model-state.d.ts → routing/model-state.d.ts} +0 -0
- /package/dist/proxy/{usage-window-tracker.d.ts → routing/usage-window-tracker.d.ts} +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ConcurrencyConfig } from "./types.js";
|
|
2
|
+
export type { ConcurrencyConfig };
|
|
3
|
+
export interface EnhancementConfig {
|
|
4
|
+
claude_code_enabled: boolean;
|
|
5
|
+
tool_call_loop_enabled: boolean;
|
|
6
|
+
stream_loop_enabled: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Provider 自适应/手动并发配置(DB 字段) */
|
|
9
|
+
export interface ProviderConcurrencyParams {
|
|
10
|
+
adaptive_enabled: number;
|
|
11
|
+
max_concurrency: number;
|
|
12
|
+
queue_timeout_ms: number;
|
|
13
|
+
max_queue_size: number;
|
|
14
|
+
}
|
|
15
|
+
export interface StateRegistry {
|
|
16
|
+
/** 刷新重试规则缓存(RetryRuleMatcher.load) */
|
|
17
|
+
refreshRetryRules(): void;
|
|
18
|
+
/** 更新 provider 并发配置(ProviderSemaphoreManager.updateConfig) */
|
|
19
|
+
updateProviderConcurrency(providerId: string, config: ConcurrencyConfig): void;
|
|
20
|
+
/** 移除 provider 的信号量(ProviderSemaphoreManager.remove) */
|
|
21
|
+
removeProvider(providerId: string): void;
|
|
22
|
+
/** 移除所有信号量配置(ProviderSemaphoreManager.removeAll) */
|
|
23
|
+
removeAllProviders(): void;
|
|
24
|
+
/** 获取 provider 并发状态(ProviderSemaphoreManager.getStatus) */
|
|
25
|
+
getProviderStatus(providerId: string): {
|
|
26
|
+
active: number;
|
|
27
|
+
queued: number;
|
|
28
|
+
};
|
|
29
|
+
/** 清空所有会话模型状态(modelState.clearAll) */
|
|
30
|
+
clearModelState(): void;
|
|
31
|
+
/** 删除指定会话模型状态(modelState.delete) */
|
|
32
|
+
deleteModelState(keyId: string, sessionId: string): void;
|
|
33
|
+
/** 读取 proxy enhancement 配置 */
|
|
34
|
+
getEnhancementConfig(): EnhancementConfig;
|
|
35
|
+
/** 同步 provider 的自适应并发配置(AdaptiveConcurrencyController.syncProvider) */
|
|
36
|
+
syncAdaptiveProvider(providerId: string, params: ProviderConcurrencyParams): void;
|
|
37
|
+
/** 移除 provider 的自适应并发状态(AdaptiveConcurrencyController.remove) */
|
|
38
|
+
removeAdaptiveProvider(providerId: string): void;
|
|
39
|
+
/** 获取 provider 的自适应并发状态 */
|
|
40
|
+
getAdaptiveStatus(providerId: string): import("../proxy/adaptive-controller.js").AdaptiveState | undefined;
|
|
41
|
+
/** 从 DB 重新读取所有 provider 配置,重建信号量/adaptive/tracker 缓存(导入配置后调用) */
|
|
42
|
+
reinitializeProviders(): void;
|
|
43
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export interface Target {
|
|
2
|
+
backend_model: string;
|
|
3
|
+
provider_id: string;
|
|
4
|
+
overflow_provider_id?: string;
|
|
5
|
+
overflow_model?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ResolveContext {
|
|
8
|
+
now: Date;
|
|
9
|
+
excludeTargets?: Target[];
|
|
10
|
+
}
|
|
11
|
+
/** Provider 级并发控制配置(唯一来源,替代 semaphore.ts 和 registry.ts 中的重复定义) */
|
|
12
|
+
export interface ConcurrencyConfig {
|
|
13
|
+
maxConcurrency: number;
|
|
14
|
+
queueTimeoutMs: number;
|
|
15
|
+
maxQueueSize: number;
|
|
16
|
+
}
|
|
17
|
+
export interface ConcurrencyOverride {
|
|
18
|
+
max_concurrency?: number;
|
|
19
|
+
queue_timeout_ms?: number;
|
|
20
|
+
max_queue_size?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface ResolveResult {
|
|
23
|
+
target: Target;
|
|
24
|
+
concurrency_override?: ConcurrencyOverride;
|
|
25
|
+
/** 活跃规则(schedule 或 base)中的 target 总数,用于 failover 判断 */
|
|
26
|
+
targetCount: number;
|
|
27
|
+
}
|
|
28
|
+
export interface MetricsResult {
|
|
29
|
+
input_tokens: number | null;
|
|
30
|
+
output_tokens: number | null;
|
|
31
|
+
cache_creation_tokens: number | null;
|
|
32
|
+
cache_read_tokens: number | null;
|
|
33
|
+
ttft_ms: number | null;
|
|
34
|
+
/** T6 - T0: proxy end-to-end streaming duration */
|
|
35
|
+
total_duration_ms: number | null;
|
|
36
|
+
/** @deprecated Use total_tps instead */
|
|
37
|
+
tokens_per_second: number | null;
|
|
38
|
+
stop_reason: string | null;
|
|
39
|
+
is_complete: number;
|
|
40
|
+
input_tokens_estimated?: number;
|
|
41
|
+
thinking_tokens: number | null;
|
|
42
|
+
/** T3 - T0: request start to last thinking delta */
|
|
43
|
+
thinking_duration_ms: number | null;
|
|
44
|
+
thinking_tps: number | null;
|
|
45
|
+
/** T6 - T3 (thinking) or T6 - T0 (non-thinking) */
|
|
46
|
+
non_thinking_duration_ms: number | null;
|
|
47
|
+
non_thinking_tps: number | null;
|
|
48
|
+
total_tps: number | null;
|
|
49
|
+
text_tokens: number | null;
|
|
50
|
+
tool_use_tokens: number | null;
|
|
51
|
+
}
|
|
52
|
+
export type RawHeaders = Record<string, string | string[] | undefined>;
|
|
53
|
+
export type TransportResult = {
|
|
54
|
+
kind: "success";
|
|
55
|
+
statusCode: number;
|
|
56
|
+
body: string;
|
|
57
|
+
headers: Record<string, string>;
|
|
58
|
+
sentHeaders: Record<string, string>;
|
|
59
|
+
sentBody: string;
|
|
60
|
+
} | {
|
|
61
|
+
kind: "stream_success";
|
|
62
|
+
statusCode: number;
|
|
63
|
+
metrics?: MetricsResult;
|
|
64
|
+
upstreamResponseHeaders?: Record<string, string>;
|
|
65
|
+
sentHeaders: Record<string, string>;
|
|
66
|
+
} | {
|
|
67
|
+
kind: "stream_error";
|
|
68
|
+
statusCode: number;
|
|
69
|
+
body: string;
|
|
70
|
+
headers: Record<string, string>;
|
|
71
|
+
sentHeaders: Record<string, string>;
|
|
72
|
+
headersSent?: boolean;
|
|
73
|
+
} | {
|
|
74
|
+
kind: "stream_abort";
|
|
75
|
+
statusCode: number;
|
|
76
|
+
metrics?: MetricsResult;
|
|
77
|
+
upstreamResponseHeaders?: Record<string, string>;
|
|
78
|
+
sentHeaders: Record<string, string>;
|
|
79
|
+
} | {
|
|
80
|
+
kind: "error";
|
|
81
|
+
statusCode: number;
|
|
82
|
+
body: string;
|
|
83
|
+
headers: Record<string, string>;
|
|
84
|
+
sentHeaders: Record<string, string>;
|
|
85
|
+
sentBody: string;
|
|
86
|
+
} | {
|
|
87
|
+
kind: "throw";
|
|
88
|
+
error: Error;
|
|
89
|
+
headersSent?: boolean;
|
|
90
|
+
};
|
|
91
|
+
/** 单次 resilience 尝试的记录 */
|
|
92
|
+
export interface ResilienceAttempt {
|
|
93
|
+
target: Target;
|
|
94
|
+
attemptIndex: number;
|
|
95
|
+
statusCode: number | null;
|
|
96
|
+
error: string | null;
|
|
97
|
+
latencyMs: number;
|
|
98
|
+
responseBody: string | null;
|
|
99
|
+
/** 上游响应 headers(throw 和 stream_success/stream_abort 时为 null) */
|
|
100
|
+
responseHeaders: Record<string, string> | null;
|
|
101
|
+
/** TransportResult.kind,用于区分 stream_error 等特殊类型 */
|
|
102
|
+
resultKind: TransportResult["kind"];
|
|
103
|
+
}
|
|
104
|
+
/** 流式传输阶段状态 */
|
|
105
|
+
export type StreamState = "BUFFERING" | "STREAMING" | "COMPLETED" | "EARLY_ERROR" | "ABORTED";
|
package/dist/db/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export { getMappingGroup, getMappingGroupById, getAllMappingGroups, createMappin
|
|
|
6
6
|
export type { MappingGroup, ProviderModelEntry } from "./mappings.js";
|
|
7
7
|
export { getActiveRetryRules, getAllRetryRules, getRetryRuleById, createRetryRule, updateRetryRule, deleteRetryRule, } from "./retry-rules.js";
|
|
8
8
|
export type { RetryRule } from "./retry-rules.js";
|
|
9
|
-
export { insertRequestLog, getRequestLogs, getRequestLogById, deleteLogsBefore, getRequestLogChildren, getRequestLogsGrouped,
|
|
9
|
+
export { insertRequestLog, getRequestLogs, getRequestLogById, deleteLogsBefore, getRequestLogChildren, getRequestLogsGrouped, updateLogStreamContent, updateLogClientStatus, estimateLogTableSize, deleteOldestLogs, getLogCount, updateLogPipelineSnapshot, } from "./logs.js";
|
|
10
10
|
export type { RequestLog, RequestLogGroupedRow, RequestLogListRow } from "./logs.js";
|
|
11
11
|
export { getRouterKeyByHash, getAllRouterKeys, getRouterKeyById, createRouterKey, updateRouterKey, deleteRouterKey, getAvailableModels, } from "./router-keys.js";
|
|
12
12
|
export type { RouterKey } from "./router-keys.js";
|
package/dist/db/index.js
CHANGED
|
@@ -85,7 +85,7 @@ export function initDatabase(dbPath) {
|
|
|
85
85
|
export { getActiveProviders, getAllProviders, getProviderById, getActiveProviderByName, getActiveProvidersWithModels, createProvider, updateProvider, deleteProvider, PROVIDER_CONCURRENCY_DEFAULTS, } from "./providers.js";
|
|
86
86
|
export { getMappingGroup, getMappingGroupById, getAllMappingGroups, createMappingGroup, updateMappingGroup, deleteMappingGroup, getActiveProviderModels, resolveByProviderModel, } from "./mappings.js";
|
|
87
87
|
export { getActiveRetryRules, getAllRetryRules, getRetryRuleById, createRetryRule, updateRetryRule, deleteRetryRule, } from "./retry-rules.js";
|
|
88
|
-
export { insertRequestLog, getRequestLogs, getRequestLogById, deleteLogsBefore, getRequestLogChildren, getRequestLogsGrouped,
|
|
88
|
+
export { insertRequestLog, getRequestLogs, getRequestLogById, deleteLogsBefore, getRequestLogChildren, getRequestLogsGrouped, updateLogStreamContent, updateLogClientStatus, estimateLogTableSize, deleteOldestLogs, getLogCount, updateLogPipelineSnapshot, } from "./logs.js";
|
|
89
89
|
export { getRouterKeyByHash, getAllRouterKeys, getRouterKeyById, createRouterKey, updateRouterKey, deleteRouterKey, getAvailableModels, } from "./router-keys.js";
|
|
90
90
|
export { getMetricsSummary, getMetricsTimeseries, insertMetrics } from "./metrics.js";
|
|
91
91
|
export { getStats } from "./stats.js";
|
package/dist/db/logs.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import Database from "better-sqlite3";
|
|
2
|
+
import type { LogFileWriter } from "../storage/log-file-writer.js";
|
|
3
|
+
import { type RetryMatcher } from "../proxy/log-detail-policy.js";
|
|
2
4
|
export interface RequestLog {
|
|
3
5
|
id: string;
|
|
4
6
|
api_type: string;
|
|
@@ -17,14 +19,6 @@ export interface RequestLog {
|
|
|
17
19
|
is_failover: number;
|
|
18
20
|
original_request_id: string | null;
|
|
19
21
|
original_model: string | null;
|
|
20
|
-
input_tokens: number | null;
|
|
21
|
-
output_tokens: number | null;
|
|
22
|
-
cache_read_tokens: number | null;
|
|
23
|
-
ttft_ms: number | null;
|
|
24
|
-
tokens_per_second: number | null;
|
|
25
|
-
stop_reason: string | null;
|
|
26
|
-
backend_model: string | null;
|
|
27
|
-
metrics_complete: number;
|
|
28
22
|
stream_text_content: string | null;
|
|
29
23
|
session_id: string | null;
|
|
30
24
|
}
|
|
@@ -53,8 +47,14 @@ export interface RequestLogInsert {
|
|
|
53
47
|
original_model?: string | null;
|
|
54
48
|
session_id?: string | null;
|
|
55
49
|
client_status_code?: number | null;
|
|
50
|
+
pipeline_snapshot?: string | null;
|
|
56
51
|
}
|
|
57
|
-
export
|
|
52
|
+
export interface LogWriteContext {
|
|
53
|
+
matcher?: RetryMatcher | null;
|
|
54
|
+
logFileWriter?: LogFileWriter | null;
|
|
55
|
+
responseBody?: string | null;
|
|
56
|
+
}
|
|
57
|
+
export declare function insertRequestLog(db: Database.Database, log: RequestLogInsert, writeContext?: LogWriteContext): void;
|
|
58
58
|
export declare function getRequestLogs(db: Database.Database, options: {
|
|
59
59
|
page: number;
|
|
60
60
|
limit: number;
|
|
@@ -69,24 +69,10 @@ export declare function getRequestLogs(db: Database.Database, options: {
|
|
|
69
69
|
total: number;
|
|
70
70
|
};
|
|
71
71
|
export declare function getRequestLogById(db: Database.Database, id: string): RequestLogListRow | undefined;
|
|
72
|
-
type MetricsUpdate = {
|
|
73
|
-
input_tokens?: number | null;
|
|
74
|
-
output_tokens?: number | null;
|
|
75
|
-
cache_read_tokens?: number | null;
|
|
76
|
-
ttft_ms?: number | null;
|
|
77
|
-
tokens_per_second?: number | null;
|
|
78
|
-
stop_reason?: string | null;
|
|
79
|
-
is_complete?: number;
|
|
80
|
-
input_tokens_estimated?: number;
|
|
81
|
-
};
|
|
82
|
-
/** 双写:collectTransportMetrics 写 request_metrics 的同时,更新 request_logs 的冗余列 */
|
|
83
|
-
export declare function updateLogMetrics(db: Database.Database, logId: string, m: MetricsUpdate): void;
|
|
84
72
|
/** 流式请求完成后,将 tracker 中累积的文本内容写入 request_logs */
|
|
85
73
|
export declare function updateLogStreamContent(db: Database.Database, logId: string, textContent: string): void;
|
|
86
74
|
/** 当 router 返回给客户端的 status code 与上游不同时,记录实际发送的 status */
|
|
87
75
|
export declare function updateLogClientStatus(db: Database.Database, logId: string, clientStatusCode: number): void;
|
|
88
|
-
/** 启动时回填:从 request_metrics 补齐 metrics_complete = 0 但实际有指标的行 */
|
|
89
|
-
export declare function backfillMetricsFromRequestMetrics(db: Database.Database): number;
|
|
90
76
|
export declare function deleteLogsBefore(db: Database.Database, beforeDate: string): number;
|
|
91
77
|
/** 估算 request_logs 表占用字节数 */
|
|
92
78
|
export declare function estimateLogTableSize(db: Database.Database): number;
|
|
@@ -113,4 +99,5 @@ export declare function getRequestLogsGrouped(db: Database.Database, options: {
|
|
|
113
99
|
data: RequestLogGroupedRow[];
|
|
114
100
|
total: number;
|
|
115
101
|
};
|
|
116
|
-
|
|
102
|
+
/** 后续 pipeline 阶段完成后,回写 snapshot 到已有日志 */
|
|
103
|
+
export declare function updateLogPipelineSnapshot(db: Database.Database, logId: string, snapshot: string): void;
|
package/dist/db/logs.js
CHANGED
|
@@ -1,17 +1,35 @@
|
|
|
1
|
+
import { shouldPreserveDetail } from "../proxy/log-detail-policy.js";
|
|
1
2
|
// --- request_logs ---
|
|
2
|
-
/** 日志列表查询共享的 SELECT 列 + JOIN 子句(metrics 已冗余到 request_logs,无需 JOIN request_metrics) */
|
|
3
3
|
const LOG_LIST_SELECT = `rl.id, rl.api_type, rl.model, rl.provider_id, rl.status_code, rl.client_status_code, rl.latency_ms,
|
|
4
4
|
rl.is_stream, rl.error_message, rl.created_at, rl.is_retry, rl.is_failover, rl.original_request_id, rl.original_model,
|
|
5
5
|
CASE WHEN rl.provider_id = 'router' THEN rl.upstream_request ELSE NULL END AS upstream_request,
|
|
6
|
-
rl.
|
|
7
|
-
|
|
6
|
+
rl.session_id, rl.pipeline_snapshot,
|
|
7
|
+
rm.input_tokens, rm.output_tokens, rm.cache_read_tokens, rm.ttft_ms,
|
|
8
|
+
rm.tokens_per_second, rm.stop_reason, rm.backend_model, rm.is_complete AS metrics_complete,
|
|
9
|
+
rm.input_tokens_estimated,
|
|
8
10
|
COALESCE(p.name, rl.provider_id) AS provider_name`;
|
|
9
|
-
const LOG_LIST_JOIN = `LEFT JOIN providers p ON p.id = rl.provider_id`;
|
|
10
|
-
export function insertRequestLog(db, log) {
|
|
11
|
+
const LOG_LIST_JOIN = `LEFT JOIN providers p ON p.id = rl.provider_id LEFT JOIN request_metrics rm ON rm.request_log_id = rl.id`;
|
|
12
|
+
export function insertRequestLog(db, log, writeContext) {
|
|
13
|
+
// 文件写入:始终写入全文
|
|
14
|
+
if (writeContext?.logFileWriter) {
|
|
15
|
+
writeContext.logFileWriter.write({
|
|
16
|
+
id: log.id,
|
|
17
|
+
created_at: log.created_at,
|
|
18
|
+
api_type: log.api_type,
|
|
19
|
+
status_code: log.status_code,
|
|
20
|
+
client_request: log.client_request ?? null,
|
|
21
|
+
upstream_request: log.upstream_request ?? null,
|
|
22
|
+
upstream_response: log.upstream_response ?? null,
|
|
23
|
+
stream_text_content: null,
|
|
24
|
+
pipeline_snapshot: log.pipeline_snapshot ?? null,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
// 详情保留判定
|
|
28
|
+
const preserveDetail = shouldPreserveDetail(log.status_code, writeContext?.responseBody ?? null, writeContext?.matcher ?? null, !!writeContext?.logFileWriter);
|
|
11
29
|
db.prepare(`INSERT INTO request_logs (id, api_type, model, provider_id, status_code, client_status_code, latency_ms,
|
|
12
30
|
is_stream, error_message, created_at, client_request, upstream_request, upstream_response,
|
|
13
|
-
is_retry, is_failover, original_request_id, router_key_id, original_model, session_id)
|
|
14
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(log.id, log.api_type, log.model, log.provider_id, log.status_code, log.client_status_code ?? null, log.latency_ms, log.is_stream, log.error_message, log.created_at, log.client_request ?? null, log.upstream_request ?? null, log.upstream_response ?? null, log.is_retry ?? 0, log.is_failover ?? 0, log.original_request_id ?? null, log.router_key_id ?? null, log.original_model ?? null, log.session_id ?? null);
|
|
31
|
+
is_retry, is_failover, original_request_id, router_key_id, original_model, session_id, pipeline_snapshot)
|
|
32
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(log.id, log.api_type, log.model, log.provider_id, log.status_code, log.client_status_code ?? null, log.latency_ms, log.is_stream, log.error_message, log.created_at, preserveDetail ? (log.client_request ?? null) : null, preserveDetail ? (log.upstream_request ?? null) : null, preserveDetail ? (log.upstream_response ?? null) : null, log.is_retry ?? 0, log.is_failover ?? 0, log.original_request_id ?? null, log.router_key_id ?? null, log.original_model ?? null, log.session_id ?? null, log.pipeline_snapshot ?? null);
|
|
15
33
|
}
|
|
16
34
|
function buildLogWhereClause(options, baseCondition) {
|
|
17
35
|
let where = baseCondition;
|
|
@@ -63,19 +81,15 @@ export function getRequestLogs(db, options) {
|
|
|
63
81
|
return { data, total };
|
|
64
82
|
}
|
|
65
83
|
export function getRequestLogById(db, id) {
|
|
66
|
-
return db.prepare(`SELECT rl.*,
|
|
67
|
-
|
|
84
|
+
return db.prepare(`SELECT rl.*, rm.input_tokens, rm.output_tokens, rm.cache_read_tokens, rm.ttft_ms,
|
|
85
|
+
rm.tokens_per_second, rm.stop_reason, rm.backend_model, rm.is_complete AS metrics_complete,
|
|
86
|
+
rm.input_tokens_estimated,
|
|
87
|
+
COALESCE(p.name, rl.provider_id) AS provider_name
|
|
88
|
+
FROM request_logs rl
|
|
89
|
+
LEFT JOIN providers p ON p.id = rl.provider_id
|
|
90
|
+
LEFT JOIN request_metrics rm ON rm.request_log_id = rl.id
|
|
68
91
|
WHERE rl.id = ?`).get(id);
|
|
69
92
|
}
|
|
70
|
-
/** 双写:collectTransportMetrics 写 request_metrics 的同时,更新 request_logs 的冗余列 */
|
|
71
|
-
export function updateLogMetrics(db, logId, m) {
|
|
72
|
-
db.prepare(`UPDATE request_logs SET
|
|
73
|
-
input_tokens = ?, output_tokens = ?, cache_read_tokens = ?,
|
|
74
|
-
ttft_ms = ?, tokens_per_second = ?, stop_reason = ?,
|
|
75
|
-
backend_model = (SELECT backend_model FROM request_metrics WHERE request_log_id = ?),
|
|
76
|
-
metrics_complete = ?, input_tokens_estimated = ?
|
|
77
|
-
WHERE id = ?`).run(m.input_tokens ?? null, m.output_tokens ?? null, m.cache_read_tokens ?? null, m.ttft_ms ?? null, m.tokens_per_second ?? null, m.stop_reason ?? null, logId, m.is_complete ?? 1, m.input_tokens_estimated ?? 0, logId);
|
|
78
|
-
}
|
|
79
93
|
/** 流式请求完成后,将 tracker 中累积的文本内容写入 request_logs */
|
|
80
94
|
export function updateLogStreamContent(db, logId, textContent) {
|
|
81
95
|
db.prepare("UPDATE request_logs SET stream_text_content = ? WHERE id = ?").run(textContent, logId);
|
|
@@ -84,25 +98,6 @@ export function updateLogStreamContent(db, logId, textContent) {
|
|
|
84
98
|
export function updateLogClientStatus(db, logId, clientStatusCode) {
|
|
85
99
|
db.prepare("UPDATE request_logs SET client_status_code = ? WHERE id = ?").run(clientStatusCode, logId);
|
|
86
100
|
}
|
|
87
|
-
/** 启动时回填:从 request_metrics 补齐 metrics_complete = 0 但实际有指标的行 */
|
|
88
|
-
export function backfillMetricsFromRequestMetrics(db) {
|
|
89
|
-
return db.prepare(`
|
|
90
|
-
UPDATE request_logs
|
|
91
|
-
SET
|
|
92
|
-
input_tokens = rm.input_tokens,
|
|
93
|
-
output_tokens = rm.output_tokens,
|
|
94
|
-
cache_read_tokens = rm.cache_read_tokens,
|
|
95
|
-
ttft_ms = rm.ttft_ms,
|
|
96
|
-
tokens_per_second = rm.tokens_per_second,
|
|
97
|
-
stop_reason = rm.stop_reason,
|
|
98
|
-
backend_model = rm.backend_model,
|
|
99
|
-
metrics_complete = rm.is_complete,
|
|
100
|
-
input_tokens_estimated = rm.input_tokens_estimated
|
|
101
|
-
FROM request_metrics rm
|
|
102
|
-
WHERE rm.request_log_id = request_logs.id
|
|
103
|
-
AND request_logs.metrics_complete = 0
|
|
104
|
-
`).run().changes;
|
|
105
|
-
}
|
|
106
101
|
export function deleteLogsBefore(db, beforeDate) {
|
|
107
102
|
const changes = db.prepare("DELETE FROM request_logs WHERE created_at < ?").run(beforeDate).changes;
|
|
108
103
|
if (changes > 0) {
|
|
@@ -118,7 +113,7 @@ export function estimateLogTableSize(db) {
|
|
|
118
113
|
SELECT COALESCE(SUM(
|
|
119
114
|
COALESCE(length(client_request), 0) + COALESCE(length(upstream_request), 0) +
|
|
120
115
|
COALESCE(length(upstream_response), 0) + COALESCE(length(stream_text_content), 0) +
|
|
121
|
-
COALESCE(length(error_message), 0) + ?
|
|
116
|
+
COALESCE(length(error_message), 0) + COALESCE(length(pipeline_snapshot), 0) + ?
|
|
122
117
|
), 0) as size
|
|
123
118
|
FROM request_logs
|
|
124
119
|
`).get(ROW_METADATA_BYTES);
|
|
@@ -177,3 +172,7 @@ export function getRequestLogsGrouped(db, options) {
|
|
|
177
172
|
.all(...params, options.limit, offset);
|
|
178
173
|
return { data, total };
|
|
179
174
|
}
|
|
175
|
+
/** 后续 pipeline 阶段完成后,回写 snapshot 到已有日志 */
|
|
176
|
+
export function updateLogPipelineSnapshot(db, logId, snapshot) {
|
|
177
|
+
db.prepare("UPDATE request_logs SET pipeline_snapshot = ? WHERE id = ?").run(snapshot, logId);
|
|
178
|
+
}
|
package/dist/db/metrics.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
|
-
import { MS_PER_SECOND } from "../constants.js";
|
|
2
|
+
import { MS_PER_SECOND } from "../core/constants.js";
|
|
3
3
|
export function insertMetrics(db, m) {
|
|
4
4
|
const id = randomUUID();
|
|
5
5
|
db.prepare(`INSERT INTO request_metrics (id, request_log_id, provider_id, backend_model, api_type, router_key_id, status_code,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE request_logs ADD COLUMN pipeline_snapshot TEXT;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- 034_drop_redundant_log_columns.sql
|
|
2
|
+
-- request_logs 与 request_metrics 双写冗余清理:
|
|
3
|
+
-- metrics 字段统一由 request_metrics 承载,日志列表查询改用 LEFT JOIN。
|
|
4
|
+
|
|
5
|
+
ALTER TABLE request_logs DROP COLUMN input_tokens;
|
|
6
|
+
ALTER TABLE request_logs DROP COLUMN output_tokens;
|
|
7
|
+
ALTER TABLE request_logs DROP COLUMN cache_read_tokens;
|
|
8
|
+
ALTER TABLE request_logs DROP COLUMN ttft_ms;
|
|
9
|
+
ALTER TABLE request_logs DROP COLUMN tokens_per_second;
|
|
10
|
+
ALTER TABLE request_logs DROP COLUMN stop_reason;
|
|
11
|
+
ALTER TABLE request_logs DROP COLUMN backend_model;
|
|
12
|
+
ALTER TABLE request_logs DROP COLUMN metrics_complete;
|
|
13
|
+
ALTER TABLE request_logs DROP COLUMN input_tokens_estimated;
|
package/dist/db/settings.d.ts
CHANGED
|
@@ -10,3 +10,5 @@ export declare function getLogTableMaxSizeMb(db: Database.Database): number;
|
|
|
10
10
|
export declare function setLogTableMaxSizeMb(db: Database.Database, mb: number): void;
|
|
11
11
|
export declare function getConfigSyncSource(db: Database.Database): "github" | "gitee";
|
|
12
12
|
export declare function setConfigSyncSource(db: Database.Database, source: "github" | "gitee"): void;
|
|
13
|
+
export declare function getDetailLogEnabled(db: Database.Database): boolean;
|
|
14
|
+
export declare function getLogFileRetentionDays(db: Database.Database): number;
|
package/dist/db/settings.js
CHANGED
|
@@ -39,3 +39,12 @@ export function getConfigSyncSource(db) {
|
|
|
39
39
|
export function setConfigSyncSource(db, source) {
|
|
40
40
|
setSetting(db, "config_sync_source", source);
|
|
41
41
|
}
|
|
42
|
+
export function getDetailLogEnabled(db) {
|
|
43
|
+
const row = db.prepare("SELECT value FROM settings WHERE key = ?").get("detail_log_enabled");
|
|
44
|
+
return row ? row.value !== "0" : true;
|
|
45
|
+
}
|
|
46
|
+
const DEFAULT_LOG_FILE_RETENTION_DAYS = 3;
|
|
47
|
+
export function getLogFileRetentionDays(db) {
|
|
48
|
+
const row = db.prepare("SELECT value FROM settings WHERE key = ?").get("log_file_retention_days");
|
|
49
|
+
return row ? parseInt(row.value, 10) : DEFAULT_LOG_FILE_RETENTION_DAYS;
|
|
50
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { FastifyInstance } from "fastify";
|
|
3
|
-
import { Config } from "./config.js";
|
|
4
|
-
import {
|
|
3
|
+
import { Config } from "./config/index.js";
|
|
4
|
+
import { ProviderSemaphoreManager } from "./proxy/orchestration/semaphore.js";
|
|
5
|
+
import { AdaptiveConcurrencyController } from "./proxy/adaptive-controller.js";
|
|
6
|
+
import { RequestTracker } from "./monitor/request-tracker.js";
|
|
7
|
+
import { UsageWindowTracker } from "./proxy/routing/usage-window-tracker.js";
|
|
5
8
|
import { CheckerOptions } from "./upgrade/checker.js";
|
|
6
9
|
import Database from "better-sqlite3";
|
|
7
10
|
export interface AppOptions {
|
|
@@ -9,6 +12,11 @@ export interface AppOptions {
|
|
|
9
12
|
db?: Database.Database;
|
|
10
13
|
upgradeCheckerOptions?: CheckerOptions;
|
|
11
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* 共享初始化逻辑 — 启动时和导入配置后都需要调用。
|
|
17
|
+
* 从 DB 读取所有 provider,初始化信号量/自适应并发/tracker 缓存。
|
|
18
|
+
*/
|
|
19
|
+
export declare function initializeProviderState(db: Database.Database, semaphoreManager: ProviderSemaphoreManager, adaptiveController: AdaptiveConcurrencyController, tracker: RequestTracker): void;
|
|
12
20
|
export declare function buildApp(options?: AppOptions): Promise<{
|
|
13
21
|
app: FastifyInstance;
|
|
14
22
|
db: Database.Database;
|