@agentfare/hook 0.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 (62) hide show
  1. package/README.md +36 -0
  2. package/dist/fetch-patch.d.ts +13 -0
  3. package/dist/fetch-patch.d.ts.map +1 -0
  4. package/dist/fetch-patch.js +202 -0
  5. package/dist/fetch-patch.js.map +1 -0
  6. package/dist/headers.d.ts +8 -0
  7. package/dist/headers.d.ts.map +1 -0
  8. package/dist/headers.js +36 -0
  9. package/dist/headers.js.map +1 -0
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +45 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/protocol/anthropic-to-openai-request.d.ts +36 -0
  15. package/dist/protocol/anthropic-to-openai-request.d.ts.map +1 -0
  16. package/dist/protocol/anthropic-to-openai-request.js +122 -0
  17. package/dist/protocol/anthropic-to-openai-request.js.map +1 -0
  18. package/dist/protocol/anthropic-to-openai.d.ts +2 -0
  19. package/dist/protocol/anthropic-to-openai.d.ts.map +1 -0
  20. package/dist/protocol/anthropic-to-openai.js +51 -0
  21. package/dist/protocol/anthropic-to-openai.js.map +1 -0
  22. package/dist/protocol/openai-to-anthropic-response.d.ts +5 -0
  23. package/dist/protocol/openai-to-anthropic-response.d.ts.map +1 -0
  24. package/dist/protocol/openai-to-anthropic-response.js +57 -0
  25. package/dist/protocol/openai-to-anthropic-response.js.map +1 -0
  26. package/dist/protocol/openai-to-anthropic-sse.d.ts +20 -0
  27. package/dist/protocol/openai-to-anthropic-sse.d.ts.map +1 -0
  28. package/dist/protocol/openai-to-anthropic-sse.js +156 -0
  29. package/dist/protocol/openai-to-anthropic-sse.js.map +1 -0
  30. package/dist/protocol/openai-to-anthropic.d.ts +23 -0
  31. package/dist/protocol/openai-to-anthropic.d.ts.map +1 -0
  32. package/dist/protocol/openai-to-anthropic.js +61 -0
  33. package/dist/protocol/openai-to-anthropic.js.map +1 -0
  34. package/dist/protocol/sse-transform.d.ts +2 -0
  35. package/dist/protocol/sse-transform.d.ts.map +1 -0
  36. package/dist/protocol/sse-transform.js +41 -0
  37. package/dist/protocol/sse-transform.js.map +1 -0
  38. package/dist/protocol/types.d.ts +31 -0
  39. package/dist/protocol/types.d.ts.map +1 -0
  40. package/dist/protocol/types.js +3 -0
  41. package/dist/protocol/types.js.map +1 -0
  42. package/dist/proxy-server.d.ts +7 -0
  43. package/dist/proxy-server.d.ts.map +1 -0
  44. package/dist/proxy-server.js +52 -0
  45. package/dist/proxy-server.js.map +1 -0
  46. package/dist/reentry-guard.d.ts +2 -0
  47. package/dist/reentry-guard.d.ts.map +1 -0
  48. package/dist/reentry-guard.js +9 -0
  49. package/dist/reentry-guard.js.map +1 -0
  50. package/dist/request-handler.d.ts +34 -0
  51. package/dist/request-handler.d.ts.map +1 -0
  52. package/dist/request-handler.js +133 -0
  53. package/dist/request-handler.js.map +1 -0
  54. package/dist/response-handler.d.ts +9 -0
  55. package/dist/response-handler.d.ts.map +1 -0
  56. package/dist/response-handler.js +92 -0
  57. package/dist/response-handler.js.map +1 -0
  58. package/dist/url-detector.d.ts +2 -0
  59. package/dist/url-detector.d.ts.map +1 -0
  60. package/dist/url-detector.js +17 -0
  61. package/dist/url-detector.js.map +1 -0
  62. package/package.json +36 -0
