@sunflower0305/claude-proxy 1.1.0 → 1.1.1

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/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # claude-proxy
2
2
 
3
3
  [![CI](https://github.com/sunflower0305/claude-proxy/actions/workflows/ci.yml/badge.svg)](https://github.com/sunflower0305/claude-proxy/actions/workflows/ci.yml)
4
+ [![CD](https://github.com/sunflower0305/claude-proxy/actions/workflows/cd.yml/badge.svg)](https://github.com/sunflower0305/claude-proxy/actions/workflows/cd.yml)
4
5
  [![Coverage Status](https://coveralls.io/repos/github/sunflower0305/claude-proxy/badge.svg?branch=master)](https://coveralls.io/github/sunflower0305/claude-proxy?branch=master)
5
6
  [![npm version](https://img.shields.io/npm/v/%40sunflower0305%2Fclaude-proxy)](https://www.npmjs.com/package/@sunflower0305/claude-proxy)
6
7
  [![License](https://img.shields.io/github/license/sunflower0305/claude-proxy)](https://github.com/sunflower0305/claude-proxy/blob/master/LICENSE)
@@ -39,17 +40,17 @@ QWEN_MODEL=qwen-plus
39
40
 
40
41
  Available variables:
41
42
 
42
- | Variable | Purpose |
43
- | --- | --- |
44
- | `PROVIDER` | Active provider. Defaults to `qwen`. |
45
- | `PROXY_PORT` | Local server port. Defaults to `8080`. |
46
- | `QWEN_API_KEY` | API key for Qwen. |
47
- | `DEEPSEEK_API_KEY` | API key for DeepSeek. |
48
- | `GLM_API_KEY` | API key for GLM. |
49
- | `MINIMAX_API_KEY` | API key for MiniMax. |
50
- | `KIMI_API_KEY` | API key for Kimi. |
43
+ | Variable | Purpose |
44
+ | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
45
+ | `PROVIDER` | Active provider. Defaults to `qwen`. |
46
+ | `PROXY_PORT` | Local server port. Defaults to `8080`. |
47
+ | `QWEN_API_KEY` | API key for Qwen. |
48
+ | `DEEPSEEK_API_KEY` | API key for DeepSeek. |
49
+ | `GLM_API_KEY` | API key for GLM. |
50
+ | `MINIMAX_API_KEY` | API key for MiniMax. |
51
+ | `KIMI_API_KEY` | API key for Kimi. |
51
52
  | `QWEN_ANTHROPIC_BASE_URL`, `DEEPSEEK_ANTHROPIC_BASE_URL`, `GLM_ANTHROPIC_BASE_URL`, `MINIMAX_ANTHROPIC_BASE_URL`, `KIMI_ANTHROPIC_BASE_URL` | Override the upstream Anthropic-compatible base URL for a provider. |
52
- | `QWEN_MODEL`, `DEEPSEEK_MODEL`, `GLM_MODEL`, `MINIMAX_MODEL`, `KIMI_MODEL` | Override the default upstream model for a provider. |
53
+ | `QWEN_MODEL`, `DEEPSEEK_MODEL`, `GLM_MODEL`, `MINIMAX_MODEL`, `KIMI_MODEL` | Override the default upstream model for a provider. |
53
54
 
54
55
  You can use the bundled example as a starting point:
55
56
 
@@ -87,12 +88,12 @@ const client = new Anthropic({
87
88
 
88
89
  ## Runtime Endpoints
89
90
 
90
- | Method | Path | Description |
91
- | --- | --- | --- |
92
- | `POST` | `/v1/messages` | Main Anthropic Messages API proxy endpoint |
93
- | `GET` | `/v1/models` | Lists supported Claude-facing model ids |
94
- | `GET` | `/health` | Health check |
95
- | `GET` / `POST` | `/api/provider` | Read or switch the active provider |
91
+ | Method | Path | Description |
92
+ | -------------- | --------------- | ------------------------------------------ |
93
+ | `POST` | `/v1/messages` | Main Anthropic Messages API proxy endpoint |
94
+ | `GET` | `/v1/models` | Lists supported Claude-facing model ids |
95
+ | `GET` | `/health` | Health check |
96
+ | `GET` / `POST` | `/api/provider` | Read or switch the active provider |
96
97
 
97
98
  Health check:
98
99
 
@@ -121,20 +122,21 @@ app.listen(8080);
121
122
 
122
123
  ## Release Verification
123
124
 
124
- `v1.0.0` was verified on April 15, 2026 after publishing `@sunflower0305/claude-proxy` to npm.
125
+ `v1.1.0` was verified on April 21, 2026 after publishing `@sunflower0305/claude-proxy` to npm.
125
126
 
126
127
  Verified items:
127
128
 
129
+ - `npm view @sunflower0305/claude-proxy version dist-tags --json` confirmed `version: 1.1.0` and `latest: 1.1.0`
128
130
  - `npm install @sunflower0305/claude-proxy` completed successfully in a clean temporary directory
129
131
  - the published `claude-proxy` CLI started correctly from the installed package
130
132
  - `GET /health` and `GET /v1/models` returned `200 OK`
131
- - end-to-end proxying against a local mock Anthropic-compatible upstream passed for both non-streaming and streaming `POST /v1/messages`
132
- - end-to-end proxying against the real Qwen Anthropic-compatible upstream passed for both non-streaming and streaming `POST /v1/messages`
133
+ - local end-to-end proxying against a mock Anthropic-compatible upstream passed for both non-streaming and streaming `POST /v1/messages`
133
134
 
134
135
  Observed behavior during verification:
135
136
 
136
- - model remapping worked as expected, including `claude-sonnet-4-6 -> qwen-plus`
137
- - the real Qwen verification returned a valid assistant response for both buffered JSON and SSE streaming modes
137
+ - smoke-test startup succeeded with `PROVIDER=qwen`
138
+ - the published artifact returned the expected `health` payload with `provider: qwen` and `model: qwen-plus`
139
+ - the published artifact returned the expected Claude-facing model list from `GET /v1/models`
138
140
  - the published package included the expected CLI entrypoint, `dist/` build output, `README.md`, `LICENSE`, and `.env.example`
139
141
 
140
142
  ## Development
@@ -148,15 +150,32 @@ npm run dev
148
150
 
149
151
  ## CI And Releases
150
152
 
151
- GitHub Actions currently provides a CI baseline only:
153
+ GitHub Actions provides separate CI and CD workflows:
152
154
 
153
- - install dependencies with `pnpm`
154
- - run `npm run build`
155
- - run `npm run test:proxy-local`
156
- - run `npm run test:coverage`
157
- - upload `coverage/lcov.info` to Coveralls without blocking the workflow if the upload service is temporarily unavailable
155
+ - `CI` runs on branch pushes and pull requests
156
+ - `CD` runs when you push a `vX.Y.Z` tag and can also be re-run manually with `workflow_dispatch`
158
157
 
159
- Publishing to npm remains a manual step. The package still relies on `prepack` and `prepublishOnly` in `package.json` to build and verify the artifact before release.
158
+ The `CD` workflow:
159
+
160
+ - checks that the tag exactly matches `package.json.version`
161
+ - requires `docs/releases/<version>.md` to exist before publishing
162
+ - runs `npm run build`, `npm run test:proxy-local`, `npm run test:coverage`, and `npm pack --dry-run`
163
+ - fails fast if the npm version already exists
164
+ - publishes the package to npm using the `NPM_TOKEN` repository secret
165
+ - creates or updates the GitHub Release from `docs/releases/<version>.md`
166
+
167
+ Required repository secret:
168
+
169
+ - `NPM_TOKEN`: npm automation token with permission to publish `@sunflower0305/claude-proxy`
170
+
171
+ Release flow:
172
+
173
+ 1. bump `package.json`, `CHANGELOG.md`, and `docs/releases/<version>.md`
174
+ 2. commit the release prep
175
+ 3. create and push the matching `vX.Y.Z` tag
176
+ 4. let the `CD` workflow publish npm and GitHub Release
177
+
178
+ The package still relies on `prepack` and `prepublishOnly` in `package.json` to build and verify the artifact before release.
160
179
 
161
180
  Build and local package verification:
162
181
 
@@ -171,7 +190,7 @@ Local integration test:
171
190
  npm run test:proxy-local
172
191
  ```
173
192
 
174
- Release notes for `v1.0.0` are available in [docs/releases/1.0.0.md](/Users/joe/ai/claude-proxy/docs/releases/1.0.0.md).
193
+ Release notes for `v1.1.0` are available in [docs/releases/1.1.0.md](docs/releases/1.1.0.md).
175
194
 
176
195
  ## License
177
196
 
package/dist/proxy.js CHANGED
@@ -338,7 +338,7 @@ export function createApp() {
338
338
  app.get("/v1/models", (_req, res) => {
339
339
  res.json({
340
340
  data: [
341
- { id: "claude-opus-4-6", object: "model" },
341
+ { id: "claude-opus-4-7", object: "model" },
342
342
  { id: "claude-sonnet-4-6", object: "model" },
343
343
  { id: "claude-haiku-4-5", object: "model" },
344
344
  ],
@@ -406,13 +406,13 @@ if (isMainModule()) {
406
406
  app.listen(PORT, () => {
407
407
  console.log(`
408
408
  ╔═══════════════════════════════════════════════════════╗
409
- claude-proxy
409
+ claude-proxy
410
410
  ╠═══════════════════════════════════════════════════════╣
411
- ║ http://localhost:${PORT}
412
- ║ Backend: ${initialProvider} (${initialConfig.model})
411
+ ║ http://localhost:${PORT}
412
+ ║ Backend: ${initialProvider} (${initialConfig.model})
413
413
  ╠═══════════════════════════════════════════════════════╣
414
414
  ║ Set these env vars in your app: ║
415
- ║ ANTHROPIC_BASE_URL=http://localhost:${PORT}
415
+ ║ ANTHROPIC_BASE_URL=http://localhost:${PORT}
416
416
  ║ ANTHROPIC_API_KEY=any-string-works ║
417
417
  ╚═══════════════════════════════════════════════════════╝
418
418
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sunflower0305/claude-proxy",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "type": "module",
5
5
  "description": "A proxy that lets Claude Agent SDK use domestic Chinese LLMs (DeepSeek, Qwen, GLM, MiniMax) as backend",
6
6
  "license": "MIT",
package/dist/app.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import express from "express";
2
- import { type ProxyRuntime } from "./runtime";
3
- export declare function createApp(runtime?: ProxyRuntime): express.Express;
package/dist/app.js DELETED
@@ -1,79 +0,0 @@
1
- import cors from "cors";
2
- import express from "express";
3
- import { handleMessagesRequest } from "./messages";
4
- import { isProviderKey } from "./providers";
5
- import { createRuntime } from "./runtime";
6
- const SUPPORTED_MODELS = [
7
- { id: "claude-opus-4-6", object: "model" },
8
- { id: "claude-sonnet-4-6", object: "model" },
9
- { id: "claude-haiku-4-5", object: "model" },
10
- ];
11
- export function createApp(runtime = createRuntime()) {
12
- const app = express();
13
- app.use(cors());
14
- app.use(express.json({ limit: "50mb" }));
15
- app.get("/", (_req, res) => {
16
- const config = runtime.getCurrentConfig();
17
- res.json({
18
- name: "claude-proxy",
19
- status: "running",
20
- provider: runtime.getCurrentProvider(),
21
- model: config.model,
22
- endpoints: {
23
- messages: "POST /v1/messages",
24
- health: "GET /health",
25
- models: "GET /v1/models",
26
- provider: "GET|POST /api/provider",
27
- },
28
- });
29
- });
30
- app.post("/v1/messages", async (req, res) => {
31
- await handleMessagesRequest(req, res, runtime);
32
- });
33
- app.get("/health", (_req, res) => {
34
- const config = runtime.getCurrentConfig();
35
- res.json({
36
- status: "ok",
37
- provider: runtime.getCurrentProvider(),
38
- model: config.model,
39
- });
40
- });
41
- app.get("/v1/models", (_req, res) => {
42
- res.json({ data: SUPPORTED_MODELS });
43
- });
44
- app.get("/api/provider", (_req, res) => {
45
- const config = runtime.getCurrentConfig();
46
- res.json({
47
- provider: runtime.getCurrentProvider(),
48
- model: config.model,
49
- baseUrl: config.baseUrl,
50
- availableProviders: [...runtime.providerKeys],
51
- });
52
- });
53
- app.post("/api/provider", (req, res) => {
54
- const { provider, model } = (req.body ?? {});
55
- const targetProvider = provider ?? runtime.inferProviderFromModel(model);
56
- if (!isProviderKey(targetProvider)) {
57
- res.status(400).json({
58
- error: `Unknown provider: ${targetProvider}`,
59
- available: [...runtime.providerKeys],
60
- });
61
- return;
62
- }
63
- const targetConfig = runtime.getConfig(targetProvider);
64
- if (!targetConfig.apiKey) {
65
- res.status(400).json({
66
- error: `API key not set for: ${targetProvider}`,
67
- });
68
- return;
69
- }
70
- const switchResult = runtime.setCurrentProvider(targetProvider);
71
- console.log(`Provider: ${switchResult.previousProvider} -> ${switchResult.provider}`);
72
- res.json({
73
- success: true,
74
- provider: switchResult.provider,
75
- model: switchResult.config.model,
76
- });
77
- });
78
- return app;
79
- }
@@ -1,3 +0,0 @@
1
- import type express from "express";
2
- import type { ProxyRuntime } from "./runtime";
3
- export declare function handleMessagesRequest(req: express.Request, res: express.Response, runtime: ProxyRuntime): Promise<void>;
package/dist/messages.js DELETED
@@ -1,221 +0,0 @@
1
- import { Readable } from "node:stream";
2
- const DEFAULT_ANTHROPIC_VERSION = "2023-06-01";
3
- const HOP_BY_HOP_RESPONSE_HEADERS = new Set([
4
- "connection",
5
- "content-encoding",
6
- "content-length",
7
- "keep-alive",
8
- "proxy-authenticate",
9
- "proxy-authorization",
10
- "te",
11
- "trailer",
12
- "transfer-encoding",
13
- "upgrade",
14
- ]);
15
- function getHeaderValue(value) {
16
- if (Array.isArray(value))
17
- return value.join(",");
18
- return value;
19
- }
20
- function buildUpstreamHeaders(req, stream, apiKey) {
21
- const headers = {
22
- "content-type": "application/json",
23
- "x-api-key": apiKey,
24
- "anthropic-version": getHeaderValue(req.headers["anthropic-version"]) ||
25
- DEFAULT_ANTHROPIC_VERSION,
26
- accept: getHeaderValue(req.headers.accept) ||
27
- (stream ? "text/event-stream" : "application/json"),
28
- };
29
- const anthropicBeta = getHeaderValue(req.headers["anthropic-beta"]);
30
- if (anthropicBeta) {
31
- headers["anthropic-beta"] = anthropicBeta;
32
- }
33
- return headers;
34
- }
35
- function getUpstreamUrl(baseUrl) {
36
- return `${baseUrl.replace(/\/$/, "")}/v1/messages`;
37
- }
38
- function buildUpstreamBody(body, targetModel) {
39
- const normalized = typeof body === "object" && body !== null
40
- ? { ...body }
41
- : {};
42
- normalized.model = targetModel;
43
- return normalized;
44
- }
45
- function copyUpstreamHeaders(upstream, res) {
46
- for (const [key, value] of upstream.headers.entries()) {
47
- if (HOP_BY_HOP_RESPONSE_HEADERS.has(key.toLowerCase()))
48
- continue;
49
- res.setHeader(key, value);
50
- }
51
- }
52
- function createProxyError(message) {
53
- return {
54
- type: "error",
55
- error: {
56
- type: "internal_error",
57
- message,
58
- },
59
- };
60
- }
61
- function toErrorMessage(error) {
62
- if (error instanceof Error && error.message)
63
- return error.message;
64
- return String(error);
65
- }
66
- function logTimingEvent(trace, phase, extra = {}) {
67
- console.log(`[ProxyTiming] ${JSON.stringify({
68
- request_id: trace.requestId,
69
- provider: trace.provider,
70
- requested_model: trace.requestedModel,
71
- target_model: trace.targetModel,
72
- stream: trace.stream,
73
- phase,
74
- elapsed_ms: Date.now() - trace.startedAt,
75
- at: new Date().toISOString(),
76
- ...extra,
77
- })}`);
78
- }
79
- function prepareUpstreamRequest(req, runtime, stream) {
80
- const config = runtime.getCurrentConfig();
81
- const targetModel = runtime.getTargetModel(req.body?.model);
82
- return {
83
- apiKey: config.apiKey,
84
- providerModel: config.model,
85
- requestBody: buildUpstreamBody(req.body, targetModel),
86
- requestedModel: req.body?.model,
87
- targetModel,
88
- trace: runtime.createRequestTrace(req.body?.model, targetModel, stream),
89
- upstreamUrl: getUpstreamUrl(config.baseUrl),
90
- };
91
- }
92
- async function handleNonStreamingRequest(req, res, runtime) {
93
- const prepared = prepareUpstreamRequest(req, runtime, false);
94
- console.log(`\n[${new Date().toISOString()}] ${String(prepared.requestedModel || prepared.providerModel)} -> ${prepared.targetModel} (non-streaming)`);
95
- logTimingEvent(prepared.trace, "start");
96
- try {
97
- const upstream = await fetch(prepared.upstreamUrl, {
98
- method: "POST",
99
- headers: buildUpstreamHeaders(req, false, prepared.apiKey),
100
- body: JSON.stringify(prepared.requestBody),
101
- });
102
- logTimingEvent(prepared.trace, "upstream_headers", {
103
- status: upstream.status,
104
- content_type: upstream.headers.get("content-type") || "",
105
- });
106
- const payload = Buffer.from(await upstream.arrayBuffer());
107
- copyUpstreamHeaders(upstream, res);
108
- res.status(upstream.status).send(payload);
109
- logTimingEvent(prepared.trace, "completed", {
110
- status: upstream.status,
111
- bytes: payload.byteLength,
112
- });
113
- }
114
- catch (error) {
115
- const message = toErrorMessage(error);
116
- console.error("Request error:", error);
117
- logTimingEvent(prepared.trace, "error", { message });
118
- res.status(500).json(createProxyError(message));
119
- }
120
- }
121
- async function handleStreamingRequest(req, res, runtime) {
122
- const prepared = prepareUpstreamRequest(req, runtime, true);
123
- const abortController = new AbortController();
124
- let clientClosed = false;
125
- let streamCompleted = false;
126
- let sawFirstChunk = false;
127
- console.log(`\n[${new Date().toISOString()}] ${String(prepared.requestedModel || prepared.providerModel)} -> ${prepared.targetModel} (streaming)`);
128
- logTimingEvent(prepared.trace, "start");
129
- res.on("close", () => {
130
- if (streamCompleted)
131
- return;
132
- clientClosed = true;
133
- abortController.abort();
134
- logTimingEvent(prepared.trace, "client_aborted");
135
- });
136
- try {
137
- const upstream = await fetch(prepared.upstreamUrl, {
138
- method: "POST",
139
- headers: buildUpstreamHeaders(req, true, prepared.apiKey),
140
- body: JSON.stringify(prepared.requestBody),
141
- signal: abortController.signal,
142
- });
143
- logTimingEvent(prepared.trace, "upstream_headers", {
144
- status: upstream.status,
145
- content_type: upstream.headers.get("content-type") || "",
146
- });
147
- copyUpstreamHeaders(upstream, res);
148
- res.status(upstream.status);
149
- if (!upstream.body) {
150
- streamCompleted = true;
151
- res.end();
152
- logTimingEvent(prepared.trace, "completed", {
153
- status: upstream.status,
154
- bytes: 0,
155
- no_body: true,
156
- });
157
- return;
158
- }
159
- const upstreamStream = Readable.fromWeb(upstream.body);
160
- upstreamStream.on("data", (chunk) => {
161
- if (sawFirstChunk)
162
- return;
163
- sawFirstChunk = true;
164
- const chunkSize = Buffer.isBuffer(chunk)
165
- ? chunk.byteLength
166
- : Buffer.byteLength(String(chunk));
167
- logTimingEvent(prepared.trace, "first_chunk", {
168
- status: upstream.status,
169
- chunk_bytes: chunkSize,
170
- });
171
- });
172
- upstreamStream.on("error", (error) => {
173
- if (clientClosed)
174
- return;
175
- console.error("Upstream stream error:", error);
176
- logTimingEvent(prepared.trace, "error", {
177
- status: upstream.status,
178
- message: toErrorMessage(error),
179
- });
180
- if (!res.writableEnded)
181
- res.end();
182
- });
183
- upstreamStream.pipe(res);
184
- await new Promise((resolve, reject) => {
185
- upstreamStream.on("end", () => {
186
- streamCompleted = true;
187
- logTimingEvent(prepared.trace, "completed", {
188
- status: upstream.status,
189
- });
190
- resolve();
191
- });
192
- upstreamStream.on("error", reject);
193
- res.on("close", () => resolve());
194
- });
195
- }
196
- catch (error) {
197
- const wasAborted = error instanceof Error && error.name === "AbortError"
198
- ? true
199
- : abortController.signal.aborted;
200
- if (clientClosed || wasAborted) {
201
- console.warn("[Proxy] Client disconnected, streaming aborted");
202
- return;
203
- }
204
- const message = toErrorMessage(error);
205
- console.error("Request error:", error);
206
- logTimingEvent(prepared.trace, "error", { message });
207
- if (!res.headersSent) {
208
- res.status(500).json(createProxyError(message));
209
- return;
210
- }
211
- if (!res.writableEnded)
212
- res.end();
213
- }
214
- }
215
- export async function handleMessagesRequest(req, res, runtime) {
216
- if (req.body?.stream) {
217
- await handleStreamingRequest(req, res, runtime);
218
- return;
219
- }
220
- await handleNonStreamingRequest(req, res, runtime);
221
- }
@@ -1,11 +0,0 @@
1
- export interface ProviderConfig {
2
- baseUrl: string;
3
- apiKey: string;
4
- model: string;
5
- }
6
- export declare const PROVIDER_KEYS: readonly ["deepseek", "qwen", "glm", "minimax", "kimi"];
7
- export type ProviderKey = (typeof PROVIDER_KEYS)[number];
8
- export type ProviderMap = Record<ProviderKey, ProviderConfig>;
9
- export declare const DEFAULT_PROVIDER: ProviderKey;
10
- export declare function isProviderKey(value: string | undefined): value is ProviderKey;
11
- export declare function loadProviders(env?: NodeJS.ProcessEnv): ProviderMap;
package/dist/providers.js DELETED
@@ -1,53 +0,0 @@
1
- export const PROVIDER_KEYS = [
2
- "deepseek",
3
- "qwen",
4
- "glm",
5
- "minimax",
6
- "kimi",
7
- ];
8
- export const DEFAULT_PROVIDER = "qwen";
9
- function pickEnv(env, ...keys) {
10
- for (const key of keys) {
11
- const value = env[key]?.trim();
12
- if (value)
13
- return value;
14
- }
15
- return undefined;
16
- }
17
- export function isProviderKey(value) {
18
- return Boolean(value && PROVIDER_KEYS.includes(value));
19
- }
20
- export function loadProviders(env = process.env) {
21
- return {
22
- deepseek: {
23
- baseUrl: pickEnv(env, "DEEPSEEK_ANTHROPIC_BASE_URL") ||
24
- "https://api.deepseek.com/anthropic",
25
- apiKey: env.DEEPSEEK_API_KEY || "",
26
- model: pickEnv(env, "DEEPSEEK_MODEL") || "deepseek-chat",
27
- },
28
- qwen: {
29
- baseUrl: pickEnv(env, "QWEN_ANTHROPIC_BASE_URL") ||
30
- "https://dashscope.aliyuncs.com/apps/anthropic",
31
- apiKey: env.QWEN_API_KEY || "",
32
- model: pickEnv(env, "QWEN_MODEL") || "qwen-plus",
33
- },
34
- glm: {
35
- baseUrl: pickEnv(env, "GLM_ANTHROPIC_BASE_URL") ||
36
- "https://open.bigmodel.cn/api/anthropic",
37
- apiKey: env.GLM_API_KEY || "",
38
- model: pickEnv(env, "GLM_MODEL") || "glm-5",
39
- },
40
- minimax: {
41
- baseUrl: pickEnv(env, "MINIMAX_ANTHROPIC_BASE_URL") ||
42
- "https://api.minimaxi.com/anthropic",
43
- apiKey: env.MINIMAX_API_KEY || "",
44
- model: pickEnv(env, "MINIMAX_MODEL") || "MiniMax-M2.7-highspeed",
45
- },
46
- kimi: {
47
- baseUrl: pickEnv(env, "KIMI_ANTHROPIC_BASE_URL") ||
48
- "https://api.moonshot.cn/anthropic",
49
- apiKey: env.KIMI_API_KEY || "",
50
- model: pickEnv(env, "KIMI_MODEL") || "kimi-k2.5",
51
- },
52
- };
53
- }
package/dist/runtime.d.ts DELETED
@@ -1,27 +0,0 @@
1
- import { type ProviderConfig, type ProviderKey, type ProviderMap } from "./providers";
2
- export interface RequestTrace {
3
- requestId: string;
4
- provider: ProviderKey;
5
- requestedModel: string;
6
- targetModel: string;
7
- stream: boolean;
8
- startedAt: number;
9
- }
10
- export interface ProxyRuntime {
11
- readonly providerKeys: readonly ProviderKey[];
12
- getCurrentProvider(): ProviderKey;
13
- getCurrentConfig(): ProviderConfig;
14
- getConfig(provider?: ProviderKey): ProviderConfig;
15
- getTargetModel(requestedModel: unknown): string;
16
- inferProviderFromModel(model: string | undefined): ProviderKey | undefined;
17
- setCurrentProvider(provider: ProviderKey): {
18
- previousProvider: ProviderKey;
19
- provider: ProviderKey;
20
- config: ProviderConfig;
21
- };
22
- createRequestTrace(requestedModel: unknown, targetModel: string, stream: boolean): RequestTrace;
23
- getStartupWarning(): string | undefined;
24
- }
25
- export declare function resolveTargetModel(requestedModel: unknown, currentModel: string): string;
26
- export declare function inferProviderFromModel(model: string | undefined): ProviderKey | undefined;
27
- export declare function createRuntime(env?: NodeJS.ProcessEnv, providers?: ProviderMap): ProxyRuntime;
package/dist/runtime.js DELETED
@@ -1,83 +0,0 @@
1
- import { DEFAULT_PROVIDER, PROVIDER_KEYS, isProviderKey, loadProviders, } from "./providers";
2
- export function resolveTargetModel(requestedModel, currentModel) {
3
- if (typeof requestedModel !== "string" || !requestedModel) {
4
- return currentModel;
5
- }
6
- const normalizedModel = requestedModel.toLowerCase();
7
- if (normalizedModel === "opus" ||
8
- normalizedModel === "sonnet" ||
9
- normalizedModel === "haiku") {
10
- return currentModel;
11
- }
12
- if (normalizedModel.startsWith("claude-") &&
13
- (normalizedModel.includes("-opus") ||
14
- normalizedModel.includes("-sonnet") ||
15
- normalizedModel.includes("-haiku"))) {
16
- return currentModel;
17
- }
18
- return requestedModel;
19
- }
20
- export function inferProviderFromModel(model) {
21
- const normalizedModel = model?.toLowerCase();
22
- if (!normalizedModel)
23
- return undefined;
24
- if (normalizedModel.includes("kimi"))
25
- return "kimi";
26
- if (normalizedModel.includes("qwen"))
27
- return "qwen";
28
- if (normalizedModel.includes("deepseek"))
29
- return "deepseek";
30
- if (normalizedModel.includes("glm"))
31
- return "glm";
32
- if (normalizedModel.includes("minimax"))
33
- return "minimax";
34
- return undefined;
35
- }
36
- export function createRuntime(env = process.env, providers = loadProviders(env)) {
37
- let currentProvider = isProviderKey(env.PROVIDER)
38
- ? env.PROVIDER
39
- : DEFAULT_PROVIDER;
40
- let requestSequence = 0;
41
- function getConfig(provider = currentProvider) {
42
- return providers[provider] || providers[DEFAULT_PROVIDER];
43
- }
44
- return {
45
- providerKeys: PROVIDER_KEYS,
46
- getCurrentProvider() {
47
- return currentProvider;
48
- },
49
- getCurrentConfig() {
50
- return getConfig();
51
- },
52
- getConfig,
53
- getTargetModel(requestedModel) {
54
- return resolveTargetModel(requestedModel, getConfig().model);
55
- },
56
- inferProviderFromModel,
57
- setCurrentProvider(provider) {
58
- const previousProvider = currentProvider;
59
- currentProvider = provider;
60
- return {
61
- previousProvider,
62
- provider: currentProvider,
63
- config: getConfig(),
64
- };
65
- },
66
- createRequestTrace(requestedModel, targetModel, stream) {
67
- const config = getConfig();
68
- return {
69
- requestId: `req-${++requestSequence}`,
70
- provider: currentProvider,
71
- requestedModel: String(requestedModel || config.model),
72
- targetModel,
73
- stream,
74
- startedAt: Date.now(),
75
- };
76
- },
77
- getStartupWarning() {
78
- if (getConfig().apiKey)
79
- return undefined;
80
- return `Warning: API key not configured for provider: ${currentProvider}`;
81
- },
82
- };
83
- }