bizrouter 0.3.3 → 0.3.4
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/AGENT_MANUAL.md +9 -2
- package/README.md +5 -2
- package/dist/commands/console.js +18 -2
- package/dist/commands/misc.js +1 -1
- package/dist/commands/models.js +1 -1
- package/dist/commands/setup.js +15 -3
- package/dist/harness/claude.js +61 -14
- package/dist/index.js +13 -4
- package/package.json +1 -1
package/AGENT_MANUAL.md
CHANGED
|
@@ -186,8 +186,15 @@ server named `bizrouter` inside Claude Code, Codex and OpenCode for that run
|
|
|
186
186
|
and `bizrouter_search` with the same rules as above — `bizrouter_api` refuses
|
|
187
187
|
mutating calls unless `confirm: true` is passed after the user agreed.
|
|
188
188
|
|
|
189
|
-
Claude Code
|
|
190
|
-
|
|
189
|
+
Claude Code runs any chat model in the catalog. Its `/model` picker lists
|
|
190
|
+
Claude models by their code and every other chat model as
|
|
191
|
+
`claude-code/<code>` (Claude Code only shows ids containing `claude` or
|
|
192
|
+
`anthropic`); `--model <code>` without the prefix works too. 1M-window models
|
|
193
|
+
carry Claude Code's `[1m]` marker so it accounts for the full window. On a
|
|
194
|
+
non-Anthropic model the gateway drops the Anthropic-only hints Claude Code
|
|
195
|
+
always sends (`cache_control`, `thinking`, `context_management`, earlier
|
|
196
|
+
thinking blocks) and reports dropped breakpoints in
|
|
197
|
+
`x-bizrouter-cache-control-dropped`.
|
|
191
198
|
|
|
192
199
|
## 7a. BizRouter Search — answers grounded in live data
|
|
193
200
|
|
package/README.md
CHANGED
|
@@ -26,15 +26,18 @@ bizrouter hermes # Hermes
|
|
|
26
26
|
|
|
27
27
|
| 도구 | 실행 시 하는 일 | 설정 파일 변경 |
|
|
28
28
|
| --- | --- | --- |
|
|
29
|
-
| Claude Code | `ANTHROPIC_BASE_URL=https://api.bizrouter.ai/claude`, 토큰, 빈 `ANTHROPIC_API_KEY`, 모델 선택창 자동
|
|
29
|
+
| Claude Code | `ANTHROPIC_BASE_URL=https://api.bizrouter.ai/claude`, 토큰, 빈 `ANTHROPIC_API_KEY`, 모델 선택창 자동 채움(이 키로 쓸 수 있는 채팅 모델 전체)을 넘기고, 사용자 settings.json의 다른 게이트웨이 설정이 이기지 못하도록 명령행 settings로 고정 | 없음 |
|
|
30
30
|
| Codex CLI | `-c` 오버라이드로 BizRouter provider(Responses API)와 모델·추론 강도 지정 | 없음 |
|
|
31
31
|
| OpenCode | `OPENCODE_CONFIG_CONTENT`로 이 키가 쓸 수 있는 모델 전체가 담긴 `bizrouter` provider를 주입 | 없음 |
|
|
32
32
|
| Hermes | `custom` provider(`CUSTOM_BASE_URL`/`CUSTOM_API_KEY`)와 모델을 이번 실행에만 지정 | 없음 |
|
|
33
33
|
|
|
34
34
|
도구는 평소처럼 실행됩니다. 바뀌는 것은 그 실행에서 모델을 호출하는 주소와 인증뿐이어서, 화면과 사용법은 같고 과금·모델 정책·감사 로그는 BizRouter 콘솔에 남습니다. `bizrouter` 없이 실행하면 평소대로 동작합니다. 우리 옵션 뒤의 인자는 도구에 그대로 전달됩니다.
|
|
35
35
|
|
|
36
|
+
Claude Code는 컨텍스트 창 크기를 모델 ID의 `[1m]` 마커로만 판단합니다(모델 목록의 `context_length`는 무시). 그래서 `bizrouter claude`는 모델을 지정하지 않으면 이 키가 쓸 수 있는 1M 컨텍스트 Claude 모델(Sonnet 우선)을 `ANTHROPIC_MODEL=<모델>[1m]`으로 넘기고, 직접 지정한 1M 모델에도 마커를 붙입니다. 200k 모델에는 붙이지 않습니다. 1M 입력은 표준 단가로 과금됩니다.
|
|
37
|
+
|
|
36
38
|
```bash
|
|
37
39
|
bizrouter claude --model anthropic/claude-opus-5 -p "실패하는 테스트 고쳐줘"
|
|
40
|
+
bizrouter claude --model bizrouter/glm-5.3 # GPT·Gemini·GLM·Kimi 등 이 키가 쓸 수 있는 모든 채팅 모델
|
|
38
41
|
bizrouter codex --model openai/gpt-5.5 --reasoning-effort high exec "README 요약해줘"
|
|
39
42
|
bizrouter opencode --model google/gemini-3.5-pro
|
|
40
43
|
bizrouter claude --dry-run # 실행 대신 넘겨줄 환경 변수와 명령을 보여줍니다
|
|
@@ -93,7 +96,7 @@ bizrouter auth / logout / env / update
|
|
|
93
96
|
|
|
94
97
|
## 알아둘 것
|
|
95
98
|
|
|
96
|
-
- Claude Code
|
|
99
|
+
- Claude Code에서도 이 키가 쓸 수 있는 채팅 모델 전체를 씁니다. `/model` 선택창에는 Claude 모델은 그대로, 나머지는 `claude-code/` 접두를 붙여(예: `claude-code/bizrouter/glm-5.3[1m]`) 나타나고, `--model`이나 `/model`에는 접두 없는 카탈로그 ID를 그대로 써도 됩니다. Claude 외 모델로 갈 때 게이트웨이가 Claude Code가 항상 보내는 Anthropic 전용 힌트(`cache_control`, `thinking`, `context_management`, 이전 턴 thinking 블록)를 떼어 내며, 뗀 `cache_control` 개수는 응답 헤더 `x-bizrouter-cache-control-dropped`로 알립니다. 1M 컨텍스트 모델에는 `[1m]`을 붙여 Claude Code가 200k로 잘못 계산하지 않게 합니다.
|
|
97
100
|
- 콘솔 세션은 로그인한 사용자의 권한(owner/member)을 그대로 따릅니다. 구성원(member)은 자기 API 키와 사용량만 다룰 수 있습니다.
|
|
98
101
|
- API 키(`sk-br-v1-…`)의 권한은 예전과 같습니다. 모델 호출만 되고, 콘솔 관리는 브라우저에서 승인한 사람의 콘솔 세션으로만 됩니다. 범위는 그 사람이 웹 콘솔에서 할 수 있는 일과 같습니다.
|
|
99
102
|
- 콘솔의 「사용량 조회 API」 키는 별개의 읽기 전용 키입니다. CLI는 쓰지도 바꾸지도 않습니다.
|
package/dist/commands/console.js
CHANGED
|
@@ -382,10 +382,25 @@ export async function orgCommand(argv) {
|
|
|
382
382
|
}
|
|
383
383
|
}
|
|
384
384
|
const AUDIT_USAGE = [
|
|
385
|
-
'bizrouter audit list [--status success|
|
|
385
|
+
'bizrouter audit list [--status success|failure] [--response-type normal|sensitive|blocked] [--model ID] [--key 이름] [--app 이름] [--user 이메일|이름] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--search 텍스트] [--limit N] [--cursor C] [--json]',
|
|
386
386
|
'bizrouter audit show <log_id> [--json]',
|
|
387
387
|
'bizrouter audit stats [--json]',
|
|
388
388
|
].join('\n');
|
|
389
|
+
// 서버 감사 로그의 실제 값 (RequestLog.STATUS_CHOICES / RESPONSE_TYPE_CHOICES).
|
|
390
|
+
// 예전 도움말이 `--status error|blocked`를 안내해 0행을 조용히 돌려주는 원인이었다.
|
|
391
|
+
const AUDIT_STATUS_VALUES = ['success', 'failure'];
|
|
392
|
+
const AUDIT_RESPONSE_TYPE_VALUES = ['normal', 'sensitive', 'blocked'];
|
|
393
|
+
export function auditFlagValue(parsed, name, allowed, label) {
|
|
394
|
+
const value = flagString(parsed, name);
|
|
395
|
+
if (value === undefined)
|
|
396
|
+
return undefined;
|
|
397
|
+
if (!allowed.includes(value)) {
|
|
398
|
+
throw new CliError(`--${name} 값은 ${allowed.join('|')} 중 하나여야 합니다. (입력: ${value})`, {
|
|
399
|
+
hint: `${label}에 --response-type을 쓰는 것과 헷갈리지 마십시오. 감사 로그의 status는 요청 성패(success|failure)이고, 차단 여부는 response_type(blocked)입니다.`,
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
return value;
|
|
403
|
+
}
|
|
389
404
|
export async function auditCommand(argv) {
|
|
390
405
|
const parsed = parseArgs(argv);
|
|
391
406
|
const [sub, ...rest] = parsed.positional;
|
|
@@ -395,7 +410,8 @@ export async function auditCommand(argv) {
|
|
|
395
410
|
const from = flagString(parsed, 'from');
|
|
396
411
|
const to = flagString(parsed, 'to');
|
|
397
412
|
const data = await get('/audit-logs/', {
|
|
398
|
-
status:
|
|
413
|
+
status: auditFlagValue(parsed, 'status', AUDIT_STATUS_VALUES, '--status'),
|
|
414
|
+
response_type: auditFlagValue(parsed, 'response-type', AUDIT_RESPONSE_TYPE_VALUES, '--response-type'),
|
|
399
415
|
model: flagString(parsed, 'model'),
|
|
400
416
|
api_key: flagString(parsed, 'key'),
|
|
401
417
|
app_name: flagString(parsed, 'app'),
|
package/dist/commands/misc.js
CHANGED
|
@@ -2,7 +2,7 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { ENV_KEY_NAME } from '../config.js';
|
|
3
3
|
import { c, info, print } from '../ui.js';
|
|
4
4
|
import { requireApiKey } from './shared.js';
|
|
5
|
-
export const VERSION = '0.3.
|
|
5
|
+
export const VERSION = '0.3.4';
|
|
6
6
|
/** `eval "$(bizrouter env)"` exports the saved key for tools configured by `bizrouter setup`. */
|
|
7
7
|
export function envCommand() {
|
|
8
8
|
const key = requireApiKey();
|
package/dist/commands/models.js
CHANGED
|
@@ -52,7 +52,7 @@ export async function modelsCommand(argv) {
|
|
|
52
52
|
}
|
|
53
53
|
print();
|
|
54
54
|
print(c.dim(`${rows.length}개 · 원화 단가는 100만 토큰당 · 환율 ${catalog.exchange_rate}원/달러 · ${catalog.from_cache ? '캐시(최대 10분)' : '지금 조회'}`));
|
|
55
|
-
print(c.dim('예: bizrouter codex --model openai/gpt-5.5 · bizrouter claude --model anthropic/claude-opus-5'));
|
|
55
|
+
print(c.dim('예: bizrouter codex --model openai/gpt-5.5 · bizrouter claude --model anthropic/claude-opus-5 · bizrouter claude --model bizrouter/glm-5.3'));
|
|
56
56
|
print(c.dim('Search: 어느 채팅 모델이든 뒤에 :search 를 붙이면 실제 데이터를 조회해 답합니다 (예: bizrouter search "질문" --model openai/gpt-5.5)'));
|
|
57
57
|
return 0;
|
|
58
58
|
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -4,7 +4,7 @@ import { dirname, join } from 'node:path';
|
|
|
4
4
|
import { fetchCatalog } from '../api.js';
|
|
5
5
|
import { pickDefaultModel, FALLBACK_DEFAULT } from '../catalog.js';
|
|
6
6
|
import { apiBase, ENV_KEY_NAME } from '../config.js';
|
|
7
|
-
import { claudeEnv } from '../harness/claude.js';
|
|
7
|
+
import { catalogCodeOf, claudeEnv, claudeModelArg, defaultClaudeModel, ONE_MILLION_CONTEXT_MARKER } from '../harness/claude.js';
|
|
8
8
|
import { CODEX_PROVIDER_ID } from '../harness/codex.js';
|
|
9
9
|
import { OPENCODE_PROVIDER_ID, opencodeProvider } from '../harness/opencode.js';
|
|
10
10
|
import { c, CliError, info, ok, print, warn } from '../ui.js';
|
|
@@ -119,8 +119,19 @@ export async function setupCommand(argv) {
|
|
|
119
119
|
const apiKey = requireApiKey();
|
|
120
120
|
const base = apiBase();
|
|
121
121
|
if (target === 'claude') {
|
|
122
|
+
// ADR-0031: pin a model so plain `claude` runs on the 1M window. The
|
|
123
|
+
// --model value, else the model already in settings.json, keeps its choice
|
|
124
|
+
// and gets `[1m]` only when the catalog lists it as a 1M model.
|
|
122
125
|
const path = claudeSettingsPath();
|
|
123
|
-
const
|
|
126
|
+
const existing = readJsonObject(path);
|
|
127
|
+
const chosen = pinned ?? (typeof existing.model === 'string' ? existing.model : undefined);
|
|
128
|
+
const catalog = await fetchCatalog(apiKey, { allowStale: true }).catch(() => undefined);
|
|
129
|
+
const claudeModel = chosen
|
|
130
|
+
? claudeModelArg(chosen, catalog?.models.find((m) => m.id === catalogCodeOf(chosen))?.context_length)
|
|
131
|
+
: defaultClaudeModel(catalog?.models);
|
|
132
|
+
const next = mergeClaudeSettings(existing, claudeEnv({ apiKey, apiBase: base, closedNetwork: false }));
|
|
133
|
+
if (claudeModel)
|
|
134
|
+
next.model = claudeModel;
|
|
124
135
|
const text = `${JSON.stringify(next, null, 2)}\n`;
|
|
125
136
|
if (dryRun) {
|
|
126
137
|
print(text);
|
|
@@ -128,7 +139,8 @@ export async function setupCommand(argv) {
|
|
|
128
139
|
}
|
|
129
140
|
const bak = backup(path);
|
|
130
141
|
writeText(path, text);
|
|
131
|
-
|
|
142
|
+
const modelNote = claudeModel ? ` 기본 모델은 ${claudeModel}${claudeModel.endsWith(ONE_MILLION_CONTEXT_MARKER) ? '(1M 컨텍스트)' : ''}입니다.` : '';
|
|
143
|
+
ok(`${path}의 env 블록에 BizRouter 설정을 넣었습니다.${modelNote}${bak ? ` (백업: ${bak})` : ''}`);
|
|
132
144
|
warn('이 파일에는 API 키가 그대로 저장됩니다. 저장소에 커밋되는 프로젝트 .claude/settings.json이 아니라 사용자 설정이라 안전하지만, 기기를 공유한다면 `bizrouter claude` 실행 방식을 권장합니다.');
|
|
133
145
|
info('이제 `claude`만 실행해도 BizRouter로 연결됩니다. 되돌리려면 백업 파일을 복원하세요.');
|
|
134
146
|
return 0;
|
package/dist/harness/claude.js
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import { unlinkSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
+
import { chatModels } from '../api.js';
|
|
3
4
|
import { hasFlag } from '../args.js';
|
|
4
|
-
import { isAnthropicModelId } from '../catalog.js';
|
|
5
5
|
import { ensureTmpDir } from '../config.js';
|
|
6
|
-
import { CliError } from '../ui.js';
|
|
7
6
|
import { claudeMcpConfig } from './mcp.js';
|
|
7
|
+
/** Claude Code's own marker for a 1M context window; it strips it before sending. */
|
|
8
|
+
export const ONE_MILLION_CONTEXT_MARKER = '[1m]';
|
|
9
|
+
/** Prefix the gateway's Claude Code discovery surface puts on non-Anthropic catalog codes. */
|
|
10
|
+
export const CLAUDE_CODE_MODEL_ALIAS_PREFIX = 'claude-code/';
|
|
11
|
+
const ONE_MILLION_CONTEXT_TOKENS = 1_000_000;
|
|
12
|
+
/**
|
|
13
|
+
* The catalog code behind a model id as Claude Code's `/model` picker shows it
|
|
14
|
+
* (`claude-code/<code>[1m]`). Mirrors the gateway's
|
|
15
|
+
* `normalize_claude_code_surface_model`, so catalog lookups accept whatever the
|
|
16
|
+
* user copied from the picker.
|
|
17
|
+
*/
|
|
18
|
+
export function catalogCodeOf(model) {
|
|
19
|
+
let code = model.trim();
|
|
20
|
+
if (code.endsWith(ONE_MILLION_CONTEXT_MARKER))
|
|
21
|
+
code = code.slice(0, -ONE_MILLION_CONTEXT_MARKER.length).trimEnd();
|
|
22
|
+
if (code.startsWith(CLAUDE_CODE_MODEL_ALIAS_PREFIX))
|
|
23
|
+
code = code.slice(CLAUDE_CODE_MODEL_ALIAS_PREFIX.length);
|
|
24
|
+
return code;
|
|
25
|
+
}
|
|
8
26
|
/**
|
|
9
27
|
* Environment Claude Code needs to talk to BizRouter. Mirrors what the
|
|
10
28
|
* integration guide documents; `ANTHROPIC_API_KEY` must be present and empty
|
|
@@ -21,19 +39,43 @@ export function claudeEnv(options) {
|
|
|
21
39
|
env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
|
|
22
40
|
return env;
|
|
23
41
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
42
|
+
/**
|
|
43
|
+
* The `--model` value Claude Code receives. Any BizRouter catalog id works on
|
|
44
|
+
* the gateway (`/claude/v1/messages` converts non-Anthropic models and drops
|
|
45
|
+
* the Anthropic-only hints Claude Code always sends); this only appends the
|
|
46
|
+
* `[1m]` marker for a 1M-window model so Claude Code does not compact five
|
|
47
|
+
* times too early.
|
|
48
|
+
*/
|
|
49
|
+
export function claudeModelArg(model, contextLength) {
|
|
50
|
+
if (model.endsWith(ONE_MILLION_CONTEXT_MARKER))
|
|
51
|
+
return model;
|
|
52
|
+
if (contextLength !== undefined && contextLength >= ONE_MILLION_CONTEXT_TOKENS)
|
|
53
|
+
return `${model}${ONE_MILLION_CONTEXT_MARKER}`;
|
|
54
|
+
return model;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* ADR-0031: the `[1m]`-marked Claude model to default to when the user pinned
|
|
58
|
+
* nothing, so a bare `bizrouter claude` session is accounted against the 1M
|
|
59
|
+
* window instead of Claude Code's 200k fallback. Sonnet first (the same
|
|
60
|
+
* family the other harnesses default to), then any 1M Claude model. Undefined
|
|
61
|
+
* when the catalog is unavailable or lists no 1M Claude model, leaving Claude
|
|
62
|
+
* Code's own alias defaults in place.
|
|
63
|
+
*/
|
|
64
|
+
export function defaultClaudeModel(models) {
|
|
65
|
+
const oneM = chatModels(models ?? []).filter((m) => m.id.startsWith('anthropic/claude-') && m.context_length >= ONE_MILLION_CONTEXT_TOKENS);
|
|
66
|
+
const found = oneM.find((m) => m.id.startsWith('anthropic/claude-sonnet')) ?? oneM[0];
|
|
67
|
+
return found ? claudeModelArg(found.id, found.context_length) : undefined;
|
|
30
68
|
}
|
|
31
69
|
export function buildClaudePlan(options) {
|
|
32
|
-
if (options.model)
|
|
33
|
-
assertClaudeModel(options.model);
|
|
34
70
|
const env = claudeEnv(options);
|
|
35
71
|
const args = [];
|
|
36
72
|
let cleanup;
|
|
73
|
+
const model = options.model ? claudeModelArg(options.model, options.modelContextLength) : undefined;
|
|
74
|
+
// The default goes in the env, not argv: `--model` in passthrough or
|
|
75
|
+
// `/model` in the session still wins.
|
|
76
|
+
const injected = model ? undefined : defaultClaudeModel(options.models);
|
|
77
|
+
if (injected)
|
|
78
|
+
env.ANTHROPIC_MODEL = injected;
|
|
37
79
|
// A user-level settings.json `env` block outranks shell variables, so a
|
|
38
80
|
// stale ANTHROPIC_BASE_URL there would silently win. The command-line
|
|
39
81
|
// settings level beats every file, so we hand the same env block over as a
|
|
@@ -51,14 +93,19 @@ export function buildClaudePlan(options) {
|
|
|
51
93
|
}
|
|
52
94
|
};
|
|
53
95
|
}
|
|
54
|
-
if (
|
|
55
|
-
args.push('--model',
|
|
96
|
+
if (model && !hasFlag(options.passthrough, '--model'))
|
|
97
|
+
args.push('--model', model);
|
|
56
98
|
if (options.mcp && !hasFlag(options.passthrough, '--mcp-config'))
|
|
57
99
|
args.push('--mcp-config', claudeMcpConfig(options.mcp));
|
|
58
100
|
args.push(...options.passthrough);
|
|
59
101
|
const notes = [
|
|
60
|
-
`Claude Code → ${env.ANTHROPIC_BASE_URL}` +
|
|
61
|
-
|
|
102
|
+
`Claude Code → ${env.ANTHROPIC_BASE_URL}` +
|
|
103
|
+
(model
|
|
104
|
+
? ` · 모델 ${model}`
|
|
105
|
+
: injected
|
|
106
|
+
? ` · 기본 모델 ${injected} (1M 컨텍스트)`
|
|
107
|
+
: ' · 모델은 Claude Code 기본값(sonnet/opus 별칭 자동 매핑)'),
|
|
108
|
+
'`/model` 선택창에 이 키로 쓸 수 있는 채팅 모델 전체가 채워집니다. Claude 외 모델은 `claude-code/` 접두로 표시되고, 1M 컨텍스트 모델에는 `[1m]`이 붙습니다.',
|
|
62
109
|
...(options.mcp ? ['콘솔 MCP 서버 「bizrouter」 를 이 세션에 연결합니다 (API 키·정책·통계 조작 · 끄기: --no-mcp).'] : []),
|
|
63
110
|
];
|
|
64
111
|
return { bin: 'claude', args, env, notes, cleanup };
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { isVirtualModelId, searchModelFor, stripSearchSuffix } from './search.js
|
|
|
16
16
|
import { setupCommand } from './commands/setup.js';
|
|
17
17
|
import { requireApiKey } from './commands/shared.js';
|
|
18
18
|
import { apiBase, loadUserConfig, resolveSession } from './config.js';
|
|
19
|
-
import { buildClaudePlan } from './harness/claude.js';
|
|
19
|
+
import { buildClaudePlan, catalogCodeOf } from './harness/claude.js';
|
|
20
20
|
import { buildCodexPlan, codexConfigPinsServiceTier } from './harness/codex.js';
|
|
21
21
|
import { codexConfigPath } from './commands/setup.js';
|
|
22
22
|
import { existsSync, readFileSync } from 'node:fs';
|
|
@@ -44,8 +44,8 @@ async function resolveModel(harness, args, apiKey) {
|
|
|
44
44
|
}
|
|
45
45
|
if (pinned) {
|
|
46
46
|
// `bizrouter/route`, `bizrouter/search` and `<id>:search` are policies layered on catalog rows, not rows themselves.
|
|
47
|
-
const lookup = stripSearchSuffix(pinned);
|
|
48
|
-
if (models.length && !isVirtualModelId(
|
|
47
|
+
const lookup = catalogCodeOf(stripSearchSuffix(pinned));
|
|
48
|
+
if (models.length && !isVirtualModelId(lookup) && !models.some((m) => m.id === lookup)) {
|
|
49
49
|
const suggestions = suggestModels(models, lookup);
|
|
50
50
|
warn(`「${pinned}」 는 이 키로 쓸 수 있는 모델 목록에 없습니다.${suggestions.length ? ` 비슷한 모델: ${suggestions.join(', ')}` : ''}`);
|
|
51
51
|
info('그대로 시도합니다. 키의 「API key 사용 범위」나 조직의 모델 정책이 막고 있으면 요청이 거절됩니다.');
|
|
@@ -93,7 +93,16 @@ async function launch(harness, argv) {
|
|
|
93
93
|
let plan;
|
|
94
94
|
switch (harness) {
|
|
95
95
|
case 'claude':
|
|
96
|
-
plan = buildClaudePlan({
|
|
96
|
+
plan = buildClaudePlan({
|
|
97
|
+
apiKey,
|
|
98
|
+
apiBase: base,
|
|
99
|
+
model,
|
|
100
|
+
modelContextLength: model ? models.find((m) => m.id === catalogCodeOf(model))?.context_length : undefined,
|
|
101
|
+
models,
|
|
102
|
+
closedNetwork: args.closedNetwork,
|
|
103
|
+
passthrough: args.passthrough,
|
|
104
|
+
mcp,
|
|
105
|
+
});
|
|
97
106
|
if (args.reasoningEffort)
|
|
98
107
|
warn('Claude Code는 추론 강도를 실행 옵션으로 받지 않습니다. 세션 안에서 /effort를 사용하세요.');
|
|
99
108
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bizrouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "BizRouter CLI - run Claude Code, Codex, OpenCode, and Hermes through BizRouter, operate the BizRouter console (API keys, usage, policies, audit logs) from the terminal or as an MCP server, and ask BizRouter Search for answers grounded in 50+ live data sources",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|