package/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # @agentfare/hook
2
+
3
+ fetch 拦截层 —— 拦截全局 `fetch` 调用,将 LLM API 请求通过路由引擎处理后转发。
4
+
5
+ ## 功能
6
+
7
+ - 自动拦截 OpenAI / Anthropic API 调用
8
+ - 跨 Provider 协议转换(OpenAI ↔ Anthropic SSE)
9
+ - 重入保护(防止路由请求被二次拦截)
10
+
11
+ ## 集成方式
12
+
13
+ ### Node.js --require 预加载
14
+
15
+ ```bash
16
+ NODE_OPTIONS="--require @agentfare/hook" node your-app.js
17
+ ```
18
+
19
+ ### 编程式
20
+
21
+ ```typescript
22
+ import { installFetchPatch } from "@agentfare/hook/fetch-patch";
23
+
24
+ const uninstall = installFetchPatch({
25
+ handler,
26
+ costTracker,
27
+ onRouting: (result) => console.log(result),
28
+ });
29
+
30
+ // 卸载
31
+ uninstall();
32
+ ```
33
+
34
+ ## License
35
+
36
+ MIT
@@ -0,0 +1,13 @@
1
+ import type { RequestHandler, HandleResult } from "./request-handler.js";
2
+ import type { CostTracker, QualitySignalCollector } from "@agentfare/core";
3
+ export interface FetchPatchOptions {
4
+ handler: RequestHandler;
5
+ costTracker?: CostTracker;
6
+ qualitySignalCollector?: QualitySignalCollector;
7
+ onlineLearner?: any;
8
+ onRouting?: (result: HandleResult) => void;
9
+ onError?: (err: unknown) => void;
10
+ }
11
+ export declare function installFetchPatch(options: FetchPatchOptions): () => void;
12
+ export declare function getOriginalFetch(): typeof globalThis.fetch;
13
+ //# sourceMappingURL=fetch-patch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-patch.d.ts","sourceRoot":"","sources":["../src/fetch-patch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzE,OAAO,KAAK,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAW3E,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD,aAAa,CAAC,EAAE,GAAG,CAAC;IACpB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IAC3C,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAClC;AAcD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,IAAI,CA4MxE;AAOD,wBAAgB,gBAAgB,IAAI,OAAO,UAAU,CAAC,KAAK,CAE1D"}
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.installFetchPatch = installFetchPatch;
4
+ exports.getOriginalFetch = getOriginalFetch;
5
+ const url_detector_js_1 = require("./url-detector.js");
6
+ const headers_js_1 = require("./headers.js");
7
+ const response_handler_js_1 = require("./response-handler.js");
8
+ const openai_to_anthropic_js_1 = require("./protocol/openai-to-anthropic.js");
9
+ const anthropic_to_openai_js_1 = require("./protocol/anthropic-to-openai.js");
10
+ const sse_transform_js_1 = require("./protocol/sse-transform.js");
11
+ const anthropic_to_openai_request_js_1 = require("./protocol/anthropic-to-openai-request.js");
12
+ const openai_to_anthropic_response_js_1 = require("./protocol/openai-to-anthropic-response.js");
13
+ const openai_to_anthropic_sse_js_1 = require("./protocol/openai-to-anthropic-sse.js");
14
+ const ORIGINAL_FETCH_SYMBOL = Symbol("agentfare:originalFetch");
15
+ const ANALYZER_TIMEOUT_MS = 500;
16
+ function logErrorToFile(err) {
17
+ try {
18
+ const fs = require("node:fs");
19
+ const path = require("node:path");
20
+ const os = require("node:os");
21
+ const logPath = path.join(os.homedir(), ".agentfare", "errors.log");
22
+ const timestamp = new Date().toISOString();
23
+ const message = err instanceof Error ? err.stack ?? err.message : String(err);
24
+ fs.appendFileSync(logPath, `[${timestamp}] ${message}\n`);
25
+ }
26
+ catch { }
27
+ }
28
+ function installFetchPatch(options) {
29
+ const originalFetch = globalThis.fetch;
30
+ globalThis[ORIGINAL_FETCH_SYMBOL] = originalFetch;
31
+ const qualityCollector = options.qualitySignalCollector;
32
+ const onlineLearner = options.onlineLearner;
33
+ globalThis.fetch = async function patchedFetch(input, init) {
34
+ const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
35
+ if (!(0, url_detector_js_1.isLLMApiCall)(url)) {
36
+ return originalFetch.call(this, input, init);
37
+ }
38
+ if ((0, headers_js_1.isInternalRequest)(init)) {
39
+ return originalFetch.call(this, input, init);
40
+ }
41
+ try {
42
+ const bodyStr = typeof init?.body === "string" ? init.body : undefined;
43
+ if (!bodyStr)
44
+ return originalFetch.call(this, input, init);
45
+ const headers = (0, headers_js_1.extractHeaders)(init?.headers);
46
+ const body = JSON.parse(bodyStr);
47
+ const currentModel = body.model;
48
+ if (qualityCollector && currentModel) {
49
+ const sessionId = headers["x-request-id"] ?? headers["x-session-id"] ?? "default";
50
+ if (qualityCollector.detectManualSwitch(sessionId, currentModel)) {
51
+ qualityCollector.recordSignal(currentModel, "unknown", "manual_switch", sessionId);
52
+ }
53
+ }
54
+ const result = await Promise.race([
55
+ options.handler.handle(url, bodyStr, headers),
56
+ new Promise((resolve) => setTimeout(() => resolve(null), ANALYZER_TIMEOUT_MS)),
57
+ ]);
58
+ if (!result || !result.decision.targetModel) {
59
+ return originalFetch.call(this, input, init);
60
+ }
61
+ const targetModel = result.decision.targetModel;
62
+ const modifiedInit = {
63
+ ...init,
64
+ body: result.modifiedBody,
65
+ };
66
+ // Cross-provider: rewrite URL, headers, and convert request body
67
+ let sourceProtocol = null;
68
+ let needsProtocolConversion = false;
69
+ if (result.decision.providerSwitched) {
70
+ const targetApi = targetModel.api;
71
+ const effectiveBaseUrl = result.decision.enterpriseConfig?.baseUrl ?? targetApi.baseUrl;
72
+ // Detect source protocol from original URL
73
+ sourceProtocol = url.includes("anthropic.com") ? "anthropic" : "openai";
74
+ const targetProtocol = targetApi.protocol;
75
+ needsProtocolConversion = sourceProtocol !== targetProtocol;
76
+ input = targetApi.protocol === "anthropic"
77
+ ? `${effectiveBaseUrl}/v1/messages`
78
+ : `${effectiveBaseUrl}/chat/completions`;
79
+ if (result.decision.apiKey) {
80
+ const authHeaders = { ...headers };
81
+ if (targetApi.protocol === "anthropic") {
82
+ delete authHeaders["Authorization"];
83
+ authHeaders["x-api-key"] = result.decision.apiKey;
84
+ authHeaders["anthropic-version"] = "2023-06-01";
85
+ }
86
+ else {
87
+ authHeaders["Authorization"] = `Bearer ${result.decision.apiKey}`;
88
+ }
89
+ modifiedInit.headers = authHeaders;
90
+ }
91
+ // ISSUE-028: Protocol conversion — convert request body when crossing providers
92
+ if (needsProtocolConversion && sourceProtocol) {
93
+ try {
94
+ const requestBody = JSON.parse(result.modifiedBody);
95
+ let converted;
96
+ if (sourceProtocol === "openai" && targetProtocol === "anthropic") {
97
+ converted = (0, openai_to_anthropic_js_1.convertOpenAIToAnthropicRequest)(requestBody, targetApi.modelId);
98
+ }
99
+ else if (sourceProtocol === "anthropic" && targetProtocol === "openai") {
100
+ converted = (0, anthropic_to_openai_request_js_1.convertAnthropicToOpenAIRequest)(requestBody, targetApi.modelId);
101
+ }
102
+ if (converted) {
103
+ modifiedInit.body = JSON.stringify(converted);
104
+ }
105
+ }
106
+ catch (conversionErr) {
107
+ logErrorToFile(`协议转换请求体失败: ${conversionErr}`);
108
+ }
109
+ }
110
+ }
111
+ const response = await originalFetch.call(this, input, modifiedInit);
112
+ // 5xx fallback
113
+ if (response.status >= 500) {
114
+ logErrorToFile(`目标模型 ${targetModel.id} 返回 ${response.status}`);
115
+ if (qualityCollector) {
116
+ qualityCollector.recordSignal(targetModel.id, result.analysis.stepType, "error", result.sessionId);
117
+ onlineLearner?.recordSignal(targetModel.id, result.analysis.stepType, "error");
118
+ }
119
+ return originalFetch.call(this, input, init);
120
+ }
121
+ if (qualityCollector) {
122
+ qualityCollector.recordRoutedModel(result.sessionId, targetModel.id, targetModel.tier);
123
+ qualityCollector.recordRequest(result.sessionId, targetModel.id, result.analysis.stepType);
124
+ }
125
+ // ISSUE-009: strip apiKey from onRouting callback to prevent accidental leakage
126
+ const { apiKey: _apiKey, enterpriseConfig: _ec, ...safeDecision } = result.decision;
127
+ options.onRouting?.({ ...result, decision: safeDecision });
128
+ // ISSUE-028: Protocol conversion — convert response when crossing providers
129
+ const protocol = targetModel.api.protocol;
130
+ // Streaming response: wrap with optional SSE protocol converter
131
+ if (response.body && isStreamingResponse(response)) {
132
+ let sseConverter;
133
+ if (needsProtocolConversion && sourceProtocol) {
134
+ // ISSU-028 fix: response comes FROM target endpoint (protocol), must convert TO sourceProtocol
135
+ if (sourceProtocol === "anthropic" && protocol === "openai") {
136
+ // Response from OpenAI endpoint → convert to Anthropic SSE for original caller
137
+ (0, openai_to_anthropic_sse_js_1.resetSSEState)();
138
+ sseConverter = (chunk) => (0, openai_to_anthropic_sse_js_1.convertOpenAISSEToAnthropic)(chunk, body.model ?? "");
139
+ }
140
+ else if (sourceProtocol === "openai" && protocol === "anthropic") {
141
+ // Response from Anthropic endpoint → convert to OpenAI SSE for original caller
142
+ sseConverter = (chunk) => (0, sse_transform_js_1.convertAnthropicSSEToOpenAI)(chunk, body.model ?? "");
143
+ }
144
+ }
145
+ return (0, response_handler_js_1.createStreamingResponseWrapper)(response, protocol, (tokens) => {
146
+ if (options.costTracker) {
147
+ options.costTracker.record(result.analysis, body.model ?? "", undefined, targetModel, result.sessionId, "unknown", tokens);
148
+ }
149
+ if (qualityCollector) {
150
+ qualityCollector.recordSignal(targetModel.id, result.analysis.stepType, "success", result.sessionId);
151
+ onlineLearner?.recordSignal(targetModel.id, result.analysis.stepType, "success");
152
+ }
153
+ // ISSUE-009: strip apiKey from onRouting callback
154
+ const { apiKey: _ak, enterpriseConfig: _aec, ...safeDec } = result.decision;
155
+ options.onRouting?.({ ...result, decision: safeDec, tokenUsage: tokens });
156
+ }, sseConverter);
157
+ }
158
+ // Non-streaming response: convert response body if protocol mismatch
159
+ if (needsProtocolConversion && sourceProtocol) {
160
+ try {
161
+ const respBody = await response.json();
162
+ let converted;
163
+ // ISSUE-028 fix: response comes FROM target endpoint (protocol), must convert TO sourceProtocol
164
+ if (sourceProtocol === "anthropic" && protocol === "openai") {
165
+ // Response from OpenAI endpoint → convert to Anthropic format for original caller
166
+ converted = (0, openai_to_anthropic_response_js_1.convertOpenAIToAnthropicResponse)(respBody, body.model ?? "");
167
+ }
168
+ else if (sourceProtocol === "openai" && protocol === "anthropic") {
169
+ // Response from Anthropic endpoint → convert to OpenAI format for original caller
170
+ converted = (0, anthropic_to_openai_js_1.convertAnthropicToOpenAIResponse)(respBody, body.model ?? "");
171
+ }
172
+ if (converted) {
173
+ return new Response(JSON.stringify(converted), {
174
+ status: response.status,
175
+ headers: response.headers,
176
+ });
177
+ }
178
+ }
179
+ catch (conversionErr) {
180
+ logErrorToFile(`协议转换响应体失败: ${conversionErr}`);
181
+ }
182
+ }
183
+ return response;
184
+ }
185
+ catch (err) {
186
+ logErrorToFile(err);
187
+ options.onError?.(err);
188
+ return originalFetch.call(this, input, init);
189
+ }
190
+ };
191
+ return () => {
192
+ globalThis.fetch = originalFetch;
193
+ };
194
+ }
195
+ function isStreamingResponse(response) {
196
+ const ct = response.headers.get("content-type") ?? "";
197
+ return ct.includes("text/event-stream");
198
+ }
199
+ function getOriginalFetch() {
200
+ return globalThis[ORIGINAL_FETCH_SYMBOL] ?? globalThis.fetch;
201
+ }
202
+ //# sourceMappingURL=fetch-patch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-patch.js","sourceRoot":"","sources":["../src/fetch-patch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Shared header extraction utility.
3
+ * Handles all three HeadersInit formats: Headers object, [string, string][], Record<string, string>.
4
+ */
5
+ export declare function extractHeaders(headers: HeadersInit | undefined): Record<string, string>;
6
+ export declare function isInternalRequest(init: RequestInit | undefined): boolean;
7
+ export declare function makeInternalHeaders(existing?: Record<string, string>): Record<string, string>;
8
+ //# sourceMappingURL=headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAavF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAIxE;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAE7F"}
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ /**
3
+ * Shared header extraction utility.
4
+ * Handles all three HeadersInit formats: Headers object, [string, string][], Record<string, string>.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.extractHeaders = extractHeaders;
8
+ exports.isInternalRequest = isInternalRequest;
9
+ exports.makeInternalHeaders = makeInternalHeaders;
10
+ const DISPATCH_INTERNAL_HEADER = "x-agentfare-internal";
11
+ function extractHeaders(headers) {
12
+ if (!headers)
13
+ return {};
14
+ if (headers instanceof Headers) {
15
+ const result = {};
16
+ headers.forEach((v, k) => { result[k] = v; });
17
+ return result;
18
+ }
19
+ if (Array.isArray(headers)) {
20
+ const result = {};
21
+ for (const [k, v] of headers)
22
+ result[k] = v;
23
+ return result;
24
+ }
25
+ return headers;
26
+ }
27
+ function isInternalRequest(init) {
28
+ if (!init?.headers)
29
+ return false;
30
+ const headers = extractHeaders(init.headers);
31
+ return headers[DISPATCH_INTERNAL_HEADER] === "true";
32
+ }
33
+ function makeInternalHeaders(existing) {
34
+ return { ...existing, [DISPATCH_INTERNAL_HEADER]: "true" };
35
+ }
36
+ //# sourceMappingURL=headers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.js","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAIH,wCAaC;AAED,8CAIC;AAED,kDAEC;AAzBD,MAAM,wBAAwB,GAAG,sBAAsB,CAAC;AAExD,SAAgB,cAAc,CAAC,OAAgC;IAC7D,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,IAAI,OAAO,YAAY,OAAO,EAAE,CAAC;QAC/B,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,OAAO;YAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC5C,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,OAAiC,CAAC;AAC3C,CAAC;AAED,SAAgB,iBAAiB,CAAC,IAA6B;IAC7D,IAAI,CAAC,IAAI,EAAE,OAAO;QAAE,OAAO,KAAK,CAAC;IACjC,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,OAAO,OAAO,CAAC,wBAAwB,CAAC,KAAK,MAAM,CAAC;AACtD,CAAC;AAED,SAAgB,mBAAmB,CAAC,QAAiC;IACnE,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ // @agentfare/hook — Entry point
3
+ // Initializes config, registry, handler, tracker, quality signal collector, and installs fetch patch
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ const core_1 = require("@agentfare/core");
6
+ const models_1 = require("@agentfare/models");
7
+ const request_handler_js_1 = require("./request-handler.js");
8
+ const fetch_patch_js_1 = require("./fetch-patch.js");
9
+ const models_2 = require("@agentfare/models");
10
+ function initializeHook() {
11
+ try {
12
+ const config = (0, core_1.loadConfigFromDisk)();
13
+ const registry = new models_1.ModelRegistry(config.customModels);
14
+ const handler = new request_handler_js_1.RequestHandler(config, registry);
15
+ const dbPath = (0, models_2.getDbPath)();
16
+ const db = new core_1.TrackingDatabase(dbPath);
17
+ const costTracker = new core_1.CostTracker(db);
18
+ const qualitySignalCollector = new core_1.QualitySignalCollector();
19
+ // ISSUE-011: close DB connection on process exit
20
+ process.on("exit", () => {
21
+ try {
22
+ db.close();
23
+ }
24
+ catch { }
25
+ });
26
+ (0, fetch_patch_js_1.installFetchPatch)({
27
+ handler,
28
+ costTracker,
29
+ qualitySignalCollector,
30
+ onRouting: () => { },
31
+ });
32
+ console.log("[AgentFare] Hook 已安装 — 智能模型路由已启用");
33
+ }
34
+ catch (err) {
35
+ try {
36
+ const fs = require("node:fs");
37
+ const logPath = (0, models_2.getErrorLogPath)();
38
+ fs.appendFileSync(logPath, `[${new Date().toISOString()}] Hook init failed: ${err}\n`);
39
+ }
40
+ catch { }
41
+ console.warn("[AgentFare] Hook 初始化失败,已跳过(不影响宿主进程)");
42
+ }
43
+ }
44
+ initializeHook();
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,gCAAgC;AAChC,qGAAqG;;AAErG,0CAA4G;AAC5G,8CAAkD;AAClD,6DAAsD;AACtD,qDAAqD;AACrD,8CAA+D;AAE/D,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,yBAAkB,GAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,IAAI,sBAAa,CAAC,MAAM,CAAC,YAAmB,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,IAAI,mCAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAErD,MAAM,MAAM,GAAG,IAAA,kBAAS,GAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,IAAI,uBAAgB,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,WAAW,GAAG,IAAI,kBAAW,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,sBAAsB,GAAG,IAAI,6BAAsB,EAAE,CAAC;QAE5D,iDAAiD;QACjD,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;YACtB,IAAI,CAAC;gBAAC,EAAE,CAAC,KAAK,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QAC9B,CAAC,CAAC,CAAC;QAEH,IAAA,kCAAiB,EAAC;YAChB,OAAO;YACP,WAAW;YACX,sBAAsB;YACtB,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;SACpB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;YAC9B,MAAM,OAAO,GAAG,IAAA,wBAAe,GAAE,CAAC;YAClC,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,uBAAuB,GAAG,IAAI,CAAC,CAAC;QACzF,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,OAAO,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED,cAAc,EAAE,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { AnthropicMessage } from "./types.js";
2
+ interface AnthropicRequest {
3
+ model: string;
4
+ max_tokens: number;
5
+ system?: string;
6
+ messages: AnthropicMessage[];
7
+ tools?: any[];
8
+ stream: boolean;
9
+ temperature?: number;
10
+ stop_sequences?: string[];
11
+ }
12
+ interface OpenAIChatMessage {
13
+ role: "system" | "user" | "assistant" | "tool";
14
+ content: string | null;
15
+ tool_calls?: Array<{
16
+ id: string;
17
+ type: "function";
18
+ function: {
19
+ name: string;
20
+ arguments: string;
21
+ };
22
+ }>;
23
+ tool_call_id?: string;
24
+ }
25
+ interface OpenAIRequest {
26
+ model: string;
27
+ messages: OpenAIChatMessage[];
28
+ max_tokens?: number;
29
+ stream?: boolean;
30
+ tools?: any[];
31
+ temperature?: number;
32
+ stop?: string[];
33
+ }
34
+ export declare function convertAnthropicToOpenAIRequest(anthropic: AnthropicRequest, targetModelId?: string): OpenAIRequest;
35
+ export {};
36
+ //# sourceMappingURL=anthropic-to-openai-request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic-to-openai-request.d.ts","sourceRoot":"","sources":["../../src/protocol/anthropic-to-openai-request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAyB,MAAM,YAAY,CAAC;AAE1E,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,UAAU,iBAAiB;IACzB,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,UAAU,CAAC;QACjB,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;KAC/C,CAAC,CAAC;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,gBAAgB,EAC3B,aAAa,CAAC,EAAE,MAAM,GACrB,aAAa,CAqCf"}
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertAnthropicToOpenAIRequest = convertAnthropicToOpenAIRequest;
4
+ function convertAnthropicToOpenAIRequest(anthropic, targetModelId) {
5
+ const result = {
6
+ model: targetModelId ?? "gpt-4o",
7
+ messages: [],
8
+ max_tokens: anthropic.max_tokens,
9
+ stream: anthropic.stream,
10
+ };
11
+ // Anthropic system prompt -> OpenAI system message
12
+ if (anthropic.system) {
13
+ result.messages.push({ role: "system", content: anthropic.system });
14
+ }
15
+ for (const msg of anthropic.messages) {
16
+ if (msg.role === "user") {
17
+ const converted = convertUserMessage(msg);
18
+ result.messages.push(...converted);
19
+ }
20
+ else if (msg.role === "assistant") {
21
+ result.messages.push(convertAssistantMessage(msg));
22
+ }
23
+ }
24
+ if (anthropic.tools) {
25
+ result.tools = anthropic.tools.map((t) => ({
26
+ type: "function",
27
+ function: {
28
+ name: t.name,
29
+ description: t.description,
30
+ parameters: t.input_schema,
31
+ },
32
+ }));
33
+ }
34
+ if (anthropic.temperature !== undefined)
35
+ result.temperature = anthropic.temperature;
36
+ if (anthropic.stop_sequences)
37
+ result.stop = anthropic.stop_sequences;
38
+ return result;
39
+ }
40
+ /**
41
+ * Anthropic user messages may contain tool_result content blocks.
42
+ * These need to become separate "tool" role messages in OpenAI format.
43
+ */
44
+ function convertUserMessage(msg) {
45
+ const results = [];
46
+ if (typeof msg.content === "string") {
47
+ results.push({ role: "user", content: msg.content });
48
+ }
49
+ else if (Array.isArray(msg.content)) {
50
+ const textParts = [];
51
+ const toolResults = [];
52
+ for (const block of msg.content) {
53
+ const typed = block;
54
+ if (typed.type === "text") {
55
+ textParts.push(typed.text);
56
+ }
57
+ else if (typed.type === "tool_result") {
58
+ let resultContent;
59
+ if (typeof typed.content === "string") {
60
+ resultContent = typed.content;
61
+ }
62
+ else if (Array.isArray(typed.content)) {
63
+ resultContent = typed.content
64
+ .filter((b) => b.type === "text")
65
+ .map((b) => b.text)
66
+ .join("");
67
+ }
68
+ else {
69
+ resultContent = "";
70
+ }
71
+ toolResults.push({ tool_use_id: typed.tool_use_id, content: resultContent });
72
+ }
73
+ }
74
+ if (textParts.length > 0) {
75
+ results.push({ role: "user", content: textParts.join("\n") });
76
+ }
77
+ for (const tr of toolResults) {
78
+ results.push({ role: "tool", content: tr.content, tool_call_id: tr.tool_use_id });
79
+ }
80
+ }
81
+ return results;
82
+ }
83
+ /**
84
+ * Anthropic assistant messages may contain tool_use content blocks.
85
+ * These map to OpenAI tool_calls on the assistant message.
86
+ */
87
+ function convertAssistantMessage(msg) {
88
+ const result = { role: "assistant", content: null };
89
+ if (typeof msg.content === "string") {
90
+ result.content = msg.content;
91
+ }
92
+ else if (Array.isArray(msg.content)) {
93
+ const textParts = [];
94
+ const toolCalls = [];
95
+ for (const block of msg.content) {
96
+ const typed = block;
97
+ if (typed.type === "text") {
98
+ textParts.push(typed.text);
99
+ }
100
+ else if (typed.type === "tool_use") {
101
+ let args;
102
+ try {
103
+ args = JSON.stringify(typed.input);
104
+ }
105
+ catch {
106
+ args = "{}";
107
+ }
108
+ toolCalls.push({
109
+ id: typed.id,
110
+ type: "function",
111
+ function: { name: typed.name, arguments: args },
112
+ });
113
+ }
114
+ }
115
+ result.content = textParts.length > 0 ? textParts.join("\n") : null;
116
+ if (toolCalls.length > 0) {
117
+ result.tool_calls = toolCalls;
118
+ }
119
+ }
120
+ return result;
121
+ }
122
+ //# sourceMappingURL=anthropic-to-openai-request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic-to-openai-request.js","sourceRoot":"","sources":["../../src/protocol/anthropic-to-openai-request.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function convertAnthropicToOpenAIResponse(anthropicResp: any, model: string): any;
2
+ //# sourceMappingURL=anthropic-to-openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic-to-openai.d.ts","sourceRoot":"","sources":["../../src/protocol/anthropic-to-openai.ts"],"names":[],"mappings":"AAAA,wBAAgB,gCAAgC,CAC9C,aAAa,EAAE,GAAG,EAClB,KAAK,EAAE,MAAM,GACZ,GAAG,CAoBL"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertAnthropicToOpenAIResponse = convertAnthropicToOpenAIResponse;
4
+ function convertAnthropicToOpenAIResponse(anthropicResp, model) {
5
+ return {
6
+ id: anthropicResp.id ?? "chatcmpl-agentfare",
7
+ object: "chat.completion",
8
+ model,
9
+ choices: [{
10
+ index: 0,
11
+ message: {
12
+ role: "assistant",
13
+ content: extractTextContent(anthropicResp.content),
14
+ tool_calls: extractToolCalls(anthropicResp.content),
15
+ },
16
+ finish_reason: mapFinishReason(anthropicResp.stop_reason),
17
+ }],
18
+ usage: {
19
+ prompt_tokens: anthropicResp.usage?.input_tokens ?? 0,
20
+ completion_tokens: anthropicResp.usage?.output_tokens ?? 0,
21
+ total_tokens: (anthropicResp.usage?.input_tokens ?? 0) + (anthropicResp.usage?.output_tokens ?? 0),
22
+ },
23
+ };
24
+ }
25
+ function extractTextContent(content) {
26
+ if (!Array.isArray(content))
27
+ return "";
28
+ return content.filter((b) => b.type === "text").map((b) => b.text).join("");
29
+ }
30
+ function extractToolCalls(content) {
31
+ if (!Array.isArray(content))
32
+ return undefined;
33
+ const toolUses = content.filter((b) => b.type === "tool_use");
34
+ if (toolUses.length === 0)
35
+ return undefined;
36
+ return toolUses.map((tu, i) => ({
37
+ id: tu.id,
38
+ type: "function",
39
+ function: { name: tu.name, arguments: JSON.stringify(tu.input) },
40
+ }));
41
+ }
42
+ function mapFinishReason(reason) {
43
+ switch (reason) {
44
+ case "end_turn": return "stop";
45
+ case "max_tokens": return "length";
46
+ case "stop_sequence": return "stop";
47
+ case "tool_use": return "tool_calls";
48
+ default: return "stop";
49
+ }
50
+ }
51
+ //# sourceMappingURL=anthropic-to-openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic-to-openai.js","sourceRoot":"","sources":["../../src/protocol/anthropic-to-openai.ts"],"names":[],"mappings":";;AAAA,4EAuBC;AAvBD,SAAgB,gCAAgC,CAC9C,aAAkB,EAClB,KAAa;IAEb,OAAO;QACL,EAAE,EAAE,aAAa,CAAC,EAAE,IAAI,oBAAoB;QAC5C,MAAM,EAAE,iBAAiB;QACzB,KAAK;QACL,OAAO,EAAE,CAAC;gBACR,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE;oBACP,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,kBAAkB,CAAC,aAAa,CAAC,OAAO,CAAC;oBAClD,UAAU,EAAE,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC;iBACpD;gBACD,aAAa,EAAE,eAAe,CAAC,aAAa,CAAC,WAAW,CAAC;aAC1D,CAAC;QACF,KAAK,EAAE;YACL,aAAa,EAAE,aAAa,CAAC,KAAK,EAAE,YAAY,IAAI,CAAC;YACrD,iBAAiB,EAAE,aAAa,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC;YAC1D,YAAY,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC,CAAC;SACnG;KACF,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAc;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IACvC,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxF,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAc;IACtC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;IACnE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5C,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAO,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC;QAC3C,EAAE,EAAE,EAAE,CAAC,EAAE;QACT,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE;KACjE,CAAC,CAAC,CAAC;AACN,CAAC;AAED,SAAS,eAAe,CAAC,MAA0B;IACjD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,UAAU,CAAC,CAAC,OAAO,MAAM,CAAC;QAC/B,KAAK,YAAY,CAAC,CAAC,OAAO,QAAQ,CAAC;QACnC,KAAK,eAAe,CAAC,CAAC,OAAO,MAAM,CAAC;QACpC,KAAK,UAAU,CAAC,CAAC,OAAO,YAAY,CAAC;QACrC,OAAO,CAAC,CAAC,OAAO,MAAM,CAAC;IACzB,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Convert an OpenAI chat completion response into Anthropic message format.
3
+ */
4
+ export declare function convertOpenAIToAnthropicResponse(openaiResp: any, model: string): any;
5
+ //# sourceMappingURL=openai-to-anthropic-response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-to-anthropic-response.d.ts","sourceRoot":"","sources":["../../src/protocol/openai-to-anthropic-response.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,CA6CpF"}