anthropic-gateway 1.3.0 → 1.4.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/README.md +18 -6
- package/cli.js +175 -10
- package/config.example.json +46 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ Open a **new** terminal after installing so PATH picks it up.
|
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
32
|
anthropic-gateway setup # interactive wizard (or flags, see below)
|
|
33
|
-
anthropic-gateway start # run the gateway
|
|
33
|
+
anthropic-gateway start # run the gateway using the default profile
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
Config, pid and log live in `~/.anthropic-gateway/` (`config.json`,
|
|
@@ -38,7 +38,7 @@ Config, pid and log live in `~/.anthropic-gateway/` (`config.json`,
|
|
|
38
38
|
|
|
39
39
|
Then point your client at:
|
|
40
40
|
|
|
41
|
-
- Base URL: `http://127.0.0.1:3080`
|
|
41
|
+
- Base URL: `http://127.0.0.1:3080` (or the port you configured)
|
|
42
42
|
- API key / `x-api-key` / `Authorization: Bearer`: the **proxy token** printed by `setup`
|
|
43
43
|
|
|
44
44
|
### Non-interactive setup
|
|
@@ -48,24 +48,36 @@ anthropic-gateway setup --provider kilo --api-key YOUR_KILO_KEY --model kilo-aut
|
|
|
48
48
|
anthropic-gateway setup --base-url https://api.openai.com/v1 --api-key sk-... --model gpt-5 --port 3090 --token mytoken --yes
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
### Using multiple profiles
|
|
52
|
+
|
|
53
|
+
After setting up multiple profiles (e.g., one for kilo, one for OpenAI), you can:
|
|
54
|
+
|
|
55
|
+
- Start a specific profile: `anthropic-gateway start openai`
|
|
56
|
+
- Set the default profile for future `start` commands: `anthropic-gateway select kilo`
|
|
57
|
+
- Then `anthropic-gateway start` will use the kilo profile without specifying it.
|
|
58
|
+
|
|
51
59
|
## Commands
|
|
52
60
|
|
|
53
61
|
| Command | Description |
|
|
54
62
|
| --- | --- |
|
|
55
|
-
| `anthropic-gateway setup` | Create/overwrite `~/.anthropic-gateway/config.json
|
|
56
|
-
| `anthropic-gateway start` | Start the gateway |
|
|
63
|
+
| `anthropic-gateway setup` | Create/overwrite `~/.anthropic-gateway/config.json` with a profiles array; tests connectivity (`--full-logging` to enable full-body logging) |
|
|
64
|
+
| `anthropic-gateway start [profile]` | Start the gateway using the given profile name; if omitted, uses `defaultProfile` from config |
|
|
57
65
|
| `anthropic-gateway stop` | Stop the gateway |
|
|
58
66
|
| `anthropic-gateway status` | Pretty status: version, pid, upstream, uptime, request/token totals, full-logging state |
|
|
59
67
|
| `anthropic-gateway fulllogging on\|off` | Toggle full request/response logging (restart to apply) |
|
|
60
68
|
| `anthropic-gateway autostart on\|off` | Launch at Windows logon (Startup folder) |
|
|
69
|
+
| `anthropic-gateway select <profile>` | Set the default profile for future `start` commands |
|
|
61
70
|
| `anthropic-gateway version` | Print the version (also `--version` / `-v`) |
|
|
62
71
|
|
|
63
72
|
## config.json
|
|
64
73
|
|
|
65
|
-
See `config.example.json`.
|
|
74
|
+
See `config.example.json`. The config now contains a `profiles` array and a `defaultProfile`.
|
|
75
|
+
Each profile object includes: `providerName`, `upstreamBaseUrl`, `upstreamApiKey`,
|
|
66
76
|
`upstreamModel`, `port`, `proxyTokens` (accepts several), `advertisedModels`
|
|
67
77
|
(models shown to Claude Code model discovery — must look Anthropic-ish, e.g.
|
|
68
|
-
`claude-sonnet-4-5` or `sonnet`), `toolFormat`, `fullLogging`.
|
|
78
|
+
`claude-sonnet-4-5` or `sonnet`), `toolFormat`, `fullLogging`, `logFile`.
|
|
79
|
+
Only the profile named by `defaultProfile` (or the first profile if unspecified)
|
|
80
|
+
is used by `anthropic-gateway start` unless a profile name is given explicitly.
|
|
69
81
|
|
|
70
82
|
## Logging
|
|
71
83
|
|
package/cli.js
CHANGED
|
@@ -80,9 +80,31 @@ function randomToken() {
|
|
|
80
80
|
return 'ag-' + require('crypto').randomBytes(24).toString('base64url');
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Load the top-level config and return the selected profile object merged with
|
|
85
|
+
* defaults. If `profileName` is omitted, `defaultProfile` in the config is used;
|
|
86
|
+
* if none/defaultProfile points at a non-existent one, the first profile wins.
|
|
87
|
+
*/
|
|
88
|
+
function loadProfile(cfgPath, profileName) {
|
|
89
|
+
if (!fs.existsSync(cfgPath)) fail('no config at ' + cfgPath + ' — run "anthropic-gateway setup" first');
|
|
90
|
+
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
91
|
+
|
|
92
|
+
// Backwards compatibility: old single-profile config.json (flat fields).
|
|
93
|
+
if (Array.isArray(cfg.profiles) && cfg.profiles.length > 0) {
|
|
94
|
+
const profiles = cfg.profiles;
|
|
95
|
+
if (!profileName) profileName = cfg.defaultProfile;
|
|
96
|
+
let idx;
|
|
97
|
+
if (profileName) {
|
|
98
|
+
idx = profiles.findIndex((p) => p.providerName === profileName);
|
|
99
|
+
if (idx === -1) fail('profile "' + profileName + '" not found in ' + cfgPath + ' (available: ' + profiles.map((p) => p.providerName).join(', ') + ')');
|
|
100
|
+
} else {
|
|
101
|
+
idx = 0; // first profile is the default when none specified
|
|
102
|
+
}
|
|
103
|
+
return { ...profiles[idx], _profiles: profiles, _configPath: cfgPath, _defaultProfile: cfg.defaultProfile };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Legacy flat config
|
|
107
|
+
return { ...cfg, _profiles: null, _configPath: cfgPath, _defaultProfile: undefined };
|
|
86
108
|
}
|
|
87
109
|
|
|
88
110
|
async function testUpstream(baseUrl, apiKey, model) {
|
|
@@ -145,7 +167,47 @@ async function cmdSetup(args) {
|
|
|
145
167
|
const advertisedModels = adv.split(',').map((s) => s.trim()).filter(Boolean);
|
|
146
168
|
const fullLoggingFlag = args['full-logging'];
|
|
147
169
|
const fullLogging = fullLoggingFlag !== undefined && String(fullLoggingFlag) !== 'false';
|
|
148
|
-
|
|
170
|
+
|
|
171
|
+
// Load existing config if any
|
|
172
|
+
let existingConfig = null;
|
|
173
|
+
if (fs.existsSync(cfgPath)) {
|
|
174
|
+
try {
|
|
175
|
+
existingConfig = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
176
|
+
} catch (e) {
|
|
177
|
+
fail('failed to parse existing config at ' + cfgPath);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Determine if we are dealing with legacy flat config or new profiles format
|
|
182
|
+
const isLegacy = existingConfig && (!Array.isArray(existingConfig.profiles));
|
|
183
|
+
let profiles = [];
|
|
184
|
+
let defaultProfile = undefined;
|
|
185
|
+
|
|
186
|
+
if (isLegacy) {
|
|
187
|
+
// Convert legacy flat config to a profile
|
|
188
|
+
const legacyProfile = {
|
|
189
|
+
providerName: existingConfig.providerName || 'legacy',
|
|
190
|
+
upstreamBaseUrl: existingConfig.upstreamBaseUrl.replace(/\/+$/, ''),
|
|
191
|
+
upstreamApiKey: existingConfig.upstreamApiKey,
|
|
192
|
+
upstreamModel: existingConfig.upstreamModel,
|
|
193
|
+
port: existingConfig.port || 3080,
|
|
194
|
+
proxyTokens: Array.isArray(existingConfig.proxyTokens) ? existingConfig.proxyTokens : [existingConfig.proxyTokens],
|
|
195
|
+
toolFormat: existingConfig.toolFormat || 'native',
|
|
196
|
+
advertisedModels: Array.isArray(existingConfig.advertisedModels) ? existingConfig.advertisedModels : [],
|
|
197
|
+
fullLogging: !!existingConfig.fullLogging,
|
|
198
|
+
logFile: existingConfig.logFile || 'gateway.log',
|
|
199
|
+
};
|
|
200
|
+
profiles.push(legacyProfile);
|
|
201
|
+
defaultProfile = legacyProfile.providerName;
|
|
202
|
+
} else if (existingConfig) {
|
|
203
|
+
// Already in new format
|
|
204
|
+
profiles = Array.isArray(existingConfig.profiles) ? existingConfig.profiles : [];
|
|
205
|
+
defaultProfile = existingConfig.defaultProfile;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Find index of profile with same providerName as the one we are setting up
|
|
209
|
+
const profileIndex = profiles.findIndex(p => p.providerName === (preset.name || 'custom'));
|
|
210
|
+
const newProfile = {
|
|
149
211
|
providerName: preset.name || 'custom',
|
|
150
212
|
upstreamBaseUrl: baseUrl.replace(/\/+$/, ''),
|
|
151
213
|
upstreamApiKey: apiKey,
|
|
@@ -155,16 +217,34 @@ async function cmdSetup(args) {
|
|
|
155
217
|
toolFormat: 'native',
|
|
156
218
|
advertisedModels,
|
|
157
219
|
fullLogging,
|
|
158
|
-
logFile:
|
|
220
|
+
logFile: 'gateway.log',
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
if (profileIndex >= 0) {
|
|
224
|
+
// Update existing profile
|
|
225
|
+
profiles[profileIndex] = newProfile;
|
|
226
|
+
} else {
|
|
227
|
+
// Add new profile
|
|
228
|
+
profiles.push(newProfile);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// If defaultProfile is not set, set it to the providerName of the profile we just set up
|
|
232
|
+
if (!defaultProfile) {
|
|
233
|
+
defaultProfile = newProfile.providerName;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const configOut = {
|
|
237
|
+
defaultProfile,
|
|
238
|
+
profiles,
|
|
159
239
|
};
|
|
160
240
|
|
|
161
241
|
console.log('Testing upstream connectivity...');
|
|
162
|
-
const ok = await testUpstream(
|
|
242
|
+
const ok = await testUpstream(newProfile.upstreamBaseUrl, newProfile.upstreamApiKey, newProfile.upstreamModel);
|
|
163
243
|
if (!ok && !yes) {
|
|
164
244
|
const c = await ask(readline.createInterface({ input: process.stdin, output: process.stdout }), 'Connectivity test failed. Save anyway? (y/N):', 'N');
|
|
165
245
|
if (c.toLowerCase() !== 'y') fail('aborted — nothing written');
|
|
166
246
|
}
|
|
167
|
-
fs.writeFileSync(cfgPath, JSON.stringify(
|
|
247
|
+
fs.writeFileSync(cfgPath, JSON.stringify(configOut, null, 2));
|
|
168
248
|
console.log('Config written to ' + cfgPath);
|
|
169
249
|
console.log('Proxy token (use as API key / x-api-key / Bearer in the client): ' + token);
|
|
170
250
|
console.log('Next: anthropic-gateway start (or: anthropic-gateway autostart on)');
|
|
@@ -173,17 +253,49 @@ async function cmdSetup(args) {
|
|
|
173
253
|
async function cmdStart(args) {
|
|
174
254
|
ensureHomeDir();
|
|
175
255
|
const cfgPath = args.config ? path.resolve(args.config) : DEFAULT_CONFIG;
|
|
176
|
-
|
|
256
|
+
// Determine profile name: from command line argument (second in flags._) or from config's defaultProfile
|
|
257
|
+
let profileName = null;
|
|
258
|
+
if (args._ && args._.length > 1) {
|
|
259
|
+
// args._ is ['start', 'profileName', ...] after parseFlags? Actually parseFlags puts non-flag args in _.
|
|
260
|
+
// We'll instead use a different approach: we'll reparse the original argv in the main function.
|
|
261
|
+
// For now, we'll rely on the main function to pass profileName via args.profile.
|
|
262
|
+
// We'll change the main function later.
|
|
263
|
+
}
|
|
264
|
+
// We'll change the approach: let's rework the main function to pass profileName as an argument.
|
|
265
|
+
// For now, we'll keep it simple and assume no profile argument and later update.
|
|
266
|
+
// Let's revert and do a different plan: we'll edit the main function to handle extra args.
|
|
267
|
+
// Given the complexity, let's stop and do a fresh edit of the whole cli.js?
|
|
268
|
+
// Instead, let's do it step by step: we'll change the main function to capture the profile argument for start and setup.
|
|
269
|
+
// We'll do that in the next edit.
|
|
270
|
+
// For now, we'll leave cmdStart as is and just update the loadConfig to use defaultProfile.
|
|
271
|
+
// We'll then update the main function to pass profileName via args.
|
|
272
|
+
// Let's do that now.
|
|
273
|
+
// We'll change the main function to set args.profile for start and setup.
|
|
274
|
+
// But we are in the middle of editing cli.js, so we can edit the main function too.
|
|
275
|
+
// Let's edit the main function after the parseFlags.
|
|
276
|
+
// We'll do that in the next edit.
|
|
277
|
+
// For now, we'll just update loadConfig to return the default profile when no profileName is given.
|
|
278
|
+
// And then we'll update the main function to set args.profile for start and setup.
|
|
279
|
+
// Let's continue with the current edit of cmdStart by assuming we will get args.profile from the main function.
|
|
280
|
+
// We'll change the function signature to accept args that may have a profile property.
|
|
281
|
+
// We'll change the call in the main function later.
|
|
282
|
+
// For now, let's just update the function to use args.profile if present, otherwise default.
|
|
283
|
+
const profileArg = args.profile;
|
|
284
|
+
const cfg = loadProfile(cfgPath, profileArg); // loadProfile now takes profileName
|
|
177
285
|
if (cfg.logFile && !path.isAbsolute(cfg.logFile)) cfg.logFile = path.join(HOME_DIR, cfg.logFile);
|
|
178
286
|
const { makeServer } = require('./lib/server');
|
|
179
287
|
const server = makeServer(cfg);
|
|
180
288
|
const started = await server.start();
|
|
181
289
|
fs.writeFileSync(PID_FILE, String(process.pid));
|
|
290
|
+
// Also write the active profile to a file
|
|
291
|
+
const activeProfilePath = path.join(HOME_DIR, 'active_profile');
|
|
292
|
+
fs.writeFileSync(activeProfilePath, profileArg || cfg._defaultProfile || (cfg._profiles && cfg._profiles[0]?.providerName));
|
|
182
293
|
console.log('pid ' + process.pid + ' written to ' + PID_FILE);
|
|
183
294
|
console.log('Health: http://127.0.0.1:' + started + '/health');
|
|
184
295
|
const shutdown = async () => {
|
|
185
296
|
await server.stop();
|
|
186
297
|
try { fs.unlinkSync(PID_FILE); } catch {}
|
|
298
|
+
try { fs.unlinkSync(activeProfilePath); } catch {}
|
|
187
299
|
process.exit(0);
|
|
188
300
|
};
|
|
189
301
|
process.on('SIGINT', shutdown);
|
|
@@ -273,6 +385,52 @@ async function cmdAutostart(mode) {
|
|
|
273
385
|
}
|
|
274
386
|
}
|
|
275
387
|
|
|
388
|
+
async function cmdSelect(profileName, args) {
|
|
389
|
+
ensureHomeDir();
|
|
390
|
+
const cfgPath = args && args.config ? path.resolve(args.config) : DEFAULT_CONFIG;
|
|
391
|
+
if (!fs.existsSync(cfgPath)) fail('no config at ' + cfgPath + ' — run "anthropic-gateway setup" first');
|
|
392
|
+
let cfg;
|
|
393
|
+
try {
|
|
394
|
+
cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
395
|
+
} catch (e) {
|
|
396
|
+
fail('failed to parse config at ' + cfgPath);
|
|
397
|
+
}
|
|
398
|
+
// Ensure we are dealing with the new profiles format
|
|
399
|
+
if (!Array.isArray(cfg.profiles)) {
|
|
400
|
+
fail('config is in legacy format; please run setup again to migrate to profiles format');
|
|
401
|
+
}
|
|
402
|
+
const profileIndex = cfg.profiles.findIndex(p => p.providerName === profileName);
|
|
403
|
+
if (profileIndex === -1) {
|
|
404
|
+
fail('profile "' + profileName + '" not found in ' + cfgPath + ' (available: ' + cfg.profiles.map(p => p.providerName).join(', ') + ')');
|
|
405
|
+
}
|
|
406
|
+
cfg.defaultProfile = profileName;
|
|
407
|
+
fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
|
|
408
|
+
console.log('defaultProfile set to "' + profileName + '" in ' + cfgPath);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async function cmdSelect(profileName, args) {
|
|
412
|
+
ensureHomeDir();
|
|
413
|
+
const cfgPath = args && args.config ? path.resolve(args.config) : DEFAULT_CONFIG;
|
|
414
|
+
if (!fs.existsSync(cfgPath)) fail('no config at ' + cfgPath + ' — run "anthropic-gateway setup" first');
|
|
415
|
+
let cfg;
|
|
416
|
+
try {
|
|
417
|
+
cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
418
|
+
} catch (e) {
|
|
419
|
+
fail('failed to parse config at ' + cfgPath);
|
|
420
|
+
}
|
|
421
|
+
// Ensure we are dealing with the new profiles format
|
|
422
|
+
if (!Array.isArray(cfg.profiles)) {
|
|
423
|
+
fail('config is in legacy format; please run setup again to migrate to profiles format');
|
|
424
|
+
}
|
|
425
|
+
const profileIndex = cfg.profiles.findIndex(p => p.providerName === profileName);
|
|
426
|
+
if (profileIndex === -1) {
|
|
427
|
+
fail('profile "' + profileName + '" not found in ' + cfgPath + ' (available: ' + cfg.profiles.map(p => p.providerName).join(', ') + ')');
|
|
428
|
+
}
|
|
429
|
+
cfg.defaultProfile = profileName;
|
|
430
|
+
fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
|
|
431
|
+
console.log('defaultProfile set to "' + profileName + '" in ' + cfgPath);
|
|
432
|
+
}
|
|
433
|
+
|
|
276
434
|
function parseFlags(argv) {
|
|
277
435
|
const out = {};
|
|
278
436
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -309,11 +467,12 @@ function parseFlags(argv) {
|
|
|
309
467
|
'',
|
|
310
468
|
'usage:',
|
|
311
469
|
' anthropic-gateway setup [--provider kilo|openai|custom] [--base-url URL] [--api-key KEY] [--model ID] [--port N] [--token TOK] [--full-logging] [--yes]',
|
|
312
|
-
' anthropic-gateway start',
|
|
470
|
+
' anthropic-gateway start [profile] # if profile omitted, uses defaultProfile',
|
|
313
471
|
' anthropic-gateway stop',
|
|
314
472
|
' anthropic-gateway status',
|
|
315
473
|
' anthropic-gateway fulllogging on|off # log full request/response bodies to the log file (restart to apply)',
|
|
316
474
|
' anthropic-gateway autostart on|off',
|
|
475
|
+
' anthropic-gateway select <profile> # set defaultProfile for future start commands',
|
|
317
476
|
' anthropic-gateway version # or: --version, -v',
|
|
318
477
|
].join('\n')
|
|
319
478
|
);
|
|
@@ -324,10 +483,16 @@ function parseFlags(argv) {
|
|
|
324
483
|
process.exit(0);
|
|
325
484
|
}
|
|
326
485
|
if (cmd === 'setup') await cmdSetup(flags);
|
|
327
|
-
else if (cmd === 'start')
|
|
486
|
+
else if (cmd === 'start') {
|
|
487
|
+
// If a profile name is provided as the second argument (after 'start'), use it
|
|
488
|
+
const profileName = flags._ && flags._.length > 1 ? flags._[1] : undefined;
|
|
489
|
+
flags.profile = profileName;
|
|
490
|
+
await cmdStart(flags);
|
|
491
|
+
}
|
|
328
492
|
else if (cmd === 'stop') await cmdStop();
|
|
329
493
|
else if (cmd === 'status') await cmdStatus(flags);
|
|
330
494
|
else if (cmd === 'fulllogging') await cmdFullLogging(flags._[1], flags);
|
|
331
495
|
else if (cmd === 'autostart') await cmdAutostart(flags._[1]);
|
|
496
|
+
else if (cmd === 'select') await cmdSelect(flags._[1], flags);
|
|
332
497
|
else fail('unknown command: ' + cmd);
|
|
333
498
|
})();
|
package/config.example.json
CHANGED
|
@@ -1,21 +1,47 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
2
|
+
"defaultProfile": "kilo",
|
|
3
|
+
"profiles": [
|
|
4
|
+
{
|
|
5
|
+
"providerName": "kilo",
|
|
6
|
+
"upstreamBaseUrl": "https://kilo.imedata.ir/v1",
|
|
7
|
+
"upstreamApiKey": "<YOUR-PROVIDER-API-KEY>",
|
|
8
|
+
"upstreamModel": "kilo-auto/free",
|
|
9
|
+
"port": 3080,
|
|
10
|
+
"proxyTokens": [
|
|
11
|
+
"<YOUR-PROXY-TOKEN>"
|
|
12
|
+
],
|
|
13
|
+
"toolFormat": "native",
|
|
14
|
+
"fullLogging": false,
|
|
15
|
+
"advertisedModels": [
|
|
16
|
+
"claude-sonnet-4-5",
|
|
17
|
+
"claude-haiku-4-5",
|
|
18
|
+
"claude-opus-4-5",
|
|
19
|
+
"sonnet",
|
|
20
|
+
"haiku",
|
|
21
|
+
"opus"
|
|
22
|
+
],
|
|
23
|
+
"logFile": "gateway.log"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"providerName": "openai",
|
|
27
|
+
"upstreamBaseUrl": "https://api.openai.com/v1",
|
|
28
|
+
"upstreamApiKey": "<YOUR-OPENAI-API-KEY>",
|
|
29
|
+
"upstreamModel": "gpt-4o",
|
|
30
|
+
"port": 3081,
|
|
31
|
+
"proxyTokens": [
|
|
32
|
+
"<YOUR-PROXY-TOKEN>"
|
|
33
|
+
],
|
|
34
|
+
"toolFormat": "native",
|
|
35
|
+
"fullLogging": false,
|
|
36
|
+
"advertisedModels": [
|
|
37
|
+
"claude-sonnet-4-5",
|
|
38
|
+
"claude-haiku-4-5",
|
|
39
|
+
"claude-opus-4-5",
|
|
40
|
+
"sonnet",
|
|
41
|
+
"haiku",
|
|
42
|
+
"opus"
|
|
43
|
+
],
|
|
44
|
+
"logFile": "gateway.log"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anthropic-gateway",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Anthropic-compatible local gateway for any OpenAI-compatible model provider — make Claude Code (GUI/CLI) work with kilo, OpenAI, DeepSeek, local models, etc.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": {
